0

I wrote simple shared library:

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

Disassembled, to see how some_func is referenced:

$ 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    $0x8,%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 $0x200956,%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 $0xffffffffffdff580,%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    $0x8,%rsp
 6d5:   41 5f                   pop    %r15
 6d7:   5d                      pop    %rbp
 6d8:   c3                      retq

Looked where .got.plt is located:

$ readelf -S libtest.so
...
[21] .got.plt          PROGBITS         0000000000201000  00001000
       0000000000000020  0000000000000008  WA       0     0     8
...

What is the relocation:

$ 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


In 6aa-6bb we get absolute location of GOT: 6aa + 0x200956 = 0x201000 That agrees with readelf -S libtest.so 's output.

We skip 3 reserved bytes in GOT(functions-related) and determine that some_func's absolute address should be found at +0x18(forth byte from GOT) offset at runtime.

That agrees with readelf -r libtest.so.

But 6c1 instruction in objdump's disassembly shows:

  movabs $0xfff...dff580, %rdx  

I expect that source operand will hold +0x18 (offset from GOT, its address located at rax), but instead it has some large negative number.

Could you explain what it shows that number but not 0x18?

4

1 回答 1

2

有两种重定位:静态和动态(1);一个用于静态链接器ld,另一个用于加载器(动态链接器,rtld) -ld-linux.so.2用于 linux 的 glibc 2.*(检查Dynamic Linking and Loading, 1999Static Linkers and Dyanmic Link Loaders)。

当您使用objdump转储重定位时,它具有-r静态重定位和-R动态重定位的选项。

您的案例不仅仅是 GOT,它是 GOT.PLT - GOT 用于程序链接。这种访问使用动态重定位。因此,您应该检查 的输出objdump -dR libtest.so,它会在其中显示反汇编和动态重定位。

引用的行readelf -r libtest.so仅适用于 PLT 表,不适用于代码。

http://www.airs.com/blog/archives/41

或函数调用,程序链接器将设置一个 PLT 条目,如下所示:

jmp *offset(%ebx)
pushl #index
jmp first_plt_entry

程序链接器将在 GOT 中为 PLT 中的每个条目分配一个条目。它将为 JMP_SLOT 类型的 GOT 条目创建动态重定位。它将 GOT 条目初始化为共享库的基地址加上上面代码序列中第二条指令的地址。当动态链接器对 JMP_SLOT reloc 进行初始惰性绑定时,它会简单地将共享库加载地址和共享库基地址之间的差异添加到 GOT 条目中。效果是第一条 jmp 指令会跳转到第二条指令,第二条指令会推送索引条目并跳转到第一个 PLT 条目。第一个 PLT 条目很特殊,如下所示:

pushl 4(%ebx)
jmp *8(%ebx)

这引用了 GOT 中的第二个和第三个条目。动态链接器会将它们初始化为具有适当的值,以便回调到动态链接器本身。动态链接器将使用第一个代码序列推送的索引来查找 JMP_SLOT 重定位。当动态链接器确定要调用的函数时,它将通过第一个代码序列将该函数的地址存储到GOT条目引用中。因此,下次调用该函数时,jmp 指令将直接跳转到正确的代码。

于 2016-10-05T17:53:08.843 回答