Bug 20253

Summary: Unnecessary PLT entry for IFUNC function via GOT
Product: binutils Reporter: H.J. Lu <hjl.tools>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P2    
Version: 2.27   
Target Milestone: 2.27   
Host: Target: x86
Build: Last reconfirmed:

Description H.J. Lu 2016-06-14 00:36:27 UTC
[hjl@gnu-6 saved]$ cat x.S
	.text
	.globl	foo
	.type	foo, @gnu_indirect_function
foo:
	ret
	.text
	.type	bar, @gnu_indirect_function
bar:
	ret
	.globl	_start
	.type	_start, @function
_start:
#ifdef __x86_64__
	call	*foo@GOTPCREL(%rip)
	jmp	*bar@GOTPCREL(%rip)
	movq	$0, bar@GOTPCREL(%rip)
	cmpq	$0, foo@GOTPCREL(%rip)
	cmpq	foo@GOTPCREL(%rip), %rcx
	cmpq	bar@GOTPCREL(%rip), %rcx
#else
	call	*foo@GOT
	jmp	*bar@GOT
	movl	$0, bar@GOT
	cmpl	$0, foo@GOT
	cmpl	foo@GOT, %ecx
	cmpl	bar@GOT, %ecx
#endif
[hjl@gnu-6 saved]$ make x32
gcc -B./ -c -mx32 -o x32.o x.S
ld -z nocombreloc -m elf32_x86_64 -o x32 x32.o
objdump -dw x32

x32:     file format elf32-x86-64


Disassembly of section .plt:

00400090 <.plt>:
  400090:	ff 25 62 00 20 00    	jmpq   *0x200062(%rip)        # 6000f8 <_GLOBAL_OFFSET_TABLE_+0x18>
  400096:	68 00 00 00 00       	pushq  $0x0
  40009b:	e9 00 00 00 00       	jmpq   4000a0 <foo-0x10>
  4000a0:	ff 25 5a 00 20 00    	jmpq   *0x20005a(%rip)        # 600100 <_GLOBAL_OFFSET_TABLE_+0x20>
  4000a6:	68 00 00 00 00       	pushq  $0x0
  4000ab:	e9 00 00 00 00       	jmpq   4000b0 <foo>

Disassembly of section .text:

004000b0 <foo>:
  4000b0:	c3                   	retq   

004000b1 <bar>:
  4000b1:	c3                   	retq   

004000b2 <_start>:
  4000b2:	ff 15 40 00 20 00    	callq  *0x200040(%rip)        # 6000f8 <_GLOBAL_OFFSET_TABLE_+0x18>
  4000b8:	ff 25 42 00 20 00    	jmpq   *0x200042(%rip)        # 600100 <_GLOBAL_OFFSET_TABLE_+0x20>
  4000be:	48 c7 05 37 00 20 00 00 00 00 00 	movq   $0x0,0x200037(%rip)        # 600100 <_GLOBAL_OFFSET_TABLE_+0x20>
  4000c9:	48 83 3d 27 00 20 00 00 	cmpq   $0x0,0x200027(%rip)        # 6000f8 <_GLOBAL_OFFSET_TABLE_+0x18>
  4000d1:	48 3b 0d 20 00 20 00 	cmp    0x200020(%rip),%rcx        # 6000f8 <_GLOBAL_OFFSET_TABLE_+0x18>
  4000d8:	48 3b 0d 21 00 20 00 	cmp    0x200021(%rip),%rcx        # 600100 <_GLOBAL_OFFSET_TABLE_+0x20>
[hjl@gnu-6 saved]$ make i386
gcc -B./ -c -m32 -o i386.o x.S
ld -z nocombreloc -m elf_i386 -o i386 i386.o
objdump -dw i386

i386:     file format elf32-i386


Disassembly of section .plt:

08048090 <.plt>:
 8048090:	ff 25 e8 90 04 08    	jmp    *0x80490e8
 8048096:	68 00 00 00 00       	push   $0x0
 804809b:	e9 00 00 00 00       	jmp    80480a0 <foo-0x10>
 80480a0:	ff 25 ec 90 04 08    	jmp    *0x80490ec
 80480a6:	68 00 00 00 00       	push   $0x0
 80480ab:	e9 00 00 00 00       	jmp    80480b0 <foo>

Disassembly of section .text:

080480b0 <foo>:
 80480b0:	c3                   	ret    

080480b1 <bar>:
 80480b1:	c3                   	ret    

080480b2 <_start>:
 80480b2:	ff 15 e8 90 04 08    	call   *0x80490e8
 80480b8:	ff 25 ec 90 04 08    	jmp    *0x80490ec
 80480be:	c7 05 ec 90 04 08 00 00 00 00 	movl   $0x0,0x80490ec
 80480c8:	83 3d e8 90 04 08 00 	cmpl   $0x0,0x80490e8
 80480cf:	3b 0d e8 90 04 08    	cmp    0x80490e8,%ecx
 80480d5:	3b 0d ec 90 04 08    	cmp    0x80490ec,%ecx
[hjl@gnu-6 saved]$ make x86_64
gcc -B./ -c -m64 -o x86_64.o x.S
ld -z nocombreloc -m elf_x86_64 -o x86_64 x86_64.o
objdump -dw x86_64

x86_64:     file format elf64-x86-64


Disassembly of section .plt:

00000000004000e0 <.plt>:
  4000e0:	ff 25 62 00 20 00    	jmpq   *0x200062(%rip)        # 600148 <_GLOBAL_OFFSET_TABLE_+0x18>
  4000e6:	68 00 00 00 00       	pushq  $0x0
  4000eb:	e9 00 00 00 00       	jmpq   4000f0 <foo-0x10>
  4000f0:	ff 25 5a 00 20 00    	jmpq   *0x20005a(%rip)        # 600150 <_GLOBAL_OFFSET_TABLE_+0x20>
  4000f6:	68 00 00 00 00       	pushq  $0x0
  4000fb:	e9 00 00 00 00       	jmpq   400100 <foo>

Disassembly of section .text:

0000000000400100 <foo>:
  400100:	c3                   	retq   

0000000000400101 <bar>:
  400101:	c3                   	retq   

0000000000400102 <_start>:
  400102:	ff 15 40 00 20 00    	callq  *0x200040(%rip)        # 600148 <_GLOBAL_OFFSET_TABLE_+0x18>
  400108:	ff 25 42 00 20 00    	jmpq   *0x200042(%rip)        # 600150 <_GLOBAL_OFFSET_TABLE_+0x20>
  40010e:	48 c7 05 37 00 20 00 00 00 00 00 	movq   $0x0,0x200037(%rip)        # 600150 <_GLOBAL_OFFSET_TABLE_+0x20>
  400119:	48 83 3d 27 00 20 00 00 	cmpq   $0x0,0x200027(%rip)        # 600148 <_GLOBAL_OFFSET_TABLE_+0x18>
  400121:	48 3b 0d 20 00 20 00 	cmp    0x200020(%rip),%rcx        # 600148 <_GLOBAL_OFFSET_TABLE_+0x18>
  400128:	48 3b 0d 21 00 20 00 	cmp    0x200021(%rip),%rcx        # 600150 <_GLOBAL_OFFSET_TABLE_+0x20>
[hjl@gnu-6 saved]$ 

All of PLT entries should be removed.
Comment 1 Sourceware Commits 2016-06-18 16:18:35 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=233cc9c13af8e8182d0ce5b306526b59f5b11f37

commit 233cc9c13af8e8182d0ce5b306526b59f5b11f37
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sat Jun 18 09:16:52 2016 -0700

    Don't generate PLT for IFUNC GOT/pointer reference
    
    If a backend supports it, PLT entry isn't needed when all references
    to a STT_GNU_IFUNC symbols are done via GOT or static function pointers.
    For GOT entries, We generate dynamic R_*_GLOB_DAT relocations for
    preemptable symbols and R_*_IRELATIVE relocations for non-preemptable
    symbols to update them with real function address.  For static pointer
    pointers, we generate dynamic pointer relocations and store them in:
    
    1. .rel[a].ifunc section in PIC object.
    2. .rel[a].got section in dynamic executable.
    3. .rel[a].iplt section in static executable.
    
    We don't allocate GOT entry if it isn't used.
    
    bfd/
    
    	PR ld/20253
    	* elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): Add an
    	bfd_boolean argument.
    	* elf-ifunc.c (_bfd_elf_create_ifunc_sections): Replace
    	"shared object" with "PIC object" in comments.
    	(_bfd_elf_allocate_ifunc_dyn_relocs): Updated.  Replace
    	"shared object" with "PIC object" in comments.  Avoid PLT if
    	requested.  Generate dynamic relocations for non-GOT references.
    	Make room for the special first entry in PLT and allocate PLT
    	entry only for PLT and PC-relative references.  Store dynamic
    	GOT relocations in .rel[a].iplt section for static executables.
    	If PLT isn't used, always use GOT for symbol value.  Don't
    	allocate GOT entry if it isn't used.
    	* elf32-i386.c (elf_i386_check_relocs): Increment PLT reference
    	count only in the code section.  Allocate dynamic pointer
    	relocation against STT_GNU_IFUNC symbol in the non-code section.
    	(elf_i386_adjust_dynamic_symbol): Increment PLT reference count
    	only for PC-relative references.
    	(elf_i386_allocate_dynrelocs): Pass TRUE to
    	_bfd_elf_allocate_ifunc_dyn_relocs.
    	(elf_i386_relocate_section): Allow R_386_GOT32/R_386_GOT32X
    	relocations against STT_GNU_IFUNC symbols without PLT.  Generate
    	dynamic pointer relocation against STT_GNU_IFUNC symbol in
    	the non-code section and store it in the proper REL section.
    	Don't allow non-pointer relocation against STT_GNU_IFUNC symbol
    	without PLT.
    	(elf_i386_finish_dynamic_symbol): Generate dynamic
    	R_386_IRELATIVE and R_386_GLOB_DAT GOT relocations against
    	STT_GNU_IFUNC symbols without PLT.
    	(elf_i386_finish_dynamic_sections): Don't handle local
    	STT_GNU_IFUNC symbols here.
    	(elf_i386_output_arch_local_syms): Handle local STT_GNU_IFUNC
    	symbols here.
    	(elf_backend_output_arch_local_syms): New.
    	* elf32-x86-64.c (elf_i386_check_relocs): Increment PLT reference
    	count only in the code section.  Allocate dynamic pointer
    	relocation against STT_GNU_IFUNC symbol in the non-code section.
    	(elf_x86_64_adjust_dynamic_symbol): Increment PLT reference
    	count only for PC-relative references.
    	(elf_x86_64_allocate_dynrelocs): Pass TRUE to
    	_bfd_elf_allocate_ifunc_dyn_relocs.
    	(elf_x86_64_relocate_section): Allow R_X86_64_GOTPCREL,
    	R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX and
    	R_X86_64_GOTPCREL64 relocations against STT_GNU_IFUNC symbols
    	without PLT.  Generate dynamic pointer relocation against
    	STT_GNU_IFUNC symbol in the non-code section and store it in
    	the proper RELA section.  Don't allow non-pointer relocation
    	against STT_GNU_IFUNC symbol without PLT.
    	(elf_x86_64_finish_dynamic_symbol): Generate dynamic
    	R_X86_64_IRELATIVE and R_X86_64_GLOB_DAT GOT relocations against
    	STT_GNU_IFUNC symbols without PLT.
    	(elf_x86_64_finish_dynamic_sections): Don't handle local
    	STT_GNU_IFUNC symbols here.
    	(elf_x86_64_output_arch_local_syms): Handle local STT_GNU_IFUNC
    	symbols here.
    	(elf_backend_output_arch_local_syms): New.
    	* elfnn-aarch64.c (elfNN_aarch64_allocate_ifunc_dynrelocs):
    	Pass FALSE to _bfd_elf_allocate_ifunc_dyn_relocs.
    
    ld/
    
    	PR ld/20253
    	* testsuite/ld-i386/i386.exp: Run PR ld/20253 tests.
    	* testsuite/ld-i386/no-plt.exp: Likewise.
    	* testsuite/ld-x86-64/no-plt.exp: Likewise.
    	* testsuite/ld-i386/pr13302.d: Remove .rel.plt section.
    	* testsuite/ld-ifunc/ifunc-13-i386.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-13-x86-64.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-15-i386.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-15-x86-64.d: Likewise.
    	* testsuite/ld-x86-64/pr13082-5a.d: Likewise.
    	* testsuite/ld-x86-64/pr13082-5b.d: Likewise.
    	* testsuite/ld-x86-64/pr13082-6a.d: Likewise.
    	* testsuite/ld-x86-64/pr13082-6b.d: Likewise.
    	* testsuite/ld-i386/pr20244-2a.d: Remove .plt section.
    	* testsuite/ld-ifunc/ifunc-21-i386.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-21-x86-64.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-22-i386.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-22-x86-64.d: Likewise.
    	* testsuite/ld-i386/pr20244-2b.d: Updated.
    	* testsuite/ld-i386/pr20244-2c.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18a-i386.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18a-x86-64.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18b-i386.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18b-x86-64.d: Likewise.
    	* testsuite/ld-i386/pr20253-1a.c: New file.
    	* testsuite/ld-i386/pr20253-1b.S: Likewise.
    	* testsuite/ld-i386/pr20253-1c.S: Likewise.
    	* testsuite/ld-i386/pr20253-1d.S: Likewise.
    	* testsuite/ld-i386/pr20253-2a.c: Likewise.
    	* testsuite/ld-i386/pr20253-2b.S: Likewise.
    	* testsuite/ld-i386/pr20253-2c.S: Likewise.
    	* testsuite/ld-i386/pr20253-2d.S: Likewise.
    	* testsuite/ld-i386/pr20253-3.d: Likewise.
    	* testsuite/ld-i386/pr20253-3.s: Likewise.
    	* testsuite/ld-i386/pr20253-4.s: Likewise.
    	* testsuite/ld-i386/pr20253-4a.d: Likewise.
    	* testsuite/ld-i386/pr20253-4b.d: Likewise.
    	* testsuite/ld-i386/pr20253-4c.d: Likewise.
    	* testsuite/ld-i386/pr20253-5.d: Likewise.
    	* testsuite/ld-i386/pr20253-5.s: Likewise.
    	* testsuite/ld-ifunc/ifunc-23-x86.s: Likewise.
    	* testsuite/ld-ifunc/ifunc-23a-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-23b-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-23c-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-24-x86.s: Likewise.
    	* testsuite/ld-ifunc/ifunc-24a-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-24b-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-24c-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-25-x86.s: Likewise.
    	* testsuite/ld-ifunc/ifunc-25a-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-25b-x86.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-25c-x86.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1.s: Likewise.
    	* testsuite/ld-x86-64/pr20253-1a.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1b.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1c.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1d.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1e.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1f.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1g.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1h.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1i.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1j.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1k.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-1l.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-2a.c: Likewise.
    	* testsuite/ld-x86-64/pr20253-2b.S: Likewise.
    	* testsuite/ld-x86-64/pr20253-2c.S: Likewise.
    	* testsuite/ld-x86-64/pr20253-2d.S: Likewise.
    	* testsuite/ld-x86-64/pr20253-3.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-3.s: Likewise.
    	* testsuite/ld-x86-64/pr20253-4.s: Likewise.
    	* testsuite/ld-x86-64/pr20253-4a.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-4b.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-4c.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-4d.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-4e.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-4f.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-5.s: Likewise.
    	* testsuite/ld-x86-64/pr20253-5a.d: Likewise.
    	* testsuite/ld-x86-64/pr20253-5b.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18a-i386.d: Remove extra IRELATIVE
    	relocation.
    	* testsuite/ld-ifunc/ifunc-18a-x86-64.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18b-i386.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18b-x86-64.d: Likewise.
    	* testsuite/ld-ifunc/ifunc-18a.s: Fix a typo.
    	* testsuite/ld-x86-64/x86-64.exp: Run pr20253-1 tests.
Comment 2 H.J. Lu 2016-06-18 16:21:37 UTC
Fixed for 2.27.