This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[GOLD] Edit PowerPC64 ELFv2 function entry code
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Wed, 25 Nov 2015 12:10:26 +1030
- Subject: [GOLD] Edit PowerPC64 ELFv2 function entry code
- Authentication-results: sourceware.org; auth=none
In an fixed position executable, the entry code does not need to be
PIC and can thus lose a dependency on r12.
This makes use of the new infrastructure added by the previous patch.
* powerpc.cc (Target_powerpc::Relocate::relocate): Edit ELFv2
entry code.
(Target_powerpc::relocate_relocs): Edit relocs to suit.
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index c1a6213..6e2c3d3 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -6995,7 +6995,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
Target_powerpc* target,
Output_section* os,
size_t relnum,
- const unsigned char*,
+ const unsigned char* preloc,
const elfcpp::Rela<size, big_endian>& rela,
unsigned int r_type,
const Sized_symbol<size>* gsym,
@@ -7003,7 +7003,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
unsigned char* view,
Address address,
section_size_type view_size,
- Relocatable_relocs*)
+ Relocatable_relocs* rr)
{
if (view == NULL)
return true;
@@ -7025,6 +7025,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;
@@ -7656,6 +7658,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 (rr)
+ {
+ rr->set_strategy(relnum - 1,
+ Relocatable_relocs::RELOC_SPECIAL);
+ rr->set_strategy(relnum,
+ Relocatable_relocs::RELOC_SPECIAL);
+ }
+ return true;
+ }
+ }
+ }
+ break;
}
}
@@ -8316,8 +8367,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();
--
Alan Modra
Australia Development Lab, IBM