inline bool
local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
Target_powerpc* ,
- Sized_relobj_file<size, big_endian>* ,
+ Sized_relobj_file<size, big_endian>* relobj,
unsigned int ,
Output_section* ,
const elfcpp::Rela<size, big_endian>& ,
// may be folded and we'll still keep function addresses distinct.
// That means no reloc is of concern here.
if (size == 64)
- return false;
- // For 32-bit, conservatively assume anything but calls to
+ {
+ Powerpc_relobj<size, big_endian>* ppcobj = static_cast
+ <Powerpc_relobj<size, big_endian>*>(relobj);
+ if (ppcobj->abiversion() == 1)
+ return false;
+ }
+ // For 32-bit and ELFv2, conservatively assume anything but calls to
// function code might be taking the address of the function.
return !is_branch_reloc(r_type);
}
inline bool
global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
Target_powerpc* ,
- Sized_relobj_file<size, big_endian>* ,
+ Sized_relobj_file<size, big_endian>* relobj,
unsigned int ,
Output_section* ,
const elfcpp::Rela<size, big_endian>& ,
{
// As above.
if (size == 64)
- return false;
+ {
+ Powerpc_relobj<size, big_endian>* ppcobj = static_cast
+ <Powerpc_relobj<size, big_endian>*>(relobj);
+ if (ppcobj->abiversion() == 1)
+ return false;
+ }
return !is_branch_reloc(r_type);
}
{
CHECK_NONE,
CHECK_SIGNED,
- CHECK_BITFIELD
+ CHECK_UNSIGNED,
+ CHECK_BITFIELD,
+ CHECK_LOW_INSN,
+ CHECK_HIGH_INSN
};
enum Status
template<int valsize>
static inline bool
- has_overflow_bitfield(Address value)
+ has_overflow_unsigned(Address value)
{
Address limit = static_cast<Address>(1) << ((valsize - 1) >> 1);
limit <<= ((valsize - 1) >> 1);
limit <<= ((valsize - 1) - 2 * ((valsize - 1) >> 1));
- return value > (limit << 1) - 1 && value + limit > (limit << 1) - 1;
+ return value > (limit << 1) - 1;
+ }
+
+ template<int valsize>
+ static inline bool
+ has_overflow_bitfield(Address value)
+ {
+ return (has_overflow_unsigned<valsize>(value)
+ && has_overflow_signed<valsize>(value));
}
template<int valsize>
if (has_overflow_signed<valsize>(value))
return STATUS_OVERFLOW;
}
+ else if (overflow == CHECK_UNSIGNED)
+ {
+ if (has_overflow_unsigned<valsize>(value))
+ return STATUS_OVERFLOW;
+ }
else if (overflow == CHECK_BITFIELD)
{
if (has_overflow_bitfield<valsize>(value))
}
// Do a simple RELA relocation
- template<int valsize>
+ template<int fieldsize, int valsize>
static inline Status
rela(unsigned char* view, Address value, Overflow_check overflow)
{
- typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<fieldsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
- elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
+ elfcpp::Swap<fieldsize, big_endian>::writeval(wv, value);
return overflowed<valsize>(value, overflow);
}
- template<int valsize>
+ template<int fieldsize, int valsize>
static inline Status
rela(unsigned char* view,
unsigned int right_shift,
- typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+ typename elfcpp::Valtype_base<fieldsize>::Valtype dst_mask,
Address value,
Overflow_check overflow)
{
- typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<fieldsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
- Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ Valtype val = elfcpp::Swap<fieldsize, big_endian>::readval(wv);
Valtype reloc = value >> right_shift;
val &= ~dst_mask;
reloc &= dst_mask;
- elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+ elfcpp::Swap<fieldsize, big_endian>::writeval(wv, val | reloc);
return overflowed<valsize>(value >> right_shift, overflow);
}
// Do a simple RELA relocation, unaligned.
- template<int valsize>
+ template<int fieldsize, int valsize>
static inline Status
rela_ua(unsigned char* view, Address value, Overflow_check overflow)
{
- elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, value);
+ elfcpp::Swap_unaligned<fieldsize, big_endian>::writeval(view, value);
return overflowed<valsize>(value, overflow);
}
- template<int valsize>
+ template<int fieldsize, int valsize>
static inline Status
rela_ua(unsigned char* view,
unsigned int right_shift,
- typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+ typename elfcpp::Valtype_base<fieldsize>::Valtype dst_mask,
Address value,
Overflow_check overflow)
{
- typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ typedef typename elfcpp::Swap_unaligned<fieldsize, big_endian>::Valtype
Valtype;
- Valtype val = elfcpp::Swap<valsize, big_endian>::readval(view);
+ Valtype val = elfcpp::Swap<fieldsize, big_endian>::readval(view);
Valtype reloc = value >> right_shift;
val &= ~dst_mask;
reloc &= dst_mask;
- elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, val | reloc);
+ elfcpp::Swap_unaligned<fieldsize, big_endian>::writeval(view, val | reloc);
return overflowed<valsize>(value >> right_shift, overflow);
}
// R_PPC64_ADDR64: (Symbol + Addend)
static inline void
addr64(unsigned char* view, Address value)
- { This::template rela<64>(view, value, CHECK_NONE); }
+ { This::template rela<64,64>(view, value, CHECK_NONE); }
// R_PPC64_UADDR64: (Symbol + Addend) unaligned
static inline void
addr64_u(unsigned char* view, Address value)
- { This::template rela_ua<64>(view, value, CHECK_NONE); }
+ { This::template rela_ua<64,64>(view, value, CHECK_NONE); }
// R_POWERPC_ADDR32: (Symbol + Addend)
static inline Status
addr32(unsigned char* view, Address value, Overflow_check overflow)
- { return This::template rela<32>(view, value, overflow); }
+ { return This::template rela<32,32>(view, value, overflow); }
// R_POWERPC_UADDR32: (Symbol + Addend) unaligned
static inline Status
addr32_u(unsigned char* view, Address value, Overflow_check overflow)
- { return This::template rela_ua<32>(view, value, overflow); }
+ { return This::template rela_ua<32,32>(view, value, overflow); }
// R_POWERPC_ADDR24: (Symbol + Addend) & 0x3fffffc
static inline Status
addr24(unsigned char* view, Address value, Overflow_check overflow)
{
- Status stat = This::template rela<32>(view, 0, 0x03fffffc, value, overflow);
+ Status stat = This::template rela<32,26>(view, 0, 0x03fffffc,
+ value, overflow);
if (overflow != CHECK_NONE && (value & 3) != 0)
stat = STATUS_OVERFLOW;
return stat;
// R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff
static inline Status
addr16(unsigned char* view, Address value, Overflow_check overflow)
- { return This::template rela<16>(view, value, overflow); }
+ { return This::template rela<16,16>(view, value, overflow); }
// R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff, unaligned
static inline Status
addr16_u(unsigned char* view, Address value, Overflow_check overflow)
- { return This::template rela_ua<16>(view, value, overflow); }
+ { return This::template rela_ua<16,16>(view, value, overflow); }
// R_POWERPC_ADDR16_DS: (Symbol + Addend) & 0xfffc
static inline Status
addr16_ds(unsigned char* view, Address value, Overflow_check overflow)
{
- Status stat = This::template rela<16>(view, 0, 0xfffc, value, overflow);
+ Status stat = This::template rela<16,16>(view, 0, 0xfffc, value, overflow);
if (overflow != CHECK_NONE && (value & 3) != 0)
stat = STATUS_OVERFLOW;
return stat;
// R_POWERPC_ADDR16_HI: ((Symbol + Addend) >> 16) & 0xffff
static inline void
addr16_hi(unsigned char* view, Address value)
- { This::template rela<16>(view, 16, 0xffff, value, CHECK_NONE); }
+ { This::template rela<16,16>(view, 16, 0xffff, value, CHECK_NONE); }
// R_POWERPC_ADDR16_HA: ((Symbol + Addend + 0x8000) >> 16) & 0xffff
static inline void
// R_POWERPC_ADDR16_HIGHER: ((Symbol + Addend) >> 32) & 0xffff
static inline void
addr16_hi2(unsigned char* view, Address value)
- { This::template rela<16>(view, 32, 0xffff, value, CHECK_NONE); }
+ { This::template rela<16,16>(view, 32, 0xffff, value, CHECK_NONE); }
// R_POWERPC_ADDR16_HIGHERA: ((Symbol + Addend + 0x8000) >> 32) & 0xffff
static inline void
// R_POWERPC_ADDR16_HIGHEST: ((Symbol + Addend) >> 48) & 0xffff
static inline void
addr16_hi3(unsigned char* view, Address value)
- { This::template rela<16>(view, 48, 0xffff, value, CHECK_NONE); }
+ { This::template rela<16,16>(view, 48, 0xffff, value, CHECK_NONE); }
// R_POWERPC_ADDR16_HIGHESTA: ((Symbol + Addend + 0x8000) >> 48) & 0xffff
static inline void
static inline Status
addr14(unsigned char* view, Address value, Overflow_check overflow)
{
- Status stat = This::template rela<32>(view, 0, 0xfffc, value, overflow);
+ Status stat = This::template rela<32,16>(view, 0, 0xfffc, value, overflow);
if (overflow != CHECK_NONE && (value & 3) != 0)
stat = STATUS_OVERFLOW;
return stat;
void
Powerpc_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
{
- Sized_relobj_file<size, big_endian>::do_read_symbols(sd);
+ this->base_read_symbols(sd);
if (size == 64)
{
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
}
}
-// Call Sized_dynobj::do_read_symbols to read the symbols then
+// Call Sized_dynobj::base_read_symbols to read the symbols then
// read .opd from a dynamic object, filling in opd_ent_ vector,
template<int size, bool big_endian>
void
Powerpc_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
{
- Sized_dynobj<size, big_endian>::do_read_symbols(sd);
+ this->base_read_symbols(sd);
if (size == 64)
{
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
// the stubbed branches.
Stub_control(int32_t size)
: state_(NO_GROUP), stub_group_size_(abs(size)),
- stub14_group_size_(abs(size)),
+ stub14_group_size_(abs(size) >> 10),
stubs_always_before_branch_(size < 0), suppress_size_errors_(false),
group_end_addr_(0), owner_(NULL), output_section_(NULL)
{
output_section()
{ return output_section_; }
+ void
+ set_output_and_owner(Output_section* o,
+ const Output_section::Input_section* i)
+ {
+ this->output_section_ = o;
+ this->owner_ = i;
+ }
+
private:
typedef enum
{
{
stub_table->init(stub_control.owner(),
stub_control.output_section());
+ stub_control.set_output_and_owner(*o, &*i);
stub_table = NULL;
}
if (stub_table == NULL)
/* libanl */
"getaddrinfo_a",
/* libgomp */
+ "GOMP_parallel",
"GOMP_parallel_start",
+ "GOMP_parallel_loop_static",
"GOMP_parallel_loop_static_start",
+ "GOMP_parallel_loop_dynamic",
"GOMP_parallel_loop_dynamic_start",
+ "GOMP_parallel_loop_guided",
"GOMP_parallel_loop_guided_start",
+ "GOMP_parallel_loop_runtime",
"GOMP_parallel_loop_runtime_start",
+ "GOMP_parallel_sections",
"GOMP_parallel_sections_start",
+ /* libgo */
+ "__go_go",
};
if (parameters->options().shared())
if (plt == this->glink_)
{
// See Output_data_glink::do_write() for glink contents.
- if (size == 64)
+ if (len == 0)
+ {
+ gold_assert(parameters->doing_static_link());
+ // Static linking may need stubs, to support ifunc and long
+ // branches. We need to create an output section for
+ // .eh_frame early in the link process, to have a place to
+ // attach stub .eh_frame info. We also need to have
+ // registered a CIE that matches the stub CIE. Both of
+ // these requirements are satisfied by creating an FDE and
+ // CIE for .glink, even though static linking will leave
+ // .glink zero length.
+ // ??? Hopefully generating an FDE with a zero address range
+ // won't confuse anything that consumes .eh_frame info.
+ }
+ else if (size == 64)
{
// There is one word before __glink_PLTresolve
address += 8;
// The first covers the branch table, the second
// __glink_PLTresolve at the end of glink.
off_t resolve_size = this->glink_->pltresolve_size;
- if (oview[9] == 0)
+ if (oview[9] == elfcpp::DW_CFA_nop)
len -= resolve_size;
else
{
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_2 = 0x3d820000;
static const uint32_t addis_12_12 = 0x3d8c0000;
static const uint32_t b = 0x48000000;
static const uint32_t bcl_20_31 = 0x429f0005;
{
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)
+ {
+ write_insn<big_endian>(p, addis_11_2 + ha(off));
+ p += 4;
+ write_insn<big_endian>(p, ld_12_11 + l(off));
+ p += 4;
+ }
+ else
+ {
+ write_insn<big_endian>(p, addis_12_2 + ha(off));
+ p += 4;
+ write_insn<big_endian>(p, ld_12_12 + l(off));
+ p += 4;
+ }
if (plt_load_toc
&& ha(off + 8 + 8 * static_chain) != ha(off))
{
}
else
{
- 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, addis_12_2 + ha(brltoff)), p += 4;
+ write_insn<big_endian>(p, ld_12_12 + l(brltoff)), p += 4;
}
write_insn<big_endian>(p, mtctr_12), p += 4;
write_insn<big_endian>(p, bctr);
if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type, target))
|| (size == 64 && is_ifunc && target->abiversion() < 2))
{
- if (gsym->may_need_copy_reloc())
+ if (!parameters->options().output_is_position_independent()
+ && gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type, target)))
{
- if (gsym->may_need_copy_reloc())
+ if (!parameters->options().output_is_position_independent()
+ && gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym,
Powerpc_relobj<size, big_endian>* const object
= static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
Address value = 0;
- bool has_plt_value = false;
+ bool has_stub_value = false;
unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
if ((gsym != NULL
? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
gold_assert(off != invalid_address);
value = stub_table->stub_address() + off;
}
- has_plt_value = true;
+ has_stub_value = true;
}
if (r_type == elfcpp::R_POWERPC_GOT16
else if (gsym != NULL
&& (r_type == elfcpp::R_POWERPC_REL24
|| r_type == elfcpp::R_PPC_PLTREL24)
- && has_plt_value)
+ && has_stub_value)
{
if (size == 64)
{
value = psymval->value(object, rela.get_r_addend());
}
}
- else if (!has_plt_value)
+ else if (!has_stub_value)
{
Address addend = 0;
unsigned int dest_shndx;
{
Address off = stub_table->find_long_branch_entry(object, value);
if (off != invalid_address)
- value = (stub_table->stub_address() + stub_table->plt_size()
- + off);
+ {
+ value = (stub_table->stub_address() + stub_table->plt_size()
+ + off);
+ has_stub_value = true;
+ }
}
}
}
}
typename Reloc::Overflow_check overflow = Reloc::CHECK_NONE;
+ elfcpp::Shdr<size, big_endian> shdr(relinfo->data_shdr);
switch (r_type)
{
case elfcpp::R_POWERPC_ADDR32:
overflow = Reloc::CHECK_SIGNED;
break;
- case elfcpp::R_POWERPC_ADDR24:
- case elfcpp::R_POWERPC_ADDR16:
case elfcpp::R_POWERPC_UADDR16:
- case elfcpp::R_PPC64_ADDR16_DS:
- case elfcpp::R_POWERPC_ADDR14:
- case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
- case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
overflow = Reloc::CHECK_BITFIELD;
break;
+ case elfcpp::R_POWERPC_ADDR16:
+ // We really should have three separate relocations,
+ // one for 16-bit data, one for insns with 16-bit signed fields,
+ // and one for insns with 16-bit unsigned fields.
+ overflow = Reloc::CHECK_BITFIELD;
+ if ((shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+ overflow = Reloc::CHECK_LOW_INSN;
+ break;
+
case elfcpp::R_POWERPC_ADDR16_HI:
case elfcpp::R_POWERPC_ADDR16_HA:
case elfcpp::R_POWERPC_GOT16_HI:
case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
case elfcpp::R_POWERPC_REL16_HI:
case elfcpp::R_POWERPC_REL16_HA:
- if (size == 32)
- break;
- case elfcpp::R_POWERPC_REL24:
- case elfcpp::R_PPC_PLTREL24:
- case elfcpp::R_PPC_LOCAL24PC:
+ if (size != 32)
+ overflow = Reloc::CHECK_HIGH_INSN;
+ break;
+
case elfcpp::R_POWERPC_REL16:
case elfcpp::R_PPC64_TOC16:
case elfcpp::R_POWERPC_GOT16:
case elfcpp::R_POWERPC_SECTOFF:
case elfcpp::R_POWERPC_TPREL16:
case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ overflow = Reloc::CHECK_LOW_INSN;
+ break;
+
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ case elfcpp::R_PPC64_ADDR16_DS:
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_PPC_LOCAL24PC:
case elfcpp::R_PPC64_TPREL16_DS:
case elfcpp::R_PPC64_DTPREL16_DS:
case elfcpp::R_PPC64_TOC16_DS:
case elfcpp::R_POWERPC_REL14:
case elfcpp::R_POWERPC_REL14_BRTAKEN:
case elfcpp::R_POWERPC_REL14_BRNTAKEN:
- case elfcpp::R_POWERPC_GOT_TLSGD16:
- case elfcpp::R_POWERPC_GOT_TLSLD16:
- case elfcpp::R_POWERPC_GOT_TPREL16:
- case elfcpp::R_POWERPC_GOT_DTPREL16:
overflow = Reloc::CHECK_SIGNED;
break;
}
+ if (overflow == Reloc::CHECK_LOW_INSN
+ || overflow == Reloc::CHECK_HIGH_INSN)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+
+ overflow = Reloc::CHECK_SIGNED;
+ if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+ overflow = Reloc::CHECK_BITFIELD;
+ else if (overflow == Reloc::CHECK_LOW_INSN
+ ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+ || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+ || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
+ : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
+ || (insn & (0x3f << 26)) == 25u << 26 /* oris */
+ || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+ overflow = Reloc::CHECK_UNSIGNED;
+ }
+
typename Powerpc_relocate_functions<size, big_endian>::Status status
= Powerpc_relocate_functions<size, big_endian>::STATUS_OK;
switch (r_type)
r_type);
break;
}
- if (status != Powerpc_relocate_functions<size, big_endian>::STATUS_OK)
- gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
- _("relocation overflow"));
+ if (status != Powerpc_relocate_functions<size, big_endian>::STATUS_OK
+ && (has_stub_value
+ || !(gsym != NULL
+ && gsym->is_weak_undefined()
+ && is_branch_reloc(r_type))))
+ {
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("relocation overflow"));
+ if (has_stub_value)
+ gold_info(_("try relinking with a smaller --stub-group-size"));
+ }
return true;
}