Proposal for STT_GNU_IFUNC and R_*_IRELATIVE
H.J. Lu
hjl.tools@gmail.com
Sat Jun 6 15:29:00 GMT 2009
On Sat, Jun 6, 2009 at 5:55 AM, Roland McGrath <roland@redhat.com> wrote:
>
>> 1. A STT_GNU_IFUNC function should never access any data which need
>> relocation.
>
> This does not seem like too much of a constraint, given that it also
> unavoidably has to work before the DSO's initializers have run.
> i.e., it is always special-purpose code that has to be written very
> carefully. Being PIC code it should not be relying on much to have been
> done before. It just has to avoid any PLT calls or other GOT use itself.
>
>> 2. Dynamic relocations against STT_GNU_INFUNC symbols should be
>> placed after all other relocations.
>
> This is not possible, is it? Some DSO has a reference to "&strlen".
> It has no idea that libc's definition will be STT_GNU_IFUNC.
> The DSO might even have been linked against a libc.so that did
> not use STT_GNU_IFUNC to define "strlen".
>
> The only other alternative to #1 that I see is some scheme whereby "&func"
> will in all cases resolve to a PLT entry rather than the actual
> STT_GNU_IFUNC symbol's st_value. i.e., the ifunc resolver is only called
> for PLT resolution (and you can do all those last for BIND_NOW).
>
> e.g. in the defining DSO make ld generate a PLT entry with second symbol a
> la executables' PLT entries, and then have rtld ignore the STT_GNU_IFUNC
> symbol when resolving non-PLT relocs. (Seems highly dubious.)
>
> But in fact any scheme with that result might be undesireable in practice.
> If the executable does not refer to "&func", then we don't have the pointer
> equality issue and so DSOs with function pointer tables pointing to other
> DSOs' entry points would do the extra indirection of a PLT jump when it
> could be avoided except for this initialization order question.
>
>
This patch implements #2. It may not solve all the problems. But it
works for my simple testcase.
--
H.J.
----
bfd/
2009-06-06 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_link_hash_table): Add irelifunc.
(elf_i386_link_hash_table_create): Initialize irelifunc.
(elf_i386_check_relocs): Updated. Set up irelifunc for
shared objects.
(elf_i386_allocate_dynrelocs): Use irelifunc for dynamic
relocation for non-GOT reference of STT_GNU_IFUNC symbol in
shared objects.
(elf_i386_relocate_section): Likewise.
* elf64-x86-64.c (elf64_x86_64_link_hash_table): Add irelifunc.
(elf64_x86_64_link_hash_table_create): Initialize irelifunc.
(elf64_x86_64_check_relocs): Updated. Set up irelifunc for
shared objects.
(elf64_x86_64_allocate_dynrelocs): Use irelifunc for dynamic
relocation for non-GOT reference of STT_GNU_IFUNC symbol in
shared objects.
(elf64_x86_64_relocate_section): Likewise.
* elf-bfd.h (_bfd_elf_create_static_ifunc_sections): Renamed to
...
(_bfd_elf_create_ifunc_sections): This.
* elflink.c (_bfd_elf_create_static_ifunc_sections): Renamd to
...
(_bfd_elf_create_ifunc_sections): This. Create .rel[a].ifunc
for shared objects.
ld/
2009-06-06 H.J. Lu <hongjiu.lu@intel.com>
* scripttempl/elf.sc: Add .rel.ifunc and .rela.ifunc.
-------------- next part --------------
bfd/
2009-06-06 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_link_hash_table): Add irelifunc.
(elf_i386_link_hash_table_create): Initialize irelifunc.
(elf_i386_check_relocs): Updated. Set up irelifunc for
shared objects.
(elf_i386_allocate_dynrelocs): Use irelifunc for dynamic
relocation for non-GOT reference of STT_GNU_IFUNC symbol in
shared objects.
(elf_i386_relocate_section): Likewise.
* elf64-x86-64.c (elf64_x86_64_link_hash_table): Add irelifunc.
(elf64_x86_64_link_hash_table_create): Initialize irelifunc.
(elf64_x86_64_check_relocs): Updated. Set up irelifunc for
shared objects.
(elf64_x86_64_allocate_dynrelocs): Use irelifunc for dynamic
relocation for non-GOT reference of STT_GNU_IFUNC symbol in
shared objects.
(elf64_x86_64_relocate_section): Likewise.
* elf-bfd.h (_bfd_elf_create_static_ifunc_sections): Renamed to
...
(_bfd_elf_create_ifunc_sections): This.
* elflink.c (_bfd_elf_create_static_ifunc_sections): Renamd to
...
(_bfd_elf_create_ifunc_sections): This. Create .rel[a].ifunc
for shared objects.
ld/
2009-06-06 H.J. Lu <hongjiu.lu@intel.com>
* scripttempl/elf.sc: Add .rel.ifunc and .rela.ifunc.
Index: ld/scripttempl/elf.sc
===================================================================
--- ld/scripttempl/elf.sc (revision 6083)
+++ ld/scripttempl/elf.sc (working copy)
@@ -326,6 +326,8 @@ eval $COMBRELOCCAT <<EOF
.rel.bss ${RELOCATING-0} : { *(.rel.bss${RELOCATING+ .rel.bss.* .rel.gnu.linkonce.b.*}) }
.rela.bss ${RELOCATING-0} : { *(.rela.bss${RELOCATING+ .rela.bss.* .rela.gnu.linkonce.b.*}) }
${REL_LARGE}
+ .rel.ifunc ${RELOCATING-0} : { *(.rel.ifunc) }
+ .rela.ifunc ${RELOCATING-0} : { *(.rela.ifunc) }
EOF
if [ -n "$COMBRELOC" ]; then
Index: bfd/elflink.c
===================================================================
--- bfd/elflink.c (revision 6083)
+++ bfd/elflink.c (working copy)
@@ -12492,31 +12492,17 @@ _bfd_elf_make_dynamic_reloc_section (ase
return reloc_sec;
}
-/* Create sections needed by STT_GNU_IFUNC symbol for static
- executables. */
+/* Create sections needed by STT_GNU_IFUNC symbol. */
bfd_boolean
-_bfd_elf_create_static_ifunc_sections (bfd *abfd,
- struct bfd_link_info *info)
+_bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
{
flagword flags, pltflags;
int ptralign;
asection *s;
- const struct elf_backend_data *bed;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- /* Should never be called for shared library. */
- BFD_ASSERT (!info->shared);
-
- /* This function may be called more than once. */
- s = bfd_get_section_by_name (abfd, ".iplt");
- if (s != NULL)
- return TRUE;
-
- bed = get_elf_backend_data (abfd);
-
- /* We need to create .iplt, .rel[a].iplt, .igot, .igot.plt, */
flags = bed->dynamic_sec_flags;
-
pltflags = flags;
if (bed->plt_not_loaded)
/* We do not clear SEC_ALLOC here because we still want the OS to
@@ -12528,47 +12514,68 @@ _bfd_elf_create_static_ifunc_sections (b
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
- s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
- if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
- return FALSE;
-
- s = bfd_make_section_with_flags (abfd,
- (bed->rela_plts_and_copies_p
- ? ".rela.iplt" : ".rel.iplt"),
- flags | SEC_READONLY);
- if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
- return FALSE;
-
- switch (bed->s->arch_size)
+ if (info->shared)
{
- case 32:
- ptralign = 2;
- break;
-
- case 64:
- ptralign = 3;
- break;
-
- default:
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
+ /* We need to create .rel[a].ifunc for shared objects. */
+ const char *rel_sec = (bed->rela_plts_and_copies_p
+ ? ".rela.ifunc" : ".rel.ifunc");
+
+ /* This function should be called only once. */
+ s = bfd_get_section_by_name (abfd, rel_sec);
+ if (s != NULL)
+ abort ();
- /* We don't need the .igot section if we have the .igot.plt
- section. */
-
- if (bed->want_got_plt)
- {
- s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
+ s = bfd_make_section_with_flags (abfd, rel_sec,
+ flags | SEC_READONLY);
if (s == NULL
- || !bfd_set_section_alignment (abfd, s, ptralign))
+ || ! bfd_set_section_alignment (abfd, s,
+ bed->s->log_file_align))
return FALSE;
}
else
{
- s = bfd_make_section_with_flags (abfd, ".igot", flags);
+ /* This function should be called only once. */
+ s = bfd_get_section_by_name (abfd, ".iplt");
+ if (s != NULL)
+ abort ();
+
+ /* We need to create .iplt, .rel[a].iplt, .igot and .igot.plt
+ for static executables. */
+ s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
+ return FALSE;
+
+ s = bfd_make_section_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.iplt" : ".rel.iplt"),
+ flags | SEC_READONLY);
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s,
+ bed->s->log_file_align))
+ return FALSE;
+
+ switch (bed->s->arch_size)
+ {
+ case 32:
+ ptralign = 2;
+ break;
+
+ case 64:
+ ptralign = 3;
+ break;
+
+ default:
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* We don't need the .igot section if we have the .igot.plt
+ section. */
+ if (bed->want_got_plt)
+ s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
+ else
+ s = bfd_make_section_with_flags (abfd, ".igot", flags);
if (s == NULL
|| !bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
Index: bfd/elf-bfd.h
===================================================================
--- bfd/elf-bfd.h (revision 6083)
+++ bfd/elf-bfd.h (working copy)
@@ -2146,7 +2146,7 @@ extern int _bfd_elf_obj_attrs_arg_type (
extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *);
extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *);
-extern bfd_boolean _bfd_elf_create_static_ifunc_sections
+extern bfd_boolean _bfd_elf_create_ifunc_sections
(bfd *, struct bfd_link_info *);
/* Large common section. */
Index: bfd/elf64-x86-64.c
===================================================================
--- bfd/elf64-x86-64.c (revision 6083)
+++ bfd/elf64-x86-64.c (working copy)
@@ -496,6 +496,7 @@ struct elf64_x86_64_link_hash_table
asection *igotplt;
asection *iplt;
asection *irelplt;
+ asection *irelifunc;
/* The offset into splt of the PLT entry for the TLS descriptor
resolver. Special values are 0, if not necessary (or not found
@@ -591,6 +592,7 @@ elf64_x86_64_link_hash_table_create (bfd
ret->igotplt= NULL;
ret->iplt = NULL;
ret->irelplt= NULL;
+ ret->irelifunc = NULL;
ret->sym_sec.abfd = NULL;
ret->tlsdesc_plt = 0;
ret->tlsdesc_got = 0;
@@ -1065,21 +1067,30 @@ elf64_x86_64_check_relocs (bfd *abfd, st
case R_X86_64_PLT32:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCREL64:
- if (!info->shared && htab->iplt == NULL)
+ if (htab->irelifunc == NULL && htab->iplt == NULL)
{
- if (!_bfd_elf_create_static_ifunc_sections (abfd,
- info))
+ if (!_bfd_elf_create_ifunc_sections (abfd, info))
return FALSE;
- htab->iplt = bfd_get_section_by_name (abfd, ".iplt");
- htab->irelplt = bfd_get_section_by_name (abfd,
- ".rela.iplt");
- htab->igotplt = bfd_get_section_by_name (abfd,
- ".igot.plt");
- if (!htab->iplt
- || !htab->irelplt
- || !htab->igotplt)
- abort ();
+ if (info->shared)
+ {
+ htab->irelifunc = bfd_get_section_by_name (abfd,
+ ".rela.ifunc");
+ if (!htab->irelifunc)
+ abort ();
+ }
+ else
+ {
+ htab->iplt = bfd_get_section_by_name (abfd, ".iplt");
+ htab->irelplt = bfd_get_section_by_name (abfd,
+ ".rela.iplt");
+ htab->igotplt = bfd_get_section_by_name (abfd,
+ ".igot.plt");
+ if (!htab->iplt
+ || !htab->irelplt
+ || !htab->igotplt)
+ abort ();
+ }
}
break;
}
@@ -1880,10 +1891,7 @@ elf64_x86_64_allocate_dynrelocs (struct
/* Finally, allocate space. */
for (p = eh->dyn_relocs; p != NULL; p = p->next)
- {
- asection * sreloc = elf_section_data (p->sec)->sreloc;
- sreloc->size += p->count * sizeof (Elf64_External_Rela);
- }
+ htab->irelifunc->size += p->count * sizeof (Elf64_External_Rela);
/* For STT_GNU_IFUNC symbol, .got.plt has the real function
addres and .got has the PLT entry adddress. We will load
@@ -2730,7 +2738,7 @@ elf64_x86_64_relocate_section (bfd *outp
outrel.r_addend = 0;
}
- sreloc = elf_section_data (input_section)->sreloc;
+ sreloc = htab->irelifunc;
loc = sreloc->contents;
loc += (sreloc->reloc_count++
* sizeof (Elf64_External_Rela));
Index: bfd/elf32-i386.c
===================================================================
--- bfd/elf32-i386.c (revision 6083)
+++ bfd/elf32-i386.c (working copy)
@@ -678,6 +678,7 @@ struct elf_i386_link_hash_table
asection *igotplt;
asection *iplt;
asection *irelplt;
+ asection *irelifunc;
/* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */
asection *srelplt2;
@@ -777,6 +778,7 @@ elf_i386_link_hash_table_create (bfd *ab
ret->igotplt= NULL;
ret->iplt = NULL;
ret->irelplt= NULL;
+ ret->irelifunc = NULL;
ret->tls_ldm_got.refcount = 0;
ret->next_tls_desc_index = 0;
ret->sgotplt_jump_table_size = 0;
@@ -1279,21 +1281,30 @@ elf_i386_check_relocs (bfd *abfd,
case R_386_PLT32:
case R_386_GOT32:
case R_386_GOTOFF:
- if (!info->shared && htab->iplt == NULL)
+ if (htab->irelifunc == NULL && htab->iplt == NULL)
{
- if (!_bfd_elf_create_static_ifunc_sections (abfd,
- info))
+ if (!_bfd_elf_create_ifunc_sections (abfd, info))
return FALSE;
- htab->iplt = bfd_get_section_by_name (abfd, ".iplt");
- htab->irelplt = bfd_get_section_by_name (abfd,
- ".rel.iplt");
- htab->igotplt = bfd_get_section_by_name (abfd,
- ".igot.plt");
- if (!htab->iplt
- || !htab->irelplt
- || !htab->igotplt)
- abort ();
+ if (info->shared)
+ {
+ htab->irelifunc = bfd_get_section_by_name (abfd,
+ ".rel.ifunc");
+ if (!htab->irelifunc)
+ abort ();
+ }
+ else
+ {
+ htab->iplt = bfd_get_section_by_name (abfd, ".iplt");
+ htab->irelplt = bfd_get_section_by_name (abfd,
+ ".rel.iplt");
+ htab->igotplt = bfd_get_section_by_name (abfd,
+ ".igot.plt");
+ if (!htab->iplt
+ || !htab->irelplt
+ || !htab->igotplt)
+ abort ();
+ }
}
break;
}
@@ -2038,10 +2049,7 @@ elf_i386_allocate_dynrelocs (struct elf_
/* Finally, allocate space. */
for (p = eh->dyn_relocs; p != NULL; p = p->next)
- {
- asection * sreloc = elf_section_data (p->sec)->sreloc;
- sreloc->size += p->count * sizeof (Elf32_External_Rel);
- }
+ htab->irelifunc->size += p->count * sizeof (Elf32_External_Rel);
/* For STT_GNU_IFUNC symbol, .got.plt has the real function
addres and .got has the PLT entry adddress. We will load
@@ -3010,7 +3018,7 @@ elf_i386_relocate_section (bfd *output_b
else
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
- sreloc = elf_section_data (input_section)->sreloc;
+ sreloc = htab->irelifunc;
loc = sreloc->contents;
loc += (sreloc->reloc_count++
* sizeof (Elf32_External_Rel));
More information about the Libc-alpha
mailing list