From 0fdc1bf12541e30f9a66aa20dcea5be76328a52b Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Fri, 11 Apr 2003 01:56:49 +0000 Subject: [PATCH] * 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. --- bfd/ChangeLog | 8 ++++++ bfd/elfxx-mips.c | 64 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ac7503ec433..4228d7c44e7 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2003-04-10 Alexandre Oliva + + * 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 * 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 fa165d926ef..d2ba1cf8c23 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: -- 2.30.2