complex relocation fixes

Alan Modra amodra@bigpond.net.au
Wed Sep 26 15:20:00 GMT 2007


Even when symbols are cached, the complex relocation support code
needlessly reads the symbol table from disk and converts to internal
form just to have the luxury of finding symbols in a particular
buffer.  This happens whether complex relocations are present or not.
On fixing this, I noticed that set_symbol_value wouldn't work unless
elf_bad_symtab was true (was this why MEP set it?).  You'd get accesses
past the end of the array of local symbols.

	* elflink.c (set_symbol_value): Add isymbuf and locsymcount
	params.  Change symidx to a size_t.  Don't access past end
	of symbol buffer.
	(resolve_symbol): Add isymbuf param and use instead of
	finfo->internal_syms.
	(eval_symbol, evaluate_complex_relocation_symbols): Likewise.
	(elf_link_input_bfd): Don't read symbols specially for
	evaluate_complex_relocation_symbols.

Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.278
diff -u -p -r1.278 elflink.c
--- bfd/elflink.c	18 Sep 2007 08:17:06 -0000	1.278
+++ bfd/elflink.c	26 Sep 2007 09:14:52 -0000
@@ -7230,38 +7230,43 @@ struct elf_outext_info
 
 static void
 set_symbol_value (bfd *                         bfd_with_globals,
-		  struct elf_final_link_info *  finfo,    
-		  int                           symidx,
+		  Elf_Internal_Sym *		isymbuf,
+		  size_t			locsymcount,
+		  size_t                        symidx,
 		  bfd_vma                       val)
 {
-  bfd_boolean                    is_local;
-  Elf_Internal_Sym *             sym;
-  struct elf_link_hash_entry **  sym_hashes;
-  struct elf_link_hash_entry *   h;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf_link_hash_entry *h;
+  size_t extsymoff = locsymcount;
 
-  sym_hashes = elf_sym_hashes (bfd_with_globals);
-  sym = finfo->internal_syms + symidx;  
-  is_local = ELF_ST_BIND(sym->st_info) == STB_LOCAL;
-  
-  if (is_local)
+  if (symidx < locsymcount)
     {
-      /* It is a local symbol: move it to the
-	 "absolute" section and give it a value.  */
-      sym->st_shndx = SHN_ABS;
-      sym->st_value = val;
-    }
-  else 
-    {
-      /* It is a global symbol: set its link type
-	 to "defined" and give it a value.  */
-      h = sym_hashes [symidx];	  
-      while (h->root.type == bfd_link_hash_indirect
-	     || h->root.type == bfd_link_hash_warning)
-	h = (struct elf_link_hash_entry *) h->root.u.i.link;
-      h->root.type = bfd_link_hash_defined;
-      h->root.u.def.value = val;
-      h->root.u.def.section = bfd_abs_section_ptr;
+      Elf_Internal_Sym *sym;
+
+      sym = isymbuf + symidx;
+      if (ELF_ST_BIND (sym->st_info) == STB_LOCAL)
+	{
+	  /* It is a local symbol: move it to the
+	     "absolute" section and give it a value.  */
+	  sym->st_shndx = SHN_ABS;
+	  sym->st_value = val;
+	  return;
+	}
+      BFD_ASSERT (elf_bad_symtab (bfd_with_globals));
+      extsymoff = 0;
     }
+
+  /* It is a global symbol: set its link type
+     to "defined" and give it a value.  */
+
+  sym_hashes = elf_sym_hashes (bfd_with_globals);
+  h = sym_hashes [symidx - extsymoff];
+  while (h->root.type == bfd_link_hash_indirect
+	 || h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+  h->root.type = bfd_link_hash_defined;
+  h->root.u.def.value = val;
+  h->root.u.def.section = bfd_abs_section_ptr;
 }
 
 static bfd_boolean 
@@ -7269,6 +7274,7 @@ resolve_symbol (const char *            
 		bfd *                         input_bfd,
 		struct elf_final_link_info *  finfo,
 		bfd_vma *                     result,
+		Elf_Internal_Sym *            isymbuf,
 		size_t                        locsymcount)
 {
   Elf_Internal_Sym *            sym;
@@ -7282,7 +7288,7 @@ resolve_symbol (const char *            
 
   for (i = 0; i < locsymcount; ++ i)
     {
-      sym = finfo->internal_syms + i;
+      sym = isymbuf + i;
       sec = finfo->sections [i];
 
       if (ELF_ST_BIND (sym->st_info) != STB_LOCAL)
@@ -7402,6 +7408,7 @@ eval_symbol (bfd_vma *                  
 	     struct elf_final_link_info *  finfo,
 	     bfd_vma                       addr,
 	     bfd_vma                       section_offset,
+	     Elf_Internal_Sym *            isymbuf,
 	     size_t                        locsymcount,
 	     int                           signed_p)
 {
@@ -7459,8 +7466,9 @@ eval_symbol (bfd_vma *                  
 
       if (symbol_is_section) 
 	{
-	  if ((resolve_section (symbuf, finfo->output_bfd->sections, result) != TRUE)
-	      && (resolve_symbol (symbuf, input_bfd, finfo, result, locsymcount) != TRUE))
+	  if (!resolve_section (symbuf, finfo->output_bfd->sections, result)
+	      && !resolve_symbol (symbuf, input_bfd, finfo, result,
+				  isymbuf, locsymcount))
 	    {
 	      undefined_reference ("section", symbuf);
 	      return FALSE;
@@ -7468,9 +7476,10 @@ eval_symbol (bfd_vma *                  
 	} 
       else 
 	{
-	  if ((resolve_symbol (symbuf, input_bfd, finfo, result, locsymcount) != TRUE)
-	      && (resolve_section (symbuf, finfo->output_bfd->sections,
-				   result) != TRUE))
+	  if (!resolve_symbol (symbuf, input_bfd, finfo, result,
+			       isymbuf, locsymcount)
+	      && !resolve_section (symbuf, finfo->output_bfd->sections,
+				   result))
 	    {
 	      undefined_reference ("symbol", symbuf);
 	      return FALSE;
@@ -7487,9 +7496,9 @@ eval_symbol (bfd_vma *                  
       sym += strlen (#op);					\
       if (* sym == ':')						\
         ++ sym;							\
-      if (eval_symbol (& a, sym, & sym, input_bfd, finfo, addr, \
-                       section_offset, locsymcount, signed_p)   \
-	                                             != TRUE)	\
+      if (!eval_symbol (&a, sym, &sym, input_bfd, finfo, addr,	\
+			section_offset, isymbuf, locsymcount,	\
+			signed_p))				\
         return FALSE;						\
       if (signed_p)                                             \
         * result = op ((signed)a);         			\
@@ -7505,14 +7514,14 @@ eval_symbol (bfd_vma *                  
       sym += strlen (#op);					\
       if (* sym == ':')						\
         ++ sym;							\
-      if (eval_symbol (& a, sym, & sym, input_bfd, finfo, addr, \
-                       section_offset, locsymcount, signed_p)   \
-                                                     != TRUE)	\
+      if (!eval_symbol (&a, sym, &sym, input_bfd, finfo, addr,	\
+			section_offset, isymbuf, locsymcount,	\
+			signed_p))				\
         return FALSE;						\
       ++ sym;							\
-      if (eval_symbol (& b, sym, & sym, input_bfd, finfo, addr, \
-                       section_offset, locsymcount, signed_p)   \
-                                                     != TRUE)	\
+      if (!eval_symbol (&b, sym, &sym, input_bfd, finfo, addr,	\
+			section_offset, isymbuf, locsymcount,	\
+			signed_p))				\
         return FALSE;						\
       if (signed_p)                                             \
         * result = ((signed) a) op ((signed) b);	        \
@@ -7555,8 +7564,9 @@ eval_symbol (bfd_vma *                  
 /* Entry point to evaluator, called from elf_link_input_bfd.  */
 
 static bfd_boolean
-evaluate_complex_relocation_symbols (bfd * input_bfd,
-				     struct elf_final_link_info * finfo,
+evaluate_complex_relocation_symbols (bfd *input_bfd,
+				     struct elf_final_link_info *finfo,
+				     Elf_Internal_Sym *isymbuf,
 				     size_t locsymcount)
 {
   const struct elf_backend_data * bed;
@@ -7626,7 +7636,7 @@ evaluate_complex_relocation_symbols (bfd
 	  if (index < locsymcount)
 	    {
 	      /* The symbol is local.  */
-	      sym = finfo->internal_syms + index;
+	      sym = isymbuf + index;
 
 	      /* We're only processing STT_RELC or STT_SRELC type symbols.  */
 	      if ((ELF_ST_TYPE (sym->st_info) != STT_RELC) &&
@@ -7668,10 +7678,10 @@ evaluate_complex_relocation_symbols (bfd
 	  printf (" Evaluating '%s' ...\n ", sym_name);
 #endif
 	  if (eval_symbol (& result, sym_name, & sym_name, input_bfd, 
-			   finfo, addr, section_offset, locsymcount,
+			   finfo, addr, section_offset, isymbuf, locsymcount,
 			   signed_p))
 	    /* Symbol evaluated OK.  Update to absolute value.  */
-	    set_symbol_value (input_bfd, finfo, index, result);
+	    set_symbol_value (input_bfd, isymbuf, locsymcount, index, result);
 
 	  else
 	    result = FALSE;
@@ -9066,15 +9076,6 @@ elf_link_input_bfd (struct elf_final_lin
       if (isymbuf == NULL)
 	return FALSE;
     }
-  /* evaluate_complex_relocation_symbols looks for symbols in
-     finfo->internal_syms.  */
-  else if (isymbuf != NULL && locsymcount != 0)
-    {
-      bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
-			    finfo->internal_syms,
-			    finfo->external_syms,
-			    finfo->locsym_shndx);
-    }
 
   /* Find local symbol sections and adjust values of symbols in
      SEC_MERGE sections.  Write out those local symbols we know are
@@ -9212,7 +9213,8 @@ elf_link_input_bfd (struct elf_final_lin
 	return FALSE;
     }
 
-  if (! evaluate_complex_relocation_symbols (input_bfd, finfo, locsymcount))
+  if (! evaluate_complex_relocation_symbols (input_bfd, finfo, isymbuf,
+					     locsymcount))
     return FALSE;
 
   /* Relocate the contents of each section.  */

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list