网站首页 > 博客文章 正文
当我们写完了C语言代码后,通过gcc将其编译成可执行文件运行,这中间具体经过的步骤包括预处理、编译、汇编、链接四个步骤。
最简单的hello.c源文件内容如下:
# include <stdio.h>
// 这是一行注释
int main(void)
{
printf("hello world!\n");
printf("%s\n", __DATE__);
return 0;
}
预处理
处理源文件中以“#”开头的元素,比如#include #define,将其转换后直接插入源文件中,处理后的文件通常以.i作为文件扩展名。这一步具体包括:
- 展开头文件:#include
- 宏替换: #define
- 条件编译:#if #elif else ifdef ifndef
- 删除注释
- 添加行号
- 预定义符号常量:__DATE__ __TIME__ __TIMESTAMP__ __LINE__ __FILE__ __STDC__
gcc可以通过如下指令得到预处理后的文件:gcc -E hello.c -o hello.i,hello.i文件很长,这里截取一小部分:
# 4 "hello.c"
int main(void)
{
printf("hello world!\n");
printf("%s\n", "May 3 2022");
return 0;
}
可以看到注释已经被删除了,符号常量__DATE__也已经被展开。
编译
编译阶段包括词法分析、语法分析、语义分析、中间代码生成、目标代码生成与优化,编译完成后会生成汇编代码,通常文件扩展名为.s。
gcc可以通过如下指令得到编译后的汇编代码:gcc -S hello.c -o hello.s
默认生成的汇编代码是AT&T格式的,可采用如下指令得到intel格式的汇编代码:gcc -S hello.c -o hello.s -masm=intel,intel格式的hello.s内容如下:
.file "hello.c"
.intel_syntax noprefix
.text
.section .rodata
.LC0:
.string "hello world!"
.LC1:
.string "May 3 2022"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
endbr64
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
lea rdi, .LC0[rip]
call puts@PLT
lea rdi, .LC1[rip]
call puts@PLT
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
汇编
汇编是根据汇编指令与机器指令的对应关系将汇编文件翻译成目标文件,如果从源文件开始,gcc命令是gcc -c hello.c -o hello.o,如果从汇编文件开始,gcc命令是gcc -c hello.s -o hello.o。通过file命令查看目标文件hello.o:file hello.o,终端显示为:hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped,说明这是一个ELF文件,关于ELF文件的内容将在下一篇博客中介绍。
hello.o文件内容无法直接在编辑器中显示,但可以通过objdump显示:objdump -sd hello.o -M intel。
hello.o: 文件格式 elf64-x86-64
Contents of section .text:
0000 f30f1efa 554889e5 488d3d00 000000e8 ....UH..H.=.....
0010 00000000 488d3d00 000000e8 00000000 ....H.=.........
0020 b8000000 005dc3 .....].
Contents of section .rodata:
0000 68656c6c 6f20776f 726c6421 004d6179 hello world!.May
0010 20203320 32303232 00 3 2022.
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520392e .GCC: (Ubuntu 9.
0010 342e302d 31756275 6e747531 7e32302e 4.0-1ubuntu1~20.
0020 30342e31 2920392e 342e3000 04.1) 9.4.0.
Contents of section .note.gnu.property:
0000 04000000 10000000 05000000 474e5500 ............GNU.
0010 020000c0 04000000 03000000 00000000 ................
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001 .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000 ................
0020 00000000 27000000 00450e10 8602430d ....'....E....C.
0030 065e0c07 08000000 .^......
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push rbp
5: 48 89 e5 mov rbp,rsp
8: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # f <main+0xf>
f: e8 00 00 00 00 call 14 <main+0x14>
14: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # 1b <main+0x1b>
1b: e8 00 00 00 00 call 20 <main+0x20>
20: b8 00 00 00 00 mov eax,0x0
25: 5d pop rbp
26: c3 ret
此时由于还未链接,目标文件中符号的虚拟地址无法确定。此时,如果运行hello.o会报错:可执行文件格式错误。
链接
链接包括静态链接和动态链接两种,gcc默认使用动态链接,添加编译选项-static可以进行静态链接,这一阶段将目标文件与其依赖库进行链接,主要包括地址和空间分配(Address and Storage Allocation)、符号绑定(Symbol Binding)、重定位(Relocation)等。gcc命令:gcc hello.c -o hello。经过objdump后,部分内容如下:
0000000000001149 <main>:
1149: f3 0f 1e fa endbr64
114d: 55 push rbp
114e: 48 89 e5 mov rbp,rsp
1151: 48 8d 3d ac 0e 00 00 lea rdi,[rip+0xeac] # 2004 <_IO_stdin_used+0x4>
1158: e8 f3 fe ff ff call 1050 <puts@plt>
115d: 48 8d 3d ad 0e 00 00 lea rdi,[rip+0xead] # 2011 <_IO_stdin_used+0x11>
1164: e8 e7 fe ff ff call 1050 <puts@plt>
1169: b8 00 00 00 00 mov eax,0x0
116e: 5d pop rbp
116f: c3 ret
跟未经过链接的目标文件相比,虚拟地址已经确定了,运行hello便可以得到结果:
hello world!
May 3 2022
文章来自https://www.cnblogs.com/husterzxh/p/16218820.html
猜你喜欢
- 2024-10-20 JSA宏教程WPS表格常用内置对象——单元格区域(Range)对象(一)
- 2024-10-20 CAD快捷键命令大全汇总,建议收藏保存
- 2024-10-20 是时候拯救我的 HTML 技术了(是时候拯救我的+html+技术了什么)
- 2024-10-20 Linux内核:Crash学习ARM64虚拟地址空间布局
- 2024-10-20 雾非花:清清爽爽的夏季女士宽松短袖(有编织图解)
- 2024-10-20 几毛钱一片的谷维素,可以用来治哪些病?这4大功效认可度很高
- 2024-10-20 Java 8 之后,还有哪些进化的功能?
- 2024-10-20 扒一扒西欧喷气式战斗机家族谱(3)
- 2024-10-20 「小狮子诊所」内存时序到底有什么作用?
- 2024-10-20 与你相见恨晚的100个CAD快捷键+20个CAD制图技巧,轻松玩转CAD
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)