GCC编译
GCC(英文全拼:GNU Compiler Collection)是 GNU 工具链的主要组成部分,是一套以 GPL 和 LGPL 许可证发布的程序语言编译器自由软件,由 Richard Stallman 于 1985 年开始开发。
GCC 原名为 GNU C语言编译器,因为它原本只能处理 C 语言,但如今的 GCC 不仅可以编译 C、C++ 和 Objective-C,还可以通过不同的前端模块支持各种语言,包括 Java、Fortran、Ada、Pascal、Go 和 D 语言等等。
GCC 的编译过程可以划分为四个阶段:预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)以及链接(Linking)。

#include <stdio.h>
#define HH 5
void foo(void)
{
printf("Here is a static library\n");
printf("%d\n",HH);
}
预处理
主要是处理程序中以#开头的预处理指令,将其转换后插入文本中。
gcc -e hello.c -o hello.i
- 递归处理#include预处理指令,将对应文件的内容复制到该处,出现了很多extern的函数原型
- 删除#define,并且在其被引用处递归地展开所有的宏定义
- 处理所有条件预处理指令 #if #ifdef
- 删除注释
- 添加行号和文件名标识

编译
gcc -S hello.c -o hello.s
gcc -S hello.i -o hello.s -masm= intel -fno-asynchronous-unwind-tables
-masm= intel用于指定为intel格式
-fno-asynchronous-unwind-tables 用于生成没有cfi宏的汇编指令,提高可读性
可以看到只有单个参数的printf被替换成puts了。
.file "hello.c"
.text
.section .rodata
.LC0:
.string "Here is a test of gcc"
.LC1:
.string "%d\n"
.text
.globl foo
.type foo, @function
foo:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
call puts@PLT
movl $5, %esi
leaq .LC1(%rip), %rdi
movl $0, %eax
call printf@PLT
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size foo, .-foo
.ident "GCC: (Debian 10.2.1-6) 10.2.1 20210110"
.section .note.GNU-stack,"",@progbits
汇编
汇编器根据汇编指定和机器指令对应的表进行翻译,生成目标文件。
gcc -c hello.c -o hello.o
gcc -c hello.s -o hello.o
此时hello.o是一个可重定位文件

使用objdump查看内容,可以发现此时由于没有链接,导致字符串的起始地址为0x0000,函数地址也用foo标识。
ocjdump -sd hello.o -M intel
hello.o: 文件格式 elf64-x86-64
Contents of section .text:
0000 554889e5 488d3d00 000000e8 00000000 UH..H.=.........
0010 be050000 00488d3d 00000000 b8000000 .....H.=........
0020 00e80000 0000905d c3 .......].
Contents of section .rodata:
0000 48657265 20697320 61207465 7374206f Here is a test o
0010 66206763 63002564 0a00 f gcc.%d..
Contents of section .comment:
0000 00474343 3a202844 65626961 6e203130 .GCC: (Debian 10
0010 2e322e31 2d362920 31302e32 2e312032 .2.1-6) 10.2.1 2
0020 30323130 31313000 0210110.
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001 .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000 ................
0020 00000000 29000000 00410e10 8602430d ....)....A....C.
0030 06640c07 08000000 .d......
Disassembly of section .text:
0000000000000000 <foo>:
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # b <foo+0xb>
b: e8 00 00 00 00 call 10 <foo+0x10>
10: be 05 00 00 00 mov esi,0x5
15: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # 1c <foo+0x1c>
1c: b8 00 00 00 00 mov eax,0x0
21: e8 00 00 00 00 call 26 <foo+0x26>
26: 90 nop
27: 5d pop rbp
28: c3 ret
链接
gcc默认使用动态链接,加入-static选项即可静态链接。将目标文件及其依赖库进行连接,生成可执行文件,主要包括 地址和空间分配,符号绑定,重定位。
gcc hello.o -o hello -static
由于使用静态链接,导致objdump后存在大量汇编指令

浙公网安备 33010602011771号