image.png
image.png
第一步:预处理
由预处理器cpp(C Pre-Processor)完成,主要工作是合并源文件和头文件,以及对以“#”开头的预编译指令和注释进行处理。
gcc hello.c > hello.i
第二步:编译
编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。这个过程相当复杂,但不是本文的重点。
gcc -S hello.i -o hello.s
第三步:汇编
汇编器将汇编代码转化成相应平台上的机器代码,得到.o目标文件。注意,目标文件还需要经过链接后才能执行。
as hello.s -o hello.o
第四步:链接
链接器将多个目标文件链接起来,输出一个可执行文件。链接是最复杂的一个过程,也是本文的重点。
使用以下命令来查看.o文件链接成可执行文件的过程:
gcc hello.o -o hello --verbose
image.png
image.png
静态
#include <stdio.h>
#include <unistd.h>
int g_var = 3;
int g_bss_var;
static int l_var = 5;
static int l_bss_var;
int add(int a, int b) {
return a+ b;
}
int main(int argc, char **argv) {
printf("hello world %d \n", getpid());
printf("main address: %p \n", main);
printf("add: %d\n", add(3, 4));
getchar();
}
# CFLAGS="-static"
BINS := hello hello_no_pie hello_static hello.o
all: ${BINS}
hello: hello.c
gcc -g -o $@ $^
hello_no_pie: hello.c
gcc -g -o $@ -fno-pie -no-pie $^
hello_static: hello.c
gcc -g -o $@ -static $^
hello.o: hello.c
gcc -g -c -o $@ $^
clean:
rm -rf ${BINS}
*.o和 可执行文件差异
objdump -dS hello
mgg@forever:~/Test/hello$ objdump -T hello
hello: file format elf64-littleaarch64
DYNAMIC SYMBOL TABLE:
0000000000000640 l d .init 0000000000000000 .init
0000000000011000 l d .data 0000000000000000 .data
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.17 __cxa_finalize
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.17 getpid
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.17 __libc_start_main
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.17 abort
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.17 getchar
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.17 printf
动态
image.png
image.png