aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2003-04-11 01:56:49 +0000
committerAlexandre Oliva <aoliva@redhat.com>2003-04-11 01:56:49 +0000
commit0fdc1bf12541e30f9a66aa20dcea5be76328a52b (patch)
treeba7d7640005d84b870c760699d59a57061df424f /bfd
parent9f34b04bdffbb6b903399ac04e5ed0b8a4243714 (diff)
downloadfsf-binutils-gdb-0fdc1bf12541e30f9a66aa20dcea5be76328a52b.zip
fsf-binutils-gdb-0fdc1bf12541e30f9a66aa20dcea5be76328a52b.tar.gz
fsf-binutils-gdb-0fdc1bf12541e30f9a66aa20dcea5be76328a52b.tar.bz2
* 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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/elfxx-mips.c64
2 files changed, 69 insertions, 3 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index ac7503e..4228d7c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index fa165d9..d2ba1cf 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -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: