1. 编译和链接
gcc hello.c执行的四个步骤:
#预处理(Prepressing) gcc -E hello.c -o hello.i #编译(Compilation) gcc -S hello.i -o hello.s gcc -S hello.c -o hello.s #汇编(Assembly) as hello.s -o hello.o gcc -c hello.s -o hello.o gcc -c hello.c -o hello.o #链接(Linking) ld -static -L/lib lxxx.o hello.o -o a.out
链接包括地址和空间分配(Address and Storage Allocation)、符号决议(Symbol Resolution)和重定位(Relocation)等步骤。静态链接的最基本的过程和作用就是修正引用位置的目的地址,让它们为真正的函数的地址。地址修正的过程就被叫做重定位,每个要被修正的地方叫一个重定位入口(Relocation Entry)。
2. 目标文件里面有什么
Windows下的PE(Portable Executable)和Linux的ELF(Executable Linkable Format)都是COFF(Common file format)格式的变种。目标文件(Windows的.obj和Linux的.o)、静态链接库(Windows的.lib和Linux的.a)、动态链接库(Windows的.dll和Linux的.so)和核心转储文件(Linux下的Core dump),都可广义地看成可执行文件。静态链接库稍有不同,可以简单地把它理解为一个很多目标文件组成的文件包。
文件头:存放文件属性(是否可执行、是静态链接还是动态链接及入口地址等)、段表(偏移位置及段的属性等)
代码段(Code Section)常见的名字有”.code”或”.text”:存放机器指令
数据段(Data Section)一般名字都叫”.data”:已初始化的存放全局变量和局部静态变量数据
.bss”的段:未初始化的全局变量和局部静态变量(预留位置,不占据磁盘空间)
相关工具:
size hello.o(查看ELF文件的各段的长度(dec:十进制,hex:十六进制))
readelf 查看ELF文件头信息(-s打印符号表信息 -a打印所有信息)
objdump -h hello.o(-h打印各段的基本信息,-x打印更多复杂的信息,-s以十六机制的方式打印各段内容,-d将所有包含指令的段反汇编)
这些段名都由”.”作为前缀,表示是系统保留的表名。GCC提供了一个扩展机制,使得程序员可以指定变量所处的段
// FOO和BAR是段名 __attribute__((section(“FOO”))) int global = 42; __attribute__((section(“BAR”))) void foo() {}
参考资料: