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]

Re: PATCH for 64-bit MIPS ELF relocations



   The 64-bit MIPS ELF ABI does not use the standard 64-bit ELF
   reocations.  Instead, it uses the special structure given by
   Elf64_External_Rel[a].  These structures allow the encoding of up to
   three relocations per physical relocation.

OK, let's try this a different way.  This patch handles this situation
in a type-safe manner.  If you look closely at this patch, you'll see
a new field (hash_entry_size) in elf_size_info not used for anything
just yet.  The next patch, immediately following this, uses this
field.  (I just didn't take the time to generate two separate patches
for the one or two hunks, both touching elf_size_info).  If, however,
you approve this patch, and not the other, then I will remove the
extraneous hash_entry_size bits before check-in.

How about this version?

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

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

	* elf-bfd.h (elf_size_info): Add hash_entry_size,
	int_rels_per_ext_rel, swap_dyn_out, swap_reloc_in, swap_reloc_out,
	wap_reloca_in, and swap_reloca_out. 
	* elflink.h (elf_link_read_relocs_from_section): Adjust to handle
	multiple internal relocations per external relocation.
	(link_read_relocs): Likewise.
	(elf_bfd_final_link): Likewise.
	(elf_link_input_bfd): Likewise.
	(elf_gc_mark): Likewise.
	(elf_gc_smash_unused_vtentry_relocs): Likewise.
	* elfcode.h (elf_swap_dyn_out): Adjust type to match
	elf_swap_dyn_in.
	(size_info): Add entries for new fields.
	* elf64-mips.c (mips_elf64_swap_reloc_out): Enable.
	(mips_elf64_be_swap_reloc_in): New function.
	(mips_elf64_be_swap_reloc_out): Likewise.
	(mips_elf64_be_swap_reloca_in): Likewise.
	(mips_elf64_be_swap_reloca_out): Likewise.
	(mips_elf64_size_info): Add entries for new fields.
	
Index: elf-bfd.h
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elf-bfd.h,v
retrieving revision 1.7
diff -u -p -r1.7 elf-bfd.h
--- elf-bfd.h	1999/07/01 23:20:04	1.7
+++ elf-bfd.h	1999/07/07 18:16:41
@@ -236,6 +236,13 @@ struct elf_size_info {
   unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr;
   unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note;
 
+  /* The size of entries in the .hash section.  */
+  unsigned char sizeof_hash_entry;
+
+  /* The number of internal relocations to allocate per external
+     relocation entry.  */
+  unsigned char int_rels_per_ext_rel;
+
   unsigned char arch_size, file_align;
   unsigned char elfclass, ev_current;
   int (*write_out_phdrs) PARAMS ((bfd *, const Elf_Internal_Phdr *, int));
@@ -246,6 +253,32 @@ struct elf_size_info {
     PARAMS ((bfd *, asection *, asymbol **, boolean));
   long (*slurp_symbol_table) PARAMS ((bfd *, asymbol **, boolean));
   void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *));
+  void (*swap_dyn_out) PARAMS ((bfd *, const Elf_Internal_Dyn *, PTR));
+
+  /* This function, if defined, is called to swap in a REL
+     relocation.  If an external relocation corresponds to more than
+     one internal relocation, then all relocations are swapped in at
+     once.  */
+  void (*swap_reloc_in)
+    PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rel *));
+
+  /* This function, if defined, is called to swap out a REL
+     relocation.  */
+  void (*swap_reloc_out)
+    PARAMS ((bfd *, const Elf_Internal_Rel *, bfd_byte *));
+
+  /* This function, if defined, is called to swap in a RELA
+     relocation.  If an external relocation corresponds to more than
+     one internal relocation, then all relocations are swapped in at
+     once.  */
+  void (*swap_reloca_in)
+    PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *));
+
+  /* This function, if defined, is called to swap out a RELA
+     relocation.  */
+  void (*swap_reloca_out)
+    PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *));
+
 };
 
 #define elf_symbol_from(ABFD,S) \
Index: elflink.h
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elflink.h,v
retrieving revision 1.9
diff -u -p -r1.9 elflink.h
--- elflink.h	1999/07/01 23:20:07	1.9
+++ elflink.h	1999/07/07 18:16:50
@@ -2016,6 +2018,8 @@ elf_link_read_relocs_from_section (abfd,
      PTR external_relocs;
      Elf_Internal_Rela *internal_relocs;
 {
+  struct elf_backend_data *bed;
+
   /* If there aren't any relocations, that's OK.  */
   if (!shdr)
     return true;
@@ -2029,24 +2033,36 @@ elf_link_read_relocs_from_section (abfd,
       != shdr->sh_size)
     return false;
 
+  bed = get_elf_backend_data (abfd);
+
   /* Convert the external relocations to the internal format.  */
   if (shdr->sh_entsize == sizeof (Elf_External_Rel))
     {
       Elf_External_Rel *erel;
       Elf_External_Rel *erelend;
       Elf_Internal_Rela *irela;
+      Elf_Internal_Rel *irel;
 
       erel = (Elf_External_Rel *) external_relocs;
       erelend = erel + shdr->sh_size / shdr->sh_entsize;
       irela = internal_relocs;
-      for (; erel < erelend; erel++, irela++)
+      irel = bfd_alloc (abfd, (bed->s->int_rels_per_ext_rel
+			       * sizeof (Elf_Internal_Rel)));
+      for (; erel < erelend; erel++, irela += bed->s->int_rels_per_ext_rel)
 	{
-	  Elf_Internal_Rel irel;
+	  int i;
+
+	  if (bed->s->swap_reloc_in)
+	    (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel);
+	  else
+	    elf_swap_reloc_in (abfd, erel, irel);
 
-	  elf_swap_reloc_in (abfd, erel, &irel);
-	  irela->r_offset = irel.r_offset;
-	  irela->r_info = irel.r_info;
-	  irela->r_addend = 0;
+	  for (i = 0; i < bed->s->int_rels_per_ext_rel; ++i)
+	    {
+	      irela[i].r_offset = irel[i].r_offset;
+	      irela[i].r_info = irel[i].r_info;
+	      irela[i].r_addend = 0;
+	    }
 	}
     }
   else
@@ -2060,8 +2076,13 @@ elf_link_read_relocs_from_section (abfd,
       erela = (Elf_External_Rela *) external_relocs;
       erelaend = erela + shdr->sh_size / shdr->sh_entsize;
       irela = internal_relocs;
-      for (; erela < erelaend; erela++, irela++)
-	elf_swap_reloca_in (abfd, erela, irela);
+      for (; erela < erelaend; erela++, irela += bed->s->int_rels_per_ext_rel)
+	{
+	  if (bed->s->swap_reloca_in)
+	    (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela);
+	  else
+	    elf_swap_reloca_in (abfd, erela, irela);
+	}
     }
 
   return true;
@@ -2089,6 +2110,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o
   Elf_Internal_Shdr *rel_hdr;
   PTR alloc1 = NULL;
   Elf_Internal_Rela *alloc2 = NULL;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (elf_section_data (o)->relocs != NULL)
     return elf_section_data (o)->relocs;
@@ -2102,7 +2124,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o
     {
       size_t size;
 
-      size = o->reloc_count * sizeof (Elf_Internal_Rela);
+      size = (o->reloc_count * bed->s->int_rels_per_ext_rel 
+	      * sizeof (Elf_Internal_Rela));
       if (keep_memory)
 	internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
       else
@@ -2131,7 +2154,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o
       (abfd, 
        elf_section_data (o)->rel_hdr2,
        ((bfd_byte *) external_relocs) + rel_hdr->sh_size,
-       internal_relocs + rel_hdr->sh_size / rel_hdr->sh_entsize))
+       internal_relocs + (rel_hdr->sh_size / rel_hdr->sh_entsize
+			  * bed->s->int_rels_per_ext_rel)))
     goto error_return;
 
   /* Cache the results for next time, if we can.  */
@@ -3991,7 +4018,8 @@ elf_bfd_final_link (abfd, info)
   finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
   finfo.internal_relocs = ((Elf_Internal_Rela *)
 			   bfd_malloc (max_internal_reloc_count
-				       * sizeof (Elf_Internal_Rela)));
+				       * 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)));
@@ -4845,10 +4876,11 @@ elf_link_input_bfd (finfo, input_bfd)
   long *pindex;
   asection **ppsection;
   asection *o;
+  struct elf_backend_data *bed;
 
   output_bfd = finfo->output_bfd;
-  relocate_section =
-    get_elf_backend_data (output_bfd)->elf_backend_relocate_section;
+  bed = get_elf_backend_data (output_bfd);
+  relocate_section = bed->elf_backend_relocate_section;
 
   /* If this is a dynamic object, we don't want to do anything here:
      we don't want the local symbols, and we don't want the section
@@ -5085,7 +5117,8 @@ elf_link_input_bfd (finfo, input_bfd)
 	      /* Adjust the reloc addresses and symbol indices.  */
 
 	      irela = internal_relocs;
-	      irelaend = irela + o->reloc_count;
+	      irelaend = 
+		irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
 	      rel_hash = (elf_section_data (o->output_section)->rel_hashes
 			  + o->output_section->reloc_count);
 	      for (; irela < irelaend; irela++, rel_hash++)
@@ -5695,6 +5728,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
       size_t extsymoff;
       Elf_External_Sym *locsyms, *freesyms = NULL;
       bfd *input_bfd = sec->owner;
+      struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
 
       /* GCFIXME: how to arrange so that relocs and symbols are not
 	 reread continually?  */
@@ -5738,7 +5772,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
 	  ret = false;
 	  goto out1;
 	}
-      relend = relstart + sec->reloc_count;
+      relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
       for (rel = relstart; rel < relend; rel++)
 	{
@@ -5944,6 +5978,7 @@ elf_gc_smash_unused_vtentry_relocs (h, o
   asection *sec;
   bfd_vma hstart, hend;
   Elf_Internal_Rela *relstart, *relend, *rel;
+  struct elf_backend_data *bed;
 
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
@@ -5961,7 +5996,8 @@ elf_gc_smash_unused_vtentry_relocs (h, o
 	      (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, true));
   if (!relstart)
     return *(boolean *)okp = false;
-  relend = relstart + sec->reloc_count;
+  bed = get_elf_backend_data (sec->owner);
+  relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
   for (rel = relstart; rel < relend; ++rel)
     if (rel->r_offset >= hstart && rel->r_offset < hend)
Index: elfcode.h
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elfcode.h,v
retrieving revision 1.4
diff -u -p -r1.4 elfcode.h
--- elfcode.h	1999/06/12 17:56:25	1.4
+++ elfcode.h	1999/07/07 18:16:47
@@ -423,11 +423,13 @@ elf_swap_dyn_in (abfd, p, dst)
 }
 
 INLINE void
-elf_swap_dyn_out (abfd, src, dst)
+elf_swap_dyn_out (abfd, src, p)
      bfd *abfd;
      const Elf_Internal_Dyn *src;
-     Elf_External_Dyn *dst;
+     PTR p;
 {
+  Elf_External_Dyn *dst = (Elf_External_Dyn *) p;
+
   put_word (abfd, src->d_tag, dst->d_tag);
   put_word (abfd, src->d_un.d_val, dst->d_un.d_val);
 }
@@ -1500,7 +1504,8 @@ const struct elf_size_info NAME(_bfd_elf
   sizeof (Elf_External_Sym),
   sizeof (Elf_External_Dyn),
   sizeof (Elf_External_Note),
-
+  ARCH_SIZE / 8,
+  1,
   ARCH_SIZE, FILE_ALIGN,
   ELFCLASS, EV_CURRENT,
   elf_write_out_phdrs,
@@ -1509,5 +1514,10 @@ const struct elf_size_info NAME(_bfd_elf
   elf_swap_symbol_out,
   elf_slurp_reloc_table,
   elf_slurp_symbol_table,
-  elf_swap_dyn_in
+  elf_swap_dyn_in,
+  elf_swap_dyn_out,
+  NULL,
+  NULL,
+  NULL,
+  NULL
 };
Index: elf64-mips.c
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elf64-mips.c,v
retrieving revision 1.4
diff -u -p -r1.4 elf64-mips.c
--- elf64-mips.c	1999/06/02 18:17:59	1.4
+++ elf64-mips.c	1999/07/07 18:16:46
@@ -52,14 +54,20 @@ static void mips_elf64_swap_reloc_in
 static void mips_elf64_swap_reloca_in
   PARAMS ((bfd *, const Elf64_Mips_External_Rela *,
 	   Elf64_Mips_Internal_Rela *));
-#if 0
 static void mips_elf64_swap_reloc_out
   PARAMS ((bfd *, const Elf64_Mips_Internal_Rel *,
 	   Elf64_Mips_External_Rel *));
-#endif
 static void mips_elf64_swap_reloca_out
   PARAMS ((bfd *, const Elf64_Mips_Internal_Rela *,
 	   Elf64_Mips_External_Rela *));
+static void mips_elf64_be_swap_reloc_in
+  PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rel *));
+static void mips_elf64_be_swap_reloc_out
+  PARAMS ((bfd *, const Elf_Internal_Rel *, bfd_byte *));
+static void mips_elf64_be_swap_reloca_in
+  PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *));
+static void mips_elf64_be_swap_reloca_out
+  PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *));
 static reloc_howto_type *mips_elf64_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
 static long mips_elf64_get_reloc_upper_bound PARAMS ((bfd *, asection *));
@@ -1220,10 +1231,6 @@ mips_elf64_swap_reloca_in (abfd, src, ds
   dst->r_addend = bfd_h_get_signed_64 (abfd, (bfd_byte *) src->r_addend);
 }
 
-#if 0
-
-/* This is not currently used.  */
-
 /* Swap out a MIPS 64-bit Rel reloc.  */
 
 static void
@@ -1240,8 +1247,6 @@ mips_elf64_swap_reloc_out (abfd, src, ds
   bfd_h_put_8 (abfd, src->r_type, (bfd_byte *) dst->r_type);
 }
 
-#endif /* 0 */
-
 /* Swap out a MIPS 64-bit Rela reloc.  */
 
 static void
@@ -1259,6 +1264,96 @@ mips_elf64_swap_reloca_out (abfd, src, d
   bfd_h_put_64 (abfd, src->r_addend, (bfd_byte *) dst->r_addend);
 }
 
+/* Swap in a MIPS 64-bit Rel reloc.  */
+
+static void
+mips_elf64_be_swap_reloc_in (abfd, src, dst)
+     bfd *abfd;
+     const bfd_byte *src;
+     Elf_Internal_Rel *dst;
+{
+  Elf64_Mips_Internal_Rel mirel;
+
+  mips_elf64_swap_reloc_in (abfd, 
+			    (const Elf64_Mips_External_Rel *) src,
+			    &mirel);
+
+  dst[0].r_offset = mirel.r_offset;
+  dst[0].r_info = ELF32_R_INFO (mirel.r_sym, mirel.r_type);
+  dst[1].r_offset = mirel.r_offset;
+  dst[1].r_info = ELF32_R_INFO (mirel.r_ssym, mirel.r_type2);
+  dst[2].r_offset = mirel.r_offset;
+  dst[2].r_info = ELF32_R_INFO (STN_UNDEF, mirel.r_type3);
+}
+
+/* Swap in a MIPS 64-bit Rela reloc.  */
+
+static void
+mips_elf64_be_swap_reloca_in (abfd, src, dst)
+     bfd *abfd;
+     const bfd_byte *src;
+     Elf_Internal_Rela *dst;
+{
+  Elf64_Mips_Internal_Rela mirela;
+
+  mips_elf64_swap_reloca_in (abfd, 
+			     (const Elf64_Mips_External_Rela *) src,
+			     &mirela);
+
+  dst[0].r_offset = mirela.r_offset;
+  dst[0].r_info = ELF32_R_INFO (mirela.r_sym, mirela.r_type);
+  dst[0].r_addend = mirela.r_addend;
+  dst[1].r_offset = mirela.r_offset;
+  dst[1].r_info = ELF32_R_INFO (mirela.r_ssym, mirela.r_type2);
+  dst[1].r_addend = 0;
+  dst[2].r_offset = mirela.r_offset;
+  dst[2].r_info = ELF32_R_INFO (STN_UNDEF, mirela.r_type3);
+  dst[2].r_addend = 0;
+}
+
+/* Swap out a MIPS 64-bit Rel reloc.  */
+
+static void
+mips_elf64_be_swap_reloc_out (abfd, src, dst)
+     bfd *abfd;
+     const Elf_Internal_Rel *src;
+     bfd_byte *dst;
+{
+  Elf64_Mips_Internal_Rel mirel;
+
+  mirel.r_offset = src->r_offset;
+  mirel.r_type = ELF32_R_TYPE (src->r_info);
+  mirel.r_sym = ELF32_R_SYM (src->r_info);
+  mirel.r_type2 = R_MIPS_NONE;
+  mirel.r_ssym = STN_UNDEF;
+  mirel.r_type3 = R_MIPS_NONE;
+
+  mips_elf64_swap_reloc_out (abfd, &mirel, 
+			     (Elf64_Mips_External_Rel *) dst);
+}
+
+/* Swap out a MIPS 64-bit Rela reloc.  */
+
+static void
+mips_elf64_be_swap_reloca_out (abfd, src, dst)
+     bfd *abfd;
+     const Elf_Internal_Rela *src;
+     bfd_byte *dst;
+{
+  Elf64_Mips_Internal_Rela mirela;
+
+  mirela.r_offset = src->r_offset;
+  mirela.r_type = ELF32_R_TYPE (src->r_info);
+  mirela.r_addend = src->r_addend;
+  mirela.r_sym = ELF32_R_SYM (src->r_info);
+  mirela.r_type2 = R_MIPS_NONE;
+  mirela.r_ssym = STN_UNDEF;
+  mirela.r_type3 = R_MIPS_NONE;
+
+  mips_elf64_swap_reloca_out (abfd, &mirela, 
+			      (Elf64_Mips_External_Rela *) dst);
+}
+
 /* A mapping from BFD reloc types to MIPS ELF reloc types.  */
 
 struct elf_reloc_map
@@ -2099,6 +2144,8 @@ const struct elf_size_info mips_elf64_si
   sizeof (Elf64_External_Sym),
   sizeof (Elf64_External_Dyn),
   sizeof (Elf_External_Note),
+  4,            /* hash-table entry size */
+  3,            /* internal relocations per external relocations */
   64,		/* arch_size */
   8,		/* file_align */
   ELFCLASS64,
@@ -2109,7 +2156,12 @@ const struct elf_size_info mips_elf64_si
   bfd_elf64_swap_symbol_out,
   mips_elf64_slurp_reloc_table,
   bfd_elf64_slurp_symbol_table,
-  bfd_elf64_swap_dyn_in
+  bfd_elf64_swap_dyn_in,
+  bfd_elf64_swap_dyn_out,
+  mips_elf64_be_swap_reloc_in,
+  mips_elf64_be_swap_reloc_out,
+  mips_elf64_be_swap_reloca_in,
+  mips_elf64_be_swap_reloca_out
 };
 
 #define TARGET_LITTLE_SYM		bfd_elf64_littlemips_vec


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