aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2015-12-09 10:18:44 +1030
committerAlan Modra <amodra@gmail.com>2015-12-09 10:36:43 +1030
commite3a7574e2e06f975a4933d3f7e77af1d9189d9de (patch)
treea38b95b61e6ed7db09dbb57839fc5fabac0943b3
parent91a65d2fe88fabe2d553a0362b2f76034f820175 (diff)
downloadgdb-e3a7574e2e06f975a4933d3f7e77af1d9189d9de.zip
gdb-e3a7574e2e06f975a4933d3f7e77af1d9189d9de.tar.gz
gdb-e3a7574e2e06f975a4933d3f7e77af1d9189d9de.tar.bz2
[GOLD] Edit PowerPC64 ELFv2 function entry code
In an fixed position executable, the entry code does not need to be PIC and can thus lose a dependency on r12. * powerpc.cc (Target_powerpc::Relocate::relocate): Edit ELFv2 entry code. (Target_powerpc::relocate_relocs): Edit relocs to suit.
-rw-r--r--gold/ChangeLog6
-rw-r--r--gold/powerpc.cc68
2 files changed, 72 insertions, 2 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index be004cd..824296b 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,11 @@
2015-12-09 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (Target_powerpc::Relocate::relocate): Edit ELFv2
+ entry code.
+ (Target_powerpc::relocate_relocs): Edit relocs to suit.
+
+2015-12-09 Alan Modra <amodra@gmail.com>
+
* object.h (struct Relocate_info): Add "rr".
* reloc.h (Relocatable_relocs::set_strategy): New accessor.
* reloc.cc (Sized_relobj_file::do_relocate_sections): Init
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index f16faf7..71507fe 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -7027,6 +7027,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
typedef Powerpc_relocate_functions<size, big_endian> Reloc;
typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn;
+ typedef typename Reloc_types<elfcpp::SHT_RELA,
+ size, big_endian>::Reloc Reltype;
Powerpc_relobj<size, big_endian>* const object
= static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
Address value = 0;
@@ -7700,6 +7702,55 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
}
}
break;
+
+ case elfcpp::R_POWERPC_REL16_LO:
+ // If we are generating a non-PIC executable, edit
+ // 0: addis 2,12,.TOC.-0b@ha
+ // addi 2,2,.TOC.-0b@l
+ // used by ELFv2 global entry points to set up r2, to
+ // lis 2,.TOC.@ha
+ // addi 2,2,.TOC.@l
+ // if .TOC. is in range. */
+ if (value + address - 4 + 0x80008000 <= 0xffffffff
+ && relnum != 0
+ && preloc != NULL
+ && target->abiversion() >= 2
+ && !parameters->options().output_is_position_independent()
+ && gsym != NULL
+ && strcmp(gsym->name(), ".TOC.") == 0)
+ {
+ const int reloc_size
+ = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ Reltype prev_rela(preloc - reloc_size);
+ if ((prev_rela.get_r_info()
+ == elfcpp::elf_r_info<size>(r_sym,
+ elfcpp::R_POWERPC_REL16_HA))
+ && prev_rela.get_r_offset() + 4 == rela.get_r_offset()
+ && prev_rela.get_r_addend() + 4 == rela.get_r_addend())
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn1 = elfcpp::Swap<32, big_endian>::readval(iview - 1);
+ Insn insn2 = elfcpp::Swap<32, big_endian>::readval(iview);
+
+ if ((insn1 & 0xffff0000) == addis_2_12
+ && (insn2 & 0xffff0000) == addi_2_2)
+ {
+ insn1 = lis_2 + ha(value + address - 4);
+ elfcpp::Swap<32, big_endian>::writeval(iview - 1, insn1);
+ insn2 = addi_2_2 + l(value + address - 4);
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn2);
+ if (relinfo->rr)
+ {
+ relinfo->rr->set_strategy(relnum - 1,
+ Relocatable_relocs::RELOC_SPECIAL);
+ relinfo->rr->set_strategy(relnum,
+ Relocatable_relocs::RELOC_SPECIAL);
+ }
+ return true;
+ }
+ }
+ }
+ break;
}
}
@@ -8357,8 +8408,21 @@ Target_powerpc<size, big_endian>::relocate_relocs(
}
else if (strategy == Relocatable_relocs::RELOC_SPECIAL)
{
- if (addend >= 32768)
- addend += got2_addend;
+ if (size == 32)
+ {
+ if (addend >= 32768)
+ addend += got2_addend;
+ }
+ else if (r_type == elfcpp::R_POWERPC_REL16_HA)
+ {
+ r_type = elfcpp::R_POWERPC_ADDR16_HA;
+ addend -= 2 * big_endian;
+ }
+ else if (r_type == elfcpp::R_POWERPC_REL16_LO)
+ {
+ r_type = elfcpp::R_POWERPC_ADDR16_LO;
+ addend -= 2 * big_endian + 4;
+ }
}
else
gold_unreachable();