记录学习的过程,好记性不如烂笔头———20221003
程序编译与链接
特点:
- 不是“一步到位”“一气呵成”,而是环环相扣
-
分为
预编译、编译、汇编、链接
阶段 - 每个阶段调用不同的工具去完成
- 上一编译阶段的输出作为下一编译阶段的输入
过程:
-
预处理:
源文件.c ->处理后的源文件.i -
编译:
源文件.i->汇编文件.s -
汇编:
汇编文件.s->目标文件.o -
链接:
可重定位的目标文件.o->可执行目标文件(elf)
思考:
为什么不直接生成可执行文件?
- gnu的思想,一个工具只干一件事
-
计算机工业思维:标准接口+分层
-
简化编译器的工作,提高复用性
-
适配更多的平台、cpu架构、指令集
-
目标文件类型:
-
可重定位目标文件(relocatable files),编译生成的文件,可被链接成可执行文件
eg: linux下 .o 文件
-
可执行目标文件(executable files),可以直接执行的程序,典型的ELF文件格式
eg: linux 下的/bin/bash文件
-
可被共享目标文件(shared object file),动态链接文件,可以和其他的可重定位文件和共享目标文件一起链接,生成新的目标文件
eg: linux下的 .so 文件
-
核心转存文件(core dump file),进程信息存储文件,当进程意外终止时,系统将该进程的地址空间以及终止时的一些信息存储到该文件
eg: liunx下的 core dump 文件
注:
gcc 新版本的默认配置会导致编译后直接就是共享目标文件,需要谈到PIE(position-independent-executable),这是linux程序的一种保护机制,是gcc 的一个功能选项,目的是为了让程序在任意地址装载,减少系统攻击风险,如果需要生成 executable file 直接在编译的时候加上-no-pie参数即可
可执行文件结构
文件构成:
- 由 section 组成,由 section header table 描述的一系列 section 集合
-
查看节头表
$ readelf -S main.o
- .text 可执行指令代码
- .data 初始化的全局变量和静态局部变量
- .bss 未初始化的全局变量
- .rodata 字符串、常量及printf打印的字符串常量等
描述信息:
-
ELF header 描述文件类型,运行的处理器平台等信息
- program header table 描述一个文件中有哪些段 segment,一个段通常由几个section组成,段是加载器使用的
- section header table 描述文件中有哪些 section,section 是给链接器使用的
- .strtab 字符串表,存放函数名,变量名,用于调试、反汇编
- .symtab 符号表,存放符号地址等
例子分析:
readelf -h main.o 查看 ELF header 【可重定位目标文件】
readelf -S main.o 查看 section 【可重定位目标文件】
readelf -h a.out 查看 ELF header 【可执行文件】
readelf -S a.out 查看 section 【可执行文件】
readelf -h libmath.a 查看 ELF header
readelf -h libmath.so 查看 ELF header 【可被共享目标文件】