PPC gold doesn't check for overflow properly
Corrects overflow test for rel14, addr14, rel24, addr24 branch relocs, and prints an information message to give a hint as to how a branch that can't reach a stub might be cured. bfd/ * elf64-ppc.c (group_sections): Init stub14_group_size from --stub-group-size parameter divided by 1024. gold/ * powerpc.cc (Stub_control::Stub_control): Init stub14_group_size_ from --stub-group-size parameter divided by 1024. (Powerpc_relocate_functions::rela, rela_ua): Add fieldsize template parameter. Update all uses. (Target_powerpc::Relocate::relocate): Rename has_plt_value to has_stub_value. Set for long branches. Don't report overflow for branch to undefined weak symbols. Print info message on overflowing branch to stub.
This commit is contained in:
parent
1e269e9b8f
commit
0cfb071748
@ -1,3 +1,8 @@
|
|||||||
|
2014-11-20 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* elf64-ppc.c (group_sections): Init stub14_group_size from
|
||||||
|
--stub-group-size parameter divided by 1024.
|
||||||
|
|
||||||
2014-11-20 Alan Modra <amodra@gmail.com>
|
2014-11-20 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
* elf32-ppc.c (ppc_elf_relax_section): Correct ppc476 workaround
|
* elf32-ppc.c (ppc_elf_relax_section): Correct ppc476 workaround
|
||||||
|
@ -11805,7 +11805,7 @@ group_sections (struct ppc_link_hash_table *htab,
|
|||||||
bfd_boolean suppress_size_errors;
|
bfd_boolean suppress_size_errors;
|
||||||
|
|
||||||
suppress_size_errors = FALSE;
|
suppress_size_errors = FALSE;
|
||||||
stub14_group_size = stub_group_size;
|
stub14_group_size = stub_group_size >> 10;
|
||||||
if (stub_group_size == 1)
|
if (stub_group_size == 1)
|
||||||
{
|
{
|
||||||
/* Default values. */
|
/* Default values. */
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2014-11-20 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* powerpc.cc (Stub_control::Stub_control): Init stub14_group_size_
|
||||||
|
from --stub-group-size parameter divided by 1024.
|
||||||
|
(Powerpc_relocate_functions::rela, rela_ua): Add fieldsize
|
||||||
|
template parameter. Update all uses.
|
||||||
|
(Target_powerpc::Relocate::relocate): Rename has_plt_value to
|
||||||
|
has_stub_value. Set for long branches. Don't report overflow for
|
||||||
|
branch to undefined weak symbols. Print info message on
|
||||||
|
overflowing branch to stub.
|
||||||
|
|
||||||
2014-11-20 Alan Modra <amodra@gmail.com>
|
2014-11-20 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
* powerpc.cc (Target_powerpc::do_relax): Add __go_go to thread_starters.
|
* powerpc.cc (Target_powerpc::do_relax): Add __go_go to thread_starters.
|
||||||
|
@ -1524,58 +1524,58 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do a simple RELA relocation
|
// Do a simple RELA relocation
|
||||||
template<int valsize>
|
template<int fieldsize, int valsize>
|
||||||
static inline Status
|
static inline Status
|
||||||
rela(unsigned char* view, Address value, Overflow_check overflow)
|
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);
|
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);
|
return overflowed<valsize>(value, overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int valsize>
|
template<int fieldsize, int valsize>
|
||||||
static inline Status
|
static inline Status
|
||||||
rela(unsigned char* view,
|
rela(unsigned char* view,
|
||||||
unsigned int right_shift,
|
unsigned int right_shift,
|
||||||
typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
|
typename elfcpp::Valtype_base<fieldsize>::Valtype dst_mask,
|
||||||
Address value,
|
Address value,
|
||||||
Overflow_check overflow)
|
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* 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;
|
Valtype reloc = value >> right_shift;
|
||||||
val &= ~dst_mask;
|
val &= ~dst_mask;
|
||||||
reloc &= 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);
|
return overflowed<valsize>(value >> right_shift, overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a simple RELA relocation, unaligned.
|
// Do a simple RELA relocation, unaligned.
|
||||||
template<int valsize>
|
template<int fieldsize, int valsize>
|
||||||
static inline Status
|
static inline Status
|
||||||
rela_ua(unsigned char* view, Address value, Overflow_check overflow)
|
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);
|
return overflowed<valsize>(value, overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int valsize>
|
template<int fieldsize, int valsize>
|
||||||
static inline Status
|
static inline Status
|
||||||
rela_ua(unsigned char* view,
|
rela_ua(unsigned char* view,
|
||||||
unsigned int right_shift,
|
unsigned int right_shift,
|
||||||
typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
|
typename elfcpp::Valtype_base<fieldsize>::Valtype dst_mask,
|
||||||
Address value,
|
Address value,
|
||||||
Overflow_check overflow)
|
Overflow_check overflow)
|
||||||
{
|
{
|
||||||
typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
|
typedef typename elfcpp::Swap_unaligned<fieldsize, big_endian>::Valtype
|
||||||
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;
|
Valtype reloc = value >> right_shift;
|
||||||
val &= ~dst_mask;
|
val &= ~dst_mask;
|
||||||
reloc &= 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);
|
return overflowed<valsize>(value >> right_shift, overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1583,28 +1583,29 @@ public:
|
|||||||
// R_PPC64_ADDR64: (Symbol + Addend)
|
// R_PPC64_ADDR64: (Symbol + Addend)
|
||||||
static inline void
|
static inline void
|
||||||
addr64(unsigned char* view, Address value)
|
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
|
// R_PPC64_UADDR64: (Symbol + Addend) unaligned
|
||||||
static inline void
|
static inline void
|
||||||
addr64_u(unsigned char* view, Address value)
|
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)
|
// R_POWERPC_ADDR32: (Symbol + Addend)
|
||||||
static inline Status
|
static inline Status
|
||||||
addr32(unsigned char* view, Address value, Overflow_check overflow)
|
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
|
// R_POWERPC_UADDR32: (Symbol + Addend) unaligned
|
||||||
static inline Status
|
static inline Status
|
||||||
addr32_u(unsigned char* view, Address value, Overflow_check overflow)
|
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
|
// R_POWERPC_ADDR24: (Symbol + Addend) & 0x3fffffc
|
||||||
static inline Status
|
static inline Status
|
||||||
addr24(unsigned char* view, Address value, Overflow_check overflow)
|
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)
|
if (overflow != CHECK_NONE && (value & 3) != 0)
|
||||||
stat = STATUS_OVERFLOW;
|
stat = STATUS_OVERFLOW;
|
||||||
return stat;
|
return stat;
|
||||||
@ -1613,18 +1614,18 @@ public:
|
|||||||
// R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff
|
// R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff
|
||||||
static inline Status
|
static inline Status
|
||||||
addr16(unsigned char* view, Address value, Overflow_check overflow)
|
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
|
// R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff, unaligned
|
||||||
static inline Status
|
static inline Status
|
||||||
addr16_u(unsigned char* view, Address value, Overflow_check overflow)
|
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
|
// R_POWERPC_ADDR16_DS: (Symbol + Addend) & 0xfffc
|
||||||
static inline Status
|
static inline Status
|
||||||
addr16_ds(unsigned char* view, Address value, Overflow_check overflow)
|
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)
|
if (overflow != CHECK_NONE && (value & 3) != 0)
|
||||||
stat = STATUS_OVERFLOW;
|
stat = STATUS_OVERFLOW;
|
||||||
return stat;
|
return stat;
|
||||||
@ -1633,7 +1634,7 @@ public:
|
|||||||
// R_POWERPC_ADDR16_HI: ((Symbol + Addend) >> 16) & 0xffff
|
// R_POWERPC_ADDR16_HI: ((Symbol + Addend) >> 16) & 0xffff
|
||||||
static inline void
|
static inline void
|
||||||
addr16_hi(unsigned char* view, Address value)
|
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
|
// R_POWERPC_ADDR16_HA: ((Symbol + Addend + 0x8000) >> 16) & 0xffff
|
||||||
static inline void
|
static inline void
|
||||||
@ -1643,7 +1644,7 @@ public:
|
|||||||
// R_POWERPC_ADDR16_HIGHER: ((Symbol + Addend) >> 32) & 0xffff
|
// R_POWERPC_ADDR16_HIGHER: ((Symbol + Addend) >> 32) & 0xffff
|
||||||
static inline void
|
static inline void
|
||||||
addr16_hi2(unsigned char* view, Address value)
|
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
|
// R_POWERPC_ADDR16_HIGHERA: ((Symbol + Addend + 0x8000) >> 32) & 0xffff
|
||||||
static inline void
|
static inline void
|
||||||
@ -1653,7 +1654,7 @@ public:
|
|||||||
// R_POWERPC_ADDR16_HIGHEST: ((Symbol + Addend) >> 48) & 0xffff
|
// R_POWERPC_ADDR16_HIGHEST: ((Symbol + Addend) >> 48) & 0xffff
|
||||||
static inline void
|
static inline void
|
||||||
addr16_hi3(unsigned char* view, Address value)
|
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
|
// R_POWERPC_ADDR16_HIGHESTA: ((Symbol + Addend + 0x8000) >> 48) & 0xffff
|
||||||
static inline void
|
static inline void
|
||||||
@ -1664,7 +1665,7 @@ public:
|
|||||||
static inline Status
|
static inline Status
|
||||||
addr14(unsigned char* view, Address value, Overflow_check overflow)
|
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)
|
if (overflow != CHECK_NONE && (value & 3) != 0)
|
||||||
stat = STATUS_OVERFLOW;
|
stat = STATUS_OVERFLOW;
|
||||||
return stat;
|
return stat;
|
||||||
@ -2362,7 +2363,7 @@ class Stub_control
|
|||||||
// the stubbed branches.
|
// the stubbed branches.
|
||||||
Stub_control(int32_t size)
|
Stub_control(int32_t size)
|
||||||
: state_(NO_GROUP), stub_group_size_(abs(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),
|
stubs_always_before_branch_(size < 0), suppress_size_errors_(false),
|
||||||
group_end_addr_(0), owner_(NULL), output_section_(NULL)
|
group_end_addr_(0), owner_(NULL), output_section_(NULL)
|
||||||
{
|
{
|
||||||
@ -6702,7 +6703,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
Powerpc_relobj<size, big_endian>* const object
|
Powerpc_relobj<size, big_endian>* const object
|
||||||
= static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
|
= static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
|
||||||
Address value = 0;
|
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());
|
unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
|
||||||
if ((gsym != NULL
|
if ((gsym != NULL
|
||||||
? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
|
? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
|
||||||
@ -6741,7 +6742,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
gold_assert(off != invalid_address);
|
gold_assert(off != invalid_address);
|
||||||
value = stub_table->stub_address() + off;
|
value = stub_table->stub_address() + off;
|
||||||
}
|
}
|
||||||
has_plt_value = true;
|
has_stub_value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r_type == elfcpp::R_POWERPC_GOT16
|
if (r_type == elfcpp::R_POWERPC_GOT16
|
||||||
@ -6772,7 +6773,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
else if (gsym != NULL
|
else if (gsym != NULL
|
||||||
&& (r_type == elfcpp::R_POWERPC_REL24
|
&& (r_type == elfcpp::R_POWERPC_REL24
|
||||||
|| r_type == elfcpp::R_PPC_PLTREL24)
|
|| r_type == elfcpp::R_PPC_PLTREL24)
|
||||||
&& has_plt_value)
|
&& has_stub_value)
|
||||||
{
|
{
|
||||||
if (size == 64)
|
if (size == 64)
|
||||||
{
|
{
|
||||||
@ -7077,7 +7078,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
value = psymval->value(object, rela.get_r_addend());
|
value = psymval->value(object, rela.get_r_addend());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!has_plt_value)
|
else if (!has_stub_value)
|
||||||
{
|
{
|
||||||
Address addend = 0;
|
Address addend = 0;
|
||||||
unsigned int dest_shndx;
|
unsigned int dest_shndx;
|
||||||
@ -7115,8 +7116,11 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
{
|
{
|
||||||
Address off = stub_table->find_long_branch_entry(object, value);
|
Address off = stub_table->find_long_branch_entry(object, value);
|
||||||
if (off != invalid_address)
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7667,9 +7671,17 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
r_type);
|
r_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (status != Powerpc_relocate_functions<size, big_endian>::STATUS_OK)
|
if (status != Powerpc_relocate_functions<size, big_endian>::STATUS_OK
|
||||||
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
|
&& !has_stub_value
|
||||||
_("relocation overflow"));
|
&& !(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user