Fix some minor elf64-ppc.c bugs

Alan Modra amodra@gmail.com
Fri Jun 25 03:51:00 GMT 2010


This fixes some minor elf64-ppc.c bugs and moves a block of code in
preparation for a followup patch.

	* elf64-ppc.c (is_static_defined): New function.
	(get_tls_mask, ppc_type_of_stub): Use it here.
	(ppc64_elf_edit_opd): Ensure we only attempt to edit ppc64 input.
	(ppc64_elf_tls_setup): Typo fix.
	(adjust_toc_syms): Correctly handle symbols defined past the end
	of the toc.  Move syms on removed entries to next entry rather
	than to start of toc.
	(ppc64_elf_edit_toc): Likewise.  Ensure we only attempt to
	edit ppc64 input.  Allocate one extra word in skip array.
	Honour info->keep_memory when reading relocs if we can.
	Adjust toc relocs after adjusting symbols.

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.326
diff -u -p -r1.326 elf64-ppc.c
--- bfd/elf64-ppc.c	13 Apr 2010 04:05:29 -0000	1.326
+++ bfd/elf64-ppc.c	25 Jun 2010 03:12:23 -0000
@@ -5566,6 +5566,17 @@ opd_entry_value (asection *opd_sec,
   return val;
 }
 
+/* Return true if symbol is defined in a regular object file.  */
+
+static bfd_boolean
+is_static_defined (struct elf_link_hash_entry *h)
+{
+  return ((h->root.type == bfd_link_hash_defined
+	   || h->root.type == bfd_link_hash_defweak)
+	  && h->root.u.def.section != NULL
+	  && h->root.u.def.section->output_section != NULL);
+}
+
 /* If FDH is a function descriptor symbol, return the associated code
    entry symbol if it is defined.  Return NULL otherwise.  */
 
@@ -6704,10 +6715,7 @@ get_tls_mask (unsigned char **tls_maskp,
     *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
   if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
     return 0;
-  if ((h == NULL
-       || ((h->root.type == bfd_link_hash_defined
-	    || h->root.type == bfd_link_hash_defweak)
-	   && !h->def_dynamic))
+  if ((h == NULL || is_static_defined (h))
       && (next_r == -1 || next_r == -2))
     return 1 - next_r;
   return 1;
@@ -6924,6 +6932,9 @@ ppc64_elf_edit_opd (struct bfd_link_info
       bfd_boolean need_edit, add_aux_fields;
       bfd_size_type cnt_16b = 0;
 
+      if (!is_ppc64_elf (ibfd))
+	continue;
+
       sec = bfd_get_section_by_name (ibfd, ".opd");
       if (sec == NULL || sec->size == 0)
 	continue;
@@ -7375,7 +7386,7 @@ ppc64_elf_tls_setup (struct bfd_link_inf
 		      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
 					      opt_fd->dynstr_index);
 		      if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
-			return FALSE;
+			return NULL;
 		    }
 		  htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd;
 		  tga = &htab->tls_get_addr->elf;
@@ -7840,6 +7851,7 @@ adjust_toc_syms (struct elf_link_hash_en
 {
   struct ppc_link_hash_entry *eh;
   struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
+  unsigned long i;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -7857,16 +7869,22 @@ adjust_toc_syms (struct elf_link_hash_en
 
   if (eh->elf.root.u.def.section == toc_inf->toc)
     {
-      unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3];
-      if (skip != (unsigned long) -1)
-	eh->elf.root.u.def.value -= skip;
+      if (eh->elf.root.u.def.value > toc_inf->toc->rawsize)
+	i = toc_inf->toc->rawsize >> 3;
       else
+	i = eh->elf.root.u.def.value >> 3;
+
+      if (toc_inf->skip[i] == (unsigned long) -1)
 	{
 	  (*_bfd_error_handler)
-	    (_("%s defined in removed toc entry"), eh->elf.root.root.string);
-	  eh->elf.root.u.def.section = &bfd_abs_section;
-	  eh->elf.root.u.def.value = 0;
+	    (_("%s defined on removed toc entry"), eh->elf.root.root.string);
+	  do
+	    ++i;
+	  while (toc_inf->skip[i] == (unsigned long) -1);
+	  eh->elf.root.u.def.value = (bfd_vma) i << 3;
 	}
+
+      eh->elf.root.u.def.value -= toc_inf->skip[i];
       eh->adjust_done = 1;
     }
   else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0)
@@ -7898,6 +7916,9 @@ ppc64_elf_edit_toc (struct bfd_link_info
       unsigned char *used;
       unsigned char *keep, last, some_unused;
 
+      if (!is_ppc64_elf (ibfd))
+	continue;
+
       toc = bfd_get_section_by_name (ibfd, ".toc");
       if (toc == NULL
 	  || toc->size == 0
@@ -7975,7 +7996,7 @@ ppc64_elf_edit_toc (struct bfd_link_info
 
 	      if (skip == NULL)
 		{
-		  skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8);
+		  skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8);
 		  if (skip == NULL)
 		    goto error_ret;
 		}
@@ -8025,7 +8046,8 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	      || (sec->flags & SEC_DEBUGGING) != 0)
 	    continue;
 
-	  relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE);
+	  relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+						info->keep_memory);
 	  if (relstart == NULL)
 	    goto error_ret;
 
@@ -8091,6 +8113,9 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		used[val >> 3] = 1;
 	      }
 	  while (repeat);
+
+	  if (elf_section_data (sec)->relocs != relstart)
+	    free (relstart);
 	}
 
       /* Merge the used and skip arrays.  Assume that TOC
@@ -8143,40 +8168,10 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		  memcpy (src - off, src, 8);
 		}
 	    }
+	  *drop = off;
 	  toc->rawsize = toc->size;
 	  toc->size = src - contents - off;
 
-	  if (toc->reloc_count != 0)
-	    {
-	      Elf_Internal_Rela *wrel;
-	      bfd_size_type sz;
-
-	      /* Read toc relocs.  */
-	      relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
-						    TRUE);
-	      if (relstart == NULL)
-		goto error_ret;
-
-	      /* Remove unused toc relocs, and adjust those we keep.  */
-	      wrel = relstart;
-	      for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
-		if (skip[rel->r_offset >> 3] != (unsigned long) -1)
-		  {
-		    wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
-		    wrel->r_info = rel->r_info;
-		    wrel->r_addend = rel->r_addend;
-		    ++wrel;
-		  }
-		else if (!dec_dynrel_count (rel->r_info, toc, info,
-					    &local_syms, NULL, NULL))
-		  goto error_ret;
-
-	      toc->reloc_count = wrel - relstart;
-	      sz = elf_section_data (toc)->rel_hdr.sh_entsize;
-	      elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
-	      BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
-	    }
-
 	  /* Adjust addends for relocs against the toc section sym.  */
 	  for (sec = ibfd->sections; sec != NULL; sec = sec->next)
 	    {
@@ -8185,7 +8180,7 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		continue;
 
 	      relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
-						    TRUE);
+						    info->keep_memory);
 	      if (relstart == NULL)
 		goto error_ret;
 
@@ -8196,6 +8191,7 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		  asection *sym_sec;
 		  struct elf_link_hash_entry *h;
 		  Elf_Internal_Sym *sym;
+		  bfd_vma val;
 
 		  r_type = ELF64_R_TYPE (rel->r_info);
 		  switch (r_type)
@@ -8221,8 +8217,17 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		  if (sym_sec != toc || h != NULL || sym->st_value != 0)
 		    continue;
 
-		  rel->r_addend -= skip[rel->r_addend >> 3];
+		  val = rel->r_addend;
+
+		  if (val > toc->rawsize)
+		    val = toc->rawsize;
+
+		  rel->r_addend -= skip[val >> 3];
+		  elf_section_data (sec)->relocs = relstart;
 		}
+
+	      if (elf_section_data (sec)->relocs != relstart)
+		free (relstart);
 	    }
 
 	  /* We shouldn't have local or global symbols defined in the TOC,
@@ -8237,22 +8242,30 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		if (sym->st_value != 0
 		    && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
 		  {
-		    if (skip[sym->st_value >> 3] != (unsigned long) -1)
-		      sym->st_value -= skip[sym->st_value >> 3];
+		    unsigned long i;
+
+		    if (sym->st_value > toc->rawsize)
+		      i = toc->rawsize >> 3;
 		    else
+		      i = sym->st_value >> 3;
+
+		    if (skip[sym->st_value >> 3] == (unsigned long) -1)
 		      {
 			(*_bfd_error_handler)
-			  (_("%s defined in removed toc entry"),
-			   bfd_elf_sym_name (ibfd, symtab_hdr, sym,
-					     NULL));
-			sym->st_value = 0;
-			sym->st_shndx = SHN_ABS;
+			  (_("%s defined on removed toc entry"),
+			   bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
+			do
+			  ++i;
+			while (skip[i] == (unsigned long) -1);
+			sym->st_value = (bfd_vma) i << 3;
 		      }
+
+		    sym->st_value -= skip[i];
 		    symtab_hdr->contents = (unsigned char *) local_syms;
 		  }
 	    }
 
-	  /* Finally, adjust any global syms defined in the toc.  */
+	  /* Adjust any global syms defined in this toc input section.  */
 	  if (toc_inf.global_toc_syms)
 	    {
 	      toc_inf.toc = toc;
@@ -8261,6 +8274,37 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	      elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
 				      &toc_inf);
 	    }
+
+	  if (toc->reloc_count != 0)
+	    {
+	      Elf_Internal_Rela *wrel;
+	      bfd_size_type sz;
+
+	      /* Read toc relocs.  */
+	      relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+						    TRUE);
+	      if (relstart == NULL)
+		goto error_ret;
+
+	      /* Remove unused toc relocs, and adjust those we keep.  */
+	      wrel = relstart;
+	      for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+		if (skip[rel->r_offset >> 3] != (unsigned long) -1)
+		  {
+		    wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
+		    wrel->r_info = rel->r_info;
+		    wrel->r_addend = rel->r_addend;
+		    ++wrel;
+		  }
+		else if (!dec_dynrel_count (rel->r_info, toc, info,
+					    &local_syms, NULL, NULL))
+		  goto error_ret;
+
+	      toc->reloc_count = wrel - relstart;
+	      sz = elf_section_data (toc)->rel_hdr.sh_entsize;
+	      elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
+	      BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
+	    }
 	}
 
       if (local_syms != NULL
@@ -9007,12 +9051,8 @@ ppc_type_of_stub (asection *input_sec,
 	 either a defined function descriptor or a defined entry symbol
 	 in a regular object file, then it is pointless trying to make
 	 any other type of stub.  */
-      if (!((fdh->elf.root.type == bfd_link_hash_defined
-	    || fdh->elf.root.type == bfd_link_hash_defweak)
-	    && fdh->elf.root.u.def.section->output_section != NULL)
-	  && !((h->elf.root.type == bfd_link_hash_defined
-		|| h->elf.root.type == bfd_link_hash_defweak)
-	       && h->elf.root.u.def.section->output_section != NULL))
+      if (!is_static_defined (&fdh->elf)
+	  && !is_static_defined (&h->elf))
 	return ppc_stub_none;
     }
   else if (elf_local_got_ents (input_sec->owner) != NULL)

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list