mat*_*tja 11
汇编程序和编译器都将源文件转换为目标文件.
对象文件实际上是最终可执行输出(由链接器生成)之前的中间步骤.
链接器获取指定的目标文件和库(它们是目标文件包)并解析重定位(或"fixup")记录.
当编译器/汇编器不知道源代码中使用的函数或变量的地址时,会生成这些重定位记录,并按名称生成对它的引用,链接器可以解析该引用.
例如,假设您希望程序将消息打印到屏幕上,分成两个源文件,并且您希望单独组装它们并链接它们(例如使用Linux x86-64系统调用) -
main.asm:
bits 64
section .text
extern do_message
global _start
_start:
call do_message
mov rax, 1
int 0x80
Run Code Online (Sandbox Code Playgroud)
message.asm:
bits 64
section .text
global do_message
do_message:
mov rdi, message
mov rcx, dword -1
xor rax, rax
repnz scasb
sub rdi, message
mov rax, 4
mov rbx, 1
mov rcx, message
mov rdx, rdi
int 0x80
ret
section .data
message: db "hello world",10,0
Run Code Online (Sandbox Code Playgroud)
如果你组装它们并查看main.asm的目标文件输出(例如,objdump -d main.o),你会注意到'call do_message'的地址为00 00 00 00 - 这是无效的.
0000000000000000 <_start>:
0: e8 00 00 00 00 callq 5 <_start+0x5>
5: 48 c7 c0 01 00 00 00 mov $0x1,%rax
c: cd 80 int $0x80
Run Code Online (Sandbox Code Playgroud)
但是,对地址的4个字节进行了重定位记录:
$ objdump -r main.o
main.o: file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000001 R_X86_64_PC32 do_message+0xfffffffffffffffc
000000000000000d R_X86_64_32 .data
Run Code Online (Sandbox Code Playgroud)
偏移量为"1",类型为"R_X86_64_PC32",它告诉链接器解析此引用,并将已解析的地址放入指定的偏移量.
当您将最终程序与'ld -o program main.o message.o'链接时,重定位都将被解析,如果没有解决任何问题,您将获得可执行文件.
当我们'objdump -d'可执行文件时,我们可以看到已解析的地址:
00000000004000f0 <_start>:
4000f0: e8 0b 00 00 00 callq 400100 <do_message>
4000f5: 48 c7 c0 01 00 00 00 mov $0x1,%rax
4000fc: cd 80 int $0x80
Run Code Online (Sandbox Code Playgroud)
相同类型的重定位用于变量和函数.当您将程序链接到多个大型库(例如libc)时,会发生相同的过程 - 您定义了一个名为"main"的函数,其中libc具有外部引用 - 然后libc在程序之前启动,并在调用"main"函数时调用你运行可执行文件.