2002-01-29 Chris Demetriou <cgd@broadcom.com>
authorChris Demetriou <cgd@google.com>
Wed, 30 Jan 2002 02:13:20 +0000 (02:13 +0000)
committerChris Demetriou <cgd@google.com>
Wed, 30 Jan 2002 02:13:20 +0000 (02:13 +0000)
        * elf32-mips.c: Add additional comments about HI16 relocation
        processing.
        (_bfd_mips_elf_hi16_reloc): Don't subtract address here for
        pc-relative relocations.  (Reverts change made on 2001-10-31.)
        (_bfd_mips_elf_lo16_reloc): Subtract address of LO16 part here
        for pc-relative relocations.
        (mips_elf_calculate_relocation): Add a comment about a kludge
        in the R_MIPS_GNU_REL_HI16 handling.
        (_bfd_mips_elf_relocate_section): Implement that kludge;
        adjust pc-relative HI16 relocation for difference in HI16 and
        LO16 addresses, since it can't easily be done in
        mips_elf_calculate_relocation.

bfd/ChangeLog
bfd/elf32-mips.c

index 832bce529e1de36ac4dc1fa3553dff43ff04cb2f..7f6ee721f23220db3fb203d198ed7d7deaf5a29d 100644 (file)
@@ -1,3 +1,18 @@
+2002-01-29  Chris Demetriou  <cgd@broadcom.com>
+
+       * elf32-mips.c: Add additional comments about HI16 relocation
+       processing.
+       (_bfd_mips_elf_hi16_reloc): Don't subtract address here for
+       pc-relative relocations.  (Reverts change made on 2001-10-31.)
+       (_bfd_mips_elf_lo16_reloc): Subtract address of LO16 part here
+       for pc-relative relocations.
+       (mips_elf_calculate_relocation): Add a comment about a kludge
+       in the R_MIPS_GNU_REL_HI16 handling.
+       (_bfd_mips_elf_relocate_section): Implement that kludge;
+       adjust pc-relative HI16 relocation for difference in HI16 and
+       LO16 addresses, since it can't easily be done in
+       mips_elf_calculate_relocation.
+
 2002-01-29  Martin Schwidefsky  <schwidefsky@de.ibm.com>
 
        * elf32-i386 (elf_i386_adjust_dynamic_symbol): Do not replace PLT32
index bdeed28c337c8343cf6b1626617986cf1fcbbb3d..5e5a96dd08cb0b98c0677e1155b6a94895bb165a 100644 (file)
@@ -1640,11 +1640,17 @@ static reloc_howto_type elf_mips_gnu_vtentry_howto =
 /* Do a R_MIPS_HI16 relocation.  This has to be done in combination
    with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to
    the HI16.  Here we just save the information we need; we do the
-   actual relocation when we see the LO16.  MIPS ELF requires that the
-   LO16 immediately follow the HI16.  As a GNU extension, we permit an
+   actual relocation when we see the LO16.
+
+   MIPS ELF requires that the LO16 immediately follow the HI16.  As a
+   GNU extension, for non-pc-relative relocations, we permit an
    arbitrary number of HI16 relocs to be associated with a single LO16
    reloc.  This extension permits gcc to output the HI and LO relocs
-   itself.  */
+   itself.
+
+   This cannot be done for PC-relative relocations because both the HI16
+   and LO16 parts of the relocations must be done relative to the LO16
+   part, and there can be carry to or borrow from the HI16 part.  */
 
 struct mips_hi16
 {
@@ -1727,8 +1733,6 @@ _bfd_mips_elf_hi16_reloc (abfd,
   relocation += symbol->section->output_section->vma;
   relocation += symbol->section->output_offset;
   relocation += reloc_entry->addend;
-  if (reloc_entry->howto->pc_relative)
-    relocation -= reloc_entry->address;
 
   if (reloc_entry->address > input_section->_cooked_size)
     return bfd_reloc_outofrange;
@@ -1794,6 +1798,12 @@ _bfd_mips_elf_lo16_reloc (abfd,
          val = ((insn & 0xffff) << 16) + vallo;
          val += l->addend;
 
+         /* If PC-relative, we need to subtract out the address of the LO
+            half of the HI/LO.  (The actual relocation is relative
+            to that instruction.)  */
+         if (reloc_entry->howto->pc_relative)
+           val -= reloc_entry->address;
+
          /* At this point, "val" has the value of the combined HI/LO
             pair.  If the low order 16 bits (which will be used for
             the LO16 insn) are negative, then we will need an
@@ -6864,6 +6874,11 @@ mips_elf_calculate_relocation (abfd,
       break;
 
     case R_MIPS_GNU_REL_HI16:
+      /* Instead of subtracting 'p' here, we should be subtracting the
+        equivalent value for the LO part of the reloc, since the value
+        here is relative to that address.  Because that's not easy to do,
+        we adjust 'addend' in _bfd_mips_elf_relocate_section().  See also
+        the comment there for more information.  */
       value = mips_elf_high (addend + symbol - p);
       value &= howto->dst_mask;
       break;
@@ -7390,6 +7405,16 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
                  /* Compute the combined addend.  */
                  addend += l;
+
+                 /* If PC-relative, subtract the difference between the
+                    address of the LO part of the reloc and the address of
+                    the HI part.  The relocation is relative to the LO
+                    part, but mips_elf_calculate_relocation() doesn't know
+                    it address or the difference from the HI part, so
+                    we subtract that difference here.  See also the
+                    comment in mips_elf_calculate_relocation().  */
+                 if (r_type == R_MIPS_GNU_REL_HI16)
+                   addend -= (lo16_relocation->r_offset - rel->r_offset);
                }
              else if (r_type == R_MIPS16_GPREL)
                {