HR's Blog

Swimming 🏊 in the sea🌊of code!

0%

编译过程

.

我们在执行gcc -Og -o prog main.c sum.c的时候,直接能看到了最终的产物prog。通过加上-v参数,可以让我们窥见驱动程序是如何一步一步转换成最终的可执行文件,我们接下就来讨论驱动程序都是怎么编译出可执行文件的,并在日志中标注出驱动程序都为我们完成了哪些步骤。

示例代码

1
2
3
4
5
6
7
8
9
//文件 main.c
int sum(int *a, int n);

int array[2] = {1, 2};

int main() {
int val = sum(array, 2);
return val;
}
1
2
3
4
5
6
7
8
9
//文件 sum.c
int sum(int *a, int n)
{
int i, s = 0;
for(i = 0; i < n; i++) {
s += a[i];
}
return s;
}
1
gcc -Og -v -o prog main.c sum.c

过程

第一步

C预处理器(cpp),将main.c翻译成main.i。

1
cpp [other arguments] main.c /tmp/main.i

第二步

驱动程序运行C编译器(ccl),它将main.i 翻译成ASCII汇编语言文件main.s

1
ccl /tmp/main.i -Og [other arguments] -o /tmp/main.s

第三步

驱动程序运行汇编器(as),它将main.s翻译成一个可重定位目标文件(relo-catable object file)main.o

1
as [other arguments] -o /tmp/main.o /tmp/main.s

第五步 链接

驱动程序经过相同的过程生产sum.o. 最后用ld,将main.o和sum.o组合在一起,成为一个可执行文件prog:

1
ld -o prog [system object files and args] /tmp/main.o /tmp/sum.o
1
linux> ./prog

编译器编译的实际过程

该命令在Centos7中执行

1
gcc -Og -v -o prog main.c sum.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
(base) [root@vultr 001]# gcc -Og -v -o prog main.c sum.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper

Target: x86_64-redhat-linux

Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux

Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
COLLECT_GCC_OPTIONS='-Og' '-v' '-o' 'prog' '-mtune=generic' '-march=x86-64'

【🌵ccl:编译器将man.c 翻译成cc7XYYjJ.s 上面的第一步+第二步的集合】
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v main.c -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase main -Og -version -o /tmp/cc7XYYjJ.s

GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-44) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-44), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1

GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126834
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
End of search list.

GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-44) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-44), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126834
Compiler executable checksum: 231b3394950636dbfe0428e88716bc73
COLLECT_GCC_OPTIONS='-Og' '-v' '-o' 'prog' '-mtune=generic' '-march=x86-64'

【🌵as汇编器:将cc7XYYjJ.s(main.c)翻译成ccTGUhq9.o】
as -v --64 -o /tmp/ccTGUhq9.o /tmp/cc7XYYjJ.s

GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-44.base.el7
COLLECT_GCC_OPTIONS='-Og' '-v' '-o' 'prog' '-mtune=generic' '-march=x86-64'

【🌵ccl:编译器将sum.c 翻译成cc7XYYjJ.s 上面的第一步+第二步的集合】
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v sum.c -quiet -dumpbase sum.c -mtune=generic -march=x86-64 -auxbase sum -Og -version -o /tmp/cc7XYYjJ.s

GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-44) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-44), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1

GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126834
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
End of search list.

GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-44) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-44), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126834
Compiler executable checksum: 231b3394950636dbfe0428e88716bc73

COLLECT_GCC_OPTIONS='-Og' '-v' '-o' 'prog' '-mtune=generic' '-march=x86-64'

【🌵as汇编器:将cc7XYYjJ.s(sum.c的集合)翻译成cczmU2Bz.o】
as -v --64 -o /tmp/cczmU2Bz.o /tmp/cc7XYYjJ.s

GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-44.base.el7
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:/usr/lib/

COLLECT_GCC_OPTIONS='-Og' '-v' '-o' 'prog' '-mtune=generic' '-march=x86-64'

/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o prog /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..

【🌵程序链接器ld将main和sum的可重定向目标文件合并成prog最终的目标文件】
/tmp/ccTGUhq9.o
/tmp/cczmU2Bz.o

-lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o