This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Retry powerpc gold stub grouping when groups prove too large
- From: Alan Modra <amodra at gmail dot com>
- To: Cary Coutant <ccoutant at google dot com>
- Cc: Binutils <binutils at sourceware dot org>
- Date: Wed, 26 Nov 2014 13:28:31 +1030
- Subject: Retry powerpc gold stub grouping when groups prove too large
- Authentication-results: sourceware.org; auth=none
- References: <CAHACq4rr8Z6bKL74tmunhwZYUJx1s6md=+0vg5+oWVDjNr84bA at mail dot gmail dot com> <20141120111444 dot GB4477 at bubble dot grove dot modra dot org> <CAHACq4o9xRNgZ+ddfabhh_GTQU7AjcE0aydeU70JQ91cfThBHQ at mail dot gmail dot com>
On Thu, Nov 20, 2014 at 10:33:53AM -0800, Cary Coutant wrote:
> Another idea would be to automatically reduce the stub group size and
> run another relaxation pass.
Complicated somewhat by the fact that once input sections have been
converted to relaxed sections (to hold stubs), we lack infrastructure
to revert them back to plain input sections.
* 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.
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 2319789..2cac22a 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(§ion_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)
{
--
Alan Modra
Australia Development Lab, IBM