bfd/ 2009-05-24 H.J. Lu * elf32-i386.c (elf_howto_table): Add R_386_IRELATIVE. (elf_i386_reloc_type_lookup): Likewise. (R_386_tls): Removed. (R_386_irelative): New. (R_386_vt_offset): Updated. (elf_i386_rtype_to_howto): Likewise. (elf_i386_finish_dynamic_symbol): Generate R_386_IRELATIVE relocation for local STT_GNU_IFUNC symbol. * elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_IRELATIVE. (x86_64_reloc_map): Likewise. (R_X86_64_standard): Updated. (elf64_x86_64_finish_dynamic_symbol): Generate R_X86_64_IRELATIVE relocation for local STT_GNU_IFUNC symbol. * elflink.c (_bfd_elf_symbol_refs_local_p): Return FALSE on STT_GNU_IFUNC symbol. (_bfd_elf_link_hash_hide_symbol): Don't clean plt on STT_GNU_IFUNC symbol. * reloc.c (BFD_RELOC_386_IRELATIVE): New. (BFD_RELOC_X86_64_IRELATIVE): Likewise. * bfd-in2.h: Regenerated. * libbfd.h: Likewise. include/elf/ 2009-05-24 H.J. Lu * i386.h (R_386_IRELATIVE): New. * x86-64.h (R_X86_64_IRELATIVE): Likewise. ld/testsuite/ 2009-05-24 H.J. Lu * ld-ifunc/ifunc.exp: Run *.d. * ld-ifunc/ifunc-1-x86.d: New. * ld-ifunc/ifunc-1-x86.s: Likewise. diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc \ ../binutils/src binutils diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/bfd-in2.h binutils/bfd/bfd-in2.h --- ../binutils/src/bfd/bfd-in2.h 2009-05-22 11:13:32.000000000 -0700 +++ binutils/bfd/bfd-in2.h 2009-05-24 07:26:08.000000000 -0700 @@ -2837,6 +2837,7 @@ relaxation. */ BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_386_TLS_DESC, + BFD_RELOC_386_IRELATIVE, /* x86-64/elf relocations */ BFD_RELOC_X86_64_GOT32, @@ -2865,6 +2866,7 @@ relaxation. */ BFD_RELOC_X86_64_GOTPC32_TLSDESC, BFD_RELOC_X86_64_TLSDESC_CALL, BFD_RELOC_X86_64_TLSDESC, + BFD_RELOC_X86_64_IRELATIVE, /* ns32k relocations */ BFD_RELOC_NS32K_IMM_8, diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf32-i386.c binutils/bfd/elf32-i386.c --- ../binutils/src/bfd/elf32-i386.c 2009-05-05 13:59:47.000000000 -0700 +++ binutils/bfd/elf32-i386.c 2009-05-24 19:00:11.000000000 -0700 @@ -138,10 +138,13 @@ static reloc_howto_type elf_howto_table[ HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_DESC", TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_IRELATIVE", + TRUE, 0xffffffff, 0xffffffff, FALSE), /* Another gap. */ -#define R_386_tls (R_386_TLS_DESC + 1 - R_386_tls_offset) -#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_tls) +#define R_386_irelative (R_386_IRELATIVE + 1 - R_386_tls_offset) +#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_irelative) /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_386_GNU_VTINHERIT, /* type */ @@ -316,6 +319,10 @@ elf_i386_reloc_type_lookup (bfd *abfd AT TRACE ("BFD_RELOC_386_TLS_DESC"); return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset]; + case BFD_RELOC_386_IRELATIVE: + TRACE ("BFD_RELOC_386_IRELATIVE"); + return &elf_howto_table[R_386_IRELATIVE]; + case BFD_RELOC_VTABLE_INHERIT: TRACE ("BFD_RELOC_VTABLE_INHERIT"); return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset]; @@ -355,9 +362,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsi && ((indx = r_type - R_386_ext_offset) - R_386_standard >= R_386_ext - R_386_standard) && ((indx = r_type - R_386_tls_offset) - R_386_ext - >= R_386_tls - R_386_ext) - && ((indx = r_type - R_386_vt_offset) - R_386_tls - >= R_386_vt - R_386_tls)) + >= R_386_irelative - R_386_ext) + && ((indx = r_type - R_386_vt_offset) - R_386_irelative + >= R_386_vt - R_386_irelative)) { (*_bfd_error_handler) (_("%B: invalid relocation type %d"), abfd, (int) r_type); @@ -2606,7 +2613,7 @@ elf_i386_relocate_section (bfd *output_b && ((indx = r_type - R_386_ext_offset) - R_386_standard >= R_386_ext - R_386_standard) && ((indx = r_type - R_386_tls_offset) - R_386_ext - >= R_386_tls - R_386_ext)) + >= R_386_irelative - R_386_ext)) { (*_bfd_error_handler) (_("%B: unrecognized relocation (0x%x) in section `%A'"), @@ -3684,7 +3691,10 @@ elf_i386_finish_dynamic_symbol (bfd *out /* This symbol has an entry in the procedure linkage table. Set it up. */ - if (h->dynindx == -1 + if ((h->dynindx == -1 + && !(h->forced_local + && h->def_regular + && ELF_ST_TYPE (h->type) == STT_GNU_IFUNC)) || htab->splt == NULL || htab->sgotplt == NULL || htab->srelplt == NULL) @@ -3773,7 +3783,18 @@ elf_i386_finish_dynamic_symbol (bfd *out rel.r_offset = (htab->sgotplt->output_section->vma + htab->sgotplt->output_offset + got_offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); + if (h->dynindx != -1) + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); + else + { + /* Store addend in the .got.plt section. */ + bfd_put_32 (output_bfd, + (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset), + htab->sgotplt->contents + got_offset); + rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); + } loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf64-x86-64.c binutils/bfd/elf64-x86-64.c --- ../binutils/src/bfd/elf64-x86-64.c 2009-05-22 12:49:50.000000000 -0700 +++ binutils/bfd/elf64-x86-64.c 2009-05-24 07:21:45.000000000 -0700 @@ -143,12 +143,15 @@ static reloc_howto_type x86_64_elf_howto complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_TLSDESC", FALSE, MINUS_ONE, MINUS_ONE, FALSE), + HOWTO(R_X86_64_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_IRELATIVE", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), /* We have a gap in the reloc numbers here. R_X86_64_standard counts the number up to this point, and R_X86_64_vt_offset is the value to subtract from a reloc type of R_X86_64_GNU_VT* to form an index into this table. */ -#define R_X86_64_standard (R_X86_64_TLSDESC + 1) +#define R_X86_64_standard (R_X86_64_IRELATIVE + 1) #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) /* GNU extension to record C++ vtable hierarchy. */ @@ -211,6 +214,7 @@ static const struct elf_reloc_map x86_64 { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, }, { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, }, { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, }, + { BFD_RELOC_X86_64_IRELATIVE, R_X86_64_IRELATIVE, }, { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, }; @@ -3328,7 +3332,10 @@ elf64_x86_64_finish_dynamic_symbol (bfd /* This symbol has an entry in the procedure linkage table. Set it up. */ - if (h->dynindx == -1 + if ((h->dynindx == -1 + && !(h->forced_local + && h->def_regular + && ELF_ST_TYPE (h->type) == STT_GNU_IFUNC)) || htab->splt == NULL || htab->sgotplt == NULL || htab->srelplt == NULL) @@ -3381,8 +3388,18 @@ elf64_x86_64_finish_dynamic_symbol (bfd rela.r_offset = (htab->sgotplt->output_section->vma + htab->sgotplt->output_offset + got_offset); - rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT); - rela.r_addend = 0; + if (h->dynindx != -1) + { + rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT); + rela.r_addend = 0; + } + else + { + rela.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE); + rela.r_addend = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela); bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elflink.c binutils/bfd/elflink.c --- ../binutils/src/bfd/elflink.c 2009-05-23 14:39:29.000000000 -0700 +++ binutils/bfd/elflink.c 2009-05-24 06:48:05.000000000 -0700 @@ -2845,6 +2845,10 @@ _bfd_elf_symbol_refs_local_p (struct elf if (h == NULL) return TRUE; + /* STT_GNU_IFUNC symbol must go through PLT. */ + if (h->type == STT_GNU_IFUNC) + return FALSE; + /* STV_HIDDEN or STV_INTERNAL ones must be local. */ if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL) @@ -6669,8 +6673,12 @@ _bfd_elf_link_hash_hide_symbol (struct b struct elf_link_hash_entry *h, bfd_boolean force_local) { - h->plt = elf_hash_table (info)->init_plt_offset; - h->needs_plt = 0; + /* STT_GNU_IFUNC symbol must go through PLT. */ + if (ELF_ST_TYPE (h->type) != STT_GNU_IFUNC) + { + h->plt = elf_hash_table (info)->init_plt_offset; + h->needs_plt = 0; + } if (force_local) { h->forced_local = 1; diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/libbfd.h binutils/bfd/libbfd.h --- ../binutils/src/bfd/libbfd.h 2009-05-05 10:56:24.000000000 -0700 +++ binutils/bfd/libbfd.h 2009-05-24 07:26:08.000000000 -0700 @@ -1104,6 +1104,7 @@ static const char *const bfd_reloc_code_ "BFD_RELOC_386_TLS_GOTDESC", "BFD_RELOC_386_TLS_DESC_CALL", "BFD_RELOC_386_TLS_DESC", + "BFD_RELOC_386_IRELATIVE", "BFD_RELOC_X86_64_GOT32", "BFD_RELOC_X86_64_PLT32", "BFD_RELOC_X86_64_COPY", @@ -1130,6 +1131,7 @@ static const char *const bfd_reloc_code_ "BFD_RELOC_X86_64_GOTPC32_TLSDESC", "BFD_RELOC_X86_64_TLSDESC_CALL", "BFD_RELOC_X86_64_TLSDESC", + "BFD_RELOC_X86_64_IRELATIVE", "BFD_RELOC_NS32K_IMM_8", "BFD_RELOC_NS32K_IMM_16", "BFD_RELOC_NS32K_IMM_32", diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/reloc.c binutils/bfd/reloc.c --- ../binutils/src/bfd/reloc.c 2009-05-05 10:56:24.000000000 -0700 +++ binutils/bfd/reloc.c 2009-05-24 07:26:01.000000000 -0700 @@ -2492,6 +2492,8 @@ ENUMX BFD_RELOC_386_TLS_DESC_CALL ENUMX BFD_RELOC_386_TLS_DESC +ENUMX + BFD_RELOC_386_IRELATIVE ENUMDOC i386/elf relocations @@ -2547,6 +2549,8 @@ ENUMX BFD_RELOC_X86_64_TLSDESC_CALL ENUMX BFD_RELOC_X86_64_TLSDESC +ENUMX + BFD_RELOC_X86_64_IRELATIVE ENUMDOC x86-64/elf relocations diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/include/elf/i386.h binutils/include/elf/i386.h --- ../binutils/src/include/elf/i386.h 2009-05-05 10:56:16.000000000 -0700 +++ binutils/include/elf/i386.h 2009-05-23 18:06:03.000000000 -0700 @@ -66,6 +66,7 @@ START_RELOC_NUMBERS (elf_i386_reloc_type RELOC_NUMBER (R_386_TLS_GOTDESC, 39) RELOC_NUMBER (R_386_TLS_DESC_CALL,40) RELOC_NUMBER (R_386_TLS_DESC, 41) + RELOC_NUMBER (R_386_IRELATIVE, 42) /* Adjust indirectly by program base */ /* Used by Intel. */ RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200) diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/include/elf/x86-64.h binutils/include/elf/x86-64.h --- ../binutils/src/include/elf/x86-64.h 2009-05-05 10:56:16.000000000 -0700 +++ binutils/include/elf/x86-64.h 2009-05-23 18:05:08.000000000 -0700 @@ -71,6 +71,7 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_ty RELOC_NUMBER (R_X86_64_TLSDESC_CALL, 35) /* Relaxable call through TLS descriptor. */ RELOC_NUMBER (R_X86_64_TLSDESC, 36) /* 2x64-bit TLS descriptor. */ + RELOC_NUMBER (R_X86_64_IRELATIVE, 37) /* Adjust indirectly by program base */ RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250) /* GNU C++ hack */ RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251) /* GNU C++ hack */ END_RELOC_NUMBERS (R_X86_64_max) diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.d binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.d --- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.d 1969-12-31 16:00:00.000000000 -0800 +++ binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.d 2009-05-24 19:12:28.000000000 -0700 @@ -0,0 +1,7 @@ +#ld: -shared +#objdump: -dw +#target: x86_64-*-* i?86-*-* + +#... +[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<\*ABS\*@plt> +#pass diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.s binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.s --- ../binutils/src/ld/testsuite/ld-ifunc/ifunc-1-x86.s 1969-12-31 16:00:00.000000000 -0800 +++ binutils/ld/testsuite/ld-ifunc/ifunc-1-x86.s 2009-05-24 19:11:29.000000000 -0700 @@ -0,0 +1,16 @@ + .type foo, %gnu_indirect_function + .global __GI_foo + .hidden __GI_foo + .set __GI_foo, foo + .text +.globl foo + .type foo, @function +foo: + ret + .size foo, .-foo +.globl bar + .type bar, @function +bar: + call __GI_foo@PLT + ret + .size bar, .-bar diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/testsuite/ld-ifunc/ifunc.exp binutils/ld/testsuite/ld-ifunc/ifunc.exp --- ../binutils/src/ld/testsuite/ld-ifunc/ifunc.exp 2009-05-23 14:39:29.000000000 -0700 +++ binutils/ld/testsuite/ld-ifunc/ifunc.exp 2009-05-24 19:11:29.000000000 -0700 @@ -252,3 +252,10 @@ if { $verbose < 1 } { remote_file host delete "tmpdir/static_prog" remote_file host delete "tmpdir/static_nonifunc_prog" } + +set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]] +foreach t $test_list { + # We need to strip the ".d", but can leave the dirname. + verbose [file rootname $t] + run_dump_test [file rootname $t] +}