Skip to content
Advertisement

Why GOT entry offset appears wrong?

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 6aa6bb 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?

Advertisement

Answer

There are two kinds of relocations: static and dynamic (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).

When you use objdump to dump relocations, it has -r option for static relocations, and -R for dynamic relocations.

Your case is not just GOT, it is GOT.PLT – GOT used for procedute linkage. This kind of access uses dynamic relocations. So, you should check output of objdump -dR libtest.so, it will show you both disassembly and dynamic relocations in it.

Cited line from readelf -r libtest.so is just for PLT table, not for the code.

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.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement