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]

PATCH: Generic STT_GNU_IFUNC patch


Here is the generic STT_GNU_IFUNC patch. I need it to complete
STT_GNU_IFUNC support on Linux/ia32 and Linux/Intel64.  I will
fix Linux/ia32 and Linux/Intel64 with a followup patch.

Nick, can you take a look?

Thanks.


H.J.
----
bfd/

2009-05-31  H.J. Lu  <hongjiu.lu@intel.com>

	* elf-bfd.h (struct bfd_elf_section_data): Remove indirect_relocs.
	(_bfd_elf_make_ifunc_reloc_section): Removed.
	(_bfd_elf_is_ifunc_symbol): Likewise.
	(_bfd_elf_create_static_ifunc_sections): New.

	* elflink.c (_bfd_elf_adjust_dynamic_symbol): Move STT_GNU_IFUNC
	symbol check to ...
	(elf_link_add_object_symbols): Here.
	(_bfd_elf_link_hash_hide_symbol): Don't clean plt on
	STT_GNU_IFUNC symbol.
	(elf_link_output_extsym): Call elf_backend_finish_dynamic_symbol
	if a STT_GNU_IFUNC symbol is referenced in a non-shared object.
	(IFUNC_INFIX): Removed.
	(get_ifunc_reloc_section_name): Likewise.
	(_bfd_elf_make_ifunc_reloc_section): Likewise.
	(_bfd_elf_is_ifunc_symbol): Likewise.
	(_bfd_elf_create_static_ifunc_sections): New.

ld/

2009-05-31  H.J. Lu  <hongjiu.lu@intel.com>

	* scripttempl/elf.sc (PLT): Add "*(.iplt)".
	(GOT): Add "*(.igot.plt)a" and "*(.igot)".
	(GOTPLT): Add "*(.igot)".
	(__rel_iplt_start): New.
	(__rel_iplt_end): Likewise.
	(__rela_iplt_start): Likewise.
	(__rela_iplt_end): Likewise.

diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf-bfd.h binutils/bfd/elf-bfd.h
--- ../binutils/src/bfd/elf-bfd.h	2009-05-26 15:19:00.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2009-05-30 09:38:42.000000000 -0700
@@ -1299,9 +1299,6 @@ struct bfd_elf_section_data
   /* A pointer to the bfd section used for dynamic relocs.  */
   asection *sreloc;
 
-  /* A pointer to the bfd section used for dynamic relocs against ifunc symbols.  */
-  asection *indirect_relocs;
-
   union {
     /* Group name, if this section is a member of a group.  */
     const char *name;
@@ -2149,15 +2146,12 @@ 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 asection * _bfd_elf_make_ifunc_reloc_section
-  (bfd *, asection *, bfd *, unsigned int);
+extern bfd_boolean _bfd_elf_create_static_ifunc_sections
+  (bfd *, struct bfd_link_info *);
 
 /* Large common section.  */
 extern asection _bfd_elf_large_com_section;
 
-extern bfd_boolean _bfd_elf_is_ifunc_symbol
-  (bfd *, struct elf_link_hash_entry *);
-
 /* This is the condition under which finish_dynamic_symbol will be called.
    If our finish_dynamic_symbol isn't called, we'll need to do something
    about initializing any .plt and .got entries in relocate_section.  */
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-26 15:19:00.000000000 -0700
+++ binutils/bfd/elflink.c	2009-05-31 12:01:00.000000000 -0700
@@ -2675,13 +2675,6 @@ _bfd_elf_adjust_dynamic_symbol (struct e
   dynobj = elf_hash_table (eif->info)->dynobj;
   bed = get_elf_backend_data (dynobj);
 
-
-  if (h->type == STT_GNU_IFUNC
-      && (bed->elf_osabi == ELFOSABI_LINUX
-	  /* GNU/Linux is still using the default value 0.  */
-	  || bed->elf_osabi == ELFOSABI_NONE))
-    h->needs_plt = 1;
-
   if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
     {
       eif->failed = TRUE;
@@ -4294,6 +4287,10 @@ elf_link_add_object_symbols (bfd *abfd, 
 
 	      h->type = ELF_ST_TYPE (isym->st_info);
 	    }
+      
+	  /* STT_GNU_IFUNC symbol must go through PLT.  */
+	  if (h->type == STT_GNU_IFUNC)
+	    h->needs_plt = 1;
 
 	  /* Merge st_other field.  */
 	  elf_merge_st_other (abfd, h, isym, definition, dynamic);
@@ -6669,8 +6666,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 (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;
@@ -8649,14 +8650,18 @@ elf_link_output_extsym (struct elf_link_
   /* Give the processor backend a chance to tweak the symbol value,
      and also to finish up anything that needs to be done for this
      symbol.  FIXME: Not calling elf_backend_finish_dynamic_symbol for
-     forced local syms when non-shared is due to a historical quirk.  */
-  if ((h->dynindx != -1
-       || h->forced_local)
-      && ((finfo->info->shared
-	   && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-	       || h->root.type != bfd_link_hash_undefweak))
-	  || !h->forced_local)
-      && elf_hash_table (finfo->info)->dynamic_sections_created)
+     forced local syms when non-shared is due to a historical quirk.
+     STT_GNU_IFUNC symbol must go through PLT.  */
+  if ((h->type == STT_GNU_IFUNC
+       && h->ref_regular
+       && !finfo->info->relocatable)
+      || ((h->dynindx != -1
+	   || h->forced_local)
+	  && ((finfo->info->shared
+	       && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+		   || h->root.type != bfd_link_hash_undefweak))
+	      || !h->forced_local)
+	  && elf_hash_table (finfo->info)->dynamic_sections_created))
     {
       if (! ((*bed->elf_backend_finish_dynamic_symbol)
 	     (finfo->output_bfd, finfo->info, h, &sym)))
@@ -12487,88 +12492,87 @@ _bfd_elf_make_dynamic_reloc_section (ase
   return reloc_sec;
 }
 
-/* Returns the name of the ifunc using dynamic reloc section associated with SEC.  */
-#define IFUNC_INFIX ".ifunc"
+/* Create sections needed by STT_GNU_IFUNC symbol for static
+   executables.  */
 
-static const char *
-get_ifunc_reloc_section_name (bfd *       abfd,
-			      asection *  sec)
+bfd_boolean
+_bfd_elf_create_static_ifunc_sections (bfd *abfd,
+				       struct bfd_link_info *info)
 {
-  const char *  dot;
-  char *  name;
-  const char *  base_name;
-  unsigned int  strndx = elf_elfheader (abfd)->e_shstrndx;
-  unsigned int  shnam = elf_section_data (sec)->rel_hdr.sh_name;
-
-  base_name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
-  if (base_name == NULL)
-    return NULL;
+  flagword flags, pltflags;
+  int ptralign;
+  asection *s;
+  const struct elf_backend_data *bed;
 
-  dot = strchr (base_name + 1, '.');
-  name = bfd_alloc (abfd, strlen (base_name) + strlen (IFUNC_INFIX) + 1);
-  sprintf (name, "%.*s%s%s", (int)(dot - base_name), base_name, IFUNC_INFIX, dot);
+  /* Should never be called for shared library.  */
+  BFD_ASSERT (!info->shared);
 
-  return name;
-}
-
-/* Like _bfd_elf_make_dynamic_reloc_section but it creates a
-   section for holding relocs against symbols with the STT_GNU_IFUNC
-   type.  The section is attached to the OWNER bfd but it is created
-   with a name based on SEC from ABFD.  */
+  /* This function may be called more than once.  */
+  s = bfd_get_section_by_name (abfd, ".iplt");
+  if (s != NULL)
+    return TRUE;
 
-asection *
-_bfd_elf_make_ifunc_reloc_section (bfd *         abfd,
-				   asection *    sec,
-				   bfd *         owner,
-				   unsigned int  align)
-{
-  asection * reloc_sec = elf_section_data (sec)->indirect_relocs;
+  bed = get_elf_backend_data (abfd);
 
-  if (reloc_sec == NULL)
-    {
-      const char * name = get_ifunc_reloc_section_name (abfd, sec);
+  /* We need to create .iplt, .rel[a].iplt, .igot, .igot.plt,  */
+  flags = bed->dynamic_sec_flags;
 
-      if (name == NULL)
-	return NULL;
+  pltflags = flags;
+  if (bed->plt_not_loaded)
+    /* We do not clear SEC_ALLOC here because we still want the OS to
+       allocate space for the section; it's just that there's nothing
+       to read in from the object file.  */
+    pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
+  else
+    pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD;
+  if (bed->plt_readonly)
+    pltflags |= SEC_READONLY;
 
-      reloc_sec = bfd_get_section_by_name (owner, name);
+  s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
+  if (s == NULL
+      || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
+    return FALSE;
 
-      if (reloc_sec == NULL)
-	{
-	  flagword flags;
+  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;
 
-	  flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-	  if ((sec->flags & SEC_ALLOC) != 0)
-	    flags |= SEC_ALLOC | SEC_LOAD;
+  switch (bed->s->arch_size)
+    {
+    case 32:
+      ptralign = 2;
+      break;
 
-	  reloc_sec = bfd_make_section_with_flags (owner, name, flags);
-	  
-	  if (reloc_sec != NULL
-	      && ! bfd_set_section_alignment (owner, reloc_sec, align))
-	    reloc_sec = NULL;
-	}
+    case 64:
+      ptralign = 3;
+      break;
 
-      elf_section_data (sec)->indirect_relocs = reloc_sec;
+    default:
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
     }
 
-  return reloc_sec;
-}
-
-/* Returns true if the hash entry refers to a symbol marked for
-   indirect handling during reloc processing.  */
-
-bfd_boolean
-_bfd_elf_is_ifunc_symbol (bfd *abfd, struct elf_link_hash_entry *h)
-{
-  const struct elf_backend_data * bed;
-
-  if (abfd == NULL || h == NULL)
-    return FALSE;
+  /* We don't need the .igot section if we have the .igot.plt
+     section.  */
 
-  bed = get_elf_backend_data (abfd);
+  if (bed->want_got_plt)
+    {
+      s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
+      if (s == NULL
+	  || !bfd_set_section_alignment (abfd, s, ptralign))
+	return FALSE;
+    }
+  else
+    {
+      s = bfd_make_section_with_flags (abfd, ".igot", flags);
+      if (s == NULL
+	  || !bfd_set_section_alignment (abfd, s, ptralign))
+	return FALSE;
+    }
 
-  /* GNU/Linux is still using the default value ELFOSABI_NONE.  */
-  return (h->type == STT_GNU_IFUNC
-	  && (bed->elf_osabi == ELFOSABI_LINUX
-	      || bed->elf_osabi == ELFOSABI_NONE));
+  return TRUE;
 }
diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/scripttempl/elf.sc binutils/ld/scripttempl/elf.sc
--- ../binutils/src/ld/scripttempl/elf.sc	2009-05-05 10:55:58.000000000 -0700
+++ binutils/ld/scripttempl/elf.sc	2009-05-31 20:28:01.000000000 -0700
@@ -113,15 +113,15 @@ if test -z "${INITIAL_READONLY_SECTIONS}
   INITIAL_READONLY_SECTIONS=".interp       ${RELOCATING-0} : { *(.interp) }"
 fi
 if test -z "$PLT"; then
-  PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
+  PLT=".plt          ${RELOCATING-0} : { *(.plt) *(.iplt)}"
 fi
 test -n "${DATA_PLT-${BSS_PLT-text}}" && TEXT_PLT=yes
 if test -z "$GOT"; then
   if test -z "$SEPARATE_GOTPLT"; then
-    GOT=".got          ${RELOCATING-0} : { *(.got.plt) *(.got) }"
+    GOT=".got          ${RELOCATING-0} : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }"
   else
-    GOT=".got          ${RELOCATING-0} : { *(.got) }"
-    GOTPLT=".got.plt      ${RELOCATING-0} : { *(.got.plt) }"
+    GOT=".got          ${RELOCATING-0} : { *(.got) *(.igot) }"
+    GOTPLT=".got.plt      ${RELOCATING-0} : { *(.got.plt)  *(.igot.plt) }"
   fi
 fi
 DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
@@ -354,8 +354,20 @@ EOF
 fi
 
 cat >> ldscripts/dyntmp.$$ <<EOF
-  .rel.plt      ${RELOCATING-0} : { *(.rel.plt) }
-  .rela.plt     ${RELOCATING-0} : { *(.rela.plt) }
+  .rel.plt      ${RELOCATING-0} :
+    {
+      *(.rel.plt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rel_iplt_start = .);}}
+      *(.rel.iplt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rel_iplt_end = .);}}
+    }
+  .rela.plt     ${RELOCATING-0} :
+    {
+      *(.rela.plt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rela_iplt_start = .);}}
+      *(.rela.iplt)
+      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__rela_iplt_end = .);}}
+    }
   ${OTHER_PLT_RELOC_SECTIONS}
 EOF
 


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