0x01 一个典型程序的编译、链接过程图示
hello.c源码
#include <stdio.h>
int main()
{
printf("Hello World!");
}
gcc命令实际上是具体程序(如cpp、cc1、as等)的包装命令,用户通过gcc命令来使用具体的预处理程序cpp、编译程序cc1、汇编程序as等。
0x02 预处理cpp
1、处理源文件中以“#”开头的预编译指令,包括:
- 删除“#define”并展开宏定义
- 处理所有条件预编译指令,如“#if”、“#ifdef”、“#endif”等
- 插入头文件到“#include”处,可以递归方式进行处理
- 删除所有的注释,//和/* */
- 添加行号和文件名标识,以便编译器产生调试用的行号信息
- 保留所有的#pragma编译指令(编译器需要使用)
2、预处理命令
gcc -E hello.c -o hello.i
cpp hello.c > hello.i
3、查看生成的hello.i文件内容(不包含任何宏定义)
root@kali2020:~# cat hello.i
# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
...
extern int __overflow (FILE *, int);
# 873 "/usr/include/stdio.h" 3 4
# 2 "hello.c" 2
# 2 "hello.c"
int main()
{
printf("Hello World!");
}
0x03 编译cc1
1、编译过程就是将预处理后得到的预处理文件(如hello.i)进行词法分析、语法分析、语义分析并优化,生成汇编文件代码。
2、编译命令
gcc -S hello.i -o hello.s
gcc -S hello.c -o hello.s
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 hello.c
3、查看hello.s,其实是文本文件,汇编语言源程序。
root@kali2020:~# cat hello.s
.file "hello.c"
.text
.section .rodata
.LC0:
.string "Hello World!"
.text
.globl main
.type main, @function
main:
.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
movl $0, %eax
call printf@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 9.2.1-22) 9.2.1 20200104"
.section .note.GNU-stack,"",@progbits
0x04 汇编
1、将汇编源程序转换程机器指令序列的过程。
gcc -c hello.s -o hello.o
gcc -c hello.c -o hello.o
as hello.c -o hello.o
2、查看可重定位的目标文件hello.o
root@kali2020:~# cat hello.o
ELF>�@@
WH��H�=���]�Hello World!GCC: (Debian 9.2.1-22) 9.2.1 20200104zR�A�C
�� $hello.cmain_GLOBAL_OFFSET_TABLE_printf��������
�������� .symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.rela.eh_frame @@0
90i'B�W�R@H
�
0x05 链接ld
1、链接过程是将多个可重定位的目标文件合并生成可执行的目标文件。
gcc -static -o myproject main.o test.o
ld -static -o myproject main.o test.o
2、链接操作的步骤
3、使用链接的好处
4、链接过程的本质