拆解GCC命令的预处理-编译-汇编-链接4个阶段
2012-04-07 15:40
387 查看
在linux下使用gcc命令编译程序时,整个过程实际上在底层处理分为四个步骤--预处理/编译/汇编/连接
下面通过gcc的不同命令参数来拆解这四个步骤。
源代码:hello.c
1/预处理(C预处理器)
打开预处理后的文件hello.i,发现已经与源文件大有不同。主要区别我在注释处说明。
2/编译(C编译器)
打开编译后的文件hello.s,所有语句均已替换为汇编语言,这对于嵌入式开发非常有用。
3/汇编(汇编器)
此时hello.s已经被编译为机器码hello.o,可以在vim中以二进制形式打开
也可以在终端使用命令查看.o文件中包括的函数
4/链接(连接器)
这样就最终生成了可执行文件hello
上面四步就是gcc生成可执行文件的全部步骤啦!
虽然我们常用的方式是直接让gcc帮我们一次性完成这四步
但是偶尔需要查看预处理过程或者汇编代码,这些命令还是十分有用的。
下面通过gcc的不同命令参数来拆解这四个步骤。
源代码:hello.c
#include <stdio.h> #define PP printf int main(int argc, char **argv) { int a = 5; PP("a = %d\n", a); return 0; }
1/预处理(C预处理器)
gcc -E hello.c -o hello.i//使用cpp命令
打开预处理后的文件hello.i,发现已经与源文件大有不同。主要区别我在注释处说明。
# 1 "hello.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "hello.c" # 1 "/usr/include/stdio.h" 1 3 4 # 28 "/usr/include/stdio.h" 3 4 .... extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__)); # 936 "/usr/include/stdio.h" 3 4 # 2 "hello.c" 2 //以上是插入的stdio.h头文件内容 int main(int argc, char **argv) { int a = 5; printf("a = %d\n", a); //此处,宏定义PP被替换为printf return 0; }
2/编译(C编译器)
gcc -S hello.i -o hello.s//使用cc1命令
打开编译后的文件hello.s,所有语句均已替换为汇编语言,这对于嵌入式开发非常有用。
.file "hello.c" .section .rodata .LC0: .string "a = %d\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $32, %esp movl $5, 28(%esp) movl $.LC0, %eax movl 28(%esp), %edx movl %edx, 4(%esp) movl %eax, (%esp) call printf movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1" .section .note.GNU-stack,"",@progbits
3/汇编(汇编器)
gcc -c hello.s -o hello.o//使用as命令
此时hello.s已经被编译为机器码hello.o,可以在vim中以二进制形式打开
0000000: 7f45 4c46 0101 0100 0000 0000 0000 0000 .ELF............ 0000010: 0100 0300 0100 0000 0000 0000 0000 0000 ................ 0000020: 3001 0000 0000 0000 3400 0000 0000 2800 0.......4.....(. 0000030: 0d00 0a00 553f 3f3f 3f3f 3f3f 203f 4424 ....U??????? ?D$ 0000040: 1c05 0000 003f 0000 0000 3f54 241c 3f54 .....?....?T$.?T 0000050: 2404 3f04 243f 3f3f 3f3f 3f00 0000 003f $.?.$??????....? 0000060: 3f00 0000 6120 3d20 2564 0a00 0047 4343 ?...a = %d...GCC 0000070: 3a20 2855 6275 6e74 752f 4c69 6e61 726f : (Ubuntu/Linaro 0000080: 2034 2e36 2e31 2d39 7562 756e 7475 3329 4.6.1-9ubuntu3) 0000090: 2034 2e36 2e31 0000 1400 0000 0000 0000 4.6.1.......... 00000a0: 017a 5200 017c 0801 1b0c 0404 3f01 0000 .zR..|......?... 00000b0: 1c00 0000 1c00 0000 0000 0000 2d00 0000 ............-... 00000c0: 0041 0e08 3f02 420d 0569 3f0c 0404 0000 .A..?.B..i?..... 00000d0: 002e 7379 6d74 6162 002e 7374 7274 6162 ..symtab..strtab 00000e0: 002e 7368 7374 7274 6162 002e 7265 6c2e ..shstrtab..rel. 00000f0: 7465 7874 002e 6461 7461 002e 6273 7300 text..data..bss. 0000100: 2e72 6f64 6174 6100 2e63 6f6d 6d65 6e74 .rodata..comment 0000110: 002e 6e6f 7465 2e47 4e55 2d73 7461 636b ..note.GNU-stack 0000120: 002e 7265 6c2e 6568 5f66 7261 6d65 0000 ..rel.eh_frame.. 0000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0000140: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0000150: 0000 0000 0000 0000 1f00 0000 0100 0000 ................ 0000160: 0600 0000 0000 0000 3400 0000 2d00 0000 ........4...-... 0000170: 0000 0000 0000 0000 0400 0000 0000 0000 ................ 0000180: 1b00 0000 0900 0000 0000 0000 0000 0000 ................ 0000190: 0004 0000 1000 0000 0b00 0000 0100 0000 ................ 00001a0: 0400 0000 0800 0000 2500 0000 0100 0000 ........%....... 00001b0: 0300 0000 0000 0000 6400 0000 0000 0000 ........d....... 00001c0: 0000 0000 0000 0000 0400 0000 0000 0000 ................ 00001d0: 2b00 0000 0800 0000 0300 0000 0000 0000 +............... 00001e0: 6400 0000 0000 0000 0000 0000 0000 0000 d............... 00001f0: 0400 0000 0000 0000 3000 0000 0100 0000 ........0....... 0000200: 0200 0000 0000 0000 6400 0000 0800 0000 ........d....... 0000210: 0000 0000 0000 0000 0100 0000 0000 0000 ................ 0000220: 3800 0000 0100 0000 3000 0000 0000 0000 8.......0....... 0000230: 6c00 0000 2b00 0000 0000 0000 0000 0000 l...+........... 0000240: 0100 0000 0100 0000 4100 0000 0100 0000 ........A....... 0000250: 0000 0000 0000 0000 3f00 0000 0000 0000 ........?....... 0000260: 0000 0000 0000 0000 0100 0000 0000 0000 ................ 0000270: 5500 0000 0100 0000 0200 0000 0000 0000 U............... 0000280: 3f00 0000 3800 0000 0000 0000 0000 0000 ?...8........... 0000290: 0400 0000 0000 0000 5100 0000 0900 0000 ........Q....... 00002a0: 0000 0000 0000 0000 1004 0000 0800 0000 ................ 00002b0: 0b00 0000 0800 0000 0400 0000 0800 0000 ................ 00002c0: 1100 0000 0300 0000 0000 0000 0000 0000 ................ 00002d0: 3f00 0000 5f00 0000 0000 0000 0000 0000 ?..._........... 00002e0: 0100 0000 0000 0000 0100 0000 0200 0000 ................ 00002f0: 0000 0000 0000 0000 3803 0000 3f00 0000 ........8...?... 0000300: 0c00 0000 0900 0000 0400 0000 1000 0000 ................ 0000310: 0900 0000 0300 0000 0000 0000 0000 0000 ................ 0000320: 3f03 0000 1500 0000 0000 0000 0000 0000 ?............... 0000330: 0100 0000 0000 0000 0000 0000 0000 0000 ................ 0000340: 0000 0000 0000 0000 0100 0000 0000 0000 ................ 0000350: 0000 0000 0400 3f3f 0000 0000 0000 0000 ......??........ 0000360: 0000 0000 0300 0100 0000 0000 0000 0000 ................ 0000370: 0000 0000 0300 0300 0000 0000 0000 0000 ................ 0000380: 0000 0000 0300 0400 0000 0000 0000 0000 ................ 0000390: 0000 0000 0300 0500 0000 0000 0000 0000 ................ 00003a0: 0000 0000 0300 0700 0000 0000 0000 0000 ................ 00003b0: 0000 0000 0300 0800 0000 0000 0000 0000 ................ 00003c0: 0000 0000 0300 0600 0900 0000 0000 0000 ................ 00003d0: 2d00 0000 1200 0100 0e00 0000 0000 0000 -............... 00003e0: 0000 0000 1000 0000 0068 656c 6c6f 2e63 .........hello.c 00003f0: 006d 6169 6e00 7072 696e 7466 0000 0000 .main.printf.... 0000400: 1200 0000 0105 0000 2200 0000 020a 0000 ........"....... 0000410: 2000 0000 0202 0000 0a ........
也可以在终端使用命令查看.o文件中包括的函数
jimmy@MyPet:~/code/learnc$ nm hello.o 00000000 T main U printf
4/链接(连接器)
gcc hello.o -o hello//使用ld命令
这样就最终生成了可执行文件hello
jimmy@MyPet:~$ ./hello a = 5
上面四步就是gcc生成可执行文件的全部步骤啦!
虽然我们常用的方式是直接让gcc帮我们一次性完成这四步
但是偶尔需要查看预处理过程或者汇编代码,这些命令还是十分有用的。
相关文章推荐
- 拆解GCC命令的预处理-编译-汇编-链接4个阶段
- Linux操作系统的简单指令及如何使用vim编写一个程序,然后使用gcc查看【预处理】、【编译】、【汇编】、【链接】各阶段文件的内容。
- gcc编译程序的四个阶段(预处理-编译-汇编-链接)
- gcc编译的四个阶段:预处理,编译,汇编,链接
- 1.2.在linux环境实践,使用vim编写一个程序,然后使用gcc查看【预处理】、【编译】、【汇编】、【链接】各阶段文件的内容。并熟悉相关指令。
- gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解
- GCC编译的背后( 预处理和编译 汇编和链接)
- GCC 预处理、编译、汇编、链接..
- GCC编译的四个过程 预处理 编译 汇编 链接
- gcc 的执行过程详解 预处理 编译 汇编 链接
- GCC编程四个过程:预处理-编译-汇编-链接
- GCC编程过程:预处理-编译-汇编-链接
- gcc——预处理(预编译),编译,汇编,链接
- GCC编译的背后( 预处理和编译 汇编和链接 )
- GCC编译的背后( 预处理和编译 汇编和链接 )
- gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解
- C语言预处理 编译 汇编 链接四个阶段
- [转]GCC编译的背后( 预处理和编译 汇编和链接 )
- gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接
- GCC编程四个过程:预处理-编译-汇编-链接