This is the mail archive of the binutils@sources.redhat.com 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]

powerpc64 opd edit


Current powerpc64 opd editing code leaves symbols defined in opd
unchanged when output, where they ought to be adjusted to reflect
changes caused by deleting entries.  For nm, objdump etc. symbol table
dumps this is mostly just a nuisance level bug, but when ld -r is
involved we can generate bad code taking addresses of functions.

Fixing this without adding ppc64 specific code (or another hook) to the
generic code required an extra parameter on elf_link_output_sym, as the
ppc64 code needs some means to distinguish local symbols from globals.
Looking at sym->st_info for STB_LOCAL isn't sufficient because of forced
local symbols.

I suppose an extra hook called from elf_link_input_bfd in the same place
as _bfd_merged_section_offset might have been a neater way to solve the
problem of adjusting local symbol values, but I'd already written the
patch this way before I thought of that. :)  Besides, passing the hash
entry allows a bug in elf64_hppa_link_output_symbol_hook to be fixed.
Since output_symbol_hook is called for local as well as global syms,
it was possible that the dyn_h lookup on a local sym might return
something for a global sym;  Local syms in one input file can have the
same name as a global sym in another file.

	* elf-bfd.h (struct elf_backend_data): Remove "bfd *" and add
	"elflink_hash_entry *" param to elf_backend_link_output_symbol_hook.
	Add "elflink_hash_entry *" param to elf_backend_output_arch_syms.
	* elflink.h (elf_link_output_sym): Add "elflink_hash_entry *" param,
	and pass to output_symbol_hook.
	(elf_bfd_final_link): Adjust elf_link_output_sym calls.
	(elf_link_output_extsym): Likewise.
	(elf_link_input_bfd): Likewise.
	* elf32-sh64.c (sh64_elf_link_output_symbol_hook): Adjust.
	* elf32-v850.c (v850_elf_link_output_symbol_hook): Likewise.
	* elf64-mmix.c (mmix_elf_link_output_symbol_hook): Likewise.
	* elf64-sh64.c (sh64_elf64_link_output_symbol_hook): Likewise.
	* elfxx-mips.c (_bfd_mips_elf_link_output_symbol_hook): Likewise.
	* elfxx-mips.h (_bfd_mips_elf_link_output_symbol_hook): Likewise.
	* elf64-sparc.c (sparc64_elf_output_arch_syms): Likewise.
	* elf64-hppa.c (elf64_hppa_link_output_symbol_hook): Likewise.
	Validate dynh->h against h.
	* elf64-ppc.c (struct ppc_link_hash_entry): Add adjust_done bitfield.
	(link_hash_newfunc): Init it.
	(adjust_opd_syms): New function.
	(ppc64_elf_edit_opd): Set adjust_done when global .opd sym adjusted.
	Set opd.adjust for all .opd relocs.  Call adjust_opd_syms.
	(ppc64_elf_tls_optimize): Adjust possible .opd sym values here.
	(ppc64_elf_relocate_section): Also adjust syms not a multiple of 24.
	(ppc64_elf_output_symbol_hook): New function.
	(elf_backend_link_output_symbol_hook): Define.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.123
diff -u -p -r1.123 elf-bfd.h
--- bfd/elf-bfd.h	1 Dec 2003 06:28:23 -0000	1.123
+++ bfd/elf-bfd.h	8 Dec 2003 10:41:19 -0000
@@ -626,8 +626,8 @@ struct elf_backend_data
   /* If this field is not NULL, it is called by the elf_link_output_sym
      phase of a link for each symbol which will appear in the object file.  */
   bfd_boolean (*elf_backend_link_output_symbol_hook)
-    (bfd *, struct bfd_link_info *info, const char *, Elf_Internal_Sym *,
-     asection *);
+    (struct bfd_link_info *info, const char *, Elf_Internal_Sym *,
+     asection *, struct elf_link_hash_entry *);
 
   /* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend
      linker the first time it encounters a dynamic object in the link.
@@ -793,7 +793,8 @@ struct elf_backend_data
      not handled in the hash table.  */
   bfd_boolean (*elf_backend_output_arch_syms)
     (bfd *, struct bfd_link_info *, void *,
-     bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *));
+     bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *,
+		      struct elf_link_hash_entry *));
 
   /* Copy any information related to dynamic linking from a pre-existing
      symbol to a newly created symbol.  Also called to copy flags and
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.249
diff -u -p -r1.249 elflink.h
--- bfd/elflink.h	1 Dec 2003 06:28:23 -0000	1.249
+++ bfd/elflink.h	8 Dec 2003 10:41:38 -0000
@@ -2833,7 +2833,8 @@ struct elf_final_link_info
 };
 
 static bfd_boolean elf_link_output_sym
-  (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *);
+  (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *,
+   struct elf_link_hash_entry *);
 static bfd_boolean elf_link_flush_output_syms
   (struct elf_final_link_info *);
 static bfd_boolean elf_link_output_extsym
@@ -3407,7 +3408,8 @@ elf_bfd_final_link (bfd *abfd, struct bf
       elfsym.st_info = 0;
       elfsym.st_other = 0;
       elfsym.st_shndx = SHN_UNDEF;
-      if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr))
+      if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+				 NULL))
 	goto error_return;
     }
 
@@ -3423,7 +3425,7 @@ elf_bfd_final_link (bfd *abfd, struct bf
   elfsym.st_other = 0;
   elfsym.st_shndx = SHN_ABS;
   if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd),
-			     &elfsym, bfd_abs_section_ptr))
+			     &elfsym, bfd_abs_section_ptr, NULL))
     goto error_return;
 #endif
 
@@ -3448,7 +3450,7 @@ elf_bfd_final_link (bfd *abfd, struct bf
 	    elfsym.st_value = 0;
 	  else
 	    elfsym.st_value = o->vma;
-	  if (! elf_link_output_sym (&finfo, NULL, &elfsym, o))
+	  if (! elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
 	    goto error_return;
 	  if (i == SHN_LORESERVE - 1)
 	    i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
@@ -3702,7 +3704,8 @@ elf_bfd_final_link (bfd *abfd, struct bf
   if (bed->elf_backend_output_arch_syms)
     {
       typedef bfd_boolean (*out_sym_func)
-	(void *, const char *, Elf_Internal_Sym *, asection *);
+	(void *, const char *, Elf_Internal_Sym *, asection *,
+	 struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_syms)
 	     (abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
@@ -4086,20 +4089,20 @@ static bfd_boolean
 elf_link_output_sym (struct elf_final_link_info *finfo,
 		     const char *name,
 		     Elf_Internal_Sym *elfsym,
-		     asection *input_sec)
+		     asection *input_sec,
+		     struct elf_link_hash_entry *h)
 {
   Elf_External_Sym *dest;
   Elf_External_Sym_Shndx *destshndx;
   bfd_boolean (*output_symbol_hook)
-    (bfd *, struct bfd_link_info *info, const char *,
-     Elf_Internal_Sym *, asection *);
+    (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+     struct elf_link_hash_entry *);
 
   output_symbol_hook = get_elf_backend_data (finfo->output_bfd)->
     elf_backend_link_output_symbol_hook;
   if (output_symbol_hook != NULL)
     {
-      if (! ((*output_symbol_hook)
-	     (finfo->output_bfd, finfo->info, name, elfsym, input_sec)))
+      if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h))
 	return FALSE;
     }
 
@@ -4640,7 +4643,7 @@ elf_link_output_extsym (struct elf_link_
 
   h->indx = bfd_get_symcount (finfo->output_bfd);
 
-  if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
+  if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h))
     {
       eoinfo->failed = TRUE;
       return FALSE;
@@ -4845,7 +4848,7 @@ elf_link_input_bfd (struct elf_final_lin
 	    }
 	}
 
-      if (! elf_link_output_sym (finfo, name, &osym, isec))
+      if (! elf_link_output_sym (finfo, name, &osym, isec, NULL))
 	return FALSE;
     }
 
@@ -5207,7 +5210,8 @@ elf_link_input_bfd (struct elf_final_lin
 			  finfo->indices[r_symndx]
 			    = bfd_get_symcount (output_bfd);
 
-			  if (! elf_link_output_sym (finfo, name, &sym, sec))
+			  if (! elf_link_output_sym (finfo, name, &sym, sec,
+						     NULL))
 			    return FALSE;
 			}
 
Index: bfd/elf32-sh64.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-sh64.c,v
retrieving revision 1.21
diff -u -p -r1.21 elf32-sh64.c
--- bfd/elf32-sh64.c	1 Dec 2003 06:28:23 -0000	1.21
+++ bfd/elf32-sh64.c	8 Dec 2003 10:41:21 -0000
@@ -59,8 +59,8 @@ static bfd_boolean sh64_elf_add_symbol_h
   (bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, const char **,
    flagword *, asection **, bfd_vma *);
 static bfd_boolean sh64_elf_link_output_symbol_hook
-  (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
-   asection *);
+  (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+   struct elf_link_hash_entry *);
 static bfd_boolean sh64_backend_section_from_shdr
   (bfd *, Elf_Internal_Shdr *, const char *);
 static void sh64_elf_final_write_processing
@@ -470,11 +470,11 @@ sh64_elf_add_symbol_hook (bfd *abfd, str
    DataLabel symbol.  */
 
 bfd_boolean
-sh64_elf_link_output_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED,
-				  struct bfd_link_info *info,
+sh64_elf_link_output_symbol_hook (struct bfd_link_info *info,
 				  const char *cname,
 				  Elf_Internal_Sym *sym,
-				  asection *input_sec ATTRIBUTE_UNUSED)
+				  asection *input_sec ATTRIBUTE_UNUSED,
+				  struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
 {
   char *name = (char *) cname;
 
Index: bfd/elf32-v850.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-v850.c,v
retrieving revision 1.38
diff -u -p -r1.38 elf32-v850.c
--- bfd/elf32-v850.c	27 Nov 2003 18:49:38 -0000	1.38
+++ bfd/elf32-v850.c	8 Dec 2003 10:41:22 -0000
@@ -76,8 +76,8 @@ static bfd_boolean v850_elf_add_symbol_h
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
 	   const char **, flagword *, asection **, bfd_vma *));
 static bfd_boolean v850_elf_link_output_symbol_hook
-  PARAMS ((bfd *, struct bfd_link_info *, const char *,
-	   Elf_Internal_Sym *, asection *));
+  PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+	   asection *, struct elf_link_hash_entry *));
 static bfd_boolean v850_elf_section_from_shdr
   PARAMS ((bfd *, Elf_Internal_Shdr *, const char *));
 static bfd_boolean v850_elf_gc_sweep_hook
@@ -2213,12 +2213,12 @@ v850_elf_add_symbol_hook (abfd, info, sy
 }
 
 static bfd_boolean
-v850_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
-     bfd *abfd ATTRIBUTE_UNUSED;
+v850_elf_link_output_symbol_hook (info, name, sym, input_sec, h)
      struct bfd_link_info *info ATTRIBUTE_UNUSED;
      const char *name ATTRIBUTE_UNUSED;
      Elf_Internal_Sym *sym;
      asection *input_sec;
+     struct elf_link_hash_entry *h ATTRIBUTE_UNUSED;
 {
   /* If we see a common symbol, which implies a relocatable link, then
      if a symbol was in a special common section in an input file, mark
Index: bfd/elf64-mmix.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-mmix.c,v
retrieving revision 1.28
diff -u -p -r1.28 elf64-mmix.c
--- bfd/elf64-mmix.c	27 Nov 2003 18:49:38 -0000	1.28
+++ bfd/elf64-mmix.c	8 Dec 2003 10:41:25 -0000
@@ -157,8 +157,8 @@ struct bpo_greg_section_info
   };
 
 static bfd_boolean mmix_elf_link_output_symbol_hook
-  PARAMS ((bfd *, struct bfd_link_info *, const char *,
-	   Elf_Internal_Sym *, asection *));
+  PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+	   asection *, struct elf_link_hash_entry *));
 
 static bfd_reloc_status_type mmix_elf_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
@@ -2113,12 +2113,12 @@ _bfd_mmix_check_all_relocs (abfd, info)
    number.  */
 
 static bfd_boolean
-mmix_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
-     bfd *abfd ATTRIBUTE_UNUSED;
+mmix_elf_link_output_symbol_hook (info, name, sym, input_sec, h)
      struct bfd_link_info *info ATTRIBUTE_UNUSED;
      const char *name ATTRIBUTE_UNUSED;
      Elf_Internal_Sym *sym;
      asection *input_sec;
+     struct elf_link_hash_entry *h ATTRIBUTE_UNUSED;
 {
   if (input_sec != NULL
       && input_sec->name != NULL
Index: bfd/elf64-sh64.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-sh64.c,v
retrieving revision 1.41
diff -u -p -r1.41 elf64-sh64.c
--- bfd/elf64-sh64.c	1 Dec 2003 06:28:23 -0000	1.41
+++ bfd/elf64-sh64.c	8 Dec 2003 10:41:32 -0000
@@ -144,8 +144,8 @@ static bfd_boolean sh64_elf64_add_symbol
   (bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, const char **,
    flagword *, asection **, bfd_vma *);
 static bfd_boolean sh64_elf64_link_output_symbol_hook
-  (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
-   asection *);
+  (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+   struct elf_link_hash_entry *);
 static bfd_boolean sh64_elf64_fake_sections
   (bfd *, Elf_Internal_Shdr *, asection *);
 static void sh64_elf64_final_write_processing
@@ -2982,11 +2982,11 @@ sh64_elf64_add_symbol_hook (bfd *abfd, s
    DataLabel symbol.  */
 
 static bfd_boolean
-sh64_elf64_link_output_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED,
-				    struct bfd_link_info *info,
+sh64_elf64_link_output_symbol_hook (struct bfd_link_info *info,
 				    const char *cname,
 				    Elf_Internal_Sym *sym,
-				    asection *input_sec ATTRIBUTE_UNUSED)
+				    asection *input_sec ATTRIBUTE_UNUSED,
+				    struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
 {
   char *name = (char *) cname;
 
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.85
diff -u -p -r1.85 elfxx-mips.c
--- bfd/elfxx-mips.c	27 Nov 2003 18:49:39 -0000	1.85
+++ bfd/elfxx-mips.c	8 Dec 2003 10:41:43 -0000
@@ -4818,12 +4818,12 @@ _bfd_mips_elf_add_symbol_hook (abfd, inf
    also where we undo the increment of the value for a mips16 symbol.  */
 
 bfd_boolean
-_bfd_mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
-     bfd *abfd ATTRIBUTE_UNUSED;
+_bfd_mips_elf_link_output_symbol_hook (info, name, sym, input_sec, h)
      struct bfd_link_info *info ATTRIBUTE_UNUSED;
      const char *name ATTRIBUTE_UNUSED;
      Elf_Internal_Sym *sym;
      asection *input_sec;
+     struct elf_link_hash_entry *h ATTRIBUTE_UNUSED;
 {
   /* If we see a common symbol, which implies a relocatable link, then
      if a symbol was small common in an input file, mark it as small
Index: bfd/elfxx-mips.h
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.h,v
retrieving revision 1.14
diff -u -p -r1.14 elfxx-mips.h
--- bfd/elfxx-mips.h	27 Nov 2003 16:43:25 -0000	1.14
+++ bfd/elfxx-mips.h	8 Dec 2003 10:41:43 -0000
@@ -36,8 +36,8 @@ extern bfd_boolean _bfd_mips_elf_add_sym
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
 	   const char **, flagword *, asection **, bfd_vma *));
 extern bfd_boolean _bfd_mips_elf_link_output_symbol_hook
-  PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
-	   asection *));
+  PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+	   asection *, struct elf_link_hash_entry *));
 extern bfd_boolean _bfd_mips_elf_create_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 extern bfd_boolean _bfd_mips_elf_check_relocs
Index: bfd/elf64-sparc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-sparc.c,v
retrieving revision 1.81
diff -u -p -r1.81 elf64-sparc.c
--- bfd/elf64-sparc.c	27 Nov 2003 18:49:38 -0000	1.81
+++ bfd/elf64-sparc.c	8 Dec 2003 10:41:34 -0000
@@ -65,7 +65,8 @@ static bfd_boolean sparc64_elf_add_symbo
 	   const char **, flagword *, asection **, bfd_vma *));
 static bfd_boolean sparc64_elf_output_arch_syms
   PARAMS ((bfd *, struct bfd_link_info *, PTR,
-	   bfd_boolean (*) (PTR, const char *, Elf_Internal_Sym *, asection *)));
+	   bfd_boolean (*) (PTR, const char *, Elf_Internal_Sym *,
+			    asection *, struct elf_link_hash_entry *)));
 static void sparc64_elf_symbol_processing
   PARAMS ((bfd *, asymbol *));
 
@@ -1511,7 +1512,8 @@ sparc64_elf_output_arch_syms (output_bfd
      struct bfd_link_info *info;
      PTR finfo;
      bfd_boolean (*func)
-       PARAMS ((PTR, const char *, Elf_Internal_Sym *, asection *));
+       PARAMS ((PTR, const char *, Elf_Internal_Sym *, asection *,
+		struct elf_link_hash_entry *));
 {
   int reg;
   struct sparc64_elf_app_reg *app_regs =
@@ -1557,7 +1559,8 @@ sparc64_elf_output_arch_syms (output_bfd
 	sym.st_shndx = app_regs [reg].shndx;
 	if (! (*func) (finfo, app_regs [reg].name, &sym,
 		       sym.st_shndx == SHN_ABS
-			 ? bfd_abs_section_ptr : bfd_und_section_ptr))
+			 ? bfd_abs_section_ptr : bfd_und_section_ptr,
+		       NULL))
 	  return FALSE;
       }
 
Index: bfd/elf64-hppa.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-hppa.c,v
retrieving revision 1.43
diff -u -p -r1.43 elf64-hppa.c
--- bfd/elf64-hppa.c	27 Nov 2003 18:49:38 -0000	1.43
+++ bfd/elf64-hppa.c	8 Dec 2003 10:41:24 -0000
@@ -202,8 +202,8 @@ static bfd_boolean elf64_hppa_size_dynam
   PARAMS ((bfd *, struct bfd_link_info *));
 
 static bfd_boolean elf64_hppa_link_output_symbol_hook
-  PARAMS ((bfd *abfd, struct bfd_link_info *, const char *,
-	   Elf_Internal_Sym *, asection *input_sec));
+  PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+	   asection *, struct elf_link_hash_entry *));
 
 static bfd_boolean elf64_hppa_finish_dynamic_symbol
   PARAMS ((bfd *, struct bfd_link_info *,
@@ -1893,12 +1893,12 @@ elf64_hppa_size_dynamic_sections (output
    table.  Ick.  */
 
 static bfd_boolean
-elf64_hppa_link_output_symbol_hook (abfd, info, name, sym, input_sec)
-     bfd *abfd ATTRIBUTE_UNUSED;
+elf64_hppa_link_output_symbol_hook (info, name, sym, input_sec, h)
      struct bfd_link_info *info;
      const char *name;
      Elf_Internal_Sym *sym;
      asection *input_sec ATTRIBUTE_UNUSED;
+     struct elf_link_hash_entry *h;
 {
   struct elf64_hppa_link_hash_table *hppa_info;
   struct elf64_hppa_dyn_hash_entry *dyn_h;
@@ -1912,6 +1912,8 @@ elf64_hppa_link_output_symbol_hook (abfd
   hppa_info = elf64_hppa_hash_table (info);
   dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
 				      name, FALSE, FALSE);
+  if (dyn_h->h != h)
+    return TRUE;
 
   /* Function symbols for which we created .opd entries *may* have been
      munged by finish_dynamic_symbol and have to be un-munged here.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.141
diff -u -p -r1.141 elf64-ppc.c
--- bfd/elf64-ppc.c	27 Nov 2003 18:49:38 -0000	1.141
+++ bfd/elf64-ppc.c	8 Dec 2003 11:29:43 -0000
@@ -92,6 +92,7 @@ static bfd_reloc_status_type ppc64_elf_u
 #define elf_backend_finish_dynamic_symbol     ppc64_elf_finish_dynamic_symbol
 #define elf_backend_reloc_type_class	      ppc64_elf_reloc_type_class
 #define elf_backend_finish_dynamic_sections   ppc64_elf_finish_dynamic_sections
+#define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections	      ppc64_elf_special_sections
 
 /* The name of the dynamic interpreter.  This is put in the .interp
@@ -2762,6 +2763,9 @@ struct ppc_link_hash_entry
   unsigned int is_func_descriptor:1;
   unsigned int is_entry:1;
 
+  /* Whether global opd sym has been adjusted or not.  */
+  unsigned int adjust_done:1;
+
   /* Contexts in which symbol is used in the GOT (or TOC).
      TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
      corresponding relocs are encountered during check_relocs.
@@ -2971,6 +2975,7 @@ link_hash_newfunc (struct bfd_hash_entry
       eh->is_func = 0;
       eh->is_func_descriptor = 0;
       eh->is_entry = 0;
+      eh->adjust_done = 0;
       eh->tls_mask = 0;
     }
 
@@ -4875,10 +4880,53 @@ get_tls_mask (char **tls_maskp, unsigned
   return 1;
 }
 
+/* Adjust all global syms defined in opd sections.  In gcc generated
+   code these will already have been done, but I suppose we have to
+   cater for all sorts of hand written assembly.  */
+
+static bfd_boolean
+adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
+{
+  struct ppc_link_hash_entry *eh;
+  asection *sym_sec;
+  long *opd_adjust;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  if (h->root.type != bfd_link_hash_defined
+      && h->root.type != bfd_link_hash_defweak)
+    return TRUE;
+
+  eh = (struct ppc_link_hash_entry *) h;
+  if (eh->adjust_done)
+    return TRUE;
+
+  sym_sec = eh->elf.root.u.def.section;
+  if (sym_sec != NULL
+      && elf_section_data (sym_sec) != NULL
+      && (opd_adjust = ppc64_elf_section_data (sym_sec)->opd.adjust) != NULL)
+    {
+      eh->elf.root.u.def.value += opd_adjust[eh->elf.root.u.def.value / 24];
+      eh->adjust_done = 1;
+    }
+  return TRUE;
+}
+
+/* Remove unused Official Procedure Descriptor entries.  Currently we
+   only remove those associated with functions in discarded link-once
+   sections, or weakly defined functions that have been overridden.  It
+   would be possible to remove many more entries for statically linked
+   applications.  */
+
 bfd_boolean
 ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
 {
   bfd *ibfd;
+  bfd_boolean some_edited = FALSE;
 
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
@@ -5079,23 +5127,25 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
 
 		      if (h != NULL)
 			{
-			  /* Redefine the function descriptor symbol
-			     to this location in the opd section.
-			     We've checked above that opd relocs are
-			     ordered.  */
+			  /* Redefine the function descriptor symbol to
+			     this location in the opd section.  It is
+			     necessary to update the value here rather
+			     than using an array of adjustments as we do
+			     for local symbols, because various places
+			     in the generic ELF code use the value
+			     stored in u.def.value.  */
 			  fdh->elf.root.u.def.value = wptr - sec->contents;
-			}
-		      else
-			{
-			  /* Local syms are a bit tricky.  We could
-			     tweak them as they can be cached, but
-			     we'd need to look through the local syms
-			     for the function descriptor sym which we
-			     don't have at the moment.  So keep an
-			     array of adjustments.  */
-			  adjust[rel->r_offset / 24] = wptr - rptr;
+			  fdh->adjust_done = 1;
 			}
 
+		      /* Local syms are a bit tricky.  We could
+			 tweak them as they can be cached, but
+			 we'd need to look through the local syms
+			 for the function descriptor sym which we
+			 don't have at the moment.  So keep an
+			 array of adjustments.  */
+		      adjust[rel->r_offset / 24] = wptr - rptr;
+
 		      if (wptr != rptr)
 			memcpy (wptr, rptr, 24);
 		      wptr += 24;
@@ -5153,6 +5203,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
 	  elf_section_data (sec)->rel_hdr.sh_size
 	    = sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize;
 	  BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL);
+	  some_edited = TRUE;
 	}
       else if (elf_section_data (sec)->relocs != relstart)
 	free (relstart);
@@ -5167,6 +5218,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
 	}
     }
 
+  if (some_edited)
+    elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL);
+
   return TRUE;
 }
 
@@ -5262,7 +5316,17 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
 		    value = h->root.u.def.value;
 		  }
 		else
-		  value = sym->st_value;
+		  {
+		    value = sym->st_value;
+
+		    if (elf_section_data (sym_sec) != NULL)
+		      {
+			long *adjust;
+			adjust = ppc64_elf_section_data (sym_sec)->opd.adjust;
+			if (adjust != NULL)
+			  value += adjust[value / 24];
+		      }
+		  }
 
 		ok_tprel = FALSE;
 		is_local = FALSE;
@@ -7402,7 +7466,7 @@ ppc64_elf_relocate_section (bfd *output_
 	      long *opd_sym_adjust;
 
 	      opd_sym_adjust = ppc64_elf_section_data (sec)->opd.adjust;
-	      if (opd_sym_adjust != NULL && sym->st_value % 24 == 0)
+	      if (opd_sym_adjust != NULL)
 		relocation += opd_sym_adjust[sym->st_value / 24];
 	    }
 	}
@@ -8671,6 +8735,32 @@ ppc64_elf_relocate_section (bfd *output_
     }
 
   return ret;
+}
+
+/* Adjust the value of any local symbols in opd sections.  */
+
+static bfd_boolean
+ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
+			      const char *name ATTRIBUTE_UNUSED,
+			      Elf_Internal_Sym *elfsym,
+			      asection *input_sec,
+			      struct elf_link_hash_entry *h)
+{
+  long *adjust;
+  bfd_vma value;
+
+  if (h != NULL
+      || input_sec == NULL
+      || ppc64_elf_section_data (input_sec) == NULL
+      || (adjust = ppc64_elf_section_data (input_sec)->opd.adjust) == NULL)
+    return TRUE;
+
+  value = elfsym->st_value - input_sec->output_offset;
+  if (!info->relocatable)
+    value -= input_sec->output_section->vma;
+
+  elfsym->st_value += adjust[value / 24];
+  return TRUE;
 }
 
 /* Finish up dynamic symbol handling.  We set the contents of various

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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