2010-01-14 Doug Kwan <dougkwan@google.com>
* arm.cc (map, utility): Include headers. (Target_arm::apply_cortex_a8_workaround): New method. (Arm_relobj::do_relocate_sections): Apply any Cortex-A8 workaround. (Target_arm::Scan::local): Handle R_ARM_THM_JUMP24, R_ARM_THM_JUMP19. (Target_arm::Scan::global): R_ARM_THM_JUMP19. (Target_arm::do_finalize_sections): Set fix_cortex_a8_ according to the --[no-]fix-cortex-a8 command line options. (Target_arm::Relocate::relocate): Handle R_ARM_JUMP19. (Target_arm::relocate_stub): Use addend in instruction template. * options.h (DEFINE_bool): Set the user-set flag. (General_options): Add --[no-]-fix-cortex options. * output.cc (Output_section::convert_input_sections_to_relaxed_sections) : Update fast look-up map after conversion.
This commit is contained in:
parent
459e9b03e8
commit
41263c058c
@ -1,3 +1,19 @@
|
|||||||
|
2010-01-14 Doug Kwan <dougkwan@google.com>
|
||||||
|
|
||||||
|
* arm.cc (map, utility): Include headers.
|
||||||
|
(Target_arm::apply_cortex_a8_workaround): New method.
|
||||||
|
(Arm_relobj::do_relocate_sections): Apply any Cortex-A8 workaround.
|
||||||
|
(Target_arm::Scan::local): Handle R_ARM_THM_JUMP24, R_ARM_THM_JUMP19.
|
||||||
|
(Target_arm::Scan::global): R_ARM_THM_JUMP19.
|
||||||
|
(Target_arm::do_finalize_sections): Set fix_cortex_a8_ according to
|
||||||
|
the --[no-]fix-cortex-a8 command line options.
|
||||||
|
(Target_arm::Relocate::relocate): Handle R_ARM_JUMP19.
|
||||||
|
(Target_arm::relocate_stub): Use addend in instruction template.
|
||||||
|
* options.h (DEFINE_bool): Set the user-set flag.
|
||||||
|
(General_options): Add --[no-]-fix-cortex options.
|
||||||
|
* output.cc (Output_section::convert_input_sections_to_relaxed_sections)
|
||||||
|
: Update fast look-up map after conversion.
|
||||||
|
|
||||||
2010-01-14 Sriraman Tallam <tmsriram@google.com>
|
2010-01-14 Sriraman Tallam <tmsriram@google.com>
|
||||||
|
|
||||||
* object.cc (Sized_relobj::do_layout): Change to call layout_gnu_stack
|
* object.cc (Sized_relobj::do_layout): Change to call layout_gnu_stack
|
||||||
|
129
gold/arm.cc
129
gold/arm.cc
@ -30,6 +30,8 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "elfcpp.h"
|
#include "elfcpp.h"
|
||||||
#include "parameters.h"
|
#include "parameters.h"
|
||||||
@ -1686,6 +1688,11 @@ class Target_arm : public Sized_target<32, big_endian>
|
|||||||
section_size_type, section_size_type,
|
section_size_type, section_size_type,
|
||||||
const unsigned char*, Arm_address);
|
const unsigned char*, Arm_address);
|
||||||
|
|
||||||
|
// Apply Cortex-A8 workaround to a branch.
|
||||||
|
void
|
||||||
|
apply_cortex_a8_workaround(const Cortex_a8_stub*, Arm_address,
|
||||||
|
unsigned char*, Arm_address);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Make an ELF object.
|
// Make an ELF object.
|
||||||
Object*
|
Object*
|
||||||
@ -4554,11 +4561,10 @@ Arm_relobj<big_endian>::do_relocate_sections(
|
|||||||
Arm_input_section<big_endian>* arm_input_section =
|
Arm_input_section<big_endian>* arm_input_section =
|
||||||
arm_target->find_arm_input_section(this, i);
|
arm_target->find_arm_input_section(this, i);
|
||||||
|
|
||||||
if (arm_input_section == NULL
|
if (arm_input_section != NULL
|
||||||
|| !arm_input_section->is_stub_table_owner()
|
&& arm_input_section->is_stub_table_owner()
|
||||||
|| arm_input_section->stub_table()->empty())
|
&& !arm_input_section->stub_table()->empty())
|
||||||
continue;
|
{
|
||||||
|
|
||||||
// We cannot discard a section if it owns a stub table.
|
// We cannot discard a section if it owns a stub table.
|
||||||
Output_section* os = this->output_section(i);
|
Output_section* os = this->output_section(i);
|
||||||
gold_assert(os != NULL);
|
gold_assert(os != NULL);
|
||||||
@ -4585,6 +4591,36 @@ Arm_relobj<big_endian>::do_relocate_sections(
|
|||||||
stub_table->relocate_stubs(&relinfo, arm_target, os, view, address,
|
stub_table->relocate_stubs(&relinfo, arm_target, os, view, address,
|
||||||
view_size);
|
view_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply Cortex A8 workaround if applicable.
|
||||||
|
if (this->section_has_cortex_a8_workaround(i))
|
||||||
|
{
|
||||||
|
unsigned char* view = (*pviews)[i].view;
|
||||||
|
Arm_address view_address = (*pviews)[i].address;
|
||||||
|
section_size_type view_size = (*pviews)[i].view_size;
|
||||||
|
Stub_table<big_endian>* stub_table = this->stub_tables_[i];
|
||||||
|
|
||||||
|
// Adjust view to cover section.
|
||||||
|
Output_section* os = this->output_section(i);
|
||||||
|
gold_assert(os != NULL);
|
||||||
|
Arm_address section_address = os->output_address(this, i, 0);
|
||||||
|
uint64_t section_size = this->section_size(i);
|
||||||
|
|
||||||
|
gold_assert(section_address >= view_address
|
||||||
|
&& ((section_address + section_size)
|
||||||
|
<= (view_address + view_size)));
|
||||||
|
|
||||||
|
unsigned char* section_view = view + (section_address - view_address);
|
||||||
|
|
||||||
|
// Apply the Cortex-A8 workaround to the output address range
|
||||||
|
// corresponding to this input section.
|
||||||
|
stub_table->apply_cortex_a8_workaround_to_address_range(
|
||||||
|
arm_target,
|
||||||
|
section_view,
|
||||||
|
section_address,
|
||||||
|
section_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions for both Arm_relobj and Arm_dynobj to read ARM
|
// Helper functions for both Arm_relobj and Arm_dynobj to read ARM
|
||||||
@ -5086,6 +5122,8 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
|
|||||||
case elfcpp::R_ARM_CALL:
|
case elfcpp::R_ARM_CALL:
|
||||||
case elfcpp::R_ARM_PREL31:
|
case elfcpp::R_ARM_PREL31:
|
||||||
case elfcpp::R_ARM_JUMP24:
|
case elfcpp::R_ARM_JUMP24:
|
||||||
|
case elfcpp::R_ARM_THM_JUMP24:
|
||||||
|
case elfcpp::R_ARM_THM_JUMP19:
|
||||||
case elfcpp::R_ARM_PLT32:
|
case elfcpp::R_ARM_PLT32:
|
||||||
case elfcpp::R_ARM_THM_ABS5:
|
case elfcpp::R_ARM_THM_ABS5:
|
||||||
case elfcpp::R_ARM_ABS8:
|
case elfcpp::R_ARM_ABS8:
|
||||||
@ -5272,6 +5310,7 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
|
|||||||
|
|
||||||
case elfcpp::R_ARM_JUMP24:
|
case elfcpp::R_ARM_JUMP24:
|
||||||
case elfcpp::R_ARM_THM_JUMP24:
|
case elfcpp::R_ARM_THM_JUMP24:
|
||||||
|
case elfcpp::R_ARM_THM_JUMP19:
|
||||||
case elfcpp::R_ARM_CALL:
|
case elfcpp::R_ARM_CALL:
|
||||||
case elfcpp::R_ARM_THM_CALL:
|
case elfcpp::R_ARM_THM_CALL:
|
||||||
|
|
||||||
@ -5474,11 +5513,27 @@ Target_arm<big_endian>::do_finalize_sections(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check BLX use.
|
// Check BLX use.
|
||||||
Object_attribute* attr =
|
const Object_attribute* cpu_arch_attr =
|
||||||
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch);
|
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch);
|
||||||
if (attr->int_value() > elfcpp::TAG_CPU_ARCH_V4)
|
if (cpu_arch_attr->int_value() > elfcpp::TAG_CPU_ARCH_V4)
|
||||||
this->set_may_use_blx(true);
|
this->set_may_use_blx(true);
|
||||||
|
|
||||||
|
// Check if we need to use Cortex-A8 workaround.
|
||||||
|
if (parameters->options().user_set_fix_cortex_a8())
|
||||||
|
this->fix_cortex_a8_ = parameters->options().fix_cortex_a8();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If neither --fix-cortex-a8 nor --no-fix-cortex-a8 is used, turn on
|
||||||
|
// Cortex-A8 erratum workaround for ARMv7-A or ARMv7 with unknown
|
||||||
|
// profile.
|
||||||
|
const Object_attribute* cpu_arch_profile_attr =
|
||||||
|
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile);
|
||||||
|
this->fix_cortex_a8_ =
|
||||||
|
(cpu_arch_attr->int_value() == elfcpp::TAG_CPU_ARCH_V7
|
||||||
|
&& (cpu_arch_profile_attr->int_value() == 'A'
|
||||||
|
|| cpu_arch_profile_attr->int_value() == 0));
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@ -5940,6 +5995,12 @@ Target_arm<big_endian>::Relocate::relocate(
|
|||||||
is_weakly_undefined_without_plt);
|
is_weakly_undefined_without_plt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case elfcpp::R_ARM_THM_JUMP19:
|
||||||
|
reloc_status =
|
||||||
|
Arm_relocate_functions::thm_jump19(view, object, psymval, address,
|
||||||
|
thumb_bit);
|
||||||
|
break;
|
||||||
|
|
||||||
case elfcpp::R_ARM_PREL31:
|
case elfcpp::R_ARM_PREL31:
|
||||||
reloc_status = Arm_relocate_functions::prel31(view, object, psymval,
|
reloc_status = Arm_relocate_functions::prel31(view, object, psymval,
|
||||||
address, thumb_bit);
|
address, thumb_bit);
|
||||||
@ -7711,7 +7772,7 @@ Target_arm<big_endian>::relocate_stub(
|
|||||||
gold_assert(reloc_offset + reloc_size <= view_size);
|
gold_assert(reloc_offset + reloc_size <= view_size);
|
||||||
|
|
||||||
// This is the address of the stub destination.
|
// This is the address of the stub destination.
|
||||||
Arm_address target = stub->reloc_target(i);
|
Arm_address target = stub->reloc_target(i) + insn->reloc_addend();
|
||||||
Symbol_value<32> symval;
|
Symbol_value<32> symval;
|
||||||
symval.set_output_value(target);
|
symval.set_output_value(target);
|
||||||
|
|
||||||
@ -7949,6 +8010,58 @@ Target_arm<big_endian>::scan_span_for_cortex_a8_erratum(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the Cortex-A8 workaround.
|
||||||
|
|
||||||
|
template<bool big_endian>
|
||||||
|
void
|
||||||
|
Target_arm<big_endian>::apply_cortex_a8_workaround(
|
||||||
|
const Cortex_a8_stub* stub,
|
||||||
|
Arm_address stub_address,
|
||||||
|
unsigned char* insn_view,
|
||||||
|
Arm_address insn_address)
|
||||||
|
{
|
||||||
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
|
||||||
|
Valtype* wv = reinterpret_cast<Valtype*>(insn_view);
|
||||||
|
Valtype upper_insn = elfcpp::Swap<16, big_endian>::readval(wv);
|
||||||
|
Valtype lower_insn = elfcpp::Swap<16, big_endian>::readval(wv + 1);
|
||||||
|
off_t branch_offset = stub_address - (insn_address + 4);
|
||||||
|
|
||||||
|
typedef struct Arm_relocate_functions<big_endian> RelocFuncs;
|
||||||
|
switch (stub->stub_template()->type())
|
||||||
|
{
|
||||||
|
case arm_stub_a8_veneer_b_cond:
|
||||||
|
gold_assert(!utils::has_overflow<21>(branch_offset));
|
||||||
|
upper_insn = RelocFuncs::thumb32_cond_branch_upper(upper_insn,
|
||||||
|
branch_offset);
|
||||||
|
lower_insn = RelocFuncs::thumb32_cond_branch_lower(lower_insn,
|
||||||
|
branch_offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case arm_stub_a8_veneer_b:
|
||||||
|
case arm_stub_a8_veneer_bl:
|
||||||
|
case arm_stub_a8_veneer_blx:
|
||||||
|
if ((lower_insn & 0x5000U) == 0x4000U)
|
||||||
|
// For a BLX instruction, make sure that the relocation is
|
||||||
|
// rounded up to a word boundary. This follows the semantics of
|
||||||
|
// the instruction which specifies that bit 1 of the target
|
||||||
|
// address will come from bit 1 of the base address.
|
||||||
|
branch_offset = (branch_offset + 2) & ~3;
|
||||||
|
|
||||||
|
// Put BRANCH_OFFSET back into the insn.
|
||||||
|
gold_assert(!utils::has_overflow<25>(branch_offset));
|
||||||
|
upper_insn = RelocFuncs::thumb32_branch_upper(upper_insn, branch_offset);
|
||||||
|
lower_insn = RelocFuncs::thumb32_branch_lower(lower_insn, branch_offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
gold_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the relocated value back in the object file:
|
||||||
|
elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn);
|
||||||
|
elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
|
||||||
|
}
|
||||||
|
|
||||||
template<bool big_endian>
|
template<bool big_endian>
|
||||||
class Target_selector_arm : public Target_selector
|
class Target_selector_arm : public Target_selector
|
||||||
{
|
{
|
||||||
|
@ -315,7 +315,10 @@ struct Struct_special : public Struct_var
|
|||||||
void \
|
void \
|
||||||
parse_to_value(const char*, const char*, \
|
parse_to_value(const char*, const char*, \
|
||||||
Command_line*, General_options* options) \
|
Command_line*, General_options* options) \
|
||||||
{ options->set_##varname__(false); } \
|
{ \
|
||||||
|
options->set_##varname__(false); \
|
||||||
|
options->set_user_set_##varname__(); \
|
||||||
|
} \
|
||||||
\
|
\
|
||||||
options::One_option option; \
|
options::One_option option; \
|
||||||
}; \
|
}; \
|
||||||
@ -719,6 +722,10 @@ class General_options
|
|||||||
DEFINE_string(fini, options::ONE_DASH, '\0', "_fini",
|
DEFINE_string(fini, options::ONE_DASH, '\0', "_fini",
|
||||||
N_("Call SYMBOL at unload-time"), N_("SYMBOL"));
|
N_("Call SYMBOL at unload-time"), N_("SYMBOL"));
|
||||||
|
|
||||||
|
DEFINE_bool(fix_cortex_a8, options::TWO_DASHES, '\0', false,
|
||||||
|
N_("(ARM only) Fix binaries for Cortex-A8 erratum."),
|
||||||
|
N_("(ARM only) Do not fix binaries for Cortex-A8 erratum."));
|
||||||
|
|
||||||
DEFINE_bool(g, options::EXACTLY_ONE_DASH, '\0', false,
|
DEFINE_bool(g, options::EXACTLY_ONE_DASH, '\0', false,
|
||||||
N_("Ignored"), NULL);
|
N_("Ignored"), NULL);
|
||||||
|
|
||||||
|
@ -2272,6 +2272,15 @@ Output_section::convert_input_sections_to_relaxed_sections(
|
|||||||
relaxed_sections,
|
relaxed_sections,
|
||||||
map,
|
map,
|
||||||
&this->input_sections_);
|
&this->input_sections_);
|
||||||
|
|
||||||
|
// Update fast look-up map.
|
||||||
|
if (this->is_relaxed_input_section_map_valid_)
|
||||||
|
for (size_t i = 0; i < relaxed_sections.size(); ++i)
|
||||||
|
{
|
||||||
|
Output_relaxed_input_section* poris = relaxed_sections[i];
|
||||||
|
Input_section_specifier iss(poris->relobj(), poris->shndx());
|
||||||
|
this->relaxed_input_section_map_[iss] = poris;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the output section flags based on input section flags.
|
// Update the output section flags based on input section flags.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user