This is the mail archive of the binutils@sourceware.cygnus.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]

PATCH for ld -r and MIPS N32 ABI



This patch makes ld -r work on the N32 ABI.  I think that most of the
patch is the obvious handling of rel_hdr/rel_hdr2, which is the issue
here.  However, this bit is ugly:

+  /* We are overestimating the size required for the relocation
+     sections, in the case that we are using both REL and RELA
+     relocations for a single section.  In that case, RELOC_COUNT will
+     be the total number of relocations required, and we allocate
+     space for that many REL relocations as well as that many RELA
+     relocations.  This approximation is wasteful of disk space.
+     However, until we keep track of how many of each kind of
+     relocation is required, it's difficult to calculate the right
+     value.  */
+  rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;

I don't see a nice way around this waste, for the moment.  I think
that everything else in the patch will still be correct, even once we
fix the calculation on this line, so I think the patch is a definite
improvement. 

OK to check in?

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-07-01  Mark Mitchell  <mark@codesourcery.com>

	* elf-bfd.h (bfd_elf_section_data): Add rel_count and rel_count2
	fields.
	(_bfd_elf_init_reloc_shdr): New function.
	* elf.c (_bfd_elf_new_section_hook): Use bfd_zalloc, rather than
	bfd_alloc followed by memset.
	(_bfd_elf_init_reloc_shdr): New function, split out from ...
	(elf_fake_sections): Here.
	(assign_section_numbers): Assign section numbers for the second
	relocation section, if required.
	* elflink.h (elf_link_output_relocs): New function.
	(elf_link_size_reloc_section): Likewise.
	(elf_bfd_final_link): Use elf_link_size_reloc_section.
	(elf_link_input_bfd): Use elf_link_output_relocs.
	
	* elf32-mips.c (_bfd_mips_elf_fake_sections): Use
	_bfd_elf_init_reloc_shdr to initialize rel_hdr2.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elf-bfd.h,v
retrieving revision 1.6
diff -u -p -r1.6 elf-bfd.h
--- elf-bfd.h	1999/06/22 20:58:43	1.6
+++ elf-bfd.h	1999/07/01 23:53:49
@@ -574,12 +574,19 @@ struct bfd_elf_section_data
   /* If there is a second reloc section associated with this section,
      as can happen on Irix 6, this field points to the header.  */
   Elf_Internal_Shdr *rel_hdr2;
+  /* The number of relocations currently assigned to REL_HDR.  */
+  unsigned int rel_count;
+  /* The number of relocations currently assigned to REL_HDR2.  */
+  unsigned int rel_count2;
   /* The ELF section number of this section.  Only used for an output
      file.  */
   int this_idx;
-  /* The ELF section number of the reloc section associated with this
-     section, if any.  Only used for an output file.  */
+  /* The ELF section number of the reloc section indicated by
+     REL_HDR if any.  Only used for an output file.  */
   int rel_idx;
+  /* The ELF section number of the reloc section indicated by
+     REL_HDR2 if any.  Only used for an output file.  */
+  int rel_idx2;
   /* Used by the backend linker to store the symbol hash table entries
      associated with relocs against global symbols.  */
   struct elf_link_hash_entry **rel_hashes;
@@ -897,6 +904,8 @@ extern boolean _bfd_elf_find_nearest_lin
 #define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
 extern int _bfd_elf_sizeof_headers PARAMS ((bfd *, boolean));
 extern boolean _bfd_elf_new_section_hook PARAMS ((bfd *, asection *));
+extern boolean _bfd_elf_init_reloc_shdr 
+  PARAMS ((bfd *, Elf_Internal_Shdr *, asection *, boolean));
 
 /* If the target doesn't have reloc handling written yet:  */
 extern void _bfd_elf_no_info_to_howto PARAMS ((bfd *, arelent *,
Index: bfd/elf.c
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elf.c,v
retrieving revision 1.7
diff -u -p -r1.7 elf.c
--- elf.c	1999/06/22 21:25:49	1.7
+++ elf.c	1999/07/01 23:53:51
@@ -1337,11 +1337,10 @@ _bfd_elf_new_section_hook (abfd, sec)
 {
   struct bfd_elf_section_data *sdata;
 
-  sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata));
+  sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, sizeof (*sdata));
   if (!sdata)
     return false;
   sec->used_by_bfd = (PTR) sdata;
-  memset (sdata, 0, sizeof (*sdata));
 
   /* Indicate whether or not this section should use RELA relocations.  */
   sdata->use_rela_p 
@@ -1441,6 +1440,43 @@ bfd_section_from_phdr (abfd, hdr, index)
   return true;
 }
 
+/* Initialize REL_HDR, the section-header for new section, containing
+   relocations against ASECT.  If USE_RELA_P is true, we use RELA
+   relocations; otherwise, we use REL relocations.  */
+
+boolean
+_bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     asection *asect;
+     boolean use_rela_p;
+{
+  char *name;
+  struct elf_backend_data *bed;
+
+  bed = get_elf_backend_data (abfd);
+  name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
+  if (name == NULL)
+    return false;
+  sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
+  rel_hdr->sh_name =
+    (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
+				       true, false);
+  if (rel_hdr->sh_name == (unsigned int) -1)
+    return false;
+  rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
+  rel_hdr->sh_entsize = (use_rela_p
+			 ? bed->s->sizeof_rela
+			 : bed->s->sizeof_rel);
+  rel_hdr->sh_addralign = bed->s->file_align;
+  rel_hdr->sh_flags = 0;
+  rel_hdr->sh_addr = 0;
+  rel_hdr->sh_size = 0;
+  rel_hdr->sh_offset = 0;
+
+  return true;
+}
+
 /* Set up an ELF internal section header for a section.  */
 
 /*ARGSUSED*/
@@ -1580,39 +1616,15 @@ elf_fake_sections (abfd, asect, failedpt
     (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
 
   /* If the section has relocs, set up a section header for the
-     SHT_REL[A] section.  */
-  if ((asect->flags & SEC_RELOC) != 0)
-    {
-      Elf_Internal_Shdr *rela_hdr;
-      int use_rela_p = elf_section_data (asect)->use_rela_p;
-      char *name;
-
-      rela_hdr = &elf_section_data (asect)->rel_hdr;
-      name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
-      if (name == NULL)
-	{
-	  *failedptr = true;
-	  return;
-	}
-      sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
-      rela_hdr->sh_name =
-	(unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
-					   true, false);
-      if (rela_hdr->sh_name == (unsigned int) -1)
-	{
-	  *failedptr = true;
-	  return;
-	}
-      rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
-      rela_hdr->sh_entsize = (use_rela_p
-			      ? bed->s->sizeof_rela
-			      : bed->s->sizeof_rel);
-      rela_hdr->sh_addralign = bed->s->file_align;
-      rela_hdr->sh_flags = 0;
-      rela_hdr->sh_addr = 0;
-      rela_hdr->sh_size = 0;
-      rela_hdr->sh_offset = 0;
-    }
+     SHT_REL[A] section.  If two relocation sections are required for
+     this section, it is up to the processor-specific back-end to
+     create the other.  */ 
+  if ((asect->flags & SEC_RELOC) != 0
+      && !_bfd_elf_init_reloc_shdr (abfd, 
+				    &elf_section_data (asect)->rel_hdr,
+				    asect, 
+				    elf_section_data (asect)->use_rela_p))
+    *failedptr = true;
 }
 
 /* Assign all ELF section numbers.  The dummy first section is handled here
@@ -1640,6 +1652,11 @@ assign_section_numbers (abfd)
 	d->rel_idx = 0;
       else
 	d->rel_idx = section_number++;
+
+      if (d->rel_hdr2)
+	d->rel_idx2 = section_number++;
+      else
+	d->rel_idx2 = 0;
     }
 
   t->shstrtab_section = section_number++;
@@ -1688,6 +1705,8 @@ assign_section_numbers (abfd)
       i_shdrp[d->this_idx] = &d->this_hdr;
       if (d->rel_idx != 0)
 	i_shdrp[d->rel_idx] = &d->rel_hdr;
+      if (d->rel_idx2 != 0)
+	i_shdrp[d->rel_idx2] = d->rel_hdr2;
 
       /* Fill in the sh_link and sh_info fields while we're at it.  */
 
@@ -1698,6 +1717,11 @@ assign_section_numbers (abfd)
 	{
 	  d->rel_hdr.sh_link = t->symtab_section;
 	  d->rel_hdr.sh_info = d->this_idx;
+	}
+      if (d->rel_idx2 != 0)
+	{
+	  d->rel_hdr2->sh_link = t->symtab_section;
+	  d->rel_hdr2->sh_info = d->this_idx;
 	}
 
       switch (d->this_hdr.sh_type)
Index: bfd/elf32-mips.c
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elf32-mips.c,v
retrieving revision 1.11
diff -u -p -r1.11 elf32-mips.c
--- elf32-mips.c	1999/06/30 20:13:43	1.11
+++ elf32-mips.c	1999/07/01 23:53:55
@@ -2788,6 +2788,23 @@ _bfd_mips_elf_fake_sections (abfd, hdr, 
       hdr->sh_entsize = 8;
     }
 
+  /* The generic elf_fake_sections will set up REL_HDR using the
+     default kind of relocations.  But, we may actually need both
+     kinds of relocations, so we set up the second header here.  */
+  if ((sec->flags & SEC_RELOC) != 0)
+    {
+      struct bfd_elf_section_data *esd;
+
+      esd = elf_section_data (sec);
+      BFD_ASSERT (esd->rel_hdr2 == NULL);
+      esd->rel_hdr2 
+	= (Elf_Internal_Shdr *) bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr));
+      if (!esd->rel_hdr2)
+	return false;
+      _bfd_elf_init_reloc_shdr (abfd, esd->rel_hdr2, sec,
+				!elf_section_data (sec)->use_rela_p);
+    }
+
   return true;
 }
 
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elflink.h,v
retrieving revision 1.8
diff -u -p -r1.8 elflink.h
--- elflink.h	1999/06/26 09:00:19	1.8
+++ elflink.h	1999/07/01 23:53:59
@@ -56,6 +56,10 @@ static boolean elf_link_read_relocs_from
   PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
 static void elf_link_remove_section_and_adjust_dynindices 
   PARAMS ((struct bfd_link_info *, asection *));
+static void elf_link_output_relocs
+  PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
+static boolean elf_link_size_reloc_section
+  PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -2063,12 +2067,15 @@ elf_link_read_relocs_from_section (abfd,
   return true;
 }
 
-/* Read and swap the relocs for a section.  They may have been cached.
-   If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL,
-   they are used as buffers to read into.  They are known to be large
-   enough.  If the INTERNAL_RELOCS relocs argument is NULL, the return
-   value is allocated using either malloc or bfd_alloc, according to
-   the KEEP_MEMORY argument.  */
+/* Read and swap the relocs for a section O.  They may have been
+   cached.  If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are
+   not NULL, they are used as buffers to read into.  They are known to
+   be large enough.  If the INTERNAL_RELOCS relocs argument is NULL,
+   the return value is allocated using either malloc or bfd_alloc,
+   according to the KEEP_MEMORY argument.  If O has two relocation
+   sections (both REL and RELA relocations), then the REL_HDR
+   relocations will appear first in INTERNAL_RELOCS, followed by the
+   REL_HDR2 relocations.  */
 
 Elf_Internal_Rela *
 NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
@@ -3669,6 +3676,48 @@ struct elf_outext_info
   struct elf_final_link_info *finfo;
 };
 
+/* Compute the size of, and allocate space for, REL_HDR which is the
+   section header for a section containing relocations for O.  */
+
+static boolean
+elf_link_size_reloc_section (abfd, rel_hdr, o)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     asection *o;
+{
+  register struct elf_link_hash_entry **p, **pend;
+
+  /* We are overestimating the size required for the relocation
+     sections, in the case that we are using both REL and RELA
+     relocations for a single section.  In that case, RELOC_COUNT will
+     be the total number of relocations required, and we allocate
+     space for that many REL relocations as well as that many RELA
+     relocations.  This approximation is wasteful of disk space.
+     However, until we keep track of how many of each kind of
+     relocation is required, it's difficult to calculate the right
+     value.  */
+  rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
+
+  /* The contents field must last into write_object_contents, so we
+     allocate it with bfd_alloc rather than malloc.  */
+  rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
+  if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
+    return false;
+
+  p = ((struct elf_link_hash_entry **)
+       bfd_malloc (o->reloc_count
+		   * sizeof (struct elf_link_hash_entry *)));
+  if (p == NULL && o->reloc_count != 0)
+    return false;
+
+  elf_section_data (o)->rel_hashes = p;
+  pend = p + o->reloc_count;
+  for (; p < pend; p++)
+    *p = NULL;
+
+  return true;
+}
+
 /* Do the final step of an ELF link.  */
 
 boolean
@@ -3830,32 +3879,16 @@ elf_bfd_final_link (abfd, info)
     {
       if ((o->flags & SEC_RELOC) != 0)
 	{
-	  Elf_Internal_Shdr *rel_hdr;
-	  register struct elf_link_hash_entry **p, **pend;
-
-	  rel_hdr = &elf_section_data (o)->rel_hdr;
-
-	  rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
-
-	  /* The contents field must last into write_object_contents,
-	     so we allocate it with bfd_alloc rather than malloc.  */
-	  rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
-	  if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
+	  if (!elf_link_size_reloc_section (abfd,
+					    &elf_section_data (o)->rel_hdr,
+					    o))
 	    goto error_return;
 
-	  p = ((struct elf_link_hash_entry **)
-	       bfd_malloc (o->reloc_count
-			   * sizeof (struct elf_link_hash_entry *)));
-	  if (p == NULL && o->reloc_count != 0)
+	  if (elf_section_data (o)->rel_hdr2
+	      && !elf_link_size_reloc_section (abfd,
+					       elf_section_data (o)->rel_hdr2,
+					       o))
 	    goto error_return;
-	  elf_section_data (o)->rel_hashes = p;
-	  pend = p + o->reloc_count;
-	  for (; p < pend; p++)
-	    *p = NULL;
-
-	  /* Use the reloc_count field as an index when outputting the
-	     relocs.  */
-	  o->reloc_count = 0;
 	}
     }
 
@@ -4717,6 +4750,76 @@ elf_link_output_extsym (h, data)
   return true;
 }
 
+/* Copy the relocations indicated by the INTERNAL_RELOCS (which
+   originated from the section given by INPUT_REL_HDR) to the
+   OUTPUT_BFD.  */
+
+static void
+elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, 
+			internal_relocs)
+     bfd *output_bfd;
+     asection *input_section;
+     Elf_Internal_Shdr *input_rel_hdr;
+     Elf_Internal_Rela *internal_relocs;
+{
+  Elf_Internal_Rela *irela;
+  Elf_Internal_Rela *irelaend;
+  Elf_Internal_Shdr *output_rel_hdr;
+  asection *output_section;
+  unsigned int *rel_countp;
+
+  output_section = input_section->output_section;
+  output_rel_hdr = NULL;
+
+  if (elf_section_data (output_section)->rel_hdr.sh_entsize 
+      == input_rel_hdr->sh_entsize)
+    {
+      output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
+      rel_countp = &elf_section_data (output_section)->rel_count;
+    }
+  else if (elf_section_data (output_section)->rel_hdr2
+	   && (elf_section_data (output_section)->rel_hdr2->sh_entsize
+	       == input_rel_hdr->sh_entsize))
+    {
+      output_rel_hdr = elf_section_data (output_section)->rel_hdr2;
+      rel_countp = &elf_section_data (output_section)->rel_count2;
+    }
+
+  BFD_ASSERT (output_rel_hdr != NULL);
+  
+  irela = internal_relocs;
+  irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+  if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+    {
+      Elf_External_Rel *erel;
+
+      erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp);
+      for (; irela < irelaend; irela++, erel++)
+	{
+	  Elf_Internal_Rel irel;
+
+	  irel.r_offset = irela->r_offset;
+	  irel.r_info = irela->r_info;
+	  BFD_ASSERT (irela->r_addend == 0);
+	  elf_swap_reloc_out (output_bfd, &irel, erel);
+	}
+    }
+  else
+    {
+      Elf_External_Rela *erela;
+
+      BFD_ASSERT (input_rel_hdr->sh_entsize
+		  == sizeof (Elf_External_Rela));
+      erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
+      for (; irela < irelaend; irela++, erela++)
+	elf_swap_reloca_out (output_bfd, irela, erela);
+    }
+
+  /* Bump the counter, so that we know where to add the next set of
+     relocations.  */
+  *rel_countp += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.
    This is so that we only have to read the local symbols once, and
@@ -4978,7 +5081,6 @@ elf_link_input_bfd (finfo, input_bfd)
 	      Elf_Internal_Rela *irelaend;
 	      struct elf_link_hash_entry **rel_hash;
 	      Elf_Internal_Shdr *input_rel_hdr;
-	      Elf_Internal_Shdr *output_rel_hdr;
 
 	      /* Adjust the reloc addresses and symbol indices.  */
 
@@ -5109,40 +5211,18 @@ elf_link_input_bfd (finfo, input_bfd)
 
 	      /* Swap out the relocs.  */
 	      input_rel_hdr = &elf_section_data (o)->rel_hdr;
-	      output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr;
-	      BFD_ASSERT (output_rel_hdr->sh_entsize
-			  == input_rel_hdr->sh_entsize);
-	      irela = internal_relocs;
-	      irelaend = irela + o->reloc_count;
-	      if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
-		{
-		  Elf_External_Rel *erel;
-
-		  erel = ((Elf_External_Rel *) output_rel_hdr->contents
-			  + o->output_section->reloc_count);
-		  for (; irela < irelaend; irela++, erel++)
-		    {
-		      Elf_Internal_Rel irel;
-
-		      irel.r_offset = irela->r_offset;
-		      irel.r_info = irela->r_info;
-		      BFD_ASSERT (irela->r_addend == 0);
-		      elf_swap_reloc_out (output_bfd, &irel, erel);
-		    }
-		}
-	      else
+	      elf_link_output_relocs (output_bfd, o, 
+				      input_rel_hdr,
+				      internal_relocs);
+	      input_rel_hdr = elf_section_data (o)->rel_hdr2;
+	      if (input_rel_hdr)
 		{
-		  Elf_External_Rela *erela;
-
-		  BFD_ASSERT (input_rel_hdr->sh_entsize
-			      == sizeof (Elf_External_Rela));
-		  erela = ((Elf_External_Rela *) output_rel_hdr->contents
-			   + o->output_section->reloc_count);
-		  for (; irela < irelaend; irela++, erela++)
-		    elf_swap_reloca_out (output_bfd, irela, erela);
+		  internal_relocs 
+		    += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+		  elf_link_output_relocs (output_bfd, o, 
+					  input_rel_hdr,
+					  internal_relocs);
 		}
-
-	      o->output_section->reloc_count += o->reloc_count;
 	    }
 	}
 

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