我正在尝试更好地了解Linux中的运行时重定位,特别是在不同情况下由谁执行它们。以下是我目前的理解,是否准确?
- 位置相关的静态链接可执行文件 - 不需要运行时重定位
- 动态链接可执行文件 - 动态链接器(
ld.so
)加载库,然后执行重定位 - 静态链接的PIE文件 - libc启动代码执行重定位
- 动态链接器本身 -
ld.so
是一个自重定位二进制文件
谢谢
我正在尝试更好地了解Linux中的运行时重定位,特别是在不同情况下由谁执行它们。以下是我目前的理解,是否准确?
ld.so
)加载库,然后执行重定位ld.so
是一个自重定位二进制文件谢谢
你的回答基本(大多数)都是正确的。
你可以使用调试器“观察”迁移发生的位置,并确认自己的理解。
示例:
#include <stdio.h>
int main()
{
printf("%d\n", 123);
return 0;
}
让我们从位置相关的动态链接二进制文件开始。
gcc -g -fno-pie -no-pie t.c
gdb -q ./a.out
Reading symbols from ./a.out...
(gdb) starti
Starting program: /tmp/a.out
Program stopped.
0x00007ffff7fd2090 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) disas main
Dump of assembler code for function main:
0x0000000000401126 <+0>: push %rbp
0x0000000000401127 <+1>: mov %rsp,%rbp
0x000000000040112a <+4>: mov $0x7b,%esi
0x000000000040112f <+9>: mov $0x402010,%edi
0x0000000000401134 <+14>: mov $0x0,%eax
0x0000000000401139 <+19>: call 0x401030 <printf@plt>
0x000000000040113e <+24>: mov $0x0,%eax
0x0000000000401143 <+29>: pop %rbp
0x0000000000401144 <+30>: ret
End of assembler dump.
(gdb) disas 0x401030
Dump of assembler code for function printf@plt:
0x0000000000401030 <+0>: jmp *0x2fe2(%rip) # 0x404018 <printf@got.plt>
0x0000000000401036 <+6>: push $0x0
0x000000000040103b <+11>: jmp 0x401020
End of assembler dump.
在这里,我们可以看到需要重新定位的地址是0x404018
。让我们看看这个地址在哪里得到更新:
(gdb) watch *(void**)0x404018
Hardware watchpoint 1: *(void**)0x404018
(gdb) c
Continuing.
Hardware watchpoint 1: *(void**)0x404018
Old value = (void *) 0x401036 <printf@plt+6>
New value = (void *) 0x7ffff7e54270 <printf>
0x00007ffff7fe0f10 in _dl_fixup (l=<optimized out>, reloc_arg=<optimized out>) at dl-runtime.c:146
146 dl-runtime.c: No such file or directory.
(gdb) bt
#0 0x00007ffff7fe0f10 in _dl_fixup (l=<optimized out>, reloc_arg=<optimized out>) at dl-runtime.c:146
#1 0x00007ffff7fe84fe in _dl_runtime_resolve_xsavec () at ../sysdeps/x86_64/dl-trampoline.h:126
#2 0x000000000040113e in main () at t.c:5
(gdb) info symbol $pc
_dl_fixup + 288 in section .text of /lib64/ld-linux-x86-64.so.2
gcc -g -fno-pie -no-pie t.c -Wl,-z,now
重复上述步骤并观察在main
之前发生的重定位:
(gdb) run
Starting program: /tmp/a.out
Hardware watchpoint 1: *(void**)0x403fe8
Old value = (void *) 0x401036 <printf@plt+6>
New value = (void *) 0x7ffff7e54270
elf_machine_rela (skip_ifunc=<optimized out>, reloc_addr_arg=<optimized out>, version=<optimized out>, sym=<optimized out>, reloc=<optimized out>, map=<optimized out>)
at ../sysdeps/x86_64/dl-machine.h:464
464 ../sysdeps/x86_64/dl-machine.h: No such file or directory.
(gdb) bt
#0 elf_machine_rela (skip_ifunc=<optimized out>, reloc_addr_arg=<optimized out>, version=<optimized out>, sym=<optimized out>, reloc=<optimized out>, map=<optimized out>)
at ../sysdeps/x86_64/dl-machine.h:464
#1 elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>, nrelative=<optimized out>, relsize=<optimized out>, reladdr=<optimized out>, map=0x7ffff7ffe1a0)
at do-rel.h:137
#2 _dl_relocate_object (l=l@entry=0x7ffff7ffe1a0, scope=<optimized out>, reloc_mode=<optimized out>, consider_profiling=<optimized out>, consider_profiling@entry=0)
at dl-reloc.c:274
#3 0x00007ffff7fd555b in dl_main (phdr=<optimized out>, phnum=<optimized out>, user_entry=<optimized out>, auxv=<optimized out>) at rtld.c:2341
#4 0x00007ffff7fec1a2 in _dl_sysdep_start (start_argptr=start_argptr@entry=0x7fffffffe380, dl_main=dl_main@entry=0x7ffff7fd34c0 <dl_main>) at ../elf/dl-sysdep.c:252
#5 0x00007ffff7fd3021 in _dl_start_final (arg=0x7fffffffe380) at rtld.c:504
#6 _dl_start (arg=0x7fffffffe380) at rtld.c:597
#7 0x00007ffff7fd2098 in _start () from /lib64/ld-linux-x86-64.so.2
重复其他构建组合。