* elflink.h (elf_link_adjust_relocs): New function.
authorMark Mitchell <mark@codesourcery.com>
Sun, 18 Jul 1999 06:31:29 +0000 (06:31 +0000)
committerMark Mitchell <mark@codesourcery.com>
Sun, 18 Jul 1999 06:31:29 +0000 (06:31 +0000)
(elf_bfd_final_link): Use it.
(elf_link_input_bfd): Deal with the fact that there can be
two relocation sections for a single section.
(elf_reloc_link_order): Likewise.

* elf32-mips.c (_bfd_mips_elf_final_link): Don't set GP for
a relocateable object.
(_bfd_mips_elf_relocate_section): Handle relocateable links.

bfd/ChangeLog
bfd/elf32-mips.c
bfd/elflink.h

index 7bd50813abfc6fb34134e38a043373e6f012f9a1..d2789851cb07ab71aa18bc4438622d14c2f6d716 100644 (file)
@@ -1,3 +1,15 @@
+Sat Jul 17 02:28:28 1999  Mark P. Mitchell  <mark@codesourcery.com>
+
+       * elflink.h (elf_link_adjust_relocs): New function.
+       (elf_bfd_final_link): Use it.
+       (elf_link_input_bfd): Deal with the fact that there can be 
+       two relocation sections for a single section.
+       (elf_reloc_link_order): Likewise.
+
+       * elf32-mips.c (_bfd_mips_elf_final_link): Don't set GP for 
+       a relocateable object.
+       (_bfd_mips_elf_relocate_section): Handle relocateable links.
+
 1999-07-16  Jakub Jelinek  <jj@ultra.linux.cz>
 
        * elf64-sparc.c (sparc64_elf_info_to_howto): Use ELF64_R_TYPE_ID.
index a9d3acf6e70bf21a69431b368a9ba3479d4019fc..8fecccf062daddd906cc51ae94b095e8850bdc82 100644 (file)
@@ -4388,20 +4388,6 @@ _bfd_mips_elf_final_link (abfd, info)
        elf_gp (abfd) = (h->u.def.value
                         + h->u.def.section->output_section->vma
                         + h->u.def.section->output_offset);
-      else if (info->relocateable)
-       {
-         bfd_vma lo;
-
-         /* Find the GP-relative section with the lowest offset.  */
-         lo = (bfd_vma) -1;
-         for (o = abfd->sections; o != (asection *) NULL; o = o->next)
-           if (o->vma < lo 
-               && (elf_section_data (o)->this_hdr.sh_flags & SHF_MIPS_GPREL))
-             lo = o->vma;
-
-         /* And calculate GP relative to that.  */
-         elf_gp (abfd) = lo + ELF_MIPS_GP_OFFSET (abfd);
-       }
       else
        {
          /* If the relocate_section function needs to do a reloc
@@ -6429,7 +6415,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
      Elf_Internal_Sym *local_syms;
      asection **local_sections;
 {
-  const Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *relend;
   bfd_vma addend;
   bfd_vma last_hi16_addend;
@@ -6445,10 +6431,13 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_vma value;
       reloc_howto_type *howto;
       boolean require_jalx;
+      /* True if the relocation is a RELA relocation, rather than a
+         REL relocation.  */
+      boolean rela_relocation_p = true;
+      int r_type = ELF32_R_TYPE (rel->r_info);
 
       /* Find the relocation howto for this relocation.  */
-      if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
-         && !ABI_64_P (output_bfd))
+      if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
        /* Some 32-bit code uses R_MIPS_64.  In particular, people use
           64-bit code, but make sure all their addresses are in the 
           lowermost or uppermost 32-bit section of the 64-bit address
@@ -6457,7 +6446,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
           stored value is sign-extended to 64 bits.  */
        howto = elf_mips_howto_table + R_MIPS_32;
       else
-       howto = elf_mips_howto_table + ELF32_R_TYPE (rel->r_info);
+       howto = elf_mips_howto_table + r_type;
 
       if (!use_saved_addend_p)
        {
@@ -6476,8 +6465,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            rel_hdr = elf_section_data (input_section)->rel_hdr2;
          if (rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (input_bfd))
            {
-             int r_type = ELF32_R_TYPE (rel->r_info);
+             /* Note that this is a REL relocation.  */
+             rela_relocation_p = false;
 
+             /* Get the addend, which is stored in the input file.  */
              addend = mips_elf_obtain_contents (howto, 
                                                 rel,
                                                 input_bfd,
@@ -6533,13 +6524,63 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            addend = rel->r_addend;
        }
 
+      if (info->relocateable)
+       {
+         Elf_Internal_Sym *sym;
+         unsigned long r_symndx;
+
+         /* Since we're just relocating, all we need to do is copy
+            the relocations back out to the object file, unless they're 
+            against a section symbol, in which case we need to adjust 
+            by the section offset.  */
+
+         if (!mips_elf_local_relocation_p (input_bfd, rel, local_sections))
+           /* A non-local relocation is never against a section.  */
+           continue;
+
+         r_symndx = ELF32_R_SYM (rel->r_info);
+         sym = local_syms + r_symndx;
+         if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+           continue;
+
+         /* Adjust the addend appropriately.  */
+         addend += local_sections[r_symndx]->output_offset;
+
+         /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16,
+            then we only want to write out the high-order 16 bits.
+            The subsequent R_MIPS_LO16 will handle the low-order bits.  */
+         if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16)
+           addend >>= 16;
+
+         if (rela_relocation_p)
+           /* If this is a RELA relocation, just update the addend.
+               We have to cast away constness for REL.  */
+           rel->r_addend = addend;
+         else
+           {
+             /* Otherwise, we have to write the value back out.  Note
+                that we use the source mask, rather than the
+                destination mask because the place to which we are
+                writing will be source of the addend in the final
+                link.  */
+             addend &= howto->src_mask;
+             if (!mips_elf_perform_relocation (info, howto, rel, addend,
+                                               input_bfd,  input_section, 
+                                               contents, false))
+               return false;
+           }
+
+         /* Go on to the next relocation.  */
+         continue;
+       }
+
       /* In the N32 and 64-bit ABIs there may be multiple consecutive
         relocations for the same offset.  In that case we are
         supposed to treat the output of each relocation as the addend
         for the next.  */
       if (rel + 1 < relend 
          && rel->r_offset == rel[1].r_offset
-         && ELF32_R_TYPE (rel[1].r_info) != R_MIPS_NONE)
+         && r_type != R_MIPS_NONE)
        use_saved_addend_p = true;
       else
        use_saved_addend_p = false;
@@ -6602,8 +6643,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          continue;
        }
 
-      if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
-         && !ABI_64_P (output_bfd))
+      if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
        /* See the comment above about using R_MIPS_64 in the 32-bit
           ABI.  Until now, we've been using the HOWTO for R_MIPS_32;
           that calculated the right value.  Now, however, we
index 9c00d1df80f70a58ac917b7a7b4fccdc5c6dd031..7591f6472c5e7e4b6a05ac662ae279e23cd84424 100644 (file)
@@ -56,6 +56,9 @@ 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 *));
+static void elf_link_adjust_relocs 
+  PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int, 
+          struct elf_link_hash_entry **));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -3782,6 +3785,55 @@ elf_link_size_reloc_section (abfd, rel_hdr, o)
   return true;
 }
 
+/* When performing a relocateable link, the input relocations are
+   preserved.  But, if they reference global symbols, the indices
+   referenced must be updated.  Update all the relocations in
+   REL_HDR (there are COUNT of them), using the data in REL_HASH.  */
+
+static void
+elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     unsigned int count;
+     struct elf_link_hash_entry **rel_hash;
+{
+  unsigned int i;
+
+  for (i = 0; i < count; i++, rel_hash++)
+    {
+      if (*rel_hash == NULL)
+       continue;
+
+      BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+      if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+       {
+         Elf_External_Rel *erel;
+         Elf_Internal_Rel irel;
+         
+         erel = (Elf_External_Rel *) rel_hdr->contents + i;
+         elf_swap_reloc_in (abfd, erel, &irel);
+         irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
+                                   ELF_R_TYPE (irel.r_info));
+         elf_swap_reloc_out (abfd, &irel, erel);
+       }
+      else
+       {
+         Elf_External_Rela *erela;
+         Elf_Internal_Rela irela;
+         
+         BFD_ASSERT (rel_hdr->sh_entsize
+                     == sizeof (Elf_External_Rela));
+         
+         erela = (Elf_External_Rela *) rel_hdr->contents + i;
+         elf_swap_reloca_in (abfd, erela, &irela);
+         irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+                                    ELF_R_TYPE (irela.r_info));
+         elf_swap_reloca_out (abfd, &irela, erela);
+       }
+    }
+}
+
 /* Do the final step of an ELF link.  */
 
 boolean
@@ -4268,42 +4320,14 @@ elf_bfd_final_link (abfd, info)
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
-      rel_hash = elf_section_data (o)->rel_hashes;
-      rel_hdr = &elf_section_data (o)->rel_hdr;
-      BFD_ASSERT (elf_section_data (o)->rel_count == o->reloc_count);
-      for (i = 0; i < o->reloc_count; i++, rel_hash++)
-       {
-         if (*rel_hash == NULL)
-           continue;
-
-         BFD_ASSERT ((*rel_hash)->indx >= 0);
-
-         if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
-           {
-             Elf_External_Rel *erel;
-             Elf_Internal_Rel irel;
-
-             erel = (Elf_External_Rel *) rel_hdr->contents + i;
-             elf_swap_reloc_in (abfd, erel, &irel);
-             irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                       ELF_R_TYPE (irel.r_info));
-             elf_swap_reloc_out (abfd, &irel, erel);
-           }
-         else
-           {
-             Elf_External_Rela *erela;
-             Elf_Internal_Rela irela;
-
-             BFD_ASSERT (rel_hdr->sh_entsize
-                         == sizeof (Elf_External_Rela));
-
-             erela = (Elf_External_Rela *) rel_hdr->contents + i;
-             elf_swap_reloca_in (abfd, erela, &irela);
-             irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                        ELF_R_TYPE (irela.r_info));
-             elf_swap_reloca_out (abfd, &irela, erela);
-           }
-       }
+      elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, 
+                             elf_section_data (o)->rel_count,
+                             elf_section_data (o)->rel_hashes);
+      if (elf_section_data (o)->rel_hdr2 != NULL)
+       elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
+                               elf_section_data (o)->rel_count2,
+                               (elf_section_data (o)->rel_hashes 
+                                + elf_section_data (o)->rel_count));
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -5224,7 +5248,8 @@ elf_link_input_bfd (finfo, input_bfd)
              irelaend = 
                irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
              rel_hash = (elf_section_data (o->output_section)->rel_hashes
-                         + elf_section_data (o->output_section)->rel_count);
+                         + elf_section_data (o->output_section)->rel_count
+                         + elf_section_data (o->output_section)->rel_count2);
              for (; irela < irelaend; irela++, rel_hash++)
                {
                  unsigned long r_symndx;
@@ -5414,7 +5439,8 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
 
   /* Figure out the symbol index.  */
   rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
-                 + elf_section_data (output_section)->rel_count);
+                 + elf_section_data (output_section)->rel_count
+                 + elf_section_data (output_section)->rel_count2);
   if (link_order->type == bfd_section_reloc_link_order)
     {
       indx = link_order->u.reloc.p->u.section->target_index;