为什么GOT entry offset 出现错误?
Why GOT entry offset appears wrong?
我写了简单的共享库:
extern void some_func(void);
void
function(void)
{
some_func();
}
Compiled/built:
gcc -fPIC -mcmodel=large -c test.c -o test.o
gcc -fPIC -shared test.o -o libtest.so
反汇编,看看some_func是如何被引用的:
$ objdump -d libtest.so
00000000000006a0 <function>:
6a0: 55 push %rbp
6a1: 48 89 e5 mov %rsp,%rbp
6a4: 41 57 push %r15
6a6: 48 83 ec 08 sub [=12=]x8,%rsp
6aa: 48 8d 05 f9 ff ff ff lea -0x7(%rip),%rax # 6aa <function+0xa>
6b1: 49 bb 56 09 20 00 00 movabs [=12=]x200956,%r11
6b8: 00 00 00
6bb: 4c 01 d8 add %r11,%rax
6be: 49 89 c7 mov %rax,%r15
6c1: 48 ba 80 f5 df ff ff movabs [=12=]xffffffffffdff580,%rdx
6c8: ff ff ff
6cb: 48 01 c2 add %rax,%rdx
6ce: ff d2 callq *%rdx
6d0: 90 nop
6d1: 48 83 c4 08 add [=12=]x8,%rsp
6d5: 41 5f pop %r15
6d7: 5d pop %rbp
6d8: c3 retq
查看了 .got.plt
所在的位置:
$ readelf -S libtest.so
...
[21] .got.plt PROGBITS 0000000000201000 00001000
0000000000000020 0000000000000008 WA 0 0 8
...
什么是搬迁:
$ readelf -r libtest.so
Relocation section '.rela.plt' at offset 0x538 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000201018 000400000007 R_X86_64_JUMP_SLO 0000000000000000 some_func + 0
在6aa
-6bb
我们得到GOT的绝对位置:6aa + 0x200956 = 0x201000
这与 readelf -S libtest.so
的输出一致。
我们跳过 GOT 中的 3 个保留字节(与函数相关)并确定 some_func 的绝对地址应该在运行时在 +0x18(GOT 的第四个字节)偏移量处找到。
同意 readelf -r libtest.so
。
但是objdump的反汇编中的6c1指令显示:
movabs [=15=]xfff...dff580, %rdx
我预计源操作数将保持 +0x18
(与 GOT 的偏移量,其地址位于 rax
),但它有一些大的负数。
你能解释一下它显示的是什么数字而不是 0x18
吗?
有两种重定位:静态和动态 (1); one for static linker ld
and other for loader (dynamic linker, rtld) - ld-linux.so.2
for linux's glibc 2.* (check Dynamic Linking and Loading, 1999 or Static Linkers and Dyanmic Link Loaders)。
当您使用 objdump
转储重定位时,它有 -r
静态重定位选项和 -R
动态重定位选项。
您的案例不仅仅是 GOT,它是 GOT.PLT - GOT 用于程序链接。这种访问使用动态重定位。因此,您应该检查 objdump -dR libtest.so
的输出,它会向您显示其中的反汇编和动态重定位。
来自 readelf -r libtest.so
的引用行仅适用于 PLT table,不适用于代码。
http://www.airs.com/blog/archives/41
or function calls, the program linker will set up a PLT entry to look like this:
jmp *offset(%ebx)
pushl #index
jmp first_plt_entry
The program linker will allocate an entry in the GOT for each entry in
the PLT. It will create a dynamic relocation for the GOT entry of type
JMP_SLOT. It will initialize the GOT entry to the base address of the
shared library plus the address of the second instruction in the code
sequence above. When the dynamic linker does the initial lazy binding
on a JMP_SLOT reloc, it will simply add the difference between the
shared library load address and the shared library base address to the
GOT entry. The effect is that the first jmp instruction will jump to
the second instruction, which will push the index entry and branch to
the first PLT entry. The first PLT entry is special, and looks like this:
pushl 4(%ebx)
jmp *8(%ebx)
This references the second and third entries in the GOT. The dynamic
linker will initialize them to have appropriate values for a callback
into the dynamic linker itself. The dynamic linker will use the index
pushed by the first code sequence to find the JMP_SLOT relocation.
When the dynamic linker determines the function to be called, it will
store the address of the function into the GOT entry references by the
first code sequence. Thus, the next time the function is called, the
jmp instruction will branch directly to the right code.
我写了简单的共享库:
extern void some_func(void);
void
function(void)
{
some_func();
}
Compiled/built:
gcc -fPIC -mcmodel=large -c test.c -o test.o
gcc -fPIC -shared test.o -o libtest.so
反汇编,看看some_func是如何被引用的:
$ objdump -d libtest.so
00000000000006a0 <function>:
6a0: 55 push %rbp
6a1: 48 89 e5 mov %rsp,%rbp
6a4: 41 57 push %r15
6a6: 48 83 ec 08 sub [=12=]x8,%rsp
6aa: 48 8d 05 f9 ff ff ff lea -0x7(%rip),%rax # 6aa <function+0xa>
6b1: 49 bb 56 09 20 00 00 movabs [=12=]x200956,%r11
6b8: 00 00 00
6bb: 4c 01 d8 add %r11,%rax
6be: 49 89 c7 mov %rax,%r15
6c1: 48 ba 80 f5 df ff ff movabs [=12=]xffffffffffdff580,%rdx
6c8: ff ff ff
6cb: 48 01 c2 add %rax,%rdx
6ce: ff d2 callq *%rdx
6d0: 90 nop
6d1: 48 83 c4 08 add [=12=]x8,%rsp
6d5: 41 5f pop %r15
6d7: 5d pop %rbp
6d8: c3 retq
查看了 .got.plt
所在的位置:
$ readelf -S libtest.so
...
[21] .got.plt PROGBITS 0000000000201000 00001000
0000000000000020 0000000000000008 WA 0 0 8
...
什么是搬迁:
$ readelf -r libtest.so
Relocation section '.rela.plt' at offset 0x538 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000201018 000400000007 R_X86_64_JUMP_SLO 0000000000000000 some_func + 0
在6aa
-6bb
我们得到GOT的绝对位置:6aa + 0x200956 = 0x201000
这与 readelf -S libtest.so
的输出一致。
我们跳过 GOT 中的 3 个保留字节(与函数相关)并确定 some_func 的绝对地址应该在运行时在 +0x18(GOT 的第四个字节)偏移量处找到。
同意 readelf -r libtest.so
。
但是objdump的反汇编中的6c1指令显示:
movabs [=15=]xfff...dff580, %rdx
我预计源操作数将保持 +0x18
(与 GOT 的偏移量,其地址位于 rax
),但它有一些大的负数。
你能解释一下它显示的是什么数字而不是 0x18
吗?
有两种重定位:静态和动态 (1); one for static linker ld
and other for loader (dynamic linker, rtld) - ld-linux.so.2
for linux's glibc 2.* (check Dynamic Linking and Loading, 1999 or Static Linkers and Dyanmic Link Loaders)。
当您使用 objdump
转储重定位时,它有 -r
静态重定位选项和 -R
动态重定位选项。
您的案例不仅仅是 GOT,它是 GOT.PLT - GOT 用于程序链接。这种访问使用动态重定位。因此,您应该检查 objdump -dR libtest.so
的输出,它会向您显示其中的反汇编和动态重定位。
来自 readelf -r libtest.so
的引用行仅适用于 PLT table,不适用于代码。
http://www.airs.com/blog/archives/41
or function calls, the program linker will set up a PLT entry to look like this:
jmp *offset(%ebx) pushl #index jmp first_plt_entry
The program linker will allocate an entry in the GOT for each entry in the PLT. It will create a dynamic relocation for the GOT entry of type JMP_SLOT. It will initialize the GOT entry to the base address of the shared library plus the address of the second instruction in the code sequence above. When the dynamic linker does the initial lazy binding on a JMP_SLOT reloc, it will simply add the difference between the shared library load address and the shared library base address to the GOT entry. The effect is that the first jmp instruction will jump to the second instruction, which will push the index entry and branch to the first PLT entry. The first PLT entry is special, and looks like this:
pushl 4(%ebx) jmp *8(%ebx)
This references the second and third entries in the GOT. The dynamic linker will initialize them to have appropriate values for a callback into the dynamic linker itself. The dynamic linker will use the index pushed by the first code sequence to find the JMP_SLOT relocation. When the dynamic linker determines the function to be called, it will store the address of the function into the GOT entry references by the first code sequence. Thus, the next time the function is called, the jmp instruction will branch directly to the right code.