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]

Re: ld segfault on incrementally linked object


On Sat, May 12, 2001 at 12:07:04PM -0700, Geoff Keating wrote:
> > From: amodra@one.net.au
> > Sooo, either the above quoted comment is wrong and we do need to
> > perform section relocations for incremental linking, or dwarf1.c
> > needs to relocate debug info.  I don't particularly like the second
> > option for a number of reasons.
> 
> The second option is the correct one.  If there's a reloc, and we are
> using RELA relocs, the data at the reloc can be anything.

Yeah, but it's a pain.  Here's a first pass that works for the common
case of reporting errors during a final link.  It would be possible to
flesh out _bfd_dwarf_get_relocated_section_contents with various bits
of code stolen from elflink.h in case finfo is not available, but that
could get tricky.  eg. If .debug is not going to be output, and thus
does not have an output_section, then how do you dig up the output bfd?

-- 
Alan Modra

2001-05-15  Alan Modra  <amodra@one.net.au>

	* elflink.h (struct elf_final_link_info): Move from here..
	* elf-bfd.h: .. to here.  Change type of external_syms and symbuf to PTR.
	(struct elf_backend_data): Add link_read_relocs.
	(struct elf_obj_tdata): Add finfo.
	* elflink.h (elf_bfd_final_link): Modify casts on finfo.symbuf and
	finfo.external_syms to suit type change.
	(elf_link_output_sym): Likewise.
	(elf_link_flush_output_syms): Likewise.
	(elf_link_input_bfd): Likewise.  Set elf_tdata finfo.
	* elfxx-target.h (elf_backend_link_read_relocs): Define.
	(struct elf_backend_data elf): Init link_read_relocs.

	* dwarf1.c (parse_line_table): Change type of "size" to bfd_size_type.
	Call _bfd_dwarf_get_relocated_section_contents instead of
	bfd_get_section_contents.
	(_bfd_dwarf1_find_nearest_line): Likewise.
	(_bfd_dwarf_get_relocated_section_contents): New function.
	* dwarf2.c (read_abbrevs): Use _bfd_dwarf_get_relocated_section_contents.
	(decode_line_info): Likewise.
	(_bfd_dwarf2_find_nearest_line): Likewise.
	* libbfd-in.h (_bfd_dwarf_get_relocated_section_contents): Declare.
	* libbfd.h: Regenerate.

	* elf32-ppc.c (ppc_elf_relocate_section): If debug_relocate, don't
	do relocatable or shared link processing and don't report undefined
	symbols.

Index: bfd/dwarf1.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf1.c,v
retrieving revision 1.7
diff -u -p -r1.7 dwarf1.c
--- dwarf1.c	2001/05/11 09:55:02	1.7
+++ dwarf1.c	2001/05/14 14:11:10
@@ -263,7 +263,7 @@ parse_line_table (stash, aUnit)
   if (stash->line_section == 0)
     {
       asection *msec;
-      unsigned long size;
+      bfd_size_type size;
 
       msec = bfd_get_section_by_name (stash->abfd, ".line");
       if (! msec)
@@ -275,7 +275,8 @@ parse_line_table (stash, aUnit)
       if (! stash->line_section)
 	return false;
 
-      if (! bfd_get_section_contents (stash->abfd, msec, stash->line_section, 0, size))
+      if (! _bfd_dwarf_get_relocated_section_contents (stash->abfd, msec,
+						       stash->line_section, size))
 	{
 	  stash->line_section = 0;
 	  return false;
@@ -467,7 +468,7 @@ _bfd_dwarf1_find_nearest_line (abfd, sec
   if (! stash)
     {
       asection *msec;
-      unsigned long size;
+      bfd_size_type size;
 
       stash = elf_tdata (abfd)->dwarf1_find_line_info =
 	(struct dwarf1_debug*) bfd_zalloc (abfd, sizeof (struct dwarf1_debug));
@@ -490,7 +491,8 @@ _bfd_dwarf1_find_nearest_line (abfd, sec
       if (! stash->debug_section)
 	return false;
 
-      if (! bfd_get_section_contents (abfd, msec, stash->debug_section, 0, size))
+      if (! _bfd_dwarf_get_relocated_section_contents (abfd, msec,
+						       stash->debug_section, size))
 	{
 	  stash->debug_section = 0;
 	  return false;
@@ -561,6 +563,56 @@ _bfd_dwarf1_find_nearest_line (abfd, sec
     }
 
   return false;
+}
+
+boolean
+_bfd_dwarf_get_relocated_section_contents (abfd, sec, contents, size)
+     bfd *abfd;
+     asection *sec;
+     bfd_byte *contents;
+     bfd_size_type size;
+{
+  struct elf_final_link_info *finfo;
+  bfd *output_bfd;
+  struct elf_backend_data *bed;
+  Elf_Internal_Rela *internal_relocs;
+
+  if (! bfd_get_section_contents (abfd, sec, contents, 0, size))
+    return false;
+
+  if ((sec->flags & SEC_RELOC) == 0)
+    return true;
+
+  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return true;
+
+  finfo = elf_tdata (abfd)->finfo;
+  if (!finfo)
+    return true;
+
+  /* Protect against recursive calls.  If this happens we'll probably
+     bomb elsewhere anyway.  */
+  if (finfo->info->debug_relocate)
+    return true;
+  finfo->info->debug_relocate = 1;
+
+  output_bfd = finfo->output_bfd;
+  bed = get_elf_backend_data (output_bfd);
+  internal_relocs = (*bed->link_read_relocs) (abfd, sec, NULL, NULL, false);
+  if (internal_relocs != NULL)
+    {
+      (*bed->elf_backend_relocate_section) (output_bfd, finfo->info,
+					    abfd, sec, contents,
+					    internal_relocs,
+					    finfo->internal_syms,
+					    finfo->sections);
+      /* Only free relocs if not stashed for later use.  */
+      if (elf_section_data (sec)->relocs != internal_relocs)
+	free (internal_relocs);
+    }
+
+  finfo->info->debug_relocate = 0;
+  return true;
 }
 
 /* EOF */
Index: bfd/dwarf2.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.19
diff -u -p -r1.19 dwarf2.c
--- dwarf2.c	2001/03/08 21:03:58	1.19
+++ dwarf2.c	2001/05/14 14:11:15
@@ -431,9 +431,9 @@ read_abbrevs (abfd, offset, stash)
       if (! stash->dwarf_abbrev_buffer)
 	  return 0;
 
-      if (! bfd_get_section_contents (abfd, msec,
-				      stash->dwarf_abbrev_buffer, 0,
-				      stash->dwarf_abbrev_size))
+      if (! _bfd_dwarf_get_relocated_section_contents (abfd, msec,
+						       stash->dwarf_abbrev_buffer,
+						       stash->dwarf_abbrev_size))
 	return 0;
     }
 
@@ -790,13 +790,10 @@ decode_line_info (unit, stash)
       if (! stash->dwarf_line_buffer)
 	return 0;
 
-      if (! bfd_get_section_contents (abfd, msec,
-				      stash->dwarf_line_buffer, 0,
-				      stash->dwarf_line_size))
+      if (! _bfd_dwarf_get_relocated_section_contents (abfd, msec,
+						       stash->dwarf_line_buffer,
+						       stash->dwarf_line_size))
 	return 0;
-
-      /* FIXME: We ought to apply the relocs against this section before
-	 we process it...  */
     }
 
   /* Since we are using un-relocated data, it is possible to get a bad value
@@ -1578,7 +1575,9 @@ _bfd_dwarf2_find_nearest_line (abfd, sec
 
 	  start = stash->info_ptr_end - stash->info_ptr;
 
-	  if (! bfd_get_section_contents (abfd, msec, stash->info_ptr + start, 0, size))
+	  if (! _bfd_dwarf_get_relocated_section_contents (abfd, msec,
+							   stash->info_ptr + start,
+							   size))
 	    continue;
 
 	  stash->info_ptr_end = stash->info_ptr + start + size;
@@ -1586,21 +1585,6 @@ _bfd_dwarf2_find_nearest_line (abfd, sec
 
       BFD_ASSERT (stash->info_ptr_end = stash->info_ptr + total_size);
     }
-
-  /* FIXME: There is a problem with the contents of the
-     .debug_info section.  The 'low' and 'high' addresses of the
-     comp_units are computed by relocs against symbols in the
-     .text segment.  We need these addresses in order to determine
-     the nearest line number, and so we have to resolve the
-     relocs.  There is a similar problem when the .debug_line
-     section is processed as well (e.g., there may be relocs
-     against the operand of the DW_LNE_set_address operator).
-
-     Unfortunately getting hold of the reloc information is hard...
-
-     For now, this means that disassembling object files (as
-     opposed to fully executables) does not always work as well as
-     we would like.  */
 
   /* A null info_ptr indicates that there is no dwarf2 info
      (or that an error occured while setting up the stash).  */
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.33
diff -u -p -r1.33 elf-bfd.h
--- elf-bfd.h	2001/05/11 12:23:47	1.33
+++ elf-bfd.h	2001/05/14 14:11:22
@@ -613,6 +613,10 @@ struct elf_backend_data
   void (*elf_backend_hide_symbol)
     PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 
+  /* Read and swap in the relocs for a section.  */
+  Elf_Internal_Rela * (*link_read_relocs)
+    PARAMS ((bfd *, asection *, PTR, Elf_Internal_Rela *, boolean));
+
   /* The swapping table to use when dealing with ECOFF information.
      Used for the MIPS ELF .mdebug section.  */
   const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap;
@@ -773,6 +777,48 @@ typedef struct elf_linker_section_pointe
   boolean written_address_p;			/* whether address was written yet */
 } elf_linker_section_pointers_t;
 
+/* A structure we use to avoid passing large numbers of arguments.  */
+
+struct elf_final_link_info
+{
+  /* General link information.  */
+  struct bfd_link_info *info;
+  /* Output BFD.  */
+  bfd *output_bfd;
+  /* Symbol string table.  */
+  struct bfd_strtab_hash *symstrtab;
+  /* .dynsym section.  */
+  asection *dynsym_sec;
+  /* .hash section.  */
+  asection *hash_sec;
+  /* symbol version section (.gnu.version).  */
+  asection *symver_sec;
+  /* Buffer large enough to hold contents of any section.  */
+  bfd_byte *contents;
+  /* Buffer large enough to hold external relocs of any section.  */
+  PTR external_relocs;
+  /* Buffer large enough to hold internal relocs of any section.  */
+  Elf_Internal_Rela *internal_relocs;
+  /* Buffer large enough to hold external local symbols of any input
+     BFD.  */
+  PTR external_syms;
+  /* Buffer large enough to hold internal local symbols of any input
+     BFD.  */
+  Elf_Internal_Sym *internal_syms;
+  /* Array large enough to hold a symbol index for each local symbol
+     of any input BFD.  */
+  long *indices;
+  /* Array large enough to hold a section pointer for each local
+     symbol of any input BFD.  */
+  asection **sections;
+  /* Buffer to hold swapped out symbols.  */
+  PTR symbuf;
+  /* Number of swapped out symbols in buffer.  */
+  size_t symbuf_count;
+  /* Number of symbols which fit in symbuf.  */
+  size_t symbuf_size;
+};
+
 /* Some private data is stashed away for future use using the tdata pointer
    in the bfd structure.  */
 
@@ -867,6 +913,9 @@ struct elf_obj_tdata
 
   /* Records the result of `get_program_header_size'.  */
   bfd_size_type program_header_size;
+
+  /* A place to stash final link info.  Used by dwarf1, dwarf2.  */
+  struct elf_final_link_info *finfo;
 
   /* Used by find_nearest_line entry point.  */
   PTR line_info;
Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.22
diff -u -p -r1.22 elf32-ppc.c
--- elf32-ppc.c	2001/03/08 21:04:00	1.22
+++ elf32-ppc.c	2001/05/14 14:11:35
@@ -2969,9 +2969,9 @@ ppc_elf_relocate_section (output_bfd, in
       howto = ppc_elf_howto_table[(int) r_type];
       r_symndx = ELF32_R_SYM (rel->r_info);
 
-      if (info->relocateable)
+      if (info->relocateable && !info->debug_relocate)
 	{
-	  /* This is a relocateable link.  We don't have to change
+	  /* This is a relocatable link.  We don't have to change
 	     anything, unless the reloc is against a section symbol,
 	     in which case we have to adjust according to where the
 	     section symbol winds up in the output section.  */
@@ -3107,14 +3107,12 @@ ppc_elf_relocate_section (output_bfd, in
 	    relocation = 0;
 	  else
 	    {
-	      if (! (*info->callbacks->undefined_symbol) (info,
-							 h->root.root.string,
-							 input_bfd,
-							 input_section,
-							 rel->r_offset,
-							 (!info->shared
-							  || info->no_undefined
-							  || ELF_ST_VISIBILITY (h->other))))
+	      if (!info->debug_relocate
+		  && !((*info->callbacks->undefined_symbol)
+		       (info, h->root.root.string, input_bfd, input_section,
+			rel->r_offset, (!info->shared
+					|| info->no_undefined
+					|| ELF_ST_VISIBILITY (h->other)))))
 		return false;
 	      relocation = 0;
 	    }
@@ -3176,7 +3174,7 @@ ppc_elf_relocate_section (output_bfd, in
 	case (int) R_PPC_ADDR14:
 	case (int) R_PPC_UADDR32:
 	case (int) R_PPC_UADDR16:
-	  if (info->shared)
+	  if (info->shared && !info->debug_relocate)
 	    {
 	      Elf_Internal_Rela outrel;
 	      boolean skip;
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.88
diff -u -p -r1.88 elflink.h
--- elflink.h	2001/05/09 22:34:30	1.88
+++ elflink.h	2001/05/14 14:12:15
@@ -4033,48 +4033,6 @@ elf_link_assign_sym_version (h, data)
 
 /* Final phase of ELF linker.  */
 
-/* A structure we use to avoid passing large numbers of arguments.  */
-
-struct elf_final_link_info
-{
-  /* General link information.  */
-  struct bfd_link_info *info;
-  /* Output BFD.  */
-  bfd *output_bfd;
-  /* Symbol string table.  */
-  struct bfd_strtab_hash *symstrtab;
-  /* .dynsym section.  */
-  asection *dynsym_sec;
-  /* .hash section.  */
-  asection *hash_sec;
-  /* symbol version section (.gnu.version).  */
-  asection *symver_sec;
-  /* Buffer large enough to hold contents of any section.  */
-  bfd_byte *contents;
-  /* Buffer large enough to hold external relocs of any section.  */
-  PTR external_relocs;
-  /* Buffer large enough to hold internal relocs of any section.  */
-  Elf_Internal_Rela *internal_relocs;
-  /* Buffer large enough to hold external local symbols of any input
-     BFD.  */
-  Elf_External_Sym *external_syms;
-  /* Buffer large enough to hold internal local symbols of any input
-     BFD.  */
-  Elf_Internal_Sym *internal_syms;
-  /* Array large enough to hold a symbol index for each local symbol
-     of any input BFD.  */
-  long *indices;
-  /* Array large enough to hold a section pointer for each local
-     symbol of any input BFD.  */
-  asection **sections;
-  /* Buffer to hold swapped out symbols.  */
-  Elf_External_Sym *symbuf;
-  /* Number of swapped out symbols in buffer.  */
-  size_t symbuf_count;
-  /* Number of symbols which fit in symbuf.  */
-  size_t symbuf_size;
-};
-
 static boolean elf_link_output_sym
   PARAMS ((struct elf_final_link_info *, const char *,
 	   Elf_Internal_Sym *, asection *));
@@ -4477,8 +4435,7 @@ elf_bfd_final_link (abfd, info)
     finfo.symbuf_size = 20;
   else
     finfo.symbuf_size = max_sym_count;
-  finfo.symbuf = ((Elf_External_Sym *)
-		  bfd_malloc (finfo.symbuf_size * sizeof (Elf_External_Sym)));
+  finfo.symbuf = (PTR) bfd_malloc (finfo.symbuf_size * sizeof (Elf_External_Sym));
   if (finfo.symbuf == NULL)
     goto error_return;
 
@@ -4546,9 +4503,8 @@ elf_bfd_final_link (abfd, info)
 			   bfd_malloc (max_internal_reloc_count
 				       * sizeof (Elf_Internal_Rela)
 				       * bed->s->int_rels_per_ext_rel));
-  finfo.external_syms = ((Elf_External_Sym *)
-			 bfd_malloc (max_sym_count
-				     * sizeof (Elf_External_Sym)));
+  finfo.external_syms = ((PTR) bfd_malloc (max_sym_count
+					   * sizeof (Elf_External_Sym)));
   finfo.internal_syms = ((Elf_Internal_Sym *)
 			 bfd_malloc (max_sym_count
 				     * sizeof (Elf_Internal_Sym)));
@@ -5049,7 +5005,8 @@ elf_link_output_sym (finfo, name, elfsym
     }
 
   elf_swap_symbol_out (finfo->output_bfd, elfsym,
-		       (PTR) (finfo->symbuf + finfo->symbuf_count));
+		       (PTR) ((Elf_External_Sym *) finfo->symbuf
+			      + finfo->symbuf_count));
   ++finfo->symbuf_count;
 
   ++ bfd_get_symcount (finfo->output_bfd);
@@ -5071,7 +5028,7 @@ elf_link_flush_output_syms (finfo)
 
       if (bfd_seek (finfo->output_bfd, symtab->sh_offset + symtab->sh_size,
 		    SEEK_SET) != 0
-	  || (bfd_write ((PTR) finfo->symbuf, finfo->symbuf_count,
+	  || (bfd_write (finfo->symbuf, finfo->symbuf_count,
 			 sizeof (Elf_External_Sym), finfo->output_bfd)
 	      != finfo->symbuf_count * sizeof (Elf_External_Sym)))
 	return false;
@@ -5536,7 +5493,7 @@ elf_link_input_bfd (finfo, input_bfd)
     external_syms = NULL;
   else
     {
-      external_syms = finfo->external_syms;
+      external_syms = (Elf_External_Sym *) finfo->external_syms;
       if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
 	  || (bfd_read (external_syms, sizeof (Elf_External_Sym),
 			locsymcount, input_bfd)
@@ -5718,6 +5675,8 @@ elf_link_input_bfd (finfo, input_bfd)
       if (! elf_link_output_sym (finfo, name, &osym, isec))
 	return false;
     }
+
+  elf_tdata (input_bfd)->finfo = finfo;
 
   /* Relocate the contents of each section.  */
   for (o = input_bfd->sections; o != NULL; o = o->next)
Index: bfd/elfxx-target.h
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-target.h,v
retrieving revision 1.20
diff -u -p -r1.20 elfxx-target.h
--- elfxx-target.h	2001/05/11 12:23:47	1.20
+++ elfxx-target.h	2001/05/14 14:12:17
@@ -321,6 +321,9 @@ Foundation, Inc., 59 Temple Place - Suit
 #ifndef elf_backend_hide_symbol
 #define elf_backend_hide_symbol		_bfd_elf_link_hash_hide_symbol
 #endif
+#ifndef elf_backend_link_read_relocs
+#define elf_backend_link_read_relocs	_bfd_elfNN_link_read_relocs
+#endif
 
 /* Previously, backends could only use SHT_REL or SHT_RELA relocation
    sections, but not both.  They defined USE_REL to indicate SHT_REL
@@ -402,6 +405,7 @@ static CONST struct elf_backend_data elf
   elf_backend_output_arch_syms,
   elf_backend_copy_indirect_symbol,
   elf_backend_hide_symbol,
+  elf_backend_link_read_relocs,
   elf_backend_ecoff_debug_swap,
   ELF_MACHINE_ALT1,
   ELF_MACHINE_ALT2,
Index: bfd/libbfd-in.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd-in.h,v
retrieving revision 1.14
diff -u -p -r1.14 libbfd-in.h
--- libbfd-in.h	2001/05/11 12:23:47	1.14
+++ libbfd-in.h	2001/05/14 14:12:18
@@ -373,6 +373,9 @@ extern boolean _bfd_dwarf2_find_nearest_
 	   const char **, unsigned int *, unsigned int,
 	   PTR *));
 
+extern boolean _bfd_dwarf_get_relocated_section_contents
+  PARAMS ((bfd *, asection *, bfd_byte *, bfd_size_type));
+
 /* A routine to create entries for a bfd_link_hash_table.  */
 extern struct bfd_hash_entry *_bfd_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *entry,

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