Rah*_*win 5 c linker shared-libraries
首先,我正在玩的玩具程序:
prog.c中:
int func1();
int main(int argc, char const *argv[])
{
func1();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
lib.c:
int func1()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
建立:
gcc -O3 -g -shared -fpic ./lib.c -o liba.so
gcc prog.c -g -la -L. -o prog -Wl,-rpath=$PWD
Run Code Online (Sandbox Code Playgroud)
并且为了完整性:
$ gcc --version
gcc (GCC) 6.3.1
$ ld --version
GNU ld version 2.26.1
Run Code Online (Sandbox Code Playgroud)
现在,我的问题.我已经确认了我所读到的关于动态符号的延迟绑定是如何工作的,即最初是func1在PLT后面的点的GOT条目,到跳转后的指令:
$ gdb prog
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400666 <+0>: push rbp
0x0000000000400667 <+1>: mov rbp,rsp
0x000000000040066a <+4>: sub rsp,0x10
0x000000000040066e <+8>: mov DWORD PTR [rbp-0x4],edi
0x0000000000400671 <+11>: mov QWORD PTR [rbp-0x10],rsi
0x0000000000400675 <+15>: mov eax,0x0
0x000000000040067a <+20>: call 0x400560 <func1@plt> <<< call to shared lib via PLT
0x000000000040067f <+25>: mov eax,0x0
0x0000000000400684 <+30>: leave
0x0000000000400685 <+31>: ret
End of assembler dump.
(gdb) disassemble 0x400560
Dump of assembler code for function func1@plt:
0x0000000000400560 <+0>: jmp QWORD PTR [rip+0x200ab2] # 0x601018 <<< JMP to address stored in GOT
0x0000000000400566 <+6>: push 0x0 <<< ... which initially points right back here
0x000000000040056b <+11>: jmp 0x400550
End of assembler dump.
(gdb) x/g 0x601018
0x601018: 0x400566 <<< GOT point back right after the just-executed jump
Run Code Online (Sandbox Code Playgroud)
这可以.现在,检查0x601018包含此指针的.got.plt部分,0x400566显示二进制文件本身保存地址,而动态链接器在加载时不执行任何操作.这是有道理的,因为这个地址在链接时是已知的:
$ readelf -x .got.plt ./prog
Hex dump of section '.got.plt':
NOTE: This section has relocations against it, but these have NOT been applied to this dump.
0x00601000 ???????? ???????? ???????? ???????? ..`.............
0x00601010 ???????? ???????? 66054000 ???????? ........f.@.....
Run Code Online (Sandbox Code Playgroud)
(最初存储在GOT中66054000的地址的little-endian rep.0x400566)
很好,很好.但是之后...
$ readelf -r prog
<...>
Relocation section '.rela.plt' at offset 0x518 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 func1 + 0
Run Code Online (Sandbox Code Playgroud)
为什么有这个GOT地址的重定位条目?我们已经看到正确的地址已经存在,在二进制文件中,在链接时放置在那里.我还试验性地编辑了这个重定位,使其无效,程序运行正常.所以reloc似乎没什么贡献.它在那里做了什么,更一般地说,重新定位rela.plt实际上重要的场景是什么?
更新#1:
需要说明的是,这是关于PIC代码和64位代码.以下是相关的部分地址,以帮助说明地址所属的位置:
$ readelf -S ./prog
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 9] .rela.dyn RELA 00000000004004e8 000004e8
0000000000000030 0000000000000018 A 5 0 8
[10] .rela.plt RELA 0000000000400518 00000518
0000000000000018 0000000000000018 AI 5 23 8
[12] .plt PROGBITS 0000000000400550 00000550
0000000000000020 0000000000000010 AX 0 0 16
[21] .dynamic DYNAMIC 0000000000600e00 00000e00
00000000000001f0 0000000000000010 WA 6 0 8
[22] .got PROGBITS 0000000000600ff0 00000ff0
0000000000000010 0000000000000008 WA 0 0 8
[23] .got.plt PROGBITS 0000000000601000 00001000
0000000000000020 0000000000000008 WA 0 0 8
Run Code Online (Sandbox Code Playgroud)
更新#2:
编辑节标题.rela.plt不会更改过程映像,因此我没有禁用重定位.我也曾尝试更改reloc地址(到另一个可写地址),这似乎也没有什么区别,但事实证明,在延迟绑定期间解析器不使用该地址,尽管其余的reloc是.仅在关闭延迟绑定时才使用地址本身LD_BIND_NOW.
谢谢@yugr
这可以。现在,检查 0x601018 处的 .got.plt 部分,其中包含指向 0x400566 的指针,表明二进制文件本身保存了地址,而动态链接器在加载时没有做任何事情。
并不真地。请注意,0x400566 处的代码最终会跳转到 0x400550,即PLT 存根之前的16 个字节。0x400550 处的代码会将 GOT 的地址压入堆栈并调用动态链接器。有关更多信息,请查看此演示文稿(幻灯片 14)。
这是有道理的,因为这个地址在链接时是已知的
是吗?地址将来自共享库,由于 ASLR,它将在启动时以随机地址加载,因此静态链接器无法知道地址...
为什么这个GOT地址有重定位入口?
当 PLT 存根调用动态链接器时(在第一次调用时),它会将 GOT 入口的地址传递给它。动态链接器将搜索 .rela.plt 以找出如何重定位 GOT 条目(即函数名称和偏移量)。
| 归档时间: |
|
| 查看次数: |
938 次 |
| 最近记录: |