This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH][x86_64] Convert indirect call via GOT to direct when possible


You need a R_X86_64_GOTPCRELX.  Pass -mrelax-relocations=yes to a new
version of gas.

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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]