这个编译过程人人皆知,但是真正理解的却不多,好好收藏这篇好文章!!
现在我们看一下C 的编译过程
1. 预编译,
2. 编译生成汇编,
3. 汇编生成目标文件,
4. 目标文件连接库文件生成可执行文件,
这个过程人人都知道,但是究竟如何呢?
牢骚一下:太多的编译器都是一步到位,其实这对学习不是什么好事情,至少我觉得,在学习过程中把简单的东西弄的麻烦,在工作的过程中把麻烦的东西弄的简单。
这里的例子选自 lorne
预编译 gcc -E
编译 gcc -S 这两个有gcc rpm包就可以。
汇编as
连接ld 这两个需要安装binutils rpm包
1,预编译
编写c源程序game.c
#include
int main()
{
printf("Hello World!\n");
} 传说中的helloworld
gcc -E -o pregame game.c
这是会出现一个pregame文件
看看他是什么格式
file pregame
pregame: ASCII C program text
也就说预编译之后的文件仍然是c源代码。那么预编译作了些什么呢?
可以看看都有些什么玩意.
cat pregame
你会发现 pregame和game 差不多,区别是pregame中没有了#include也灭有类似的格式。
这就是预编译的作用他把game.c中包含的头文件加在main函数的上面.
gcc -o game game.c 生成 可执行程序 game
gcc -o pregame pregame.c 生成可执行程序pregame
注意:这两个命令,我们忽略了as和ld的步骤。
pregame最好用.c做为文件名
发现 game和pregame的运行结果一样,这也说明了预编译的作用.
总结一下预编译的作用:(这些是lorne大人总结的,与我无关)
1. 把"include"的文件拷贝到要编译的源文件中。
2. 用实际值替代"define"的文本。
3. 在调用宏的地方进行宏替换。
2.编译。
这个过程是用于生成汇编语言。这是编译过程的一步,是一步,是一步啊,同志们~~~~~~~~~~~~~~!!
gcc -S -o aspregame pregame.c
会声称一个aspregame文件,看看是什么东西?
file aspregame
aspregame: ASCII assembler program text
嘿嘿出现了,汇编程序文本.
有兴趣你可以看一下
cat aspregame
.file "pregame.c"
.section .rodata
.LC0:
.string "Hello World!"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
movl $.LC0, (%esp)
call puts
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.0 20060304 (Red Hat 4.1.0-3)"
.section .note.GNU-stack,"",@progbits
传说中的汇编。
最好用.asm作为文件名。
3.生成目标文件.
这一步我们可以用gcc来完成,但是还是用as吧,总觉得一步到位的东西,不是很适合学习。
as -o ldaspregame aspregame
会生成ldaspregame文件
看看他是什么?
file ldaspregame
ldaspregame: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
ELF格式的文件,浮动的,意思是这个程序的地址是可以被修改来适应初始地址,其实就是未连接的目标文件。
注意:我们可以把任何的一个.c文件通过gcc -S变成汇编,在把他变成目标文件。
最要用.o做为文件名
4.连接成为可执行文件
那么现在我们来生成可执行文件吧
这里要说明什么是动态链接库,相当于winxxx中的dll文件,在这里是so文件,ELF格式就是支持动态链接库的。
gcc -o exldaspregame ldaspregame
好了声称了可执行文件ldaspregame
任何一个.c文件都可以生成目标文件,他们需要被连接来执行