拆解GCC命令的预处理-编译-汇编-链接4个阶段

原文链接:http://blog.csdn.net/jmy5945hh/article/details/7435234


在linux下使用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帮我们一次性完成这四步。
但是偶尔需要查看预处理过程或者汇编代码,这些命令还是十分有用的。


猜你喜欢

转载自blog.csdn.net/doniexun/article/details/38324265