PowerPC64 ELFv2 support for gold.
elfcpp/ * powerpc.h (EF_PPC64_ABI): New enum constant. (STO_PPC64_LOCAL_BIT, STO_PPC64_LOCAL_MASK): Likewise. (ppc64_decode_local_entry): New function. (ppc64_encode_local_entry): Likewise. gold/ * powerpc.cc (Powerpc_relobj::abiversion, set_abiversion, ppc64_local_entry_offset, ppc64_local_entry_offset, do_read_symbols): New functions. (Powerpc_relobj::e_flags_, st_other_): New vars. (Powerpc_relobj::Powerpc_relobj): Call set_abiversion. (Powerpc_dynobj::abiversion, set_abiversion): New functions. (Powerpc_relobj::e_flags_): New var. (Target_powerpc::first_plt_entry_offset, plt_entry_size): Inline and adjust for ELFv2. (Target_powerpc::abiversion, set_abiversion, stk_toc): New functions. (Powerpc_relobj::do_find_special_sections): Check no .opd in ELFv2. (Powerpc_dynobj::do_find_special_sections): Likewise. (Target_powerpc::do_define_standard_symbols): Define ".TOC.". (Target_powerpc::Branch_info::make_stub): Adjust stub destination to ELFv2 local entry. (Target_powerpc::do_relax): No thread safe barriers needed for ELFv2. (Output_data_plt_powerpc::initial_plt_entry_size_, plt_entry_size): Delete. Replace all uses with first_plt_entry_offset() and plt_entry_size(). (Output_data_plt_powerpc::Output_data_plt_powerpc): Remove reserved_size parm. Update callers. (Output_data_plt_powerpc::entry_count): Update. (Output_data_plt_powerpc::first_plt_entry_offset): Make private and use Target_powerpc::first_plt_entry_offset(). (Output_data_plt_powerpc::get_plt_entry_size): Similarly and rename to plt_entry_size. (Output_data_plt_powerpc::add_ifunc_entry, add_local_ifunc_entry): Adjust reloc for ELFv2. (glink_eh_frame_fde_64): Rename to glink_eh_frame_fde_64v1. (glink_eh_frame_fde_64v2): New. (Stub_table::plt_call_size): Support ELFv2 sizing. (Output_data_glink::add_eh_frame): Use the new FDE. (Output_data_glink::set_final_data_size): Adjust for ELFv2 glink. (Stub_table::do_write): Write ELFv2 stubs and glink. (Target_powerpc::Relocate::relocate): Replaces nop after call with ld 2,24(1) and adjust local offset destination for ELFv2.
This commit is contained in:
parent
d4a95d4999
commit
b4f7960d53
@ -1,3 +1,10 @@
|
||||
2013-10-30 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.h (EF_PPC64_ABI): New enum constant.
|
||||
(STO_PPC64_LOCAL_BIT, STO_PPC64_LOCAL_MASK): Likewise.
|
||||
(ppc64_decode_local_entry): New function.
|
||||
(ppc64_encode_local_entry): Likewise.
|
||||
|
||||
2013-10-30 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.h (R_PPC64_ADDR16_HIGH, R_PPC64_ADDR16_HIGHA,
|
||||
|
@ -1,6 +1,6 @@
|
||||
// powerpc.h -- ELF definitions specific to EM_PPC and EM_PPC64 -*- C++ -*-
|
||||
|
||||
// Copyright 2008, 2010, 2012 Free Software Foundation, Inc.
|
||||
// Copyright 2008, 2010, 2012, 2013 Free Software Foundation, Inc.
|
||||
// Written by David S. Miller <davem@davemloft.net>.
|
||||
|
||||
// This file is part of elfcpp.
|
||||
@ -214,6 +214,59 @@ enum
|
||||
EF_PPC_RELOCATABLE_LIB = 0x00008000, // PowerPC -mrelocatable-lib flag. */
|
||||
};
|
||||
|
||||
// e_flags values defined for powerpc64
|
||||
enum
|
||||
{
|
||||
// ABI version
|
||||
// 1 for original function descriptor using ABI,
|
||||
// 2 for revised ABI without function descriptors,
|
||||
// 0 for unspecified or not using any features affected by the differences.
|
||||
EF_PPC64_ABI = 3
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
// The ELFv2 ABI uses three bits in the symbol st_other field of a
|
||||
// function definition to specify the number of instructions between a
|
||||
// function's global entry point and local entry point.
|
||||
// The global entry point is used when it is necessary to set up the
|
||||
// toc pointer (r2) for the function. Callers must enter the global
|
||||
// entry point with r12 set to the global entry point address. On
|
||||
// return from the function, r2 may have a different value to that
|
||||
// which it had on entry.
|
||||
// The local entry point is used when r2 is known to already be valid
|
||||
// for the function. There is no requirement on r12 when using the
|
||||
// local entry point, and on return r2 will contain the same value as
|
||||
// at entry.
|
||||
// A value of zero in these bits means that the function has a single
|
||||
// entry point with no requirement on r12 or r2, and that on return r2
|
||||
// will contain the same value as at entry.
|
||||
// Values of one and seven are reserved.
|
||||
|
||||
STO_PPC64_LOCAL_BIT = 5,
|
||||
STO_PPC64_LOCAL_MASK = 0xE0
|
||||
};
|
||||
|
||||
// 3 bit other field to bytes.
|
||||
static inline unsigned int
|
||||
ppc64_decode_local_entry(unsigned int other)
|
||||
{
|
||||
return ((1 << other) >> 2) << 2;
|
||||
}
|
||||
|
||||
// bytes to field value.
|
||||
static inline unsigned int
|
||||
ppc64_encode_local_entry(unsigned int val)
|
||||
{
|
||||
return (val >= 4 * 4
|
||||
? (val >= 8 * 4
|
||||
? (val >= 16 * 4 ? 6 : 5)
|
||||
: 4)
|
||||
: (val >= 2 * 4
|
||||
? 3
|
||||
: (val >= 1 * 4 ? 2 : 0)));
|
||||
}
|
||||
|
||||
} // End namespace elfcpp.
|
||||
|
||||
#endif // !defined(ELFCPP_POWERPC_H)
|
||||
|
@ -1,3 +1,43 @@
|
||||
2013-10-30 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.cc (Powerpc_relobj::abiversion, set_abiversion,
|
||||
ppc64_local_entry_offset, ppc64_local_entry_offset,
|
||||
do_read_symbols): New functions.
|
||||
(Powerpc_relobj::e_flags_, st_other_): New vars.
|
||||
(Powerpc_relobj::Powerpc_relobj): Call set_abiversion.
|
||||
(Powerpc_dynobj::abiversion, set_abiversion): New functions.
|
||||
(Powerpc_relobj::e_flags_): New var.
|
||||
(Target_powerpc::first_plt_entry_offset, plt_entry_size): Inline
|
||||
and adjust for ELFv2.
|
||||
(Target_powerpc::abiversion, set_abiversion, stk_toc): New functions.
|
||||
(Powerpc_relobj::do_find_special_sections): Check no .opd in ELFv2.
|
||||
(Powerpc_dynobj::do_find_special_sections): Likewise.
|
||||
(Target_powerpc::do_define_standard_symbols): Define ".TOC.".
|
||||
(Target_powerpc::Branch_info::make_stub): Adjust stub destination
|
||||
to ELFv2 local entry.
|
||||
(Target_powerpc::do_relax): No thread safe barriers needed for
|
||||
ELFv2.
|
||||
(Output_data_plt_powerpc::initial_plt_entry_size_,
|
||||
plt_entry_size): Delete. Replace all uses with
|
||||
first_plt_entry_offset() and plt_entry_size().
|
||||
(Output_data_plt_powerpc::Output_data_plt_powerpc): Remove
|
||||
reserved_size parm. Update callers.
|
||||
(Output_data_plt_powerpc::entry_count): Update.
|
||||
(Output_data_plt_powerpc::first_plt_entry_offset): Make private
|
||||
and use Target_powerpc::first_plt_entry_offset().
|
||||
(Output_data_plt_powerpc::get_plt_entry_size): Similarly and
|
||||
rename to plt_entry_size.
|
||||
(Output_data_plt_powerpc::add_ifunc_entry,
|
||||
add_local_ifunc_entry): Adjust reloc for ELFv2.
|
||||
(glink_eh_frame_fde_64): Rename to glink_eh_frame_fde_64v1.
|
||||
(glink_eh_frame_fde_64v2): New.
|
||||
(Stub_table::plt_call_size): Support ELFv2 sizing.
|
||||
(Output_data_glink::add_eh_frame): Use the new FDE.
|
||||
(Output_data_glink::set_final_data_size): Adjust for ELFv2 glink.
|
||||
(Stub_table::do_write): Write ELFv2 stubs and glink.
|
||||
(Target_powerpc::Relocate::relocate): Replaces nop after call
|
||||
with ld 2,24(1) and adjust local offset destination for ELFv2.
|
||||
|
||||
2013-10-30 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.cc (Target_powerpc::Scan::check_non_pic): Handle new relocs.
|
||||
|
538
gold/powerpc.cc
538
gold/powerpc.cc
@ -77,12 +77,19 @@ public:
|
||||
const typename elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
: Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
|
||||
special_(0), has_small_toc_reloc_(false), opd_valid_(false),
|
||||
opd_ent_(), access_from_map_(), has14_(), stub_table_()
|
||||
{ }
|
||||
opd_ent_(), access_from_map_(), has14_(), stub_table_(),
|
||||
e_flags_(ehdr.get_e_flags()), st_other_()
|
||||
{
|
||||
this->set_abiversion(0);
|
||||
}
|
||||
|
||||
~Powerpc_relobj()
|
||||
{ }
|
||||
|
||||
// Read the symbols then set up st_other vector.
|
||||
void
|
||||
do_read_symbols(Read_symbols_data*);
|
||||
|
||||
// The .got2 section shndx.
|
||||
unsigned int
|
||||
got2_shndx() const
|
||||
@ -268,6 +275,22 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
abiversion() const
|
||||
{ return this->e_flags_ & elfcpp::EF_PPC64_ABI; }
|
||||
|
||||
// Set ABI version for input and output
|
||||
void
|
||||
set_abiversion(int ver);
|
||||
|
||||
unsigned int
|
||||
ppc64_local_entry_offset(const Symbol* sym) const
|
||||
{ return elfcpp::ppc64_decode_local_entry(sym->nonvis() >> 3); }
|
||||
|
||||
unsigned int
|
||||
ppc64_local_entry_offset(unsigned int symndx) const
|
||||
{ return elfcpp::ppc64_decode_local_entry(this->st_other_[symndx] >> 5); }
|
||||
|
||||
private:
|
||||
struct Opd_ent
|
||||
{
|
||||
@ -321,6 +344,12 @@ private:
|
||||
|
||||
// The stub table to use for a given input section.
|
||||
std::vector<Stub_table<size, big_endian>*> stub_table_;
|
||||
|
||||
// Header e_flags
|
||||
elfcpp::Elf_Word e_flags_;
|
||||
|
||||
// ELF st_other field for local symbols.
|
||||
std::vector<unsigned char> st_other_;
|
||||
};
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -332,8 +361,10 @@ public:
|
||||
Powerpc_dynobj(const std::string& name, Input_file* input_file, off_t offset,
|
||||
const typename elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
: Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr),
|
||||
opd_shndx_(0), opd_ent_()
|
||||
{ }
|
||||
opd_shndx_(0), opd_ent_(), e_flags_(ehdr.get_e_flags())
|
||||
{
|
||||
this->set_abiversion(0);
|
||||
}
|
||||
|
||||
~Powerpc_dynobj()
|
||||
{ }
|
||||
@ -387,6 +418,14 @@ public:
|
||||
this->opd_ent_[ndx].off = value;
|
||||
}
|
||||
|
||||
int
|
||||
abiversion() const
|
||||
{ return this->e_flags_ & elfcpp::EF_PPC64_ABI; }
|
||||
|
||||
// Set ABI version for input and output.
|
||||
void
|
||||
set_abiversion(int ver);
|
||||
|
||||
private:
|
||||
// Used to specify extent of executable sections.
|
||||
struct Sec_info
|
||||
@ -424,6 +463,9 @@ private:
|
||||
// corresponding to the address. Note that in dynamic objects,
|
||||
// offset is *not* relative to the section.
|
||||
std::vector<Opd_ent> opd_ent_;
|
||||
|
||||
// Header e_flags
|
||||
elfcpp::Elf_Word e_flags_;
|
||||
};
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -679,11 +721,25 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
||||
|
||||
// Return the offset of the first non-reserved PLT entry.
|
||||
unsigned int
|
||||
first_plt_entry_offset() const;
|
||||
first_plt_entry_offset() const
|
||||
{
|
||||
if (size == 32)
|
||||
return 0;
|
||||
if (this->abiversion() >= 2)
|
||||
return 16;
|
||||
return 24;
|
||||
}
|
||||
|
||||
// Return the size of each PLT entry.
|
||||
unsigned int
|
||||
plt_entry_size() const;
|
||||
plt_entry_size() const
|
||||
{
|
||||
if (size == 32)
|
||||
return 4;
|
||||
if (this->abiversion() >= 2)
|
||||
return 8;
|
||||
return 24;
|
||||
}
|
||||
|
||||
// Add any special sections for this symbol to the gc work list.
|
||||
// For powerpc64, this adds the code section of a function
|
||||
@ -743,6 +799,24 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
||||
plt_thread_safe() const
|
||||
{ return this->plt_thread_safe_; }
|
||||
|
||||
int
|
||||
abiversion () const
|
||||
{ return this->processor_specific_flags() & elfcpp::EF_PPC64_ABI; }
|
||||
|
||||
void
|
||||
set_abiversion (int ver)
|
||||
{
|
||||
elfcpp::Elf_Word flags = this->processor_specific_flags();
|
||||
flags &= ~elfcpp::EF_PPC64_ABI;
|
||||
flags |= ver & elfcpp::EF_PPC64_ABI;
|
||||
this->set_processor_specific_flags(flags);
|
||||
}
|
||||
|
||||
// Offset to to save stack slot
|
||||
int
|
||||
stk_toc () const
|
||||
{ return this->abiversion() < 2 ? 40 : 24; }
|
||||
|
||||
private:
|
||||
|
||||
class Track_tls
|
||||
@ -1659,6 +1733,29 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Set ABI version for input and output.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Powerpc_relobj<size, big_endian>::set_abiversion(int ver)
|
||||
{
|
||||
this->e_flags_ |= ver;
|
||||
if (this->abiversion() != 0)
|
||||
{
|
||||
Target_powerpc<size, big_endian>* target =
|
||||
static_cast<Target_powerpc<size, big_endian>*>(
|
||||
parameters->sized_target<size, big_endian>());
|
||||
if (target->abiversion() == 0)
|
||||
target->set_abiversion(this->abiversion());
|
||||
else if (target->abiversion() != this->abiversion())
|
||||
gold_error(_("%s: ABI version %d is not compatible "
|
||||
"with ABI version %d output"),
|
||||
this->name().c_str(),
|
||||
this->abiversion(), target->abiversion());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Stash away the index of .got2 or .opd in a relocatable object, if
|
||||
// such a section exists.
|
||||
|
||||
@ -1680,6 +1777,14 @@ Powerpc_relobj<size, big_endian>::do_find_special_sections(
|
||||
{
|
||||
unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
|
||||
this->special_ = ndx;
|
||||
if (size == 64)
|
||||
{
|
||||
if (this->abiversion() == 0)
|
||||
this->set_abiversion(1);
|
||||
else if (this->abiversion() > 1)
|
||||
gold_error(_("%s: .opd invalid in abiv%d"),
|
||||
this->name().c_str(), this->abiversion());
|
||||
}
|
||||
}
|
||||
return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
|
||||
}
|
||||
@ -1790,6 +1895,69 @@ Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
|
||||
}
|
||||
}
|
||||
|
||||
// Read the symbols then set up st_other vector.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Powerpc_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
{
|
||||
Sized_relobj_file<size, big_endian>::do_read_symbols(sd);
|
||||
if (size == 64)
|
||||
{
|
||||
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
|
||||
const unsigned char* const pshdrs = sd->section_headers->data();
|
||||
const unsigned int loccount = this->do_local_symbol_count();
|
||||
if (loccount != 0)
|
||||
{
|
||||
this->st_other_.resize(loccount);
|
||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
off_t locsize = loccount * sym_size;
|
||||
const unsigned int symtab_shndx = this->symtab_shndx();
|
||||
const unsigned char *psymtab = pshdrs + symtab_shndx * shdr_size;
|
||||
typename elfcpp::Shdr<size, big_endian> shdr(psymtab);
|
||||
const unsigned char* psyms = this->get_view(shdr.get_sh_offset(),
|
||||
locsize, true, false);
|
||||
psyms += sym_size;
|
||||
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(psyms);
|
||||
unsigned char st_other = sym.get_st_other();
|
||||
this->st_other_[i] = st_other;
|
||||
if ((st_other & elfcpp::STO_PPC64_LOCAL_MASK) != 0)
|
||||
{
|
||||
if (this->abiversion() == 0)
|
||||
this->set_abiversion(2);
|
||||
else if (this->abiversion() < 2)
|
||||
gold_error(_("%s: local symbol %d has invalid st_other"
|
||||
" for ABI version 1"),
|
||||
this->name().c_str(), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Powerpc_dynobj<size, big_endian>::set_abiversion(int ver)
|
||||
{
|
||||
this->e_flags_ |= ver;
|
||||
if (this->abiversion() != 0)
|
||||
{
|
||||
Target_powerpc<size, big_endian>* target =
|
||||
static_cast<Target_powerpc<size, big_endian>*>(
|
||||
parameters->sized_target<size, big_endian>());
|
||||
if (target->abiversion() == 0)
|
||||
target->set_abiversion(this->abiversion());
|
||||
else if (target->abiversion() != this->abiversion())
|
||||
gold_error(_("%s: ABI version %d is not compatible "
|
||||
"with ABI version %d output"),
|
||||
this->name().c_str(),
|
||||
this->abiversion(), target->abiversion());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Call Sized_dynobj::do_read_symbols to read the symbols then
|
||||
// read .opd from a dynamic object, filling in opd_ent_ vector,
|
||||
|
||||
@ -1821,6 +1989,12 @@ Powerpc_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS
|
||||
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
|
||||
{
|
||||
if (this->abiversion() == 0)
|
||||
this->set_abiversion(1);
|
||||
else if (this->abiversion() > 1)
|
||||
gold_error(_("%s: .opd invalid in abiv%d"),
|
||||
this->name().c_str(), this->abiversion());
|
||||
|
||||
this->opd_shndx_ = (s - pshdrs) / shdr_size;
|
||||
this->opd_address_ = shdr.get_sh_addr();
|
||||
opd_size = convert_to_section_size_type(shdr.get_sh_size());
|
||||
@ -1937,6 +2111,26 @@ Target_powerpc<size, big_endian>::do_define_standard_symbols(
|
||||
0, false, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Define .TOC. as for 32-bit _GLOBAL_OFFSET_TABLE_
|
||||
Symbol *gotsym = symtab->lookup(".TOC.", NULL);
|
||||
if (gotsym != NULL && gotsym->is_undefined())
|
||||
{
|
||||
Target_powerpc<size, big_endian>* target =
|
||||
static_cast<Target_powerpc<size, big_endian>*>(
|
||||
parameters->sized_target<size, big_endian>());
|
||||
Output_data_got_powerpc<size, big_endian>* got
|
||||
= target->got_section(symtab, layout);
|
||||
symtab->define_in_output_data(".TOC.", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
got, 0x8000, 0,
|
||||
elfcpp::STT_OBJECT,
|
||||
elfcpp::STB_LOCAL,
|
||||
elfcpp::STV_HIDDEN, 0,
|
||||
false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up PowerPC target specific relobj.
|
||||
@ -2446,7 +2640,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int max_branch_offset;
|
||||
unsigned long max_branch_offset;
|
||||
if (this->r_type_ == elfcpp::R_POWERPC_REL14
|
||||
|| this->r_type_ == elfcpp::R_POWERPC_REL14_BRTAKEN
|
||||
|| this->r_type_ == elfcpp::R_POWERPC_REL14_BRNTAKEN)
|
||||
@ -2489,6 +2683,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
|
||||
to = symtab->compute_final_value<size>(gsym, &status);
|
||||
if (status != Symbol_table::CFVS_OK)
|
||||
return;
|
||||
to += this->object_->ppc64_local_entry_offset(gsym);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2503,6 +2698,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
|
||||
|| !symval.has_output_value())
|
||||
return;
|
||||
to = symval.value(this->object_, 0);
|
||||
to += this->object_->ppc64_local_entry_offset(this->r_sym_);
|
||||
}
|
||||
to += this->addend_;
|
||||
if (stub_table == NULL)
|
||||
@ -2545,8 +2741,12 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
|
||||
unsigned int prev_brlt_size = 0;
|
||||
if (pass == 1)
|
||||
{
|
||||
bool thread_safe = parameters->options().plt_thread_safe();
|
||||
if (size == 64 && !parameters->options().user_set_plt_thread_safe())
|
||||
bool thread_safe
|
||||
= this->abiversion() < 2 && parameters->options().plt_thread_safe();
|
||||
if (size == 64
|
||||
&& this->abiversion() < 2
|
||||
&& !thread_safe
|
||||
&& !parameters->options().user_set_plt_thread_safe())
|
||||
{
|
||||
static const char* const thread_starter[] =
|
||||
{
|
||||
@ -2758,12 +2958,10 @@ class Output_data_plt_powerpc : public Output_section_data_build
|
||||
|
||||
Output_data_plt_powerpc(Target_powerpc<size, big_endian>* targ,
|
||||
Reloc_section* plt_rel,
|
||||
unsigned int reserved_size,
|
||||
const char* name)
|
||||
: Output_section_data_build(size == 32 ? 4 : 8),
|
||||
rel_(plt_rel),
|
||||
targ_(targ),
|
||||
initial_plt_entry_size_(reserved_size),
|
||||
name_(name)
|
||||
{ }
|
||||
|
||||
@ -2790,20 +2988,10 @@ class Output_data_plt_powerpc : public Output_section_data_build
|
||||
{
|
||||
if (this->current_data_size() == 0)
|
||||
return 0;
|
||||
return ((this->current_data_size() - this->initial_plt_entry_size_)
|
||||
/ plt_entry_size);
|
||||
return ((this->current_data_size() - this->first_plt_entry_offset())
|
||||
/ this->plt_entry_size());
|
||||
}
|
||||
|
||||
// Return the offset of the first non-reserved PLT entry.
|
||||
unsigned int
|
||||
first_plt_entry_offset()
|
||||
{ return this->initial_plt_entry_size_; }
|
||||
|
||||
// Return the size of a PLT entry.
|
||||
static unsigned int
|
||||
get_plt_entry_size()
|
||||
{ return plt_entry_size; }
|
||||
|
||||
protected:
|
||||
void
|
||||
do_adjust_output_section(Output_section* os)
|
||||
@ -2817,8 +3005,22 @@ class Output_data_plt_powerpc : public Output_section_data_build
|
||||
{ mapfile->print_output_data(this, this->name_); }
|
||||
|
||||
private:
|
||||
// The size of an entry in the PLT.
|
||||
static const int plt_entry_size = size == 32 ? 4 : 24;
|
||||
// Return the offset of the first non-reserved PLT entry.
|
||||
unsigned int
|
||||
first_plt_entry_offset() const
|
||||
{
|
||||
// IPLT has no reserved entry.
|
||||
if (this->name_[3] == 'I')
|
||||
return 0;
|
||||
return this->targ_->first_plt_entry_offset();
|
||||
}
|
||||
|
||||
// Return the size of each PLT entry.
|
||||
unsigned int
|
||||
plt_entry_size() const
|
||||
{
|
||||
return this->targ_->plt_entry_size();
|
||||
}
|
||||
|
||||
// Write out the PLT data.
|
||||
void
|
||||
@ -2828,8 +3030,6 @@ class Output_data_plt_powerpc : public Output_section_data_build
|
||||
Reloc_section* rel_;
|
||||
// Allows access to .glink for do_write.
|
||||
Target_powerpc<size, big_endian>* targ_;
|
||||
// The size of the first reserved entry.
|
||||
int initial_plt_entry_size_;
|
||||
// What to report in map file.
|
||||
const char *name_;
|
||||
};
|
||||
@ -2849,7 +3049,7 @@ Output_data_plt_powerpc<size, big_endian>::add_entry(Symbol* gsym)
|
||||
gsym->set_needs_dynsym_entry();
|
||||
unsigned int dynrel = elfcpp::R_POWERPC_JMP_SLOT;
|
||||
this->rel_->add_global(gsym, dynrel, this, off, 0);
|
||||
off += plt_entry_size;
|
||||
off += this->plt_entry_size();
|
||||
this->set_current_data_size(off);
|
||||
}
|
||||
}
|
||||
@ -2865,10 +3065,10 @@ Output_data_plt_powerpc<size, big_endian>::add_ifunc_entry(Symbol* gsym)
|
||||
section_size_type off = this->current_data_size();
|
||||
gsym->set_plt_offset(off);
|
||||
unsigned int dynrel = elfcpp::R_POWERPC_IRELATIVE;
|
||||
if (size == 64)
|
||||
if (size == 64 && this->targ_->abiversion() < 2)
|
||||
dynrel = elfcpp::R_PPC64_JMP_IREL;
|
||||
this->rel_->add_symbolless_global_addend(gsym, dynrel, this, off, 0);
|
||||
off += plt_entry_size;
|
||||
off += this->plt_entry_size();
|
||||
this->set_current_data_size(off);
|
||||
}
|
||||
}
|
||||
@ -2886,11 +3086,11 @@ Output_data_plt_powerpc<size, big_endian>::add_local_ifunc_entry(
|
||||
section_size_type off = this->current_data_size();
|
||||
relobj->set_local_plt_offset(local_sym_index, off);
|
||||
unsigned int dynrel = elfcpp::R_POWERPC_IRELATIVE;
|
||||
if (size == 64)
|
||||
if (size == 64 && this->targ_->abiversion() < 2)
|
||||
dynrel = elfcpp::R_PPC64_JMP_IREL;
|
||||
this->rel_->add_symbolless_local_addend(relobj, local_sym_index, dynrel,
|
||||
this, off, 0);
|
||||
off += plt_entry_size;
|
||||
off += this->plt_entry_size();
|
||||
this->set_current_data_size(off);
|
||||
}
|
||||
}
|
||||
@ -2900,50 +3100,50 @@ static const uint32_t add_2_2_11 = 0x7c425a14;
|
||||
static const uint32_t add_3_3_2 = 0x7c631214;
|
||||
static const uint32_t add_3_3_13 = 0x7c636a14;
|
||||
static const uint32_t add_11_0_11 = 0x7d605a14;
|
||||
static const uint32_t add_12_2_11 = 0x7d825a14;
|
||||
static const uint32_t add_12_12_11 = 0x7d8c5a14;
|
||||
static const uint32_t add_11_2_11 = 0x7d625a14;
|
||||
static const uint32_t add_11_11_2 = 0x7d6b1214;
|
||||
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_12 = 0x398c0000;
|
||||
static const uint32_t addi_2_2 = 0x38420000;
|
||||
static const uint32_t addi_3_2 = 0x38620000;
|
||||
static const uint32_t addi_3_3 = 0x38630000;
|
||||
static const uint32_t addis_0_2 = 0x3c020000;
|
||||
static const uint32_t addis_0_13 = 0x3c0d0000;
|
||||
static const uint32_t addis_3_2 = 0x3c620000;
|
||||
static const uint32_t addis_3_13 = 0x3c6d0000;
|
||||
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_12 = 0x3d8c0000;
|
||||
static const uint32_t addis_12_2 = 0x3d820000;
|
||||
static const uint32_t addis_3_2 = 0x3c620000;
|
||||
static const uint32_t addis_3_13 = 0x3c6d0000;
|
||||
static const uint32_t b = 0x48000000;
|
||||
static const uint32_t bcl_20_31 = 0x429f0005;
|
||||
static const uint32_t bctr = 0x4e800420;
|
||||
static const uint32_t blr = 0x4e800020;
|
||||
static const uint32_t blrl = 0x4e800021;
|
||||
static const uint32_t bnectr_p4 = 0x4ce20420;
|
||||
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;
|
||||
static const uint32_t ld_0_1 = 0xe8010000;
|
||||
static const uint32_t ld_0_12 = 0xe80c0000;
|
||||
static const uint32_t ld_11_12 = 0xe96c0000;
|
||||
static const uint32_t ld_11_2 = 0xe9620000;
|
||||
static const uint32_t ld_2_1 = 0xe8410000;
|
||||
static const uint32_t ld_2_11 = 0xe84b0000;
|
||||
static const uint32_t ld_2_12 = 0xe84c0000;
|
||||
static const uint32_t ld_2_2 = 0xe8420000;
|
||||
static const uint32_t ld_2_11 = 0xe84b0000;
|
||||
static const uint32_t ld_11_2 = 0xe9620000;
|
||||
static const uint32_t ld_11_11 = 0xe96b0000;
|
||||
static const uint32_t ld_12_2 = 0xe9820000;
|
||||
static const uint32_t ld_12_11 = 0xe98b0000;
|
||||
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_11 = 0x3d600000;
|
||||
static const uint32_t lis_12 = 0x3d800000;
|
||||
static const uint32_t lvx_0_12_0 = 0x7c0c00ce;
|
||||
static const uint32_t lwz_0_12 = 0x800c0000;
|
||||
static const uint32_t lwz_11_11 = 0x816b0000;
|
||||
static const uint32_t lwz_11_30 = 0x817e0000;
|
||||
static const uint32_t lwz_12_12 = 0x818c0000;
|
||||
static const uint32_t lwzu_0_12 = 0x840c0000;
|
||||
static const uint32_t lvx_0_12_0 = 0x7c0c00ce;
|
||||
static const uint32_t mflr_0 = 0x7c0802a6;
|
||||
static const uint32_t mflr_11 = 0x7d6802a6;
|
||||
static const uint32_t mflr_12 = 0x7d8802a6;
|
||||
@ -2954,13 +3154,16 @@ static const uint32_t mtlr_0 = 0x7c0803a6;
|
||||
static const uint32_t mtlr_12 = 0x7d8803a6;
|
||||
static const uint32_t nop = 0x60000000;
|
||||
static const uint32_t ori_0_0_0 = 0x60000000;
|
||||
static const uint32_t srdi_0_0_2 = 0x7800f082;
|
||||
static const uint32_t std_0_1 = 0xf8010000;
|
||||
static const uint32_t std_0_12 = 0xf80c0000;
|
||||
static const uint32_t std_2_1 = 0xf8410000;
|
||||
static const uint32_t stfd_0_1 = 0xd8010000;
|
||||
static const uint32_t stvx_0_12_0 = 0x7c0c01ce;
|
||||
static const uint32_t sub_11_11_12 = 0x7d6c5850;
|
||||
static const uint32_t xor_11_11_11 = 0x7d6b5a78;
|
||||
static const uint32_t sub_12_12_11 = 0x7d8b6050;
|
||||
static const uint32_t xor_2_12_12 = 0x7d826278;
|
||||
static const uint32_t xor_11_12_12 = 0x7d8b6278;
|
||||
|
||||
// Write out the PLT.
|
||||
|
||||
@ -3019,7 +3222,6 @@ Target_powerpc<size, big_endian>::make_plt_section(Symbol_table* symtab,
|
||||
ORDER_DYNAMIC_PLT_RELOCS, false);
|
||||
this->plt_
|
||||
= new Output_data_plt_powerpc<size, big_endian>(this, plt_rel,
|
||||
size == 32 ? 0 : 24,
|
||||
"** PLT");
|
||||
layout->add_output_section_data(".plt",
|
||||
(size == 32
|
||||
@ -3049,7 +3251,7 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
|
||||
this->rela_dyn_->output_section()->add_output_section_data(iplt_rel);
|
||||
this->iplt_
|
||||
= new Output_data_plt_powerpc<size, big_endian>(this, iplt_rel,
|
||||
0, "** IPLT");
|
||||
"** IPLT");
|
||||
this->plt_->output_section()->add_output_section_data(this->iplt_);
|
||||
}
|
||||
}
|
||||
@ -3225,8 +3427,8 @@ const unsigned char Eh_cie<size>::eh_frame_cie[] =
|
||||
elfcpp::DW_CFA_def_cfa, 1, 0 // def_cfa: r1 offset 0.
|
||||
};
|
||||
|
||||
// Describe __glink_PLTresolve use of LR, 64-bit version.
|
||||
static const unsigned char glink_eh_frame_fde_64[] =
|
||||
// Describe __glink_PLTresolve use of LR, 64-bit version ABIv1.
|
||||
static const unsigned char glink_eh_frame_fde_64v1[] =
|
||||
{
|
||||
0, 0, 0, 0, // Replaced with offset to .glink.
|
||||
0, 0, 0, 0, // Replaced with size of .glink.
|
||||
@ -3237,6 +3439,18 @@ static const unsigned char glink_eh_frame_fde_64[] =
|
||||
elfcpp::DW_CFA_restore_extended, 65
|
||||
};
|
||||
|
||||
// Describe __glink_PLTresolve use of LR, 64-bit version ABIv2.
|
||||
static const unsigned char glink_eh_frame_fde_64v2[] =
|
||||
{
|
||||
0, 0, 0, 0, // Replaced with offset to .glink.
|
||||
0, 0, 0, 0, // Replaced with size of .glink.
|
||||
0, // Augmentation size.
|
||||
elfcpp::DW_CFA_advance_loc + 1,
|
||||
elfcpp::DW_CFA_register, 65, 0,
|
||||
elfcpp::DW_CFA_advance_loc + 4,
|
||||
elfcpp::DW_CFA_restore_extended, 65
|
||||
};
|
||||
|
||||
// Describe __glink_PLTresolve use of LR, 32-bit version.
|
||||
static const unsigned char glink_eh_frame_fde_32[] =
|
||||
{
|
||||
@ -3493,13 +3707,16 @@ class Stub_table : public Output_relaxed_input_section
|
||||
<const Powerpc_relobj<size, big_endian>*>(p->first.object_);
|
||||
got_addr += ppcobj->toc_base_offset();
|
||||
Address off = plt_addr - got_addr;
|
||||
bool static_chain = parameters->options().plt_static_chain();
|
||||
bool thread_safe = this->targ_->plt_thread_safe();
|
||||
unsigned int bytes = (4 * 5
|
||||
+ 4 * static_chain
|
||||
+ 8 * thread_safe
|
||||
+ 4 * (ha(off) != 0)
|
||||
+ 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
|
||||
unsigned int bytes = 4 * 4 + 4 * (ha(off) != 0);
|
||||
if (this->targ_->abiversion() < 2)
|
||||
{
|
||||
bool static_chain = parameters->options().plt_static_chain();
|
||||
bool thread_safe = this->targ_->plt_thread_safe();
|
||||
bytes += (4
|
||||
+ 4 * static_chain
|
||||
+ 8 * thread_safe
|
||||
+ 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
|
||||
}
|
||||
unsigned int align = 1 << parameters->options().plt_align();
|
||||
if (align > 1)
|
||||
bytes = (bytes + align - 1) & -align;
|
||||
@ -3805,11 +4022,20 @@ class Output_data_glink : public Output_section_data
|
||||
return;
|
||||
|
||||
if (size == 64)
|
||||
layout->add_eh_frame_for_plt(this,
|
||||
Eh_cie<64>::eh_frame_cie,
|
||||
sizeof (Eh_cie<64>::eh_frame_cie),
|
||||
glink_eh_frame_fde_64,
|
||||
sizeof (glink_eh_frame_fde_64));
|
||||
{
|
||||
if (this->targ_->abiversion() < 2)
|
||||
layout->add_eh_frame_for_plt(this,
|
||||
Eh_cie<64>::eh_frame_cie,
|
||||
sizeof (Eh_cie<64>::eh_frame_cie),
|
||||
glink_eh_frame_fde_64v1,
|
||||
sizeof (glink_eh_frame_fde_64v1));
|
||||
else
|
||||
layout->add_eh_frame_for_plt(this,
|
||||
Eh_cie<64>::eh_frame_cie,
|
||||
sizeof (Eh_cie<64>::eh_frame_cie),
|
||||
glink_eh_frame_fde_64v2,
|
||||
sizeof (glink_eh_frame_fde_64v2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 32-bit .glink can use the default since the CIE return
|
||||
@ -3869,9 +4095,13 @@ Output_data_glink<size, big_endian>::set_final_data_size()
|
||||
total += this->pltresolve_size;
|
||||
|
||||
// space for branch table
|
||||
total += 8 * count;
|
||||
if (count > 0x8000)
|
||||
total += 4 * (count - 0x8000);
|
||||
total += 4 * count;
|
||||
if (this->targ_->abiversion() < 2)
|
||||
{
|
||||
total += 4 * count;
|
||||
if (count > 0x8000)
|
||||
total += 4 * (count - 0x8000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3934,8 +4164,11 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
||||
cs->first.object_->name().c_str(),
|
||||
cs->first.sym_->demangled_name().c_str());
|
||||
|
||||
bool static_chain = parameters->options().plt_static_chain();
|
||||
bool thread_safe = this->targ_->plt_thread_safe();
|
||||
bool plt_load_toc = this->targ_->abiversion() < 2;
|
||||
bool static_chain
|
||||
= plt_load_toc && parameters->options().plt_static_chain();
|
||||
bool thread_safe
|
||||
= plt_load_toc && this->targ_->plt_thread_safe();
|
||||
bool use_fake_dep = false;
|
||||
Address cmp_branch_off = 0;
|
||||
if (thread_safe)
|
||||
@ -3962,47 +4195,78 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
||||
p = oview + cs->second;
|
||||
if (ha(off) != 0)
|
||||
{
|
||||
write_insn<big_endian>(p, std_2_1 + 40), p += 4;
|
||||
write_insn<big_endian>(p, addis_12_2 + ha(off)), p += 4;
|
||||
write_insn<big_endian>(p, ld_11_12 + l(off)), p += 4;
|
||||
if (ha(off + 8 + 8 * static_chain) != ha(off))
|
||||
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
||||
p += 4;
|
||||
write_insn<big_endian>(p, addis_11_2 + ha(off));
|
||||
p += 4;
|
||||
write_insn<big_endian>(p, ld_12_11 + l(off));
|
||||
p += 4;
|
||||
if (plt_load_toc
|
||||
&& ha(off + 8 + 8 * static_chain) != ha(off))
|
||||
{
|
||||
write_insn<big_endian>(p, addi_12_12 + l(off)), p += 4;
|
||||
write_insn<big_endian>(p, addi_11_11 + l(off));
|
||||
p += 4;
|
||||
off = 0;
|
||||
}
|
||||
write_insn<big_endian>(p, mtctr_11), p += 4;
|
||||
if (use_fake_dep)
|
||||
write_insn<big_endian>(p, mtctr_12);
|
||||
p += 4;
|
||||
if (plt_load_toc)
|
||||
{
|
||||
write_insn<big_endian>(p, xor_11_11_11), p += 4;
|
||||
write_insn<big_endian>(p, add_12_12_11), p += 4;
|
||||
if (use_fake_dep)
|
||||
{
|
||||
write_insn<big_endian>(p, xor_2_12_12);
|
||||
p += 4;
|
||||
write_insn<big_endian>(p, add_11_11_2);
|
||||
p += 4;
|
||||
}
|
||||
write_insn<big_endian>(p, ld_2_11 + l(off + 8));
|
||||
p += 4;
|
||||
if (static_chain)
|
||||
{
|
||||
write_insn<big_endian>(p, ld_11_11 + l(off + 16));
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
write_insn<big_endian>(p, ld_2_12 + l(off + 8)), p += 4;
|
||||
if (static_chain)
|
||||
write_insn<big_endian>(p, ld_11_12 + l(off + 16)), p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_insn<big_endian>(p, std_2_1 + 40), p += 4;
|
||||
write_insn<big_endian>(p, ld_11_2 + l(off)), p += 4;
|
||||
if (ha(off + 8 + 8 * static_chain) != ha(off))
|
||||
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
||||
p += 4;
|
||||
write_insn<big_endian>(p, ld_12_2 + l(off));
|
||||
p += 4;
|
||||
if (plt_load_toc
|
||||
&& ha(off + 8 + 8 * static_chain) != ha(off))
|
||||
{
|
||||
write_insn<big_endian>(p, addi_2_2 + l(off)), p += 4;
|
||||
write_insn<big_endian>(p, addi_2_2 + l(off));
|
||||
p += 4;
|
||||
off = 0;
|
||||
}
|
||||
write_insn<big_endian>(p, mtctr_11), p += 4;
|
||||
if (use_fake_dep)
|
||||
write_insn<big_endian>(p, mtctr_12);
|
||||
p += 4;
|
||||
if (plt_load_toc)
|
||||
{
|
||||
write_insn<big_endian>(p, xor_11_11_11), p += 4;
|
||||
write_insn<big_endian>(p, add_2_2_11), p += 4;
|
||||
if (use_fake_dep)
|
||||
{
|
||||
write_insn<big_endian>(p, xor_11_12_12);
|
||||
p += 4;
|
||||
write_insn<big_endian>(p, add_2_2_11);
|
||||
p += 4;
|
||||
}
|
||||
if (static_chain)
|
||||
{
|
||||
write_insn<big_endian>(p, ld_11_2 + l(off + 16));
|
||||
p += 4;
|
||||
}
|
||||
write_insn<big_endian>(p, ld_2_2 + l(off + 8));
|
||||
p += 4;
|
||||
}
|
||||
if (static_chain)
|
||||
write_insn<big_endian>(p, ld_11_2 + l(off + 16)), p += 4;
|
||||
write_insn<big_endian>(p, ld_2_2 + l(off + 8)), p += 4;
|
||||
}
|
||||
if (thread_safe && !use_fake_dep)
|
||||
{
|
||||
write_insn<big_endian>(p, cmpldi_2_0), p += 4;
|
||||
write_insn<big_endian>(p, bnectr_p4), p += 4;
|
||||
write_insn<big_endian>(p, cmpldi_2_0);
|
||||
p += 4;
|
||||
write_insn<big_endian>(p, bnectr_p4);
|
||||
p += 4;
|
||||
write_insn<big_endian>(p, b | (cmp_branch_off & 0x3fffffc));
|
||||
}
|
||||
else
|
||||
@ -4031,14 +4295,14 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
||||
Address brltoff = brlt_addr - got_addr;
|
||||
if (ha(brltoff) == 0)
|
||||
{
|
||||
write_insn<big_endian>(p, ld_11_2 + l(brltoff)), p += 4;
|
||||
write_insn<big_endian>(p, ld_12_2 + l(brltoff)), p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_insn<big_endian>(p, addis_12_2 + ha(brltoff)), p += 4;
|
||||
write_insn<big_endian>(p, ld_11_12 + l(brltoff)), p += 4;
|
||||
write_insn<big_endian>(p, addis_11_2 + ha(brltoff)), p += 4;
|
||||
write_insn<big_endian>(p, ld_12_11 + l(brltoff)), p += 4;
|
||||
}
|
||||
write_insn<big_endian>(p, mtctr_11), p += 4;
|
||||
write_insn<big_endian>(p, mtctr_12), p += 4;
|
||||
write_insn<big_endian>(p, bctr);
|
||||
}
|
||||
}
|
||||
@ -4180,16 +4444,34 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
|
||||
|
||||
elfcpp::Swap<64, big_endian>::writeval(p, pltoff), p += 8;
|
||||
|
||||
write_insn<big_endian>(p, mflr_12), p += 4;
|
||||
write_insn<big_endian>(p, bcl_20_31), p += 4;
|
||||
write_insn<big_endian>(p, mflr_11), p += 4;
|
||||
write_insn<big_endian>(p, ld_2_11 + l(-16)), p += 4;
|
||||
write_insn<big_endian>(p, mtlr_12), p += 4;
|
||||
write_insn<big_endian>(p, add_12_2_11), p += 4;
|
||||
write_insn<big_endian>(p, ld_11_12 + 0), p += 4;
|
||||
write_insn<big_endian>(p, ld_2_12 + 8), p += 4;
|
||||
write_insn<big_endian>(p, mtctr_11), p += 4;
|
||||
write_insn<big_endian>(p, ld_11_12 + 16), p += 4;
|
||||
if (this->targ_->abiversion() < 2)
|
||||
{
|
||||
write_insn<big_endian>(p, mflr_12), p += 4;
|
||||
write_insn<big_endian>(p, bcl_20_31), p += 4;
|
||||
write_insn<big_endian>(p, mflr_11), p += 4;
|
||||
write_insn<big_endian>(p, ld_2_11 + l(-16)), p += 4;
|
||||
write_insn<big_endian>(p, mtlr_12), p += 4;
|
||||
write_insn<big_endian>(p, add_11_2_11), p += 4;
|
||||
write_insn<big_endian>(p, ld_12_11 + 0), p += 4;
|
||||
write_insn<big_endian>(p, ld_2_11 + 8), p += 4;
|
||||
write_insn<big_endian>(p, mtctr_12), p += 4;
|
||||
write_insn<big_endian>(p, ld_11_11 + 16), p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_insn<big_endian>(p, mflr_0), p += 4;
|
||||
write_insn<big_endian>(p, bcl_20_31), p += 4;
|
||||
write_insn<big_endian>(p, mflr_11), p += 4;
|
||||
write_insn<big_endian>(p, ld_2_11 + l(-16)), p += 4;
|
||||
write_insn<big_endian>(p, mtlr_0), p += 4;
|
||||
write_insn<big_endian>(p, sub_12_12_11), p += 4;
|
||||
write_insn<big_endian>(p, add_11_2_11), p += 4;
|
||||
write_insn<big_endian>(p, addi_0_12 + l(-48)), p += 4;
|
||||
write_insn<big_endian>(p, ld_12_11 + 0), p += 4;
|
||||
write_insn<big_endian>(p, srdi_0_0_2), p += 4;
|
||||
write_insn<big_endian>(p, mtctr_12), p += 4;
|
||||
write_insn<big_endian>(p, ld_11_11 + 8), p += 4;
|
||||
}
|
||||
write_insn<big_endian>(p, bctr), p += 4;
|
||||
while (p < oview + this->pltresolve_size)
|
||||
write_insn<big_endian>(p, nop), p += 4;
|
||||
@ -4198,14 +4480,17 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
|
||||
uint32_t indx = 0;
|
||||
while (p < oview + oview_size)
|
||||
{
|
||||
if (indx < 0x8000)
|
||||
if (this->targ_->abiversion() < 2)
|
||||
{
|
||||
write_insn<big_endian>(p, li_0_0 + indx), p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_insn<big_endian>(p, lis_0_0 + hi(indx)), p += 4;
|
||||
write_insn<big_endian>(p, ori_0_0_0 + l(indx)), p += 4;
|
||||
if (indx < 0x8000)
|
||||
{
|
||||
write_insn<big_endian>(p, li_0_0 + indx), p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_insn<big_endian>(p, lis_0_0 + hi(indx)), p += 4;
|
||||
write_insn<big_endian>(p, ori_0_0_0 + l(indx)), p += 4;
|
||||
}
|
||||
}
|
||||
uint32_t branch_off = 8 - (p - oview);
|
||||
write_insn<big_endian>(p, b + (branch_off & 0x3fffffc)), p += 4;
|
||||
@ -4690,24 +4975,6 @@ Target_powerpc<size, big_endian>::plt_entry_count() const
|
||||
return this->plt_->entry_count();
|
||||
}
|
||||
|
||||
// Return the offset of the first non-reserved PLT entry.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned int
|
||||
Target_powerpc<size, big_endian>::first_plt_entry_offset() const
|
||||
{
|
||||
return this->plt_->first_plt_entry_offset();
|
||||
}
|
||||
|
||||
// Return the size of each PLT entry.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
unsigned int
|
||||
Target_powerpc<size, big_endian>::plt_entry_size() const
|
||||
{
|
||||
return Output_data_plt_powerpc<size, big_endian>::get_plt_entry_size();
|
||||
}
|
||||
|
||||
// Create a GOT entry for local dynamic __tls_get_addr calls.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -6403,7 +6670,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
&& (insn2 == nop
|
||||
|| insn2 == cror_15_15_15 || insn2 == cror_31_31_31))
|
||||
{
|
||||
elfcpp::Swap<32, big_endian>::writeval(wv + 1, ld_2_1 + 40);
|
||||
elfcpp::Swap<32, big_endian>::
|
||||
writeval(wv + 1, ld_2_1 + target->stk_toc());
|
||||
can_plt_call = true;
|
||||
}
|
||||
}
|
||||
@ -6695,6 +6963,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
if (r_type != elfcpp::R_PPC_PLTREL24)
|
||||
addend = rela.get_r_addend();
|
||||
value = psymval->value(object, addend);
|
||||
if (gsym != NULL)
|
||||
value += object->ppc64_local_entry_offset(gsym);
|
||||
else
|
||||
value += object->ppc64_local_entry_offset(r_sym);
|
||||
if (size == 64 && is_branch_reloc(r_type))
|
||||
value = target->symval_for_branch(relinfo->symtab, value,
|
||||
gsym, object, &dest_shndx);
|
||||
|
Loading…
Reference in New Issue
Block a user