C语言的生命是从 源文件开始 的
每条C语言都必须要给翻译成 一系列的低级语言
最后 按照可执行文件格式打包 并且作为二进制文件保存起来
编译原理
我们需要使用编译器
是通过某种语言 等价输出另一个语言
可以分为前端和后端
前端
和机器无关
把源程序分解为组成要素 和 语法结构 通过这个结构创建程序的中间表示
并且要收集和源程序相关的信息 放到符号表中
后端 是通过中间表示和符号表来构造目标程序
意思就是 前端把源程序变为中间表示 然后后端通过中间表示来编译出 目标文件并且能够适用于不同类型的机器
编译大致分为5步骤 这里包括了前端和后端
(1)词法分析 :读入源程序的字符流,输出有意义的词素
(2)语法分析 :根据各个词法单元的第一个分量来创建树型的中间表示 语法树
(3)语义分析 :使用语法树和符号表的信息 来检测源程序是否满足语言定义的约束,收集类型信息
(4)中间代码生成和优化 : 根据语义分析输出,生成类机器语言的中间表示 (源代码和目标机器代码(即二进制码)之间的代码) 然后对生成的中间代码进行分析和优化
(5)代码的生成和优化 :把中间形式映射到目标机器的语言
给出两个不同流程图
GCC编译
我们先进入GCC编译过程
hello.c的源代码
#include <stdio.h>
int main(){
printf("hello world\n");
}
这是源程序 然后我们开始把他编译
gcc hello.c -o hello -save-temps --verbose
-save-temps 保存生成的中间文件
--verbose 是来查看详细工作流程
发现include
使用collect2 工具
cc1工具
同时返回了四个文件 这代表了四个阶段
四个阶段
(1)预处理阶段
(2)编译阶段
(3)汇编阶段
(4)链接阶段
最后两个其实差不多 就是再链接上动态库等其他的
预处理阶段
我们上面返回的四个程序中 hello.i就是预处理的文件
我们也可以进行单独执行预处理
gcc -E hello.c -o hello.i
我们可以发现预处理的一些规则
递归处理 include 预处理指令 将对应文件复制到该指令位置
删除所有#define指令 并且在其被应用的位置递归展开所有宏定义
宏定义 : 一种在 C/C++ 代码中用特定符号或字符串表示其他代码段的方式
删除所有条件预处理指令 #if #ifdef #elif等
删除所有注释
添加行号和文件名标识
编译阶段
gcc编译的第二阶段就是编译阶段 这个阶段就是
对预处理文件进行一系列 词法优化 语法分析 语义分析以及优化
最终生成汇编代码
gcc -S hello.c -o hello.s
gcc -S hello.c -o hello.s -masm=intel -fno-asynchronous-unwind-tables
第一种是直接生成 编译阶段的代码
第二个是 把他转换为 intel格式 还有生成 没有cfi宏的汇编代码 这样可以提高可读性
第一种
第二种
我们尝试读懂这个汇编
.file "hello.c"
文件名 hello.c
.intel_syntax noprefix
是intel类型的汇编
.text
告诉机器是存放在文本段的指令
.section .rodata
让机器生成一段 只读数据段 用来存储不需要修改的变量
.LC0:
.string "hello world"
定义了.LC0这个字符串常量 里面包括了hello world
.text
告诉机器存放在文本段中
.globl main 让这个函数可以从外面的库中取得
定义全局符号 main
.type main, @function
定义main的类型为函数 而不会被视为 变量等
main:
endbr64
endbr64 的作用是确保返回地址只能被 BR 指令修改,增强了程序的安全性。
push rbp
把rbp压入 作为栈底
mov rbp, rsp
把rsp和rbp设置为一样的 用来开辟main 的栈帧
lea rax, .LC0[rip]
把 .LC0[rip] 的地址存入 rax .LC0[rip]是是 .LC0相对于 rip的偏移量存入
这里 rax 就存放着 .LC0的绝对地址
mov rdi, rax
把rax的值给rdi 用于对puts函数传递地址
call puts@PLT
调用puts函数 plt的动态链接
mov eax, 0
把eax清零 eax为rax的低32位
pop rbp
弹出rbp 摧毁栈帧
ret
回到main函数的地方
.size main, .-main
设置main的大小为 mian到-mian的大小
.ident "GCC: (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
使用着
.section .note.GNU-stack,"",@progbits
表示代码段位 .note.GNU-stack 是一种栈的保护 如果为progbits 就说明开启保护
.section .note.gnu.property,"a"
.align 8
表示对齐到 2的8次方的字节边界
.long 1f - 0f
.long 4f - 1f
.long 5
这里是关于ELF的头文件信息
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
这里我们进行对代码的汇编的解读 就明白的puts函数的调用过程
但是这里我们之前写的是printf函数
他自动替换为puts函数 因为 printf函数在只有一个参数的时候 和puts函数十分类似
所以 用于优化 就替换为puts
汇遍阶段
gcc第三个阶段就是汇编阶段
gcc -C hello.c -o hello.o
这里汇编出来的是 可重定位文件
我们使用objdump 查看反汇编
objdump -sd hello.o -M intel
-sd 显示符号表信息 和段信息 格式为intel类型
hello.o: 文件格式 elf64-x86-64
Contents of section .interp:
0318 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
0328 7838362d 36342e73 6f2e3200 x86-64.so.2.
Contents of section .note.gnu.property:
0338 04000000 20000000 05000000 474e5500 .... .......GNU.
0348 020000c0 04000000 03000000 00000000 ................
0358 028000c0 04000000 01000000 00000000 ................
Contents of section .note.gnu.build-id:
0368 04000000 14000000 03000000 474e5500 ............GNU.
0378 fbb4fa3b 62017c35 cc7f9de6 d809003e ...;b.|5.......>
0388 51734506 QsE.
Contents of section .note.ABI-tag:
038c 04000000 10000000 01000000 474e5500 ............GNU.
039c 00000000 03000000 02000000 00000000 ................
Contents of section .gnu.hash:
03b0 02000000 06000000 01000000 06000000 ................
03c0 00008100 00000000 06000000 00000000 ................
03d0 d165ce6d .e.m
Contents of section .dynsym:
03d8 00000000 00000000 00000000 00000000 ................
03e8 00000000 00000000 10000000 12000000 ................
03f8 00000000 00000000 00000000 00000000 ................
0408 48000000 20000000 00000000 00000000 H... ...........
0418 00000000 00000000 22000000 12000000 ........".......
0428 00000000 00000000 00000000 00000000 ................
0438 64000000 20000000 00000000 00000000 d... ...........
0448 00000000 00000000 73000000 20000000 ........s... ...
0458 00000000 00000000 00000000 00000000 ................
0468 01000000 22000000 00000000 00000000 ...."...........
0478 00000000 00000000 ........
Contents of section .dynstr:
0480 005f5f63 78615f66 696e616c 697a6500 .__cxa_finalize.
0490 5f5f6c69 62635f73 74617274 5f6d6169 __libc_start_mai
04a0 6e007075 7473006c 6962632e 736f2e36 n.puts.libc.so.6
04b0 00474c49 42435f32 2e322e35 00474c49 .GLIBC_2.2.5.GLI
04c0 42435f32 2e333400 5f49544d 5f646572 BC_2.34._ITM_der
04d0 65676973 74657254 4d436c6f 6e655461 egisterTMCloneTa
04e0 626c6500 5f5f676d 6f6e5f73 74617274 ble.__gmon_start
04f0 5f5f005f 49544d5f 72656769 73746572 __._ITM_register
0500 544d436c 6f6e6554 61626c65 00 TMCloneTable.
Contents of section .gnu.version:
050e 00000200 01000300 01000100 0300 ..............
Contents of section .gnu.version_r:
0520 01000200 27000000 10000000 00000000 ....'...........
0530 751a6909 00000300 31000000 10000000 u.i.....1.......
0540 b4919606 00000200 3d000000 00000000 ........=.......
Contents of section .rela.dyn:
0550 b83d0000 00000000 08000000 00000000 .=..............
0560 40110000 00000000 c03d0000 00000000 @........=......
0570 08000000 00000000 00110000 00000000 ................
0580 08400000 00000000 08000000 00000000 .@..............
0590 08400000 00000000 d83f0000 00000000 .@.......?......
05a0 06000000 01000000 00000000 00000000 ................
05b0 e03f0000 00000000 06000000 02000000 .?..............
05c0 00000000 00000000 e83f0000 00000000 .........?......
05d0 06000000 04000000 00000000 00000000 ................
05e0 f03f0000 00000000 06000000 05000000 .?..............
05f0 00000000 00000000 f83f0000 00000000 .........?......
0600 06000000 06000000 00000000 00000000 ................
Contents of section .rela.plt:
0610 d03f0000 00000000 07000000 03000000 .?..............
0620 00000000 00000000 ........
Contents of section .init:
1000 f30f1efa 4883ec08 488b05d9 2f000048 ....H...H.../..H
1010 85c07402 ffd04883 c408c3 ..t...H....
Contents of section .plt:
1020 ff359a2f 0000f2ff 259b2f00 000f1f00 .5./....%./.....
1030 f30f1efa 68000000 00f2e9e1 ffffff90 ....h...........
Contents of section .plt.got:
1040 f30f1efa f2ff25ad 2f00000f 1f440000 ......%./....D..
Contents of section .plt.sec:
1050 f30f1efa f2ff2575 2f00000f 1f440000 ......%u/....D..
Contents of section .text:
1060 f30f1efa 31ed4989 d15e4889 e24883e4 ....1.I..^H..H..
1070 f0505445 31c031c9 488d3dca 000000ff .PTE1.1.H.=.....
1080 15532f00 00f4662e 0f1f8400 00000000 .S/...f.........
1090 488d3d79 2f000048 8d05722f 00004839 H.=y/..H..r/..H9
10a0 f8741548 8b05362f 00004885 c07409ff .t.H..6/..H..t..
10b0 e00f1f80 00000000 c30f1f80 00000000 ................
10c0 488d3d49 2f000048 8d35422f 00004829 H.=I/..H.5B/..H)
10d0 fe4889f0 48c1ee3f 48c1f803 4801c648 .H..H..?H...H..H
10e0 d1fe7414 488b0505 2f000048 85c07408 ..t.H.../..H..t.
10f0 ffe0660f 1f440000 c30f1f80 00000000 ..f..D..........
1100 f30f1efa 803d052f 00000075 2b554883 .....=./...u+UH.
1110 3de22e00 00004889 e5740c48 8b3de62e =.....H..t.H.=..
1120 0000e819 ffffffe8 64ffffff c605dd2e ........d.......
1130 0000015d c30f1f00 c30f1f80 00000000 ...]............
1140 f30f1efa e977ffff fff30f1e fa554889 .....w.......UH.
1150 e5488d05 ac0e0000 4889c7e8 f0feffff .H......H.......
1160 b8000000 005dc3 .....].
Contents of section .fini:
1168 f30f1efa 4883ec08 4883c408 c3 ....H...H....
Contents of section .rodata:
2000 01000200 68656c6c 6f20776f 726c6400 ....hello world.
Contents of section .eh_frame_hdr:
2010 011b033b 34000000 05000000 10f0ffff ...;4...........
2020 68000000 30f0ffff 90000000 40f0ffff h...0.......@...
2030 a8000000 50f0ffff 50000000 39f1ffff ....P...P...9...
2040 c0000000 ....
Contents of section .eh_frame:
2048 14000000 00000000 017a5200 01781001 .........zR..x..
2058 1b0c0708 90010000 14000000 1c000000 ................
2068 f8efffff 26000000 00440710 00000000 ....&....D......
2078 24000000 34000000 a0efffff 20000000 $...4....... ...
2088 000e1046 0e184a0f 0b770880 003f1a3a ...F..J..w...?.:
2098 2a332422 00000000 14000000 5c000000 *3$"........\...
20a8 98efffff 10000000 00000000 00000000 ................
20b8 14000000 74000000 90efffff 10000000 ....t...........
20c8 00000000 00000000 1c000000 8c000000 ................
20d8 71f0ffff 1e000000 00450e10 8602430d q........E....C.
20e8 06550c07 08000000 00000000 .U..........
Contents of section .init_array:
3db8 40110000 00000000 @.......
Contents of section .fini_array:
3dc0 00110000 00000000 ........
Contents of section .dynamic:
3dc8 01000000 00000000 27000000 00000000 ........'.......
3dd8 0c000000 00000000 00100000 00000000 ................
3de8 0d000000 00000000 68110000 00000000 ........h.......
3df8 19000000 00000000 b83d0000 00000000 .........=......
3e08 1b000000 00000000 08000000 00000000 ................
3e18 1a000000 00000000 c03d0000 00000000 .........=......
3e28 1c000000 00000000 08000000 00000000 ................
3e38 f5feff6f 00000000 b0030000 00000000 ...o............
3e48 05000000 00000000 80040000 00000000 ................
3e58 06000000 00000000 d8030000 00000000 ................
3e68 0a000000 00000000 8d000000 00000000 ................
3e78 0b000000 00000000 18000000 00000000 ................
3e88 15000000 00000000 00000000 00000000 ................
3e98 03000000 00000000 b83f0000 00000000 .........?......
3ea8 02000000 00000000 18000000 00000000 ................
3eb8 14000000 00000000 07000000 00000000 ................
3ec8 17000000 00000000 10060000 00000000 ................
3ed8 07000000 00000000 50050000 00000000 ........P.......
3ee8 08000000 00000000 c0000000 00000000 ................
3ef8 09000000 00000000 18000000 00000000 ................
3f08 1e000000 00000000 08000000 00000000 ................
3f18 fbffff6f 00000000 01000008 00000000 ...o............
3f28 feffff6f 00000000 20050000 00000000 ...o.... .......
3f38 ffffff6f 00000000 01000000 00000000 ...o............
3f48 f0ffff6f 00000000 0e050000 00000000 ...o............
3f58 f9ffff6f 00000000 03000000 00000000 ...o............
3f68 00000000 00000000 00000000 00000000 ................
3f78 00000000 00000000 00000000 00000000 ................
3f88 00000000 00000000 00000000 00000000 ................
3f98 00000000 00000000 00000000 00000000 ................
3fa8 00000000 00000000 00000000 00000000 ................
Contents of section .got:
3fb8 c83d0000 00000000 00000000 00000000 .=..............
3fc8 00000000 00000000 30100000 00000000 ........0.......
3fd8 00000000 00000000 00000000 00000000 ................
3fe8 00000000 00000000 00000000 00000000 ................
3ff8 00000000 00000000 ........
Contents of section .data:
4000 00000000 00000000 08400000 00000000 .........@......
Contents of section .comment:
0000 4743433a 20285562 756e7475 2031312e GCC: (Ubuntu 11.
0010 332e302d 31756275 6e747531 7e32322e 3.0-1ubuntu1~22.
0020 30342920 31312e33 2e3000 04) 11.3.0.
Disassembly of section .init:
0000000000001000 <_init>:
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub rsp,0x8
1008: 48 8b 05 d9 2f 00 00 mov rax,QWORD PTR [rip+0x2fd9] # 3fe8 <__gmon_start__@Base>
100f: 48 85 c0 test rax,rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 call rax
1016: 48 83 c4 08 add rsp,0x8
101a: c3 ret
Disassembly of section .plt:
0000000000001020 <.plt>:
1020: ff 35 9a 2f 00 00 push QWORD PTR [rip+0x2f9a] # 3fc0 <_GLOBAL_OFFSET_TABLE_+0x8>
1026: f2 ff 25 9b 2f 00 00 bnd jmp QWORD PTR [rip+0x2f9b] # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x10>
102d: 0f 1f 00 nop DWORD PTR [rax]
1030: f3 0f 1e fa endbr64
1034: 68 00 00 00 00 push 0x0
1039: f2 e9 e1 ff ff ff bnd jmp 1020 <_init+0x20>
103f: 90 nop
Disassembly of section .plt.got:
0000000000001040 <__cxa_finalize@plt>:
1040: f3 0f 1e fa endbr64
1044: f2 ff 25 ad 2f 00 00 bnd jmp QWORD PTR [rip+0x2fad] # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
104b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
Disassembly of section .plt.sec:
0000000000001050 <puts@plt>:
1050: f3 0f 1e fa endbr64
1054: f2 ff 25 75 2f 00 00 bnd jmp QWORD PTR [rip+0x2f75] # 3fd0 <puts@GLIBC_2.2.5>
105b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
Disassembly of section .text:
0000000000001060 <_start>:
1060: f3 0f 1e fa endbr64
1064: 31 ed xor ebp,ebp
1066: 49 89 d1 mov r9,rdx
1069: 5e pop rsi
106a: 48 89 e2 mov rdx,rsp
106d: 48 83 e4 f0 and rsp,0xfffffffffffffff0
1071: 50 push rax
1072: 54 push rsp
1073: 45 31 c0 xor r8d,r8d
1076: 31 c9 xor ecx,ecx
1078: 48 8d 3d ca 00 00 00 lea rdi,[rip+0xca] # 1149 <main>
107f: ff 15 53 2f 00 00 call QWORD PTR [rip+0x2f53] # 3fd8 <__libc_start_main@GLIBC_2.34>
1085: f4 hlt
1086: 66 2e 0f 1f 84 00 00 cs nop WORD PTR [rax+rax*1+0x0]
108d: 00 00 00
0000000000001090 <deregister_tm_clones>:
1090: 48 8d 3d 79 2f 00 00 lea rdi,[rip+0x2f79] # 4010 <__TMC_END__>
1097: 48 8d 05 72 2f 00 00 lea rax,[rip+0x2f72] # 4010 <__TMC_END__>
109e: 48 39 f8 cmp rax,rdi
10a1: 74 15 je 10b8 <deregister_tm_clones+0x28>
10a3: 48 8b 05 36 2f 00 00 mov rax,QWORD PTR [rip+0x2f36] # 3fe0 <_ITM_deregisterTMCloneTable@Base>
10aa: 48 85 c0 test rax,rax
10ad: 74 09 je 10b8 <deregister_tm_clones+0x28>
10af: ff e0 jmp rax
10b1: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
10b8: c3 ret
10b9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
00000000000010c0 <register_tm_clones>:
10c0: 48 8d 3d 49 2f 00 00 lea rdi,[rip+0x2f49] # 4010 <__TMC_END__>
10c7: 48 8d 35 42 2f 00 00 lea rsi,[rip+0x2f42] # 4010 <__TMC_END__>
10ce: 48 29 fe sub rsi,rdi
10d1: 48 89 f0 mov rax,rsi
10d4: 48 c1 ee 3f shr rsi,0x3f
10d8: 48 c1 f8 03 sar rax,0x3
10dc: 48 01 c6 add rsi,rax
10df: 48 d1 fe sar rsi,1
10e2: 74 14 je 10f8 <register_tm_clones+0x38>
10e4: 48 8b 05 05 2f 00 00 mov rax,QWORD PTR [rip+0x2f05] # 3ff0 <_ITM_registerTMCloneTable@Base>
10eb: 48 85 c0 test rax,rax
10ee: 74 08 je 10f8 <register_tm_clones+0x38>
10f0: ff e0 jmp rax
10f2: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
10f8: c3 ret
10f9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
0000000000001100 <__do_global_dtors_aux>:
1100: f3 0f 1e fa endbr64
1104: 80 3d 05 2f 00 00 00 cmp BYTE PTR [rip+0x2f05],0x0 # 4010 <__TMC_END__>
110b: 75 2b jne 1138 <__do_global_dtors_aux+0x38>
110d: 55 push rbp
110e: 48 83 3d e2 2e 00 00 cmp QWORD PTR [rip+0x2ee2],0x0 # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
1115: 00
1116: 48 89 e5 mov rbp,rsp
1119: 74 0c je 1127 <__do_global_dtors_aux+0x27>
111b: 48 8b 3d e6 2e 00 00 mov rdi,QWORD PTR [rip+0x2ee6] # 4008 <__dso_handle>
1122: e8 19 ff ff ff call 1040 <__cxa_finalize@plt>
1127: e8 64 ff ff ff call 1090 <deregister_tm_clones>
112c: c6 05 dd 2e 00 00 01 mov BYTE PTR [rip+0x2edd],0x1 # 4010 <__TMC_END__>
1133: 5d pop rbp
1134: c3 ret
1135: 0f 1f 00 nop DWORD PTR [rax]
1138: c3 ret
1139: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
0000000000001140 <frame_dummy>:
1140: f3 0f 1e fa endbr64
1144: e9 77 ff ff ff jmp 10c0 <register_tm_clones>
0000000000001149 <main>:
1149: f3 0f 1e fa endbr64
114d: 55 push rbp
114e: 48 89 e5 mov rbp,rsp
1151: 48 8d 05 ac 0e 00 00 lea rax,[rip+0xeac] # 2004 <_IO_stdin_used+0x4>
1158: 48 89 c7 mov rdi,rax
115b: e8 f0 fe ff ff call 1050 <puts@plt>
1160: b8 00 00 00 00 mov eax,0x0
1165: 5d pop rbp
1166: c3 ret
Disassembly of section .fini:
0000000000001168 <_fini>:
1168: f3 0f 1e fa endbr64
116c: 48 83 ec 08 sub rsp,0x8
1170: 48 83 c4 08 add rsp,0x8
1174: c3 ret
有很多 这里我们选出 我们需要的
2000 01000200 68656c6c 6f20776f 726c6400 ....hello world.
发现 这里 hello 的地址为 0x2000
115b: e8 f0 fe ff ff call 1050 <puts@plt>
115b: 为处理后的地址偏移量
e8 f0 fe ff ff 为跳转到puts的机器码
通过计算 115b+5 =1160 得到下一地址的偏移量
然后把这偏移量加上下一地址 得到puts函数入口
因为这里我们需要先取得函数的返回地址 然后如果返回地址 重新计算得到函数入口
链接阶段
链接有两个 动态和静态
gcc默认使用动态链接
添加 -static 可以让他作为静态链接
链接主要包括 空间分配 符号绑定 和重定位等操作
gcc hello.c -o hello -static
我们继续使用objdump
objdump -sd hello -M intel
因为这里包含了 大量库文件 所以无法得到全部 我们只需要知道 之前汇编无法确定的符号地址 变为 真正的符号地址