[GOLD] Add PowerPC64 -fsplit-stack support
PowerPC64 ELFv1 requires a tweak to find_functions in order to return code addresses, rather than OPD entry addresses. * reloc.cc (Sized_relobj_file::find_functions): Use function_location. * powerpc.cc (Target_powerpc::do_calls_non_split): New function. (addi_12_1, addis_2_12, addis_12_1, cmpld_7_12_0): New constants. (lis_0): Rename from lis_0_0.
This commit is contained in:
parent
36de76f9cc
commit
bbec1a5db7
|
@ -1,3 +1,10 @@
|
|||
2015-05-16 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* reloc.cc (Sized_relobj_file::find_functions): Use function_location.
|
||||
* powerpc.cc (Target_powerpc::do_calls_non_split): New function.
|
||||
(addi_12_1, addis_2_12, addis_12_1, cmpld_7_12_0): New constants.
|
||||
(lis_0): Rename from lis_0_0.
|
||||
|
||||
2015-04-29 Cary Coutant <cary@google.com>
|
||||
Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
|
||||
|
||||
|
|
122
gold/powerpc.cc
122
gold/powerpc.cc
|
@ -624,6 +624,13 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
|||
do_can_check_for_function_pointers() const
|
||||
{ return true; }
|
||||
|
||||
// Adjust -fsplit-stack code which calls non-split-stack code.
|
||||
void
|
||||
do_calls_non_split(Relobj* object, unsigned int shndx,
|
||||
section_offset_type fnoffset, section_size_type fnsize,
|
||||
unsigned char* view, section_size_type view_size,
|
||||
std::string* from, std::string* to) const;
|
||||
|
||||
// Relocate a section.
|
||||
void
|
||||
relocate_section(const Relocate_info<size, big_endian>*,
|
||||
|
@ -3175,12 +3182,15 @@ static const uint32_t addi_0_12 = 0x380c0000;
|
|||
static const uint32_t addi_2_2 = 0x38420000;
|
||||
static const uint32_t addi_3_3 = 0x38630000;
|
||||
static const uint32_t addi_11_11 = 0x396b0000;
|
||||
static const uint32_t addi_12_1 = 0x39810000;
|
||||
static const uint32_t addi_12_12 = 0x398c0000;
|
||||
static const uint32_t addis_0_2 = 0x3c020000;
|
||||
static const uint32_t addis_0_13 = 0x3c0d0000;
|
||||
static const uint32_t addis_2_12 = 0x3c4c0000;
|
||||
static const uint32_t addis_11_2 = 0x3d620000;
|
||||
static const uint32_t addis_11_11 = 0x3d6b0000;
|
||||
static const uint32_t addis_11_30 = 0x3d7e0000;
|
||||
static const uint32_t addis_12_1 = 0x3d810000;
|
||||
static const uint32_t addis_12_2 = 0x3d820000;
|
||||
static const uint32_t addis_12_12 = 0x3d8c0000;
|
||||
static const uint32_t b = 0x48000000;
|
||||
|
@ -3188,6 +3198,7 @@ static const uint32_t bcl_20_31 = 0x429f0005;
|
|||
static const uint32_t bctr = 0x4e800420;
|
||||
static const uint32_t blr = 0x4e800020;
|
||||
static const uint32_t bnectr_p4 = 0x4ce20420;
|
||||
static const uint32_t cmpld_7_12_0 = 0x7fac0040;
|
||||
static const uint32_t cmpldi_2_0 = 0x28220000;
|
||||
static const uint32_t cror_15_15_15 = 0x4def7b82;
|
||||
static const uint32_t cror_31_31_31 = 0x4ffffb82;
|
||||
|
@ -3204,7 +3215,7 @@ static const uint32_t ld_12_12 = 0xe98c0000;
|
|||
static const uint32_t lfd_0_1 = 0xc8010000;
|
||||
static const uint32_t li_0_0 = 0x38000000;
|
||||
static const uint32_t li_12_0 = 0x39800000;
|
||||
static const uint32_t lis_0_0 = 0x3c000000;
|
||||
static const uint32_t lis_0 = 0x3c000000;
|
||||
static const uint32_t lis_11 = 0x3d600000;
|
||||
static const uint32_t lis_12 = 0x3d800000;
|
||||
static const uint32_t lvx_0_12_0 = 0x7c0c00ce;
|
||||
|
@ -4619,7 +4630,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
|
|||
}
|
||||
else
|
||||
{
|
||||
write_insn<big_endian>(p, lis_0_0 + hi(indx)), p += 4;
|
||||
write_insn<big_endian>(p, lis_0 + hi(indx)), p += 4;
|
||||
write_insn<big_endian>(p, ori_0_0_0 + l(indx)), p += 4;
|
||||
}
|
||||
}
|
||||
|
@ -6479,6 +6490,113 @@ Target_powerpc<size, big_endian>::do_function_location(
|
|||
}
|
||||
}
|
||||
|
||||
// FNOFFSET in section SHNDX in OBJECT is the start of a function
|
||||
// compiled with -fsplit-stack. The function calls non-split-stack
|
||||
// code. Change the function to ensure it has enough stack space to
|
||||
// call some random function.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Target_powerpc<size, big_endian>::do_calls_non_split(
|
||||
Relobj* object,
|
||||
unsigned int shndx,
|
||||
section_offset_type fnoffset,
|
||||
section_size_type fnsize,
|
||||
unsigned char* view,
|
||||
section_size_type view_size,
|
||||
std::string* from,
|
||||
std::string* to) const
|
||||
{
|
||||
// 32-bit not supported.
|
||||
if (size == 32)
|
||||
{
|
||||
// warn
|
||||
Target::do_calls_non_split(object, shndx, fnoffset, fnsize,
|
||||
view, view_size, from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
// The function always starts with
|
||||
// ld %r0,-0x7000-64(%r13) # tcbhead_t.__private_ss
|
||||
// addis %r12,%r1,-allocate@ha
|
||||
// addi %r12,%r12,-allocate@l
|
||||
// cmpld %r12,%r0
|
||||
// but note that the addis or addi may be replaced with a nop
|
||||
|
||||
unsigned char *entry = view + fnoffset;
|
||||
uint32_t insn = elfcpp::Swap<32, big_endian>::readval(entry);
|
||||
|
||||
if ((insn & 0xffff0000) == addis_2_12)
|
||||
{
|
||||
/* Skip ELFv2 global entry code. */
|
||||
entry += 8;
|
||||
insn = elfcpp::Swap<32, big_endian>::readval(entry);
|
||||
}
|
||||
|
||||
unsigned char *pinsn = entry;
|
||||
bool ok = false;
|
||||
const uint32_t ld_private_ss = 0xe80d8fc0;
|
||||
if (insn == ld_private_ss)
|
||||
{
|
||||
int32_t allocate = 0;
|
||||
while (1)
|
||||
{
|
||||
pinsn += 4;
|
||||
insn = elfcpp::Swap<32, big_endian>::readval(pinsn);
|
||||
if ((insn & 0xffff0000) == addis_12_1)
|
||||
allocate += (insn & 0xffff) << 16;
|
||||
else if ((insn & 0xffff0000) == addi_12_1
|
||||
|| (insn & 0xffff0000) == addi_12_12)
|
||||
allocate += ((insn & 0xffff) ^ 0x8000) - 0x8000;
|
||||
else if (insn != nop)
|
||||
break;
|
||||
}
|
||||
if (insn == cmpld_7_12_0 && pinsn == entry + 12)
|
||||
{
|
||||
int extra = parameters->options().split_stack_adjust_size();
|
||||
allocate -= extra;
|
||||
if (allocate >= 0 || extra < 0)
|
||||
{
|
||||
object->error(_("split-stack stack size overflow at "
|
||||
"section %u offset %0zx"),
|
||||
shndx, static_cast<size_t>(fnoffset));
|
||||
return;
|
||||
}
|
||||
pinsn = entry + 4;
|
||||
insn = addis_12_1 | (((allocate + 0x8000) >> 16) & 0xffff);
|
||||
if (insn != addis_12_1)
|
||||
{
|
||||
elfcpp::Swap<32, big_endian>::writeval(pinsn, insn);
|
||||
pinsn += 4;
|
||||
insn = addi_12_12 | (allocate & 0xffff);
|
||||
if (insn != addi_12_12)
|
||||
{
|
||||
elfcpp::Swap<32, big_endian>::writeval(pinsn, insn);
|
||||
pinsn += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
insn = addi_12_1 | (allocate & 0xffff);
|
||||
elfcpp::Swap<32, big_endian>::writeval(pinsn, insn);
|
||||
pinsn += 4;
|
||||
}
|
||||
if (pinsn != entry + 12)
|
||||
elfcpp::Swap<32, big_endian>::writeval(pinsn, nop);
|
||||
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
if (!object->has_no_split_stack())
|
||||
object->error(_("failed to match split-stack sequence at "
|
||||
"section %u offset %0zx"),
|
||||
shndx, static_cast<size_t>(fnoffset));
|
||||
}
|
||||
}
|
||||
|
||||
// Scan relocations for a section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
|
|
|
@ -1415,13 +1415,21 @@ Sized_relobj_file<size, big_endian>::find_functions(
|
|||
continue;
|
||||
|
||||
bool is_ordinary;
|
||||
unsigned int sym_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
|
||||
&is_ordinary);
|
||||
if (!is_ordinary || sym_shndx != shndx)
|
||||
Symbol_location loc;
|
||||
loc.shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
|
||||
&is_ordinary);
|
||||
if (!is_ordinary)
|
||||
continue;
|
||||
|
||||
loc.object = this;
|
||||
loc.offset = isym.get_st_value();
|
||||
parameters->target().function_location(&loc);
|
||||
|
||||
if (loc.shndx != shndx)
|
||||
continue;
|
||||
|
||||
section_offset_type value =
|
||||
convert_to_section_size_type(isym.get_st_value());
|
||||
convert_to_section_size_type(loc.offset);
|
||||
section_size_type fnsize =
|
||||
convert_to_section_size_type(isym.get_st_size());
|
||||
|
||||
|
|
Loading…
Reference in New Issue