* gold/arm.cc: Added support for R_ARM_V4BX relocation
(class Arm_v4bx_stub): New class. (DEF_STUBS): Updated definition to support v4_veneer_bx. (Stub_factory::make_arm_v4bx_stub): New method. (Stub_factory::elf32_arm_stub_v4_veneer_bx): New veneer template. (Stub_table::empty): Handle v4bx stubs. (Stub_table::add_arm_v4bx_stub): New method. (Stub_table::find_arm_v4bx_stub): New method. (Arm_relocate_functions::v4bx): New method. (Target_arm::fix_v4bx): New method. (Target_arm::Target_arm): Handle R_ARM_V4BX. (Stub_table::relocate_stubs): Likewise. (Stub_table::do_write): Likewise. (Stub_table::update_data_size_and_addralign): Likewise. (Stub_table::finalize_stubs): Likewise. (Target_arm::Scan::local): Likewise. (Target_arm::Scan::global): Likewise. (Target_arm::do_finalize_sections): Likewise. (Target_arm::Relocate::relocate): Likewise. (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): Likewise. (Target_arm::scan_reloc_for_stub): Likewise. (Target_arm::scan_reloc_section_for_stubs): Likewise.
This commit is contained in:
parent
fcae584be5
commit
a21620630e
|
@ -1,3 +1,29 @@
|
||||||
|
2010-01-20 Viktor Kutuzov <vkutuzov@accesssoftek.com>
|
||||||
|
|
||||||
|
* gold/arm.cc: Added support for R_ARM_V4BX relocation
|
||||||
|
(class Arm_v4bx_stub): New class.
|
||||||
|
(DEF_STUBS): Updated definition to support v4_veneer_bx.
|
||||||
|
(Stub_factory::make_arm_v4bx_stub): New method.
|
||||||
|
(Stub_factory::elf32_arm_stub_v4_veneer_bx): New veneer template.
|
||||||
|
(Stub_table::empty): Handle v4bx stubs.
|
||||||
|
(Stub_table::add_arm_v4bx_stub): New method.
|
||||||
|
(Stub_table::find_arm_v4bx_stub): New method.
|
||||||
|
(Arm_relocate_functions::v4bx): New method.
|
||||||
|
(Target_arm::fix_v4bx): New method.
|
||||||
|
(Target_arm::Target_arm): Handle R_ARM_V4BX.
|
||||||
|
(Stub_table::relocate_stubs): Likewise.
|
||||||
|
(Stub_table::do_write): Likewise.
|
||||||
|
(Stub_table::update_data_size_and_addralign): Likewise.
|
||||||
|
(Stub_table::finalize_stubs): Likewise.
|
||||||
|
(Target_arm::Scan::local): Likewise.
|
||||||
|
(Target_arm::Scan::global): Likewise.
|
||||||
|
(Target_arm::do_finalize_sections): Likewise.
|
||||||
|
(Target_arm::Relocate::relocate): Likewise.
|
||||||
|
(Target_arm::Relocatable_size_for_reloc::get_size_for_reloc):
|
||||||
|
Likewise.
|
||||||
|
(Target_arm::scan_reloc_for_stub): Likewise.
|
||||||
|
(Target_arm::scan_reloc_section_for_stubs): Likewise.
|
||||||
|
|
||||||
2010-01-19 Ian Lance Taylor <iant@google.com>
|
2010-01-19 Ian Lance Taylor <iant@google.com>
|
||||||
|
|
||||||
* output.cc (Output_section_headers::do_sized_write): Write large
|
* output.cc (Output_section_headers::do_sized_write): Write large
|
||||||
|
|
276
gold/arm.cc
276
gold/arm.cc
|
@ -122,6 +122,7 @@ const int32_t THM2_MAX_BWD_BRANCH_OFFSET = (-(1 << 24) + 4);
|
||||||
// R_ARM_MOVT_PREL
|
// R_ARM_MOVT_PREL
|
||||||
// R_ARM_THM_MOVW_PREL_NC
|
// R_ARM_THM_MOVW_PREL_NC
|
||||||
// R_ARM_THM_MOVT_PREL
|
// R_ARM_THM_MOVT_PREL
|
||||||
|
// R_ARM_V4BX
|
||||||
// R_ARM_THM_JUMP6
|
// R_ARM_THM_JUMP6
|
||||||
// R_ARM_THM_JUMP8
|
// R_ARM_THM_JUMP8
|
||||||
// R_ARM_THM_JUMP11
|
// R_ARM_THM_JUMP11
|
||||||
|
@ -254,7 +255,8 @@ class Insn_template
|
||||||
DEF_STUB(a8_veneer_b_cond) \
|
DEF_STUB(a8_veneer_b_cond) \
|
||||||
DEF_STUB(a8_veneer_b) \
|
DEF_STUB(a8_veneer_b) \
|
||||||
DEF_STUB(a8_veneer_bl) \
|
DEF_STUB(a8_veneer_bl) \
|
||||||
DEF_STUB(a8_veneer_blx)
|
DEF_STUB(a8_veneer_blx) \
|
||||||
|
DEF_STUB(v4_veneer_bx)
|
||||||
|
|
||||||
// Stub types.
|
// Stub types.
|
||||||
|
|
||||||
|
@ -275,7 +277,7 @@ typedef enum
|
||||||
arm_stub_cortex_a8_last = arm_stub_a8_veneer_blx,
|
arm_stub_cortex_a8_last = arm_stub_a8_veneer_blx,
|
||||||
|
|
||||||
// Last stub type.
|
// Last stub type.
|
||||||
arm_stub_type_last = arm_stub_a8_veneer_blx
|
arm_stub_type_last = arm_stub_v4_veneer_bx
|
||||||
} Stub_type;
|
} Stub_type;
|
||||||
#undef DEF_STUB
|
#undef DEF_STUB
|
||||||
|
|
||||||
|
@ -748,6 +750,64 @@ class Cortex_a8_stub : public Stub
|
||||||
uint32_t original_insn_;
|
uint32_t original_insn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ARMv4 BX Rx branch relocation stub class.
|
||||||
|
class Arm_v4bx_stub : public Stub
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Arm_v4bx_stub()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Return the associated register.
|
||||||
|
uint32_t
|
||||||
|
reg() const
|
||||||
|
{ return this->reg_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Arm V4BX stubs are created via a stub factory. So these are protected.
|
||||||
|
Arm_v4bx_stub(const Stub_template* stub_template, const uint32_t reg)
|
||||||
|
: Stub(stub_template), reg_(reg)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
friend class Stub_factory;
|
||||||
|
|
||||||
|
// Return the relocation target address of the i-th relocation in the
|
||||||
|
// stub.
|
||||||
|
Arm_address
|
||||||
|
do_reloc_target(size_t)
|
||||||
|
{ gold_unreachable(); }
|
||||||
|
|
||||||
|
// This may be overridden in the child class.
|
||||||
|
virtual void
|
||||||
|
do_write(unsigned char* view, section_size_type view_size, bool big_endian)
|
||||||
|
{
|
||||||
|
if (big_endian)
|
||||||
|
this->do_fixed_endian_v4bx_write<true>(view, view_size);
|
||||||
|
else
|
||||||
|
this->do_fixed_endian_v4bx_write<false>(view, view_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// A template to implement do_write.
|
||||||
|
template<bool big_endian>
|
||||||
|
void inline
|
||||||
|
do_fixed_endian_v4bx_write(unsigned char* view, section_size_type)
|
||||||
|
{
|
||||||
|
const Insn_template* insns = this->stub_template()->insns();
|
||||||
|
elfcpp::Swap<32, big_endian>::writeval(view,
|
||||||
|
(insns[0].data()
|
||||||
|
+ (this->reg_ << 16)));
|
||||||
|
view += insns[0].size();
|
||||||
|
elfcpp::Swap<32, big_endian>::writeval(view,
|
||||||
|
(insns[1].data() + this->reg_));
|
||||||
|
view += insns[1].size();
|
||||||
|
elfcpp::Swap<32, big_endian>::writeval(view,
|
||||||
|
(insns[2].data() + this->reg_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// A register index (r0-r14), which is associated with the stub.
|
||||||
|
uint32_t reg_;
|
||||||
|
};
|
||||||
|
|
||||||
// Stub factory class.
|
// Stub factory class.
|
||||||
|
|
||||||
class Stub_factory
|
class Stub_factory
|
||||||
|
@ -782,6 +842,16 @@ class Stub_factory
|
||||||
source, destination, original_insn);
|
source, destination, original_insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make an ARM V4BX relocation stub.
|
||||||
|
// This method creates a stub from the arm_stub_v4_veneer_bx template only.
|
||||||
|
Arm_v4bx_stub*
|
||||||
|
make_arm_v4bx_stub(uint32_t reg) const
|
||||||
|
{
|
||||||
|
gold_assert(reg < 0xf);
|
||||||
|
return new Arm_v4bx_stub(this->stub_templates_[arm_stub_v4_veneer_bx],
|
||||||
|
reg);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Constructor and destructor are protected since we only return a single
|
// Constructor and destructor are protected since we only return a single
|
||||||
// instance created in Stub_factory::get_instance().
|
// instance created in Stub_factory::get_instance().
|
||||||
|
@ -804,7 +874,7 @@ class Stub_table : public Output_data
|
||||||
public:
|
public:
|
||||||
Stub_table(Arm_input_section<big_endian>* owner)
|
Stub_table(Arm_input_section<big_endian>* owner)
|
||||||
: Output_data(), owner_(owner), reloc_stubs_(), cortex_a8_stubs_(),
|
: Output_data(), owner_(owner), reloc_stubs_(), cortex_a8_stubs_(),
|
||||||
prev_data_size_(0), prev_addralign_(1)
|
arm_v4bx_stubs_(0xf), prev_data_size_(0), prev_addralign_(1)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~Stub_table()
|
~Stub_table()
|
||||||
|
@ -818,7 +888,11 @@ class Stub_table : public Output_data
|
||||||
// Whether this stub table is empty.
|
// Whether this stub table is empty.
|
||||||
bool
|
bool
|
||||||
empty() const
|
empty() const
|
||||||
{ return this->reloc_stubs_.empty() && this->cortex_a8_stubs_.empty(); }
|
{
|
||||||
|
return (this->reloc_stubs_.empty()
|
||||||
|
&& this->cortex_a8_stubs_.empty()
|
||||||
|
&& this->arm_v4bx_stubs_.empty());
|
||||||
|
}
|
||||||
|
|
||||||
// Return the current data size.
|
// Return the current data size.
|
||||||
off_t
|
off_t
|
||||||
|
@ -845,6 +919,15 @@ class Stub_table : public Output_data
|
||||||
this->cortex_a8_stubs_.insert(value);
|
this->cortex_a8_stubs_.insert(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add an ARM V4BX relocation stub. A register index will be retrieved
|
||||||
|
// from the stub.
|
||||||
|
void
|
||||||
|
add_arm_v4bx_stub(Arm_v4bx_stub* stub)
|
||||||
|
{
|
||||||
|
gold_assert(stub != NULL && this->arm_v4bx_stubs_[stub->reg()] == NULL);
|
||||||
|
this->arm_v4bx_stubs_[stub->reg()] = stub;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove all Cortex-A8 stubs.
|
// Remove all Cortex-A8 stubs.
|
||||||
void
|
void
|
||||||
remove_all_cortex_a8_stubs();
|
remove_all_cortex_a8_stubs();
|
||||||
|
@ -857,6 +940,15 @@ class Stub_table : public Output_data
|
||||||
return (p != this->reloc_stubs_.end()) ? p->second : NULL;
|
return (p != this->reloc_stubs_.end()) ? p->second : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look up an arm v4bx relocation stub using the register index.
|
||||||
|
// Return NULL if there is none.
|
||||||
|
Arm_v4bx_stub*
|
||||||
|
find_arm_v4bx_stub(const uint32_t reg) const
|
||||||
|
{
|
||||||
|
gold_assert(reg < 0xf);
|
||||||
|
return this->arm_v4bx_stubs_[reg];
|
||||||
|
}
|
||||||
|
|
||||||
// Relocate stubs in this stub table.
|
// Relocate stubs in this stub table.
|
||||||
void
|
void
|
||||||
relocate_stubs(const Relocate_info<32, big_endian>*,
|
relocate_stubs(const Relocate_info<32, big_endian>*,
|
||||||
|
@ -916,6 +1008,8 @@ class Stub_table : public Output_data
|
||||||
// List of Cortex-A8 stubs ordered by addresses of branches being
|
// List of Cortex-A8 stubs ordered by addresses of branches being
|
||||||
// fixed up in output.
|
// fixed up in output.
|
||||||
typedef std::map<Arm_address, Cortex_a8_stub*> Cortex_a8_stub_list;
|
typedef std::map<Arm_address, Cortex_a8_stub*> Cortex_a8_stub_list;
|
||||||
|
// List of Arm V4BX relocation stubs ordered by associated registers.
|
||||||
|
typedef std::vector<Arm_v4bx_stub*> Arm_v4bx_stub_list;
|
||||||
|
|
||||||
// Owner of this stub table.
|
// Owner of this stub table.
|
||||||
Arm_input_section<big_endian>* owner_;
|
Arm_input_section<big_endian>* owner_;
|
||||||
|
@ -923,6 +1017,8 @@ class Stub_table : public Output_data
|
||||||
Reloc_stub_map reloc_stubs_;
|
Reloc_stub_map reloc_stubs_;
|
||||||
// The cortex_a8_stubs.
|
// The cortex_a8_stubs.
|
||||||
Cortex_a8_stub_list cortex_a8_stubs_;
|
Cortex_a8_stub_list cortex_a8_stubs_;
|
||||||
|
// The Arm V4BX relocation stubs.
|
||||||
|
Arm_v4bx_stub_list arm_v4bx_stubs_;
|
||||||
// data size of this in the previous pass.
|
// data size of this in the previous pass.
|
||||||
off_t prev_data_size_;
|
off_t prev_data_size_;
|
||||||
// address alignment of this in the previous pass.
|
// address alignment of this in the previous pass.
|
||||||
|
@ -1452,7 +1548,7 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
stub_factory_(Stub_factory::get_instance()), may_use_blx_(false),
|
stub_factory_(Stub_factory::get_instance()), may_use_blx_(false),
|
||||||
should_force_pic_veneer_(false), arm_input_section_map_(),
|
should_force_pic_veneer_(false), arm_input_section_map_(),
|
||||||
attributes_section_data_(NULL), fix_cortex_a8_(false),
|
attributes_section_data_(NULL), fix_cortex_a8_(false),
|
||||||
cortex_a8_relocs_info_()
|
cortex_a8_relocs_info_(), fix_v4bx_(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// Whether we can use BLX.
|
// Whether we can use BLX.
|
||||||
|
@ -1685,6 +1781,14 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
fix_cortex_a8() const
|
fix_cortex_a8() const
|
||||||
{ return this->fix_cortex_a8_; }
|
{ return this->fix_cortex_a8_; }
|
||||||
|
|
||||||
|
// Whether we fix R_ARM_V4BX relocation.
|
||||||
|
// 0 - do not fix
|
||||||
|
// 1 - replace with MOV instruction (armv4 target)
|
||||||
|
// 2 - make interworking veneer (>= armv4t targets only)
|
||||||
|
int
|
||||||
|
fix_v4bx() const
|
||||||
|
{ return this->fix_v4bx_; }
|
||||||
|
|
||||||
// Scan a span of THUMB code section for Cortex-A8 erratum.
|
// Scan a span of THUMB code section for Cortex-A8 erratum.
|
||||||
void
|
void
|
||||||
scan_span_for_cortex_a8_erratum(Arm_relobj<big_endian>*, unsigned int,
|
scan_span_for_cortex_a8_erratum(Arm_relobj<big_endian>*, unsigned int,
|
||||||
|
@ -2048,6 +2152,8 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
bool fix_cortex_a8_;
|
bool fix_cortex_a8_;
|
||||||
// Map addresses to relocs for Cortex-A8 erratum.
|
// Map addresses to relocs for Cortex-A8 erratum.
|
||||||
Cortex_a8_relocs_info cortex_a8_relocs_info_;
|
Cortex_a8_relocs_info cortex_a8_relocs_info_;
|
||||||
|
// Whether we need to fix code for V4BX relocations.
|
||||||
|
int fix_v4bx_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool big_endian>
|
template<bool big_endian>
|
||||||
|
@ -2745,6 +2851,49 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
|
||||||
elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
|
elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
|
||||||
return This::STATUS_OKAY;
|
return This::STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// R_ARM_V4BX
|
||||||
|
static inline typename This::Status
|
||||||
|
v4bx(const Relocate_info<32, big_endian>* relinfo,
|
||||||
|
unsigned char *view,
|
||||||
|
const Arm_relobj<big_endian>* object,
|
||||||
|
const Arm_address address,
|
||||||
|
const bool is_interworking)
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
||||||
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||||
|
Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
|
||||||
|
|
||||||
|
// Ensure that we have a BX instruction.
|
||||||
|
gold_assert((val & 0x0ffffff0) == 0x012fff10);
|
||||||
|
const uint32_t reg = (val & 0xf);
|
||||||
|
if (is_interworking && reg != 0xf)
|
||||||
|
{
|
||||||
|
Stub_table<big_endian>* stub_table =
|
||||||
|
object->stub_table(relinfo->data_shndx);
|
||||||
|
gold_assert(stub_table != NULL);
|
||||||
|
|
||||||
|
Arm_v4bx_stub* stub = stub_table->find_arm_v4bx_stub(reg);
|
||||||
|
gold_assert(stub != NULL);
|
||||||
|
|
||||||
|
int32_t veneer_address =
|
||||||
|
stub_table->address() + stub->offset() - 8 - address;
|
||||||
|
gold_assert((veneer_address <= ARM_MAX_FWD_BRANCH_OFFSET)
|
||||||
|
&& (veneer_address >= ARM_MAX_BWD_BRANCH_OFFSET));
|
||||||
|
// Replace with a branch to veneer (B <addr>)
|
||||||
|
val = (val & 0xf0000000) | 0x0a000000
|
||||||
|
| ((veneer_address >> 2) & 0x00ffffff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Preserve Rm (lowest four bits) and the condition code
|
||||||
|
// (highest four bits). Other bits encode MOV PC,Rm.
|
||||||
|
val = (val & 0xf000000f) | 0x01a0f000;
|
||||||
|
}
|
||||||
|
elfcpp::Swap<32, big_endian>::writeval(wv, val);
|
||||||
|
return This::STATUS_OKAY;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Relocate ARM long branches. This handles relocation types
|
// Relocate ARM long branches. This handles relocation types
|
||||||
|
@ -3676,6 +3825,15 @@ Stub_factory::Stub_factory()
|
||||||
Insn_template::arm_rel_insn(0xea000000, -8) // b dest
|
Insn_template::arm_rel_insn(0xea000000, -8) // b dest
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Stub used to provide an interworking for R_ARM_V4BX relocation
|
||||||
|
// (bx r[n] instruction).
|
||||||
|
static const Insn_template elf32_arm_stub_v4_veneer_bx[] =
|
||||||
|
{
|
||||||
|
Insn_template::arm_insn(0xe3100001), // tst r<n>, #1
|
||||||
|
Insn_template::arm_insn(0x01a0f000), // moveq pc, r<n>
|
||||||
|
Insn_template::arm_insn(0xe12fff10) // bx r<n>
|
||||||
|
};
|
||||||
|
|
||||||
// Fill in the stub template look-up table. Stub templates are constructed
|
// Fill in the stub template look-up table. Stub templates are constructed
|
||||||
// per instance of Stub_factory for fast look-up without locking
|
// per instance of Stub_factory for fast look-up without locking
|
||||||
// in a thread-enabled environment.
|
// in a thread-enabled environment.
|
||||||
|
@ -3770,6 +3928,16 @@ Stub_table<big_endian>::relocate_stubs(
|
||||||
++p)
|
++p)
|
||||||
this->relocate_stub(p->second, relinfo, arm_target, output_section, view,
|
this->relocate_stub(p->second, relinfo, arm_target, output_section, view,
|
||||||
address, view_size);
|
address, view_size);
|
||||||
|
|
||||||
|
// Relocate all ARM V4BX stubs.
|
||||||
|
for (Arm_v4bx_stub_list::iterator p = this->arm_v4bx_stubs_.begin();
|
||||||
|
p != this->arm_v4bx_stubs_.end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
if (*p != NULL)
|
||||||
|
this->relocate_stub(*p, relinfo, arm_target, output_section, view,
|
||||||
|
address, view_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the stubs to file.
|
// Write out the stubs to file.
|
||||||
|
@ -3811,6 +3979,22 @@ Stub_table<big_endian>::do_write(Output_file* of)
|
||||||
big_endian);
|
big_endian);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write ARM V4BX relocation stubs.
|
||||||
|
for (Arm_v4bx_stub_list::const_iterator p = this->arm_v4bx_stubs_.begin();
|
||||||
|
p != this->arm_v4bx_stubs_.end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
if (*p == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Arm_address address = this->address() + (*p)->offset();
|
||||||
|
gold_assert(address
|
||||||
|
== align_address(address,
|
||||||
|
(*p)->stub_template()->alignment()));
|
||||||
|
(*p)->write(oview + (*p)->offset(), (*p)->stub_template()->size(),
|
||||||
|
big_endian);
|
||||||
|
}
|
||||||
|
|
||||||
of->write_output_view(this->offset(), oview_size, oview);
|
of->write_output_view(this->offset(), oview_size, oview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3847,6 +4031,19 @@ Stub_table<big_endian>::update_data_size_and_addralign()
|
||||||
+ stub_template->size());
|
+ stub_template->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Arm_v4bx_stub_list::const_iterator p = this->arm_v4bx_stubs_.begin();
|
||||||
|
p != this->arm_v4bx_stubs_.end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
if (*p == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const Stub_template* stub_template = (*p)->stub_template();
|
||||||
|
addralign = std::max(addralign, stub_template->alignment());
|
||||||
|
size = (align_address(size, stub_template->alignment())
|
||||||
|
+ stub_template->size());
|
||||||
|
}
|
||||||
|
|
||||||
// Check if either data size or alignment changed in this pass.
|
// Check if either data size or alignment changed in this pass.
|
||||||
// Update prev_data_size_ and prev_addralign_. These will be used
|
// Update prev_data_size_ and prev_addralign_. These will be used
|
||||||
// as the current data size and address alignment for the next pass.
|
// as the current data size and address alignment for the next pass.
|
||||||
|
@ -3898,6 +4095,20 @@ Stub_table<big_endian>::finalize_stubs()
|
||||||
arm_relobj->mark_section_for_cortex_a8_workaround(stub->shndx());
|
arm_relobj->mark_section_for_cortex_a8_workaround(stub->shndx());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Arm_v4bx_stub_list::const_iterator p = this->arm_v4bx_stubs_.begin();
|
||||||
|
p != this->arm_v4bx_stubs_.end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
if (*p == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const Stub_template* stub_template = (*p)->stub_template();
|
||||||
|
uint64_t stub_addralign = stub_template->alignment();
|
||||||
|
off = align_address(off, stub_addralign);
|
||||||
|
(*p)->set_offset(off);
|
||||||
|
off += stub_template->size();
|
||||||
|
}
|
||||||
|
|
||||||
gold_assert(off <= this->prev_data_size_);
|
gold_assert(off <= this->prev_data_size_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5204,6 +5415,7 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
|
||||||
case elfcpp::R_ARM_THM_JUMP6:
|
case elfcpp::R_ARM_THM_JUMP6:
|
||||||
case elfcpp::R_ARM_THM_JUMP8:
|
case elfcpp::R_ARM_THM_JUMP8:
|
||||||
case elfcpp::R_ARM_THM_JUMP11:
|
case elfcpp::R_ARM_THM_JUMP11:
|
||||||
|
case elfcpp::R_ARM_V4BX:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_ARM_GOTOFF32:
|
case elfcpp::R_ARM_GOTOFF32:
|
||||||
|
@ -5335,6 +5547,7 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
|
||||||
case elfcpp::R_ARM_THM_JUMP6:
|
case elfcpp::R_ARM_THM_JUMP6:
|
||||||
case elfcpp::R_ARM_THM_JUMP8:
|
case elfcpp::R_ARM_THM_JUMP8:
|
||||||
case elfcpp::R_ARM_THM_JUMP11:
|
case elfcpp::R_ARM_THM_JUMP11:
|
||||||
|
case elfcpp::R_ARM_V4BX:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_ARM_THM_ABS5:
|
case elfcpp::R_ARM_THM_ABS5:
|
||||||
|
@ -5603,6 +5816,13 @@ Target_arm<big_endian>::do_finalize_sections(
|
||||||
|| cpu_arch_profile_attr->int_value() == 0));
|
|| cpu_arch_profile_attr->int_value() == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we can use V4BX interworking.
|
||||||
|
// The V4BX interworking stub contains BX instruction,
|
||||||
|
// which is not specified for some profiles.
|
||||||
|
if (this->fix_v4bx() == 2 && !this->may_use_blx())
|
||||||
|
gold_error(_("unable to provide V4BX reloc interworking fix up; "
|
||||||
|
"the target profile does not support BX instruction"));
|
||||||
|
|
||||||
// Fill in some more dynamic tags.
|
// Fill in some more dynamic tags.
|
||||||
const Reloc_section* rel_plt = (this->plt_ == NULL
|
const Reloc_section* rel_plt = (this->plt_ == NULL
|
||||||
? NULL
|
? NULL
|
||||||
|
@ -6090,6 +6310,13 @@ Target_arm<big_endian>::Relocate::relocate(
|
||||||
address, thumb_bit);
|
address, thumb_bit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case elfcpp::R_ARM_V4BX:
|
||||||
|
if (target->fix_v4bx() > 0)
|
||||||
|
reloc_status =
|
||||||
|
Arm_relocate_functions::v4bx(relinfo, view, object, address,
|
||||||
|
(target->fix_v4bx() == 2));
|
||||||
|
break;
|
||||||
|
|
||||||
case elfcpp::R_ARM_TARGET1:
|
case elfcpp::R_ARM_TARGET1:
|
||||||
// This should have been mapped to another type already.
|
// This should have been mapped to another type already.
|
||||||
// Fall through.
|
// Fall through.
|
||||||
|
@ -6238,6 +6465,7 @@ Target_arm<big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
|
||||||
case elfcpp::R_ARM_MOVT_PREL:
|
case elfcpp::R_ARM_MOVT_PREL:
|
||||||
case elfcpp::R_ARM_THM_MOVW_PREL_NC:
|
case elfcpp::R_ARM_THM_MOVW_PREL_NC:
|
||||||
case elfcpp::R_ARM_THM_MOVT_PREL:
|
case elfcpp::R_ARM_THM_MOVT_PREL:
|
||||||
|
case elfcpp::R_ARM_V4BX:
|
||||||
return 4;
|
return 4;
|
||||||
|
|
||||||
case elfcpp::R_ARM_TARGET1:
|
case elfcpp::R_ARM_TARGET1:
|
||||||
|
@ -7382,6 +7610,29 @@ Target_arm<big_endian>::scan_reloc_for_stub(
|
||||||
const Arm_relobj<big_endian>* arm_relobj =
|
const Arm_relobj<big_endian>* arm_relobj =
|
||||||
Arm_relobj<big_endian>::as_arm_relobj(relinfo->object);
|
Arm_relobj<big_endian>::as_arm_relobj(relinfo->object);
|
||||||
|
|
||||||
|
if (r_type == elfcpp::R_ARM_V4BX)
|
||||||
|
{
|
||||||
|
const uint32_t reg = (addend & 0xf);
|
||||||
|
if (this->fix_v4bx() == 2 && reg < 0xf)
|
||||||
|
{
|
||||||
|
// Try looking up an existing stub from a stub table.
|
||||||
|
Stub_table<big_endian>* stub_table =
|
||||||
|
arm_relobj->stub_table(relinfo->data_shndx);
|
||||||
|
gold_assert(stub_table != NULL);
|
||||||
|
|
||||||
|
if (stub_table->find_arm_v4bx_stub(reg) == NULL)
|
||||||
|
{
|
||||||
|
// create a new stub and add it to stub table.
|
||||||
|
Arm_v4bx_stub* stub =
|
||||||
|
this->stub_factory().make_arm_v4bx_stub(reg);
|
||||||
|
gold_assert(stub != NULL);
|
||||||
|
stub_table->add_arm_v4bx_stub(stub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool target_is_thumb;
|
bool target_is_thumb;
|
||||||
Symbol_value<32> symval;
|
Symbol_value<32> symval;
|
||||||
if (gsym != NULL)
|
if (gsym != NULL)
|
||||||
|
@ -7553,7 +7804,8 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
|
||||||
&& (r_type != elfcpp::R_ARM_THM_CALL)
|
&& (r_type != elfcpp::R_ARM_THM_CALL)
|
||||||
&& (r_type != elfcpp::R_ARM_THM_XPC22)
|
&& (r_type != elfcpp::R_ARM_THM_XPC22)
|
||||||
&& (r_type != elfcpp::R_ARM_THM_JUMP24)
|
&& (r_type != elfcpp::R_ARM_THM_JUMP24)
|
||||||
&& (r_type != elfcpp::R_ARM_THM_JUMP19))
|
&& (r_type != elfcpp::R_ARM_THM_JUMP19)
|
||||||
|
&& (r_type != elfcpp::R_ARM_V4BX))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
section_offset_type offset =
|
section_offset_type offset =
|
||||||
|
@ -7568,6 +7820,18 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r_type == elfcpp::R_ARM_V4BX)
|
||||||
|
{
|
||||||
|
// Get the BX instruction.
|
||||||
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
||||||
|
const Valtype* wv = reinterpret_cast<const Valtype*>(view + offset);
|
||||||
|
elfcpp::Elf_types<32>::Elf_Swxword insn =
|
||||||
|
elfcpp::Swap<32, big_endian>::readval(wv);
|
||||||
|
this->scan_reloc_for_stub(relinfo, r_type, NULL, 0, NULL,
|
||||||
|
insn, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the addend.
|
// Get the addend.
|
||||||
Stub_addend_reader<sh_type, big_endian> stub_addend_reader;
|
Stub_addend_reader<sh_type, big_endian> stub_addend_reader;
|
||||||
elfcpp::Elf_types<32>::Elf_Swxword addend =
|
elfcpp::Elf_types<32>::Elf_Swxword addend =
|
||||||
|
|
Loading…
Reference in New Issue