This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH][x86_64] Convert indirect call via GOT to direct when possible
- From: Sriraman Tallam <tmsriram at google dot com>
- To: Rafael EspÃndola <rafael dot espindola at gmail dot com>
- Cc: "H.J. Lu" <hjl dot tools at gmail dot com>, binutils <binutils at sourceware dot org>, Cary Coutant <ccoutant at gmail dot com>, David Li <davidxl at google dot com>
- Date: Tue, 24 May 2016 15:58:20 -0700
- Subject: Re: [PATCH][x86_64] Convert indirect call via GOT to direct when possible
- Authentication-results: sourceware.org; auth=none
- References: <CAAs8HmxxdBpS7w8udZgK0QFi5TnenU3wGhpPfhWeKE8Tr=thvA at mail dot gmail dot com> <CAMe9rOpk3aOK5mMkKvYQyzeQxJ-h8o+3KjLRikKSkLmMfqoUtg at mail dot gmail dot com> <CAAs8Hmy5JtTXKLXW+OrnaNZdWJLcx8QUsRaB+Y2kfN8DuozEew at mail dot gmail dot com> <CAMe9rOpaW8oPXzm315ntp4ccp0==2TEJpn0CwJ=vg+m5gHWE6A at mail dot gmail dot com> <CAAs8Hmxj_VUY1fCZDWfhRadJYKNM-CqyLB_P6SAJbPd74OjVfA at mail dot gmail dot com> <CAG3jRe+EtyhdxRcFPJ5A-wBzfJWe9odVM2p_R6pfubzkf-t8pw at mail dot gmail dot com>
On Tue, May 24, 2016 at 3:39 PM, Rafael EspÃndola
<rafael.espindola@gmail.com> wrote:
> You need a R_X86_64_GOTPCRELX. Pass -mrelax-relocations=yes to a new
> version of gas.
Thanks! I will try that but why is this conversion not applicable for
just R_X86_64_GOTPCREL? What is the difference?
Sri
>
> Cheers,
> Rafael
>
>
> On 24 May 2016 at 18:06, Sriraman Tallam <tmsriram@google.com> wrote:
>> On Fri, May 20, 2016 at 2:32 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Fri, May 20, 2016 at 2:15 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>>>> On Fri, May 20, 2016 at 1:32 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>> On Fri, May 20, 2016 at 1:27 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>>>>>> Hi,
>>>>>>
>>>>>> GCC has option -fno-plt which converts all extern calls to indirect
>>>>>> calls via GOT to prevent the linker for generating any PLT stubs.
>>>>>> However, if the function ends up defined in the executable this patch
>>>>>> will convert those indirect calls/jumps to direct. Since the indirect
>>>>>> calls are one byte longer, an extra nop is needed at the beginning.
>>>>>>
>>>>>> Here is a simple example:
>>>>>>
>>>>>> main.c
>>>>>> ---------
>>>>>> extern int foo();
>>>>>> int main() {
>>>>>> return foo();
>>>>>> }
>>>>>>
>>>>>> deffoo.c
>>>>>> -----------
>>>>>> int foo() {
>>>>>> return 0;
>>>>>> }
>>>>>>
>>>>>> $ gcc -fno-plt main.c deffoo.c
>>>>>> $objdump -d a.out
>>>>>>
>>>>>> 0000000000400626 <main>:
>>>>>> ...
>>>>>> 40062a: ff 15 28 14 00 00 callq *0x1428(%rip) #
>>>>>> 401a58 <_DYNAMIC+0x1d8>
>>>>>>
>>>>>> The call is indirect even though foo is defined in the executable.
>>>>>>
>>>>>> With this patch,
>>>>>> 0000000000400606 <main>:
>>>>>> ....
>>>>>> 40060a: 90 nop
>>>>>> 40060b: e8 03 00 00 00 callq 400613 <foo>
>>>>>>
>>>>>> The call is now direct with an extra nop.
>>>>>>
>>>>>>
>>>>>
>>>>> Please try ld, which uses 0x67 prefix (addr32) instead of nop.
>>>>
>>>> Is this committed to ld?, trunk ld does not seem to do this.
>>>
>>> It works for me.
>>
>> I think I am missing something obvious here as this conversion is not
>> happening for me:
>>
>> foo.o: file format elf64-x86-64
>>
>> Disassembly of section .text:
>>
>> 0000000000000000 <foo>:
>> 0: 31 c0 xor %eax,%eax
>> 2: c3 retq
>>
>> 0000000000000003 <_start>:
>> 3: 31 c0 xor %eax,%eax
>> 5: ff 25 00 00 00 00 jmpq *0x0(%rip) # b <_start+0x8>
>> 7: R_X86_64_GOTPCREL foo-0x4
>>
>> Now,
>>
>> $ ld --version
>> GNU ld (GNU Binutils) 2.26.51.20160524
>> Copyright (C) 2016 Free Software Foundation, Inc.
>>
>> $ ld foo.o
>>
>> $ objdump -d a.out
>> a.out: file format elf64-x86-64
>>
>>
>> Disassembly of section .text:
>>
>> 00000000004000e8 <foo>:
>> 4000e8: 31 c0 xor %eax,%eax
>> 4000ea: c3 retq
>>
>> 00000000004000eb <_start>:
>> 4000eb: 31 c0 xor %eax,%eax
>> 4000ed: ff 25 05 00 20 00 jmpq *0x200005(%rip) # 6000f8
>> <_start+0x20000d>
>>
>>
>> The jmpq is not converted and it should be I would assume.
>>
>>>
>>>> Also a quick thing about -fPIE and -fno-plt. The assembly looks like
>>>> this for the call:
>>>>
>>>> movq foo@GOTPCREL(%rip), %rax
>>>> jmp *%rax
>>>>
>>>> Why can't we make this a single jmp *foo@GOTPCREL(%rip)
>>>
>>> Works for me:
>>
>> Right, this works at HEAD so maybe we are missing some patch that combines this.
>>
>>>
>>> [hjl@gnu-6 tmp]$ cat x.c
>>> extern void bar (void);
>>>
>>> void
>>> foo (void)
>>> {
>>> bar ();
>>> }
>>> [hjl@gnu-6 tmp]$ cat y.c
>>> extern void foo (void);
>>>
>>> void
>>> bar (void)
>>> {
>>> }
>>>
>>> int
>>> main (void)
>>> {
>>> foo ();
>>> return 0;
>>> }
>>> [hjl@gnu-6 tmp]$ /usr/gcc-6.1.1-x32/bin/gcc -S -fPIE -fno-plt -O2 x.c y.c
>>> [hjl@gnu-6 tmp]$ /usr/gcc-6.1.1-x32/bin/gcc -pie x.o y.o
>>> gcc: error: y.o: No such file or directory
>>> [hjl@gnu-6 tmp]$ /usr/gcc-6.1.1-x32/bin/gcc -S -fPIE -fno-plt -O2 x.c y.c
>>> [hjl@gnu-6 tmp]$ /usr/gcc-6.1.1-x32/bin/gcc -pie x.s y.s
>>> [hjl@gnu-6 tmp]$ cat x.s
>>> .file "x.c"
>>> .text
>>> .p2align 4,,15
>>> .globl foo
>>> .type foo, @function
>>> foo:
>>> .LFB0:
>>> .cfi_startproc
>>> jmp *bar@GOTPCREL(%rip)
>>> .cfi_endproc
>>> .LFE0:
>>> .size foo, .-foo
>>> .ident "GCC: (GNU) 6.1.1 20160428"
>>> .section .note.GNU-stack,"",@progbits
>>> [hjl@gnu-6 tmp]$ gdb a.out
>>> GNU gdb (GDB) Fedora 7.10.1-31.fc23
>>> Copyright (C) 2015 Free Software Foundation, Inc.
>>> License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
>>> This is free software: you are free to change and redistribute it.
>>> There is NO WARRANTY, to the extent permitted by law. Type "show copying"
>>> and "show warranty" for details.
>>> This GDB was configured as "x86_64-redhat-linux-gnu".
>>> Type "show configuration" for configuration details.
>>> For bug reporting instructions, please see:
>>> <http://www.gnu.org/software/gdb/bugs/>.
>>> Find the GDB manual and other documentation resources online at:
>>> <http://www.gnu.org/software/gdb/documentation/>.
>>> For help, type "help".
>>> Type "apropos word" to search for commands related to "word"...
>>> Reading symbols from a.out...(no debugging symbols found)...done.
>>> (gdb) disass foo
>>> Dump of assembler code for function foo:
>>> 0x0000000000000660 <+0>: jmpq 0x670 <bar>
>>> 0x0000000000000665 <+5>: nop
>>> End of assembler dump.
>>> (gdb)
>>>
>>>> This goes via the GOT if foo is external and that is always reachable
>>>> with a 32-bit offset. Did I miss anything obvious?
>>>>
>>>>
>>>>> Also for
>>>>>
>>>>> jmp *foo#GOTPCREL(%rip)
>>>>>
>>>>> ld converts it to
>>>>>
>>>>> jmp foo
>>>>> nop
>>>>>
>>>>> --
>>>>> H.J.
>>>
>>>
>>>
>>> --
>>> H.J.