aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-11-26 11:10:29 +1030
committerAlan Modra <amodra@gmail.com>2014-11-26 13:29:29 +1030
commita3e60ddb0b43a3aed32f2982d472ab305c7e8f67 (patch)
tree85f47346b1bb39addca84555cdc14064f092258c /gold
parentaa4893954a75660d2aa66245cb9d020049cb9546 (diff)
downloadgdb-a3e60ddb0b43a3aed32f2982d472ab305c7e8f67.zip
gdb-a3e60ddb0b43a3aed32f2982d472ab305c7e8f67.tar.gz
gdb-a3e60ddb0b43a3aed32f2982d472ab305c7e8f67.tar.bz2
Retry powerpc gold stub grouping when groups prove too large
An unusually large number of stubs can result in the default section group size being too large; sections plus stubs exceed the range of a branch. Restarting the relaxation pass with a smaller group size can sometimes help. * powerpc.cc (struct Stub_table_owner): New. (Powerpc_relobj): Rename stub_table_ to stub_table_index_, an unsigned int vector. Update all references. (powerpc_relobj::set_stub_table): Take an unsigned int param rather than a Stub_table. Update callers. (Powerpc_relobj::clear_stub_table): New function. (Target_powerpc): Add relax_failed_, relax_fail_count_ and stub_group_size_ vars. (Target_powerpc::new_stub_table): Delete. (max_branch_delta): New function, extracted from.. (Target_powerpc::Relocate::relocate): ..here.. (Target_powerpc::Branch_info::make_stub): ..and here. Return status on whether stub created successfully. (Stub_control::Stub_control): Add "no_size_errors" param. Move default sizing to.. (Target_powerpc::do_relax): ..here. Init stub_group_size_ and reduce on relax failure. (Target_powerpc::group_sections): Add "no_size_errors" param. Use stub_group_size_. Set up group info in a temp vector, before building Stub_table vector. Account for input sections possibly already converted to relaxed sections. (Stub_table::init): Delete. Merge into.. (Stub_table::Stub_table): ..here. (Stub_table::can_reach_stub): New function. (Stub_table::add_plt_call_entry): Add "from" parameter and return true iff stub could be reached. (Stub_table::add_long_branch_entry): Similarly. Add "r_type" param too. (Stub_table::clear_stubs): Add "all" param.
Diffstat (limited to 'gold')
-rw-r--r--gold/ChangeLog32
-rw-r--r--gold/powerpc.cc343
2 files changed, 243 insertions, 132 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 9b78b35..1a75a1e 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,37 @@
2014-11-26 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (struct Stub_table_owner): New.
+ (Powerpc_relobj): Rename stub_table_ to stub_table_index_, an
+ unsigned int vector. Update all references.
+ (powerpc_relobj::set_stub_table): Take an unsigned int param
+ rather than a Stub_table. Update callers.
+ (Powerpc_relobj::clear_stub_table): New function.
+ (Target_powerpc): Add relax_failed_, relax_fail_count_ and
+ stub_group_size_ vars.
+ (Target_powerpc::new_stub_table): Delete.
+ (max_branch_delta): New function, extracted from..
+ (Target_powerpc::Relocate::relocate): ..here..
+ (Target_powerpc::Branch_info::make_stub): ..and here. Return
+ status on whether stub created successfully.
+ (Stub_control::Stub_control): Add "no_size_errors" param. Move
+ default sizing to..
+ (Target_powerpc::do_relax): ..here. Init stub_group_size_ and
+ reduce on relax failure.
+ (Target_powerpc::group_sections): Add "no_size_errors" param.
+ Use stub_group_size_. Set up group info in a temp vector,
+ before building Stub_table vector. Account for input sections
+ possibly already converted to relaxed sections.
+ (Stub_table::init): Delete. Merge into..
+ (Stub_table::Stub_table): ..here.
+ (Stub_table::can_reach_stub): New function.
+ (Stub_table::add_plt_call_entry): Add "from" parameter and
+ return true iff stub could be reached.
+ (Stub_table::add_long_branch_entry): Similarly. Add "r_type"
+ param too.
+ (Stub_table::clear_stubs): Add "all" param.
+
+2014-11-26 Alan Modra <amodra@gmail.com>
+
* powerpc.cc (Stub_control::set_output_and_owner): New function.
(Target_powerpc::group_sections): Use it.
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 2319789..554bf38 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -62,6 +62,15 @@ class Output_data_glink;
template<int size, bool big_endian>
class Stub_table;
+template<int size, bool big_endian>
+class Target_powerpc;
+
+struct Stub_table_owner
+{
+ Output_section* output_section;
+ const Output_section::Input_section* owner;
+};
+
inline bool
is_branch_reloc(unsigned int r_type);
@@ -77,7 +86,7 @@ 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_index_(),
e_flags_(ehdr.get_e_flags()), st_other_()
{
this->set_abiversion(0);
@@ -260,21 +269,34 @@ public:
{ return shndx < this->has14_.size() && this->has14_[shndx]; }
void
- set_stub_table(unsigned int shndx, Stub_table<size, big_endian>* stub_table)
+ set_stub_table(unsigned int shndx, unsigned int stub_index)
{
- if (shndx >= this->stub_table_.size())
- this->stub_table_.resize(shndx + 1);
- this->stub_table_[shndx] = stub_table;
+ if (shndx >= this->stub_table_index_.size())
+ this->stub_table_index_.resize(shndx + 1);
+ this->stub_table_index_[shndx] = stub_index;
}
Stub_table<size, big_endian>*
stub_table(unsigned int shndx)
{
- if (shndx < this->stub_table_.size())
- return this->stub_table_[shndx];
+ if (shndx < this->stub_table_index_.size())
+ {
+ Target_powerpc<size, big_endian>* target
+ = static_cast<Target_powerpc<size, big_endian>*>(
+ parameters->sized_target<size, big_endian>());
+ unsigned int indx = this->stub_table_index_[shndx];
+ gold_assert(indx < target->stub_tables().size());
+ return target->stub_tables()[indx];
+ }
return NULL;
}
+ void
+ clear_stub_table()
+ {
+ this->stub_table_index_.clear();
+ }
+
int
abiversion() const
{ return this->e_flags_ & elfcpp::EF_PPC64_ABI; }
@@ -343,7 +365,7 @@ private:
std::vector<bool> has14_;
// The stub table to use for a given input section.
- std::vector<Stub_table<size, big_endian>*> stub_table_;
+ std::vector<unsigned int> stub_table_index_;
// Header e_flags
elfcpp::Elf_Word e_flags_;
@@ -487,7 +509,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
glink_(NULL), rela_dyn_(NULL), copy_relocs_(elfcpp::R_POWERPC_COPY),
tlsld_got_offset_(-1U),
stub_tables_(), branch_lookup_table_(), branch_info_(),
- plt_thread_safe_(false)
+ plt_thread_safe_(false), relax_failed_(false), relax_fail_count_(0),
+ stub_group_size_(0)
{
}
@@ -562,9 +585,6 @@ class Target_powerpc : public Sized_target<size, big_endian>
ppc_object->set_has_14bit_branch(data_shndx);
}
- Stub_table<size, big_endian>*
- new_stub_table();
-
void
do_define_standard_symbols(Symbol_table*, Layout*);
@@ -1179,7 +1199,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
// Look over all the input sections, deciding where to place stubs.
void
- group_sections(Layout*, const Task*);
+ group_sections(Layout*, const Task*, bool);
// Sort output sections by address.
struct Sort_sections
@@ -1206,7 +1226,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
{ }
// If this branch needs a plt call stub, or a long branch stub, make one.
- void
+ bool
make_stub(Stub_table<size, big_endian>*,
Stub_table<size, big_endian>*,
Symbol_table*) const;
@@ -1284,6 +1304,10 @@ class Target_powerpc : public Sized_target<size, big_endian>
Branches branch_info_;
bool plt_thread_safe_;
+
+ bool relax_failed_;
+ int relax_fail_count_;
+ int32_t stub_group_size_;
};
template<>
@@ -2361,27 +2385,13 @@ class Stub_control
// value of the parameter --stub-group-size. If --stub-group-size
// is passed a negative value, we restrict stubs to be always before
// the stubbed branches.
- Stub_control(int32_t size)
+ Stub_control(int32_t size, bool no_size_errors)
: state_(NO_GROUP), stub_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_(no_size_errors),
group_end_addr_(0), owner_(NULL), output_section_(NULL)
{
- if (stub_group_size_ == 1)
- {
- // Default values.
- if (stubs_always_before_branch_)
- {
- stub_group_size_ = 0x1e00000;
- stub14_group_size_ = 0x7800;
- }
- else
- {
- stub_group_size_ = 0x1c00000;
- stub14_group_size_ = 0x7000;
- }
- suppress_size_errors_ = true;
- }
}
// Return true iff input section can be handled by current stub
@@ -2495,12 +2505,14 @@ Stub_control::can_add_to_stub_group(Output_section* o,
template<int size, bool big_endian>
void
Target_powerpc<size, big_endian>::group_sections(Layout* layout,
- const Task*)
+ const Task*,
+ bool no_size_errors)
{
- Stub_control stub_control(parameters->options().stub_group_size());
+ Stub_control stub_control(this->stub_group_size_, no_size_errors);
// Group input sections and insert stub table
- Stub_table<size, big_endian>* stub_table = NULL;
+ Stub_table_owner* table_owner = NULL;
+ std::vector<Stub_table_owner*> tables;
Layout::Section_list section_list;
layout->get_executable_sections(&section_list);
std::stable_sort(section_list.begin(), section_list.end(), Sort_sections());
@@ -2514,50 +2526,89 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
i != (*o)->input_sections().rend();
++i)
{
- if (i->is_input_section())
+ if (i->is_input_section()
+ || i->is_relaxed_input_section())
{
Powerpc_relobj<size, big_endian>* ppcobj = static_cast
<Powerpc_relobj<size, big_endian>*>(i->relobj());
bool has14 = ppcobj->has_14bit_branch(i->shndx());
if (!stub_control.can_add_to_stub_group(*o, &*i, has14))
{
- stub_table->init(stub_control.owner(),
- stub_control.output_section());
+ table_owner->output_section = stub_control.output_section();
+ table_owner->owner = stub_control.owner();
stub_control.set_output_and_owner(*o, &*i);
- stub_table = NULL;
+ table_owner = NULL;
+ }
+ if (table_owner == NULL)
+ {
+ table_owner = new Stub_table_owner;
+ tables.push_back(table_owner);
}
- if (stub_table == NULL)
- stub_table = this->new_stub_table();
- ppcobj->set_stub_table(i->shndx(), stub_table);
+ ppcobj->set_stub_table(i->shndx(), tables.size() - 1);
}
}
}
- if (stub_table != NULL)
+ if (table_owner != NULL)
{
const Output_section::Input_section* i = stub_control.owner();
- if (!i->is_input_section())
+
+ if (tables.size() >= 2 && tables[tables.size() - 2]->owner == i)
{
// Corner case. A new stub group was made for the first
// section (last one looked at here) for some reason, but
// the first section is already being used as the owner for
// a stub table for following sections. Force it into that
// stub group.
- gold_assert(this->stub_tables_.size() >= 2);
- this->stub_tables_.pop_back();
- delete stub_table;
+ tables.pop_back();
+ delete table_owner;
Powerpc_relobj<size, big_endian>* ppcobj = static_cast
<Powerpc_relobj<size, big_endian>*>(i->relobj());
- ppcobj->set_stub_table(i->shndx(), this->stub_tables_.back());
+ ppcobj->set_stub_table(i->shndx(), tables.size() - 1);
+ }
+ else
+ {
+ table_owner->output_section = stub_control.output_section();
+ table_owner->owner = i;
}
+ }
+ for (typename std::vector<Stub_table_owner*>::iterator t = tables.begin();
+ t != tables.end();
+ ++t)
+ {
+ Stub_table<size, big_endian>* stub_table;
+
+ if ((*t)->owner->is_input_section())
+ stub_table = new Stub_table<size, big_endian>(this,
+ (*t)->output_section,
+ (*t)->owner);
+ else if ((*t)->owner->is_relaxed_input_section())
+ stub_table = static_cast<Stub_table<size, big_endian>*>(
+ (*t)->owner->relaxed_input_section());
else
- stub_table->init(i, stub_control.output_section());
+ gold_unreachable();
+ this->stub_tables_.push_back(stub_table);
+ delete *t;
}
}
+static unsigned long
+max_branch_delta (unsigned int r_type)
+{
+ if (r_type == elfcpp::R_POWERPC_REL14
+ || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
+ || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN)
+ return 1L << 15;
+ if (r_type == elfcpp::R_POWERPC_REL24
+ || r_type == elfcpp::R_PPC_PLTREL24
+ || r_type == elfcpp::R_PPC_LOCAL24PC)
+ return 1L << 25;
+ return 0;
+}
+
// If this branch needs a plt call stub, or a long branch stub, make one.
template<int size, bool big_endian>
-void
+bool
Target_powerpc<size, big_endian>::Branch_info::make_stub(
Stub_table<size, big_endian>* stub_table,
Stub_table<size, big_endian>* ifunc_stub_table,
@@ -2590,27 +2641,25 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
stub_table = ifunc_stub_table;
}
gold_assert(stub_table != NULL);
+ Address from = this->object_->get_output_section_offset(this->shndx_);
+ if (from != invalid_address)
+ from += (this->object_->output_section(this->shndx_)->address()
+ + this->offset_);
if (gsym != NULL)
- stub_table->add_plt_call_entry(this->object_, gsym,
- this->r_type_, this->addend_);
+ return stub_table->add_plt_call_entry(from,
+ this->object_, gsym,
+ this->r_type_, this->addend_);
else
- stub_table->add_plt_call_entry(this->object_, this->r_sym_,
- this->r_type_, this->addend_);
+ return stub_table->add_plt_call_entry(from,
+ this->object_, this->r_sym_,
+ this->r_type_, this->addend_);
}
}
else
{
- 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)
- max_branch_offset = 1 << 15;
- else if (this->r_type_ == elfcpp::R_POWERPC_REL24
- || this->r_type_ == elfcpp::R_PPC_PLTREL24
- || this->r_type_ == elfcpp::R_PPC_LOCAL24PC)
- max_branch_offset = 1 << 25;
- else
- return;
+ unsigned long max_branch_offset = max_branch_delta(this->r_type_);
+ if (max_branch_offset == 0)
+ return true;
Address from = this->object_->get_output_section_offset(this->shndx_);
gold_assert(from != invalid_address);
from += (this->object_->output_section(this->shndx_)->address()
@@ -2625,16 +2674,16 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
Object* symobj = gsym->object();
if (symobj->is_dynamic()
|| symobj->pluginobj() != NULL)
- return;
+ return true;
bool is_ordinary;
unsigned int shndx = gsym->shndx(&is_ordinary);
if (shndx == elfcpp::SHN_UNDEF)
- return;
+ return true;
}
break;
case Symbol::IS_UNDEFINED:
- return;
+ return true;
default:
break;
@@ -2642,7 +2691,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
Symbol_table::Compute_final_value_status status;
to = symtab->compute_final_value<size>(gsym, &status);
if (status != Symbol_table::CFVS_OK)
- return;
+ return true;
if (size == 64)
to += this->object_->ppc64_local_entry_offset(gsym);
}
@@ -2657,7 +2706,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
&symval, symtab);
if (status != ObjType::CFLV_OK
|| !symval.has_output_value())
- return;
+ return true;
to = symval.value(this->object_, 0);
if (size == 64)
to += this->object_->ppc64_local_entry_offset(this->r_sym_);
@@ -2680,11 +2729,13 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
" no long branch stub for you"),
this->object_->name().c_str(),
this->object_->section_name(this->shndx_).c_str());
- return;
+ return true;
}
- stub_table->add_long_branch_entry(this->object_, to);
+ return stub_table->add_long_branch_entry(this->object_,
+ this->r_type_, from, to);
}
}
+ return true;
}
// Relaxation hook. This is where we do stub generation.
@@ -2752,7 +2803,34 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
}
}
this->plt_thread_safe_ = thread_safe;
- this->group_sections(layout, task);
+ }
+
+ if (pass == 1)
+ {
+ this->stub_group_size_ = parameters->options().stub_group_size();
+ bool no_size_errors = true;
+ if (this->stub_group_size_ == 1)
+ this->stub_group_size_ = 0x1c00000;
+ else if (this->stub_group_size_ == -1)
+ this->stub_group_size_ = -0x1e00000;
+ else
+ no_size_errors = false;
+ this->group_sections(layout, task, no_size_errors);
+ }
+ else if (this->relax_failed_ && this->relax_fail_count_ < 3)
+ {
+ this->branch_lookup_table_.clear();
+ for (typename Stub_tables::iterator p = this->stub_tables_.begin();
+ p != this->stub_tables_.end();
+ ++p)
+ {
+ (*p)->clear_stubs(true);
+ }
+ this->stub_tables_.clear();
+ this->stub_group_size_ = this->stub_group_size_ / 4 * 3;
+ gold_info(_("%s: stub group size is too large; retrying with %d"),
+ program_name, this->stub_group_size_);
+ this->group_sections(layout, task, true);
}
// We need address of stub tables valid for make_stub.
@@ -2777,11 +2855,12 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
p != this->stub_tables_.end();
++p)
{
- (*p)->clear_stubs();
+ (*p)->clear_stubs(false);
}
}
// Build all the stubs.
+ this->relax_failed_ = false;
Stub_table<size, big_endian>* ifunc_stub_table
= this->stub_tables_.size() == 0 ? NULL : this->stub_tables_[0];
Stub_table<size, big_endian>* one_stub_table
@@ -2790,7 +2869,14 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
b != this->branch_info_.end();
b++)
{
- b->make_stub(one_stub_table, ifunc_stub_table, symtab);
+ if (!b->make_stub(one_stub_table, ifunc_stub_table, symtab)
+ && !this->relax_failed_)
+ {
+ this->relax_failed_ = true;
+ this->relax_fail_count_++;
+ if (this->relax_fail_count_ < 3)
+ return true;
+ }
}
// Did anything change size?
@@ -3475,26 +3561,35 @@ class Stub_table : public Output_relaxed_input_section
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
static const Address invalid_address = static_cast<Address>(0) - 1;
- Stub_table(Target_powerpc<size, big_endian>* targ)
- : Output_relaxed_input_section(NULL, 0, 0),
+ Stub_table(Target_powerpc<size, big_endian>* targ,
+ Output_section* output_section,
+ const Output_section::Input_section* owner)
+ : Output_relaxed_input_section(owner->relobj(), owner->shndx(),
+ owner->relobj()
+ ->section_addralign(owner->shndx())),
targ_(targ), plt_call_stubs_(), long_branch_stubs_(),
- orig_data_size_(0), plt_size_(0), last_plt_size_(0),
+ orig_data_size_(owner->current_data_size()),
+ plt_size_(0), last_plt_size_(0),
branch_size_(0), last_branch_size_(0), eh_frame_added_(false)
- { }
+ {
+ this->set_output_section(output_section);
- // Delayed Output_relaxed_input_section init.
- void
- init(const Output_section::Input_section*, Output_section*);
+ std::vector<Output_relaxed_input_section*> new_relaxed;
+ new_relaxed.push_back(this);
+ output_section->convert_input_sections_to_relaxed_sections(new_relaxed);
+ }
// Add a plt call stub.
- void
- add_plt_call_entry(const Sized_relobj_file<size, big_endian>*,
+ bool
+ add_plt_call_entry(Address,
+ const Sized_relobj_file<size, big_endian>*,
const Symbol*,
unsigned int,
Address);
- void
- add_plt_call_entry(const Sized_relobj_file<size, big_endian>*,
+ bool
+ add_plt_call_entry(Address,
+ const Sized_relobj_file<size, big_endian>*,
unsigned int,
unsigned int,
Address);
@@ -3520,20 +3615,37 @@ class Stub_table : public Output_relaxed_input_section
Address) const;
// Add a long branch stub.
- void
- add_long_branch_entry(const Powerpc_relobj<size, big_endian>*, Address);
+ bool
+ add_long_branch_entry(const Powerpc_relobj<size, big_endian>*,
+ unsigned int, Address, Address);
Address
find_long_branch_entry(const Powerpc_relobj<size, big_endian>*,
Address) const;
+ bool
+ can_reach_stub(Address from, unsigned int off, unsigned int r_type)
+ {
+ unsigned long max_branch_offset = max_branch_delta(r_type);
+ if (max_branch_offset == 0)
+ return true;
+ gold_assert(from != invalid_address);
+ Address loc = off + this->stub_address();
+ return loc - from + max_branch_offset < 2 * max_branch_offset;
+ }
+
void
- clear_stubs()
+ clear_stubs(bool all)
{
this->plt_call_stubs_.clear();
this->plt_size_ = 0;
this->long_branch_stubs_.clear();
this->branch_size_ = 0;
+ if (all)
+ {
+ this->last_plt_size_ = 0;
+ this->last_branch_size_ = 0;
+ }
}
Address
@@ -3837,44 +3949,13 @@ class Stub_table : public Output_relaxed_input_section
bool eh_frame_added_;
};
-// Make a new stub table, and record.
-
-template<int size, bool big_endian>
-Stub_table<size, big_endian>*
-Target_powerpc<size, big_endian>::new_stub_table()
-{
- Stub_table<size, big_endian>* stub_table
- = new Stub_table<size, big_endian>(this);
- this->stub_tables_.push_back(stub_table);
- return stub_table;
-}
-
-// Delayed stub table initialisation, because we create the stub table
-// before we know to which section it will be attached.
-
-template<int size, bool big_endian>
-void
-Stub_table<size, big_endian>::init(
- const Output_section::Input_section* owner,
- Output_section* output_section)
-{
- this->set_relobj(owner->relobj());
- this->set_shndx(owner->shndx());
- this->set_addralign(this->relobj()->section_addralign(this->shndx()));
- this->set_output_section(output_section);
- this->orig_data_size_ = owner->current_data_size();
-
- std::vector<Output_relaxed_input_section*> new_relaxed;
- new_relaxed.push_back(this);
- output_section->convert_input_sections_to_relaxed_sections(new_relaxed);
-}
-
// Add a plt call stub, if we do not already have one for this
// sym/object/addend combo.
template<int size, bool big_endian>
-void
+bool
Stub_table<size, big_endian>::add_plt_call_entry(
+ Address from,
const Sized_relobj_file<size, big_endian>* object,
const Symbol* gsym,
unsigned int r_type,
@@ -3886,11 +3967,13 @@ Stub_table<size, big_endian>::add_plt_call_entry(
= this->plt_call_stubs_.insert(std::make_pair(ent, off));
if (p.second)
this->plt_size_ = off + this->plt_call_size(p.first);
+ return this->can_reach_stub(from, off, r_type);
}
template<int size, bool big_endian>
-void
+bool
Stub_table<size, big_endian>::add_plt_call_entry(
+ Address from,
const Sized_relobj_file<size, big_endian>* object,
unsigned int locsym_index,
unsigned int r_type,
@@ -3902,6 +3985,7 @@ Stub_table<size, big_endian>::add_plt_call_entry(
= this->plt_call_stubs_.insert(std::make_pair(ent, off));
if (p.second)
this->plt_size_ = off + this->plt_call_size(p.first);
+ return this->can_reach_stub(from, off, r_type);
}
// Find a plt call stub.
@@ -3956,9 +4040,11 @@ Stub_table<size, big_endian>::find_plt_call_entry(
// destination.
template<int size, bool big_endian>
-void
+bool
Stub_table<size, big_endian>::add_long_branch_entry(
const Powerpc_relobj<size, big_endian>* object,
+ unsigned int r_type,
+ Address from,
Address to)
{
Branch_stub_ent ent(object, to);
@@ -3970,6 +4056,7 @@ Stub_table<size, big_endian>::add_long_branch_entry(
if (size == 64 && stub_size != 4)
this->targ_->add_branch_lookup_table(to);
}
+ return this->can_reach_stub(from, off, r_type);
}
// Find long branch stub.
@@ -7107,15 +7194,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
value = target->symval_for_branch(relinfo->symtab, value,
gsym, object, &dest_shndx);
}
- unsigned int max_branch_offset = 0;
- if (r_type == elfcpp::R_POWERPC_REL24
- || r_type == elfcpp::R_PPC_PLTREL24
- || r_type == elfcpp::R_PPC_LOCAL24PC)
- max_branch_offset = 1 << 25;
- else if (r_type == elfcpp::R_POWERPC_REL14
- || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
- || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN)
- max_branch_offset = 1 << 15;
+ unsigned long max_branch_offset = max_branch_delta(r_type);
if (max_branch_offset != 0
&& value - address + max_branch_offset >= 2 * max_branch_offset)
{