一个程序是怎样跑起来的(一)
2016-10-22 18:33
501 查看
找工作期间断断续续看了一些关于程序运行原理的东西,这里做个简单的小结。因为这方面还不熟悉,可能有些东西描述的不准确甚至有纰漏,还希望大家能及时指出。
首先看一下从一个我们编写的源代码程序到一个被电脑运行的程序需要几个步骤:
从这个转换图中可以看出,编译、装载、运行这三个步骤就是本文所描述的核心过程,中间会有部分内容涉及到对程序内容和进程的相关描述。
本文的源代码以main.c,head.h,func.c三个文件为例进行说明。
main.c
head.h
fun.c
理解了编译过程的作用,下面来详细看一下编译过程的具体细节。编译的过程可以分解为一下4个步骤:
预处理
编译
汇编
链接
针对我这里面的三个文件main.c,head.h,fun.c,整体的编译过程就是这样的:
下面详细说一下每一步的内容
1、预处理:
预处理过程主要处理源代码文件中以“#”开始的预编译指令,比如“#include”,“define”等等。特别说一下“#incldue”指令,它会把被包含的文件插入到该预编译指令的位置,而且这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。在gcc下,利用-E选项可以生成预处理后的文件。于是利用下面两条命令:
fun.i:
2、编译。编译过程是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后产生相应的汇编代码文件。这个过程往往是我们所说的整个程序构建的核心部分。我们可以用下面两条命令
main.s:
3、汇编。汇编过程就是利用汇编器,将汇编代码转变成机器可执行的指令,每一条汇编语句几乎都对应一条机器指令。我们用下面两条命令
4、链接。链接简单的理解就是将多个目标文件合并生成一个最终的可执行文件。在Linux下,这个最终的可执行文件也是一个ELF格式。命令如下
首先看一下从一个我们编写的源代码程序到一个被电脑运行的程序需要几个步骤:
从这个转换图中可以看出,编译、装载、运行这三个步骤就是本文所描述的核心过程,中间会有部分内容涉及到对程序内容和进程的相关描述。
本文的源代码以main.c,head.h,func.c三个文件为例进行说明。
main.c
#include<stdio.h> #include"head.h" int main(){ int a = 12; int b = 23; int c = add(a, b); printf("%d\n",c); return 0; }
head.h
int add(int a, int b);
fun.c
int add(int a, int b){ return (a + b); }
1、编译
再解释编译的过程之前,首先说明一下为什么要有编译这个过程。现在的计算机在执行的时候,其实只能识别机器语言(二进制形式),除了机器语言以外的东西计算机是完全看不懂的。当我们用高级语言编写好程序后,为了让我们的程序能够正常的被机器识别和执行,需要一个转换的过程来把我们用高级语言编写的程序转换为计算机能看懂的机器语言,这个过程就是编译的过程。理解了为什么需要编译过程,也就明白了编译的作用:编译过程就是把我们编写的源代码转换为机器可以识别的机器语言(二进制形式)。理解了编译过程的作用,下面来详细看一下编译过程的具体细节。编译的过程可以分解为一下4个步骤:
预处理
编译
汇编
链接
针对我这里面的三个文件main.c,head.h,fun.c,整体的编译过程就是这样的:
下面详细说一下每一步的内容
1、预处理:
预处理过程主要处理源代码文件中以“#”开始的预编译指令,比如“#include”,“define”等等。特别说一下“#incldue”指令,它会把被包含的文件插入到该预编译指令的位置,而且这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。在gcc下,利用-E选项可以生成预处理后的文件。于是利用下面两条命令:
gcc -E main.c -o main.i gcc -E fun.c -o fun.i生成预处理后的main.i文件和fun.i文件。你如果打开了main.i你会发现,单单是“#include<stdio.h>”一条,就会在main.c中插入几百行代码。
fun.i:
2、编译。编译过程是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后产生相应的汇编代码文件。这个过程往往是我们所说的整个程序构建的核心部分。我们可以用下面两条命令
gcc -S main.i -o main.s gcc -S fun.i -o fun.s产生编译的结果文件main.s 和 fun.s。这两个文件的内容现在完整的贴在下面,后面讲到运行的时候会更详细的分析他们。
main.s:
.file "main.c" 2 .section .rodata 3 .LC0: 4 .string "%d\n" 5 .text 6 .globl main 7 .type main, @function 8 main: 9 .LFB0: 10 .cfi_startproc 11 pushl %ebp 12 .cfi_def_cfa_offset 8 13 .cfi_offset 5, -8 14 movl %esp, %ebp 15 .cfi_def_cfa_register 5 16 andl $-16, %esp 17 subl $32, %esp 18 movl $12, 20(%esp) 19 movl $23, 24(%esp) 20 movl 24(%esp), %eax 21 movl %eax, 4(%esp) 22 movl 20(%esp), %eax 23 movl %eax, (%esp) 24 call add 25 movl %eax, 28(%esp) 26 movl 28(%esp), %eax 27 movl %eax, 4(%esp) 28 movl $.LC0, (%esp) 29 call printf 30 movl $0, %eax 31 leave 32 .cfi_restore 5 33 .cfi_def_cfa 4, 4 34 ret 35 .cfi_endproc 36 .LFE0: 37 .size main, .-main 38 .ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4" 39 .section .note.GNU-stack,"",@progbitsfun.s:
1 .file "fun.c" 2 .text 3 .globl add 4 .type add, @function 5 add: 6 .LFB0: 7 .cfi_startproc 8 pushl %ebp 9 .cfi_def_cfa_offset 8 10 .cfi_offset 5, -8 11 movl %esp, %ebp 12 .cfi_def_cfa_register 5 13 movl 12(%ebp), %eax 14 movl 8(%ebp), %edx 15 addl %edx, %eax 16 popl %ebp 17 .cfi_restore 5 18 .cfi_def_cfa 4, 4 19 ret 20 .cfi_endproc 21 .LFE0: 22 .size add, .-add 23 .ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4" 24 .section .note.GNU-stack,"",@progbits
3、汇编。汇编过程就是利用汇编器,将汇编代码转变成机器可执行的指令,每一条汇编语句几乎都对应一条机器指令。我们用下面两条命令
gcc -c main.s -o main.o gcc -c fun.s -o fun.o生成包含机器指令的文件。需要注意的是,汇编的结果就是机器指令了,不同于我们前两步可以用不同文本编辑器能够看到内容的普通文件,它们是二进制格式的文件,在Linux下,是一种ELF格式的文件。
4、链接。链接简单的理解就是将多个目标文件合并生成一个最终的可执行文件。在Linux下,这个最终的可执行文件也是一个ELF格式。命令如下
gcc main.o fun.o -o res这个res就是我们最终生成的可执行文件。
相关文章推荐
- 怎样写一个输出自己源代码的程序
- 一个难题: 怎样写一个输出自己源代码的程序?
- 怎样在程序中为Access表创建一个自动编号字段?
- 怎样用CMD命令将一个程序加到启动项中去
- 怎样判断一个运行的ASP.NET程序是 Degug模式还是Release模式
- 怎样实现一个程序是APP+APPWIDGET
- 怎样在Windows Mobile上设计一个美观的用户界面程序(Win32)
- 怎样在Windows Mobile上设计一个美观的用户界面程序(Win32)
- 怎样启动一个程序而不显示它
- 怎样使程序只运行一个实例
- vb怎样kill一个其它程序进程
- 怎样编写一个程序,把一个有序整数数组放到二叉树中? 编写实现链表排序的一种算法。说明为什么你会选择用这样的方法?
- 怎样在一个form里放两个submit按钮,按了以后分别提交到不同的程序
- [VB.NET]怎样才能用VB.NET的代码来关闭一个在运行的程序?????
- 菜鸟功略(怎样运行好一个HelloWorld程序)
- 怎样判断一个程序是用C编译程序还是用C++编译程序编译的?
- 怎样在一个单文档程序中添加树形控件
- 怎样在Windows Mobile(Win32编程)上设计一个美观的用户界面程序
- 怎样自动启动VC调试器调试被另外一个程序启动的程序
- 怎样在Windows Mobile上设计一个美观的用户界面程序(Win32)