* elfxx-mips.c (mips_elf_calculate_relocation): Decay
authorAlexandre Oliva <aoliva@redhat.com>
Fri, 11 Apr 2003 01:56:49 +0000 (01:56 +0000)
committerAlexandre Oliva <aoliva@redhat.com>
Fri, 11 Apr 2003 01:56:49 +0000 (01:56 +0000)
GOT_PAGE/GOT_OFST referencing overridable symbol to
GOT_DISP/addend.
(_bfd_mips_elf_check_relocs): Handle GOT_PAGE referencing
global symbol as GOT_DISP.

bfd/ChangeLog
bfd/elfxx-mips.c

index ac7503ec433b14407c5c7ee64a74a685c1ad02a2..4228d7c44e7759cba4d258b726cbe6f064e3ce53 100644 (file)
@@ -1,3 +1,11 @@
+2003-04-10  Alexandre Oliva  <aoliva@redhat.com>
+
+       * elfxx-mips.c (mips_elf_calculate_relocation): Decay
+       GOT_PAGE/GOT_OFST referencing overridable symbol to
+       GOT_DISP/addend.
+       (_bfd_mips_elf_check_relocs): Handle GOT_PAGE referencing
+       global symbol as GOT_DISP.
+
 2003-04-10  Bob Wilson  <bob.wilson@acm.org>
 
        * elf32-xtensa.c (elf_xtensa_relocate_section): Don't continue to the
index fa165d926eff8da4f50fc83f97553c015ed9e44f..d2ba1cf8c2317205921759cc37e469d483a4a8a1 100644 (file)
@@ -3196,6 +3196,13 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
      and we're going to need it, get it now.  */
   switch (r_type)
     {
+    case R_MIPS_GOT_PAGE:
+      /* If we didn't create a dynamic index for this symbol, it can
+        be regarded as local.  */
+      if (local_p || ! h || h->root.dynindx < 0)
+       break;
+      /* Fall through.  */
+
     case R_MIPS_CALL16:
     case R_MIPS_GOT16:
     case R_MIPS_GOT_DISP:
@@ -3206,7 +3213,11 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       /* Find the index into the GOT where this value is located.  */
       if (!local_p)
        {
-         BFD_ASSERT (addend == 0);
+         /* GOT_PAGE may take a non-zero addend, that is ignored in a
+            GOT_PAGE relocation that decays to GOT_DISP because the
+            symbol turns out to be global.  The addend is then added
+            as GOT_OFST.  */
+         BFD_ASSERT (addend == 0 || r_type == R_MIPS_GOT_PAGE);
          g = mips_elf_global_got_index (elf_hash_table (info)->dynobj,
                                         input_bfd,
                                         (struct elf_link_hash_entry *) h);
@@ -3220,7 +3231,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
                 We must initialize this entry in the GOT.  */
              bfd *tmpbfd = elf_hash_table (info)->dynobj;
              asection *sgot = mips_elf_got_section (tmpbfd, FALSE);
-             MIPS_ELF_PUT_WORD (tmpbfd, symbol + addend, sgot->contents + g);
+             MIPS_ELF_PUT_WORD (tmpbfd, symbol, sgot->contents + g);
            }
        }
       else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
@@ -3439,6 +3450,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       /* Fall through.  */
 
     case R_MIPS_GOT_DISP:
+    got_disp:
       value = g;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
@@ -3470,6 +3482,11 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       break;
 
     case R_MIPS_GOT_PAGE:
+      /* GOT_PAGE relocations that reference non-local symbols decay
+        to GOT_DISP.  The corresponding GOT_OFST relocation decays to
+        0.  */
+      if (! (local_p || ! h || h->root.dynindx < 0))
+       goto got_disp;
       value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
       if (value == MINUS_ONE)
        return bfd_reloc_outofrange;
@@ -3479,7 +3496,10 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       break;
 
     case R_MIPS_GOT_OFST:
-      mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value);
+      if (local_p || ! h || h->root.dynindx < 0)
+       mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value);
+      else
+       value = addend;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
@@ -5312,6 +5332,44 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
            }
          break;
 
+       case R_MIPS_GOT_PAGE:
+         /* If this is a global, overridable symbol, GOT_PAGE will
+            decay to GOT_DISP, so we'll need a GOT entry for it.  */
+         if (h == NULL)
+           break;
+         else
+           {
+             struct mips_elf_link_hash_entry *hmips =
+               (struct mips_elf_link_hash_entry *) h;
+             
+             while (hmips->root.root.type == bfd_link_hash_indirect
+                    || hmips->root.root.type == bfd_link_hash_warning)
+               hmips = (struct mips_elf_link_hash_entry *)
+                 hmips->root.root.u.i.link;
+         
+             if ((hmips->root.root.type == bfd_link_hash_defined
+                  || hmips->root.root.type == bfd_link_hash_defweak)
+                 && hmips->root.root.u.def.section
+                 && ! (info->shared && ! info->symbolic
+                       && ! (hmips->root.elf_link_hash_flags
+                             & ELF_LINK_FORCED_LOCAL))
+                 /* If we've encountered any other relocation
+                    referencing the symbol, we'll have marked it as
+                    dynamic, and, even though we might be able to get
+                    rid of the GOT entry should we know for sure all
+                    previous relocations were GOT_PAGE ones, at this
+                    point we can't tell, so just keep using the
+                    symbol as dynamic.  This is very important in the
+                    multi-got case, since we don't decide whether to
+                    decay GOT_PAGE to GOT_DISP on a per-GOT basis: if
+                    the symbol is dynamic, we'll need a GOT entry for
+                    every GOT in which the symbol is referenced with
+                    a GOT_PAGE relocation.  */
+                 && hmips->root.dynindx == -1)
+               break;
+           }
+         /* Fall through.  */
+
        case R_MIPS_GOT16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16: