一、具体流程
一个简单C程序:
编辑 (编辑器)->预编译(预处理器)->编译->汇编 (汇编器)->链接 (链接器)->可执行代码
如下:
二、 流程分析
1.编辑
写一个循环打印"Hello World",使用编辑器编辑一个文件名为:helloworld.c的文件,内容如下:
源代码:
#include <stdio.h>
#define NUM 10
int main(int argc, char argv)
{
int num;
//print
for (num = 0; num < NUM; num++) {
printf("Hello World!\n");
}
return 0;
}
2.预编译
使用gcc来进行分析,执行
gcc -E helloworld.c -o helloworld.i
进行预编译,生成helloWorld.i的预编译文件,可以使用编辑器打开HelloWorld.i这个文件。在文件里可以看到预处理的内容,最后生成如下:
797 # 5 "helloworld.c"
798 int main(int argc, char argv)
799 {
800 int num;
801
802 for (num = 0; num < 10; num++) {
803 printf("Hello World!\n");
804 }
805
806 return 0;
807 }
可以看到NUM已经被替换成 10,而且注释已经被删除。
3.编译
gcc -S helloworld.i -o helloworld.s
这个时候已经生成了对应的汇编代。
打开helloworld.s :
.file "helloworld.c"
.text
.section .rodata
.LC0:
.string "Hello World!"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movl %esi, %eax
movb %al, -24(%rbp)
movl $0, -4(%rbp)
jmp .L2
.L3:
leaq .LC0(%rip), %rdi
call puts@PLT
addl $1, -4(%rbp)
.L2:
cmpl $9, -4(%rbp)
jle .L3
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0"
.section .note.GNU-stack,"",@progbits
4.编译
gcc -c helloworld.s -o helloworld.o
把汇编处理成机器指令,但是没有进行库函数链接,所以还不是执行文件。
-rw-r--r-- 1 zl zl 1576 1月 15 11:18 helloworld.o
打开helloworld.o,里面就是执行码。
5.链接
gcc helloworld.o -o helloworld
生成的helloworld这个文件就是二进制执行文件
-rwxr-xr-x 1 zl zl 8304 1月 15 11:27 helloworld*
直接执行该文件: