This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: What is R_X86_64_GOTPLT64 used for?
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: Michael Matz <matz at suse dot de>
- Cc: "x86-64-abi at googlegroups dot com" <x86-64-abi at googlegroups dot com>, GCC Development <gcc at gcc dot gnu dot org>, Binutils <binutils at sourceware dot org>, GNU C Library <libc-alpha at sourceware dot org>
- Date: Wed, 19 Nov 2014 08:38:00 -0800
- Subject: Re: What is R_X86_64_GOTPLT64 used for?
- Authentication-results: sourceware.org; auth=none
- References: <CAMe9rOqb0g2asAe6UZ0hxh8jFf-+eBiaez0pLrPjd0oqVdP0Rg at mail dot gmail dot com> <alpine dot LNX dot 2 dot 00 dot 1411131717220 dot 405 at wotan dot suse dot de> <CAMe9rOrTg=YtVZ1EqN7ha8qUPSXzms20eMU51txVAmL3+cUsQQ at mail dot gmail dot com> <CAMe9rOrnQRo3XXowAEcd_h=i_i5v04=i=kLWjm2ANduv8MwhYQ at mail dot gmail dot com> <alpine dot LNX dot 2 dot 00 dot 1411171425020 dot 405 at wotan dot suse dot de>
On Mon, Nov 17, 2014 at 6:14 AM, Michael Matz <matz@suse.de> wrote:
> Hi,
>
> On Thu, 13 Nov 2014, H.J. Lu wrote:
>
>> Linker does:
>>
>> ... code that looks like it might create just one GOT slot ...
>>
>> So if a symbol is accessed by both @GOT and @PLTOFF, its
>> needs_plt will be true and its got.plt entry will be used for
>> both @GOT and @GOTPLT. @GOTPLT has no advantage
>> over @GOT, but potentially wastes a PLT entry.
>
> The above is not correct. Had you tried you'd see this:
>
> % cat x.c
> extern void foo (void);
> void main (void)
> {
> void (*f)(void) = foo;
> f();
> foo();
> }
> % gcc -fPIE -mcmodel=large -S x.c; cat x.s
> ...
> movabsq $foo@GOT, %rax
> ...
> movabsq $foo@PLTOFF, %rax
> ...
>
> So, foo is access via @GOT offset and @PLTOFF. Then,
>
> % cat y.c
> void foo (void) {}
> % gcc -o liby.so -shared -fPIC y.c
> % gcc -fPIE -mcmodel=large x.s liby.so
> % readelf -r a.out
> ...
> 000000600ff8 000400000006 R_X86_64_GLOB_DAT 0000000000000000 foo + 0
> ...
> 000000601028 000400000007 R_X86_64_JUMP_SLO 0000000000000000 foo + 0
> ...
>
> The first one (to 600ff8) is the normal GOT slot, the second one the GOT
> slot for the PLT entry. Both are actually used:
>
> 00000000004005f0 <foo@plt>:
> 4005f0: ff 25 32 0a 20 00 jmpq *0x200a32(%rip) # 601028 <_GLOBAL_OFFSET_TABLE_+0x28>
They are not:
Starting program: /export/home/hjl/bugs/binutils/gotplt/foo
Breakpoint 1, main () at main.c:5
5 void (*f)(void) = foo;
(gdb) disass
Dump of assembler code for function main:
0x000000000040058d <+0>: push %rbp
0x000000000040058e <+1>: mov %rsp,%rbp
0x0000000000400591 <+4>: push %rbx
0x0000000000400592 <+5>: sub $0x18,%rsp
0x0000000000400596 <+9>: lea -0x7(%rip),%rbx # 0x400596 <main+9>
0x000000000040059d <+16>: movabs $0x20042a,%r11
0x00000000004005a7 <+26>: add %r11,%rbx
=> 0x00000000004005aa <+29>: movabs $0xfffffffffffffff8,%rax
0x00000000004005b4 <+39>: mov (%rbx,%rax,1),%rax
0x00000000004005b8 <+43>: mov %rax,-0x18(%rbp)
0x00000000004005bc <+47>: mov -0x18(%rbp),%rax
0x00000000004005c0 <+51>: callq *%rax
0x00000000004005c2 <+53>: movabs $0xffffffffffdffad0,%rax
0x00000000004005cc <+63>: add %rbx,%rax
0x00000000004005cf <+66>: callq *%rax
0x00000000004005d1 <+68>: mov $0x0,%eax
0x00000000004005d6 <+73>: add $0x18,%rsp
0x00000000004005da <+77>: pop %rbx
0x00000000004005db <+78>: pop %rbp
0x00000000004005dc <+79>: retq
End of assembler dump.
(gdb) b *0x00000000004005c0
Breakpoint 2 at 0x4005c0: file main.c, line 6.
(gdb) b *0x00000000004005cf
Breakpoint 3 at 0x4005cf: file main.c, line 7.
(gdb) c
Continuing.
Breakpoint 2, 0x00000000004005c0 in main () at main.c:6
6 f();
(gdb) p $rax
$5 = 140737352012384
(gdb) disass $rax
Dump of assembler code for function foo:
0x00007ffff7df9260 <+0>: push %rbp
0x00007ffff7df9261 <+1>: mov %rsp,%rbp
0x00007ffff7df9264 <+4>: lea 0x7(%rip),%rdi # 0x7ffff7df9272
0x00007ffff7df926b <+11>: callq 0x7ffff7df9250 <puts@plt>
0x00007ffff7df9270 <+16>: pop %rbp
0x00007ffff7df9271 <+17>: retq
End of assembler dump.
(gdb) c
Continuing.
foo
Breakpoint 3, 0x00000000004005cf in main () at main.c:7
7 foo();
(gdb) p $rax
$6 = 4195472
(gdb) disass $rax
Dump of assembler code for function foo@plt:
0x0000000000400490 <+0>: jmpq *0x200552(%rip) # 0x6009e8
<foo@got.plt>
0x0000000000400496 <+6>: pushq $0x2
0x000000000040049b <+11>: jmpq 0x400460
End of assembler dump.
(gdb)
> That uses the second GOT slot, and:
>
> 00000000004006ec <main>:
> 4006ec: 55 push %rbp
> 4006ed: 48 89 e5 mov %rsp,%rbp
> 4006f0: 53 push %rbx
> 4006f1: 48 83 ec 18 sub $0x18,%rsp
> 4006f5: 48 8d 1d f9 ff ff ff lea -0x7(%rip),%rbx # 4006f5 <main+0x9>
> 4006fc: 49 bb 0b 09 20 00 00 movabs $0x20090b,%r11
> 400703: 00 00 00
> 400706: 4c 01 db add %r11,%rbx
> 400709: 48 b8 f8 ff ff ff ff movabs $0xfffffffffffffff8,%rax
> 400710: ff ff ff
> 400713: 48 8b 04 03 mov (%rbx,%rax,1),%rax
>
> This uses the first slot at 0x600ff8.
>
> So, no, currently GOT and GOTPLT (at least how it's supposed to be
> implemented) are not equivalent.
GOT reference:
void (*f)(void) = foo;
f();
gives you the address of function, foo, in liby.so, without going through
PLT, while
foo()
is called via PLT. For function call, we must use PLT. For pointer
reference, we don't use PLT slot:
1. We don't need the indirect branch in PLT.
2. All pointer references to the same function should have the same
value.
One way to optimize it is to make PLT entry to use the normal GOT
slot:
jmp *name@GOTPCREL(%rip)
8 byte nop
where name@GOTPCREL points to the normal GOT slot
updated by R_X86_64_GLOB_DAT relocation at run-time.
Should I give it a try?
--
H.J.