在完成空间和地址的分配步骤后,链接器进入了符号解析与重定位的步骤,这也是静态链接
的核心内容。
首先看一下目标文件a.o中怎么使用两个外部符号shared和swap的。用objdump -d a.o查看
反汇编后的结果,如图4.2.1:
***图4.2.1***
可以很清楚的看到a.o的反汇编结果中,a.o共定义了一个函数main,这个函数占用0x2b个字节,
共12条指令,最左边那列是每条指令的偏移量,每行代表一条指令,有的指令很长,例如偏移
量为0x09和0x11的两条指令,对于变量shared引用的是偏移为0x11的movl指令,
这条指令共计8个字节,作用是将shared的地址赋值给esp寄存器+4的偏移地址中,前面4个字节
是指令码,后面4个字节是变量shared的地址。
当源代码a.c在被编译成目标文件时,编译器不知道shared和swap的地址,因为他们定义在其他
目标文件中,所以编译器就暂时把地址0看作是shared的地址,在偏移量为0x11的movl指令中,
关于shared的地址部分是0x00000000。
另外一条偏移量为0x20的指令是对函数swap的调用,这条指令共5个字节,前面的0xe8是操作码,
该条指令是一条近址相对位移调用指令,后面四个字节就是调用函数相对于调用指令下一条指令
的偏移量,在没有重定位之前,相对偏移位置为0xFFFFFFFC(小端),它是常量-4的补码形式。
紧跟在call指令后面的那条指令为mov指令,mov指令的实际地址是0x25,而相对于mov指令偏移
量为-4的地址即是0x25-4=0x21,所以这条call指令的实际调用地址是0x21。而0x21存放的不是
swap的地址。在编译的时候,编译器并不知道swap的真正地址。
链接器在完成地址和空间分配之后,就可以确定所有符号的虚拟地址,那么链接器根据符号的
地址就能对需要重定位的指令进行地址修正,用objdump来反汇编输出可执行文件ab的汇编指令,
***图4.2.2***
***图4.2.3***
从图4.2.2可以看出在main函数中,两个需要重定位的部分地址已经被修正。