Bug 13302 - IRELATIVE relocation should come last
Summary: IRELATIVE relocation should come last
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.24
: P2 normal
Target Milestone: ---
Assignee: H.J. Lu
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-10-16 15:45 UTC by Ulrich Drepper
Modified: 2023-02-21 08:33 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
A patch (726 bytes, patch)
2011-10-17 22:49 UTC, H.J. Lu
Details | Diff
A patch (2.65 KB, patch)
2011-10-20 23:21 UTC, H.J. Lu
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ulrich Drepper 2011-10-16 15:45:24 UTC
Assume this code:

extern int f(void);

void alt1(void) { }
void alt2(void) { }

static void (*resolve (void)) (void)
{
  return f() ? alt1 : alt2;
}

void fct(void) __attribute__ ((ifunc ("resolve")));
extern __typeof(fct) int_fct __attribute__ ((alias("fct")));

void g(void) {
  int_fct();
}



And this linker map:

{
  global:
  fct;
  local:
  *;
};



Compiling using

  gcc -shared -fpic  bug.c -Wl,--version-script,bug.map


The problem is the .rela.plt / .rel.plt section.  On my x86-64 system it looks like this:

  0x0000000000200858  X86_64_JUMP_SLOT 000000000000000000      +0 __cxa_finalize
  0x0000000000200860  X86_64_IRELATIVE 000000000000000000   +1304 
  0x0000000000200868  X86_64_JUMP_SLOT 000000000000000000      +0 f



This is a problem, the ifunc for the IRELATIVE relocation calls f.  That PLT slot isn't set up yet.


There is no problem with an ifunc callback to call another function.  Therefore IRELATIVE relocation should all be moved to the back of the section.  There are no drawbacks to doing this and carefully designed DSOs can call functions in ifunc callbacks.
Comment 1 H.J. Lu 2011-10-17 22:49:36 UTC
Created attachment 6016 [details]
A patch

Please try this.
Comment 2 H.J. Lu 2011-10-20 23:21:27 UTC
Created attachment 6023 [details]
A patch

This patch can build glibc on ia32 and x86-64.
Comment 3 Sourceware Commits 2011-10-21 15:13:42 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	hjl@sourceware.org	2011-10-21 15:13:37

Modified files:
	bfd            : ChangeLog elf32-i386.c elf64-x86-64.c 
	ld/testsuite   : ChangeLog 
Added files:
	ld/testsuite/ld-ifunc: ifunc-16-i386.d ifunc-16-x86-64.d 
	                       ifunc-16-x86.s 

Log message:
	Put IRELATIVE relocations after JUMP_SLOT.
	
	bfd/
	
	2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>
	
	PR ld/13302
	* elf32-i386.c (elf_i386_link_hash_table): Add next_jump_slot_index
	and next_irelative_index.
	(elf_i386_link_hash_table_create): Initialize next_jump_slot_index
	and next_irelative_index.
	(elf_i386_allocate_dynrelocs): Increment reloc_count instead of
	next_tls_desc_index.
	(elf_i386_size_dynamic_sections): Set next_tls_desc_index and
	next_irelative_index from reloc_count.
	(elf_i386_finish_dynamic_symbol): Put R_386_IRELATIVE after
	R_386_JUMP_SLOT.
	
	* elf64-x86-64.c (elf_x86_64_link_hash_table): Add
	next_jump_slot_index and next_irelative_index.
	(elf_x86_64_link_hash_table_create): Initialize
	next_jump_slot_index and next_irelative_index.
	(elf_x86_64_size_dynamic_sections): Set next_irelative_index
	from reloc_count.
	(elf_x86_64_finish_dynamic_symbol): Put R_X86_64_IRELATIVE after
	R_X86_64_JUMP_SLOT.
	
	ld/testsuite/
	
	2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>
	
	PR ld/13302
	* ld-ifunc/ifunc-16-i386.d: New.
	* ld-ifunc/ifunc-16-x86-64.d: Likewise.
	* ld-ifunc/ifunc-16-x86.s: Likewise.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/ChangeLog.diff?cvsroot=src&r1=1.5497&r2=1.5498
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf32-i386.c.diff?cvsroot=src&r1=1.262&r2=1.263
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf64-x86-64.c.diff?cvsroot=src&r1=1.241&r2=1.242
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ChangeLog.diff?cvsroot=src&r1=1.1472&r2=1.1473
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-ifunc/ifunc-16-i386.d.diff?cvsroot=src&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-ifunc/ifunc-16-x86-64.d.diff?cvsroot=src&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-ifunc/ifunc-16-x86.s.diff?cvsroot=src&r1=NONE&r2=1.1
Comment 4 H.J. Lu 2011-10-21 18:31:06 UTC
Another problem:

[hjl@gnu-6 pr13302b]$ cat x.c
void alt2(void) { }

static void (*resolve (void)) (void)
{
  return alt2;
}

void fct(void) __attribute__ ((ifunc ("resolve")));
extern __typeof(fct) int_fct __attribute__ ((alias("fct")));

void (*g)(void)  = int_fct;
int
main ()
{
  g ();
  return 0;
}
[hjl@gnu-6 pr13302b]$ make
/usr/gcc-4.7.0-x32/bin/gcc -fpie   -c -o x.o x.c
/usr/gcc-4.7.0-x32/bin/gcc -pie -o x x.o
readelf -r --wide x

Relocation section '.rela.dyn' at offset 0x498 contains 10 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
00000000002008c8  0000000000000008 R_X86_64_RELATIVE                               00000000000006a0
00000000002008d0  0000000000000008 R_X86_64_RELATIVE                               0000000000000670
0000000000200ab0  0000000000000008 R_X86_64_RELATIVE                               0000000000000790
0000000000200ac0  0000000000000008 R_X86_64_RELATIVE                               0000000000000700
0000000000200ac8  0000000000000008 R_X86_64_RELATIVE                               00000000000006df
0000000000200b18  0000000000000008 R_X86_64_RELATIVE                               0000000000200b18
0000000000200ab8  0000000500000006 R_X86_64_GLOB_DAT      0000000000000000 __gmon_start__ + 0
0000000000200ad0  0000000a00000006 R_X86_64_GLOB_DAT      0000000000000000 _Jv_RegisterClasses + 0
0000000000200ad8  0000000b00000006 R_X86_64_GLOB_DAT      0000000000000000 __cxa_finalize + 0
0000000000200b20  0000000000000025 R_X86_64_IRELATIVE                              00000000000006d2

Relocation section '.rela.plt' at offset 0x588 contains 3 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000200af8  0000000400000007 R_X86_64_JUMP_SLOT     0000000000000000 __libc_start_main + 0
0000000000200b08  0000000b00000007 R_X86_64_JUMP_SLOT     0000000000000000 __cxa_finalize + 0
0000000000200b00  0000000000000025 R_X86_64_IRELATIVE                              00000000000006d2
[hjl@gnu-6 pr13302b]$ 

We have R_X86_64_IRELATIVE in .rela.dyn.
Comment 5 Sourceware Commits 2011-10-21 19:37:19 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	hjl@sourceware.org	2011-10-21 19:37:15

Modified files:
	bfd            : ChangeLog elf32-i386.c elf64-x86-64.c 
	ld/testsuite   : ChangeLog 
	ld/testsuite/ld-i386: i386.exp 
	ld/testsuite/ld-x86-64: pr13082-5b.d pr13082-6a.d pr13082-6b.d 
Added files:
	ld/testsuite/ld-i386: pr13302.d pr13302.s 

Log message:
	Replace IRELATIVE relocations with RELATIVE in .rel.dyn.
	
	bfd/
	
	2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>
	
	PR ld/13302
	* elf32-i386.c (elf_i386_relocate_section): Replace
	R_386_IRELATIVE with R_386_RELATIVE.
	
	* elf64-x86-64.c (elf_x86_64_relocate_section): Replace
	R_X86_64_IRELATIVE with R_X86_64_RELATIVE.
	
	ld/testsuite/
	
	2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>
	
	PR ld/13302
	* ld-i386/i386.exp: Run pr13302.
	
	* ld-i386/pr13302.d: New.
	* ld-i386/pr13302.s: Likewise.
	
	* ld-x86-64/pr13082-5b.d: Updated.
	* ld-x86-64/pr13082-6a.d: Likewise.
	* ld-x86-64/pr13082-6b.d: Likewise.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/ChangeLog.diff?cvsroot=src&r1=1.5499&r2=1.5500
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf32-i386.c.diff?cvsroot=src&r1=1.264&r2=1.265
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf64-x86-64.c.diff?cvsroot=src&r1=1.243&r2=1.244
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ChangeLog.diff?cvsroot=src&r1=1.1473&r2=1.1474
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/pr13302.d.diff?cvsroot=src&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/pr13302.s.diff?cvsroot=src&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/i386.exp.diff?cvsroot=src&r1=1.40&r2=1.41
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-x86-64/pr13082-5b.d.diff?cvsroot=src&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-x86-64/pr13082-6a.d.diff?cvsroot=src&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-x86-64/pr13082-6b.d.diff?cvsroot=src&r1=1.1&r2=1.2
Comment 6 H.J. Lu 2011-10-21 20:20:30 UTC
Fixed.
Comment 7 Alan Modra 2011-10-22 06:30:16 UTC
Only fixed x86 and x86_64.  arm, ppc32, ppc64, and sparc all support ifunc too.
Comment 8 Jiong Wang 2015-12-18 10:08:43 UTC
*** Bug 19368 has been marked as a duplicate of this bug. ***
Comment 9 Sourceware Commits 2017-09-02 22:15:23 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=5e2ac45d561dffec63af4c83a545b46db032c70c

commit 5e2ac45d561dffec63af4c83a545b46db032c70c
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sat Sep 2 07:37:05 2017 -0700

    x86: Add _bfd_x86_elf_size_dynamic_sections
    
    elf_i386_size_dynamic_sections and elf_x86_64_size_dynamic_sections are
    very similar, except for the followings:
    
    1. elf_i386_size_dynamic_sections checks GOT_TLS_IE and GOT_TLS_IE_BOTH.
    elf_x86_64_size_dynamic_sections checks only GOT_TLS_IE.  Since
    GOT_TLS_IE_BOTH is never true for x86-64, it is OK to check GOT_TLS_IE
    for both i386 and x86-64.
    2, x86-64 sets tlsdesc_plt, but i386 doesn't.  We set tlsdesc_plt only
    if target_id == X86_64_ELF_DATA.
    3. x86-64 has
    
    	  if (s != htab->elf.srelplt)
    	    s->reloc_count = 0;
    
    and i386 has
    
    	  s->reloc_count = 0;
    
    i386 did have
    
    	  if (s != htab->srelplt)
    	    s->reloc_count = 0;
    
    in the original commit:
    
    commit 67a4f2b710581acc83afecff55424af285ecbc28
    Author: Alexandre Oliva <aoliva@redhat.com>
    Date:   Wed Jan 18 21:07:51 2006 +0000
    
    But it was removed by
    
    commit 5ae0bfb60a576344d7f701605346282c1144499e
    Author: Richard Sandiford <rdsandiford@googlemail.com>
    Date:   Tue Feb 28 07:16:12 2006 +0000
    
        bfd/
                * elf32-i386.c (elf_i386_link_hash_table): Add next_tls_desc_index.
                (elf_i386_link_hash_table_create): Initialize it.
                (elf_i386_compute_jump_table_size): Use it instead of
                srelplt->reloc_count.
                (allocate_dynrelocs): Likewise.
                (elf_i386_size_dynamic_sections): Likewise.
                (elf_i386_relocate_section): Likewise.
    
    A later commit:
    
    commit e1f987424b7b3f5ac63a2a6ae044a202a44b8ff8
    Author: H.J. Lu <hjl.tools@gmail.com>
    Date:   Fri Oct 21 15:13:37 2011 +0000
    
        Put IRELATIVE relocations after JUMP_SLOT.
    
        bfd/
    
        2011-10-21  H.J. Lu  <hongjiu.lu@intel.com>
    
                PR ld/13302
                * elf32-i386.c (elf_i386_link_hash_table): Add next_jump_slot_index
                and next_irelative_index.
                (elf_i386_link_hash_table_create): Initialize next_jump_slot_index
                and next_irelative_index.
                (elf_i386_allocate_dynrelocs): Increment reloc_count instead of
                next_tls_desc_index.
                (elf_i386_size_dynamic_sections): Set next_tls_desc_index and
                next_irelative_index from reloc_count.
                (elf_i386_finish_dynamic_symbol): Put R_386_IRELATIVE after
                R_386_JUMP_SLOT.
    
    changed it back to use reloc_count again. So it is correct to use
    
    	  if (s != htab->elf.srelplt)
    	    s->reloc_count = 0;
    
    for both i386 and x86-64 now.
    4. i386 and x86-64 use different DT_XXXs.  They are handled by adding
    them to elf_x86_link_hash_table.
    
    With these changes, we can share _bfd_x86_elf_size_dynamic_sections in
    elf32-i386.c and elf64-x86-64.c.
    
    	* elf32-i386.c (elf_i386_convert_load): Renamed to ...
    	(_bfd_i386_elf_convert_load): This.  Remove static.
    	(elf_i386_size_dynamic_sections): Removed.
    	(elf_backend_size_dynamic_sections): Likewise.
    	* elf64-x86-64.c (elf_x86_64_convert_load): Renamed to ...
    	(_bfd_x86_64_elf_convert_load): This.  Remove static.
    	(elf_x86_64_size_dynamic_sections): Removed.
    	(elf_backend_size_dynamic_sections): Likewise.
    	* elfxx-x86.c (_bfd_x86_elf_allocate_dynrelocs): Renamed to ...
    	(elf_x86_allocate_dynrelocs): This.  Make it static.
    	(_bfd_x86_elf_allocate_local_dynrelocs): Renamed to ...
    	(elf_x86_allocate_local_dynreloc): This.  Make it static.
    	(elf_i386_is_reloc_section): New function.
    	(elf_x86_64_is_reloc_section): Likewise.
    	(_bfd_x86_elf_link_hash_table_create): Initialize convert_load,
    	is_reloc_section, dt_reloc, dt_reloc_sz and dt_reloc_ent.
    	Rearrange got_entry_size initialization.
    	(_bfd_x86_elf_size_dynamic_sections): New function.
    	* elfxx-x86.h (elf_x86_link_hash_table): Add convert_load,
    	is_reloc_section, dt_reloc, dt_reloc_sz and dt_reloc_ent.
    	(_bfd_i386_elf_convert_load): New.
    	(_bfd_x86_64_elf_convert_load): Likewise.
    	(_bfd_x86_elf_size_dynamic_sections): Likewise.
    	(elf_backend_size_dynamic_sections): Likewise.
    	(_bfd_x86_elf_allocate_dynrelocs): Removed.
    	(_bfd_x86_elf_allocate_local_dynrelocs): Likewise.
Comment 10 Alan Modra 2022-07-29 02:08:08 UTC
Fixed on targets mentioned in comment #7, aarch64, csky and loongarch.  s390 and riscv might still be susceptible to irelative ordering problems.
Comment 11 Nelson Chu 2023-02-21 08:33:32 UTC
For riscv, in the allocate_dynrelocs, all STT_GNU_IFUNC will be handled until allocate_ifunc_dynrelocs and allocate_local_ifunc_dynrelocs, so the offset of plt and got entries for ifunc symbols should be at last.  Besides, in the finish_dynamic_symbol, riscv inserts the dynamic relocations in the order of plt and got entry offset.  Therefore, all the dynamic relocations of ifunc should be come last in the dynamic sections.

I think the only potential risk is - if dynamic relocation of ifunc won't be IRELATIVE, it's JUMP_SLOT/32/64 relocs, then once ifunc may calls another ifunc, it is only possible for riscv to meet the order problem here.  If that so, then arm's solution cannot work for riscv since IRELATIVE not only added into rel.dyn, they can be added into rel.plt, rel.got, ... just like what x86 did.  Therefore, similar to x86, riscv also needs flags to insert the IRELATIVE at the last the dynamic relocation sections in the finish_dynamic_symbol, and probably needs more since not only rel.plt are used.