2009-11-06 Doug Kwan <dougkwan@google.com>
* arm.cc (class Reloc_stub): Correct a comment. (Target_arm::Target_arm): Initialize arm_input_section_map_. (Target_arm::scan_section_for_stubs): New method declaration. (Target_arm::do_make_elf_object, Target_arm::do_make_output_section): Change methods from private to protected. (Target_arm::do_may_relax): New method definition. (Target_arm::do_relax, Target_arm::group_sections, Target_arm::scan_reloc_for_stub, Target_arm::scan_reloc_section_for_stubs): New method declarations. (Target_arm::arm_input_section_map_): New data member declaration. (Target_arm::scan_reloc_for_stub, Target_arm::scan_reloc_section_for_stubs, Target_arm::scan_section_for_stubs, Target_arm::group_sections, Target_arm::do_relax): New method definitions.
This commit is contained in:
parent
07d59916b9
commit
eb44217c8b
2 changed files with 511 additions and 17 deletions
|
@ -1,3 +1,20 @@
|
||||||
|
2009-11-06 Doug Kwan <dougkwan@google.com>
|
||||||
|
|
||||||
|
* arm.cc (class Reloc_stub): Correct a comment.
|
||||||
|
(Target_arm::Target_arm): Initialize arm_input_section_map_.
|
||||||
|
(Target_arm::scan_section_for_stubs): New method declaration.
|
||||||
|
(Target_arm::do_make_elf_object, Target_arm::do_make_output_section):
|
||||||
|
Change methods from private to protected.
|
||||||
|
(Target_arm::do_may_relax): New method definition.
|
||||||
|
(Target_arm::do_relax, Target_arm::group_sections,
|
||||||
|
Target_arm::scan_reloc_for_stub,
|
||||||
|
Target_arm::scan_reloc_section_for_stubs): New method declarations.
|
||||||
|
(Target_arm::arm_input_section_map_): New data member declaration.
|
||||||
|
(Target_arm::scan_reloc_for_stub,
|
||||||
|
Target_arm::scan_reloc_section_for_stubs,
|
||||||
|
Target_arm::scan_section_for_stubs, Target_arm::group_sections,
|
||||||
|
Target_arm::do_relax): New method definitions.
|
||||||
|
|
||||||
2009-11-06 Mikolaj Zalewski <mikolaj@google.com>
|
2009-11-06 Mikolaj Zalewski <mikolaj@google.com>
|
||||||
|
|
||||||
* configure.ac: Check for (struct stat)::st_mtim
|
* configure.ac: Check for (struct stat)::st_mtim
|
||||||
|
|
511
gold/arm.cc
511
gold/arm.cc
|
@ -572,7 +572,7 @@ class Reloc_stub : public Stub
|
||||||
unsigned int r_sym_;
|
unsigned int r_sym_;
|
||||||
// If r_sym_ is invalid index. This points to a global symbol.
|
// If r_sym_ is invalid index. This points to a global symbol.
|
||||||
// Otherwise, this points a relobj. We used the unsized and target
|
// Otherwise, this points a relobj. We used the unsized and target
|
||||||
// independent Symbol and Relobj classes instead of Arm_symbol and
|
// independent Symbol and Relobj classes instead of Sized_symbol<32> and
|
||||||
// Arm_relobj. This is done to avoid making the stub class a template
|
// Arm_relobj. This is done to avoid making the stub class a template
|
||||||
// as most of the stub machinery is endianity-neutral. However, it
|
// as most of the stub machinery is endianity-neutral. However, it
|
||||||
// may require a bit of casting done by users of this class.
|
// may require a bit of casting done by users of this class.
|
||||||
|
@ -1145,7 +1145,8 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
|
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
|
||||||
copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL), stub_tables_(),
|
copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL), stub_tables_(),
|
||||||
stub_factory_(Stub_factory::get_instance()),
|
stub_factory_(Stub_factory::get_instance()),
|
||||||
may_use_blx_(true), should_force_pic_veneer_(false)
|
may_use_blx_(true), should_force_pic_veneer_(false),
|
||||||
|
arm_input_section_map_()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// Whether we can use BLX.
|
// Whether we can use BLX.
|
||||||
|
@ -1304,6 +1305,13 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
Stub_table<big_endian>*
|
Stub_table<big_endian>*
|
||||||
new_stub_table(Arm_input_section<big_endian>*);
|
new_stub_table(Arm_input_section<big_endian>*);
|
||||||
|
|
||||||
|
// Scan a section for stub generation.
|
||||||
|
void
|
||||||
|
scan_section_for_stubs(const Relocate_info<32, big_endian>*, unsigned int,
|
||||||
|
const unsigned char*, size_t, Output_section*,
|
||||||
|
bool, const unsigned char*, Arm_address,
|
||||||
|
section_size_type);
|
||||||
|
|
||||||
// Get the default ARM target.
|
// Get the default ARM target.
|
||||||
static const Target_arm<big_endian>&
|
static const Target_arm<big_endian>&
|
||||||
default_target()
|
default_target()
|
||||||
|
@ -1318,9 +1326,44 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
reloc_uses_thumb_bit(unsigned int r_type);
|
reloc_uses_thumb_bit(unsigned int r_type);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Make an ELF object.
|
||||||
|
Object*
|
||||||
|
do_make_elf_object(const std::string&, Input_file*, off_t,
|
||||||
|
const elfcpp::Ehdr<32, big_endian>& ehdr);
|
||||||
|
|
||||||
|
Object*
|
||||||
|
do_make_elf_object(const std::string&, Input_file*, off_t,
|
||||||
|
const elfcpp::Ehdr<32, !big_endian>&)
|
||||||
|
{ gold_unreachable(); }
|
||||||
|
|
||||||
|
Object*
|
||||||
|
do_make_elf_object(const std::string&, Input_file*, off_t,
|
||||||
|
const elfcpp::Ehdr<64, false>&)
|
||||||
|
{ gold_unreachable(); }
|
||||||
|
|
||||||
|
Object*
|
||||||
|
do_make_elf_object(const std::string&, Input_file*, off_t,
|
||||||
|
const elfcpp::Ehdr<64, true>&)
|
||||||
|
{ gold_unreachable(); }
|
||||||
|
|
||||||
|
// Make an output section.
|
||||||
|
Output_section*
|
||||||
|
do_make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||||
|
elfcpp::Elf_Xword flags)
|
||||||
|
{ return new Arm_output_section<big_endian>(name, type, flags); }
|
||||||
|
|
||||||
void
|
void
|
||||||
do_adjust_elf_header(unsigned char* view, int len) const;
|
do_adjust_elf_header(unsigned char* view, int len) const;
|
||||||
|
|
||||||
|
// We only need to generate stubs, and hence perform relaxation if we are
|
||||||
|
// not doing relocatable linking.
|
||||||
|
bool
|
||||||
|
do_may_relax() const
|
||||||
|
{ return !parameters->options().relocatable(); }
|
||||||
|
|
||||||
|
bool
|
||||||
|
do_relax(int, const Input_objects*, Symbol_table*, Layout*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The class which scans relocations.
|
// The class which scans relocations.
|
||||||
class Scan
|
class Scan
|
||||||
|
@ -1500,24 +1543,33 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
void
|
void
|
||||||
merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word);
|
merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word);
|
||||||
|
|
||||||
Object*
|
//
|
||||||
do_make_elf_object(const std::string&, Input_file*, off_t,
|
// Methods to support stub-generations.
|
||||||
const elfcpp::Ehdr<32, big_endian>& ehdr);
|
//
|
||||||
|
|
||||||
Object*
|
// Group input sections for stub generation.
|
||||||
do_make_elf_object(const std::string&, Input_file*, off_t,
|
void
|
||||||
const elfcpp::Ehdr<32, !big_endian>&)
|
group_sections(Layout*, section_size_type, bool);
|
||||||
{ gold_unreachable(); }
|
|
||||||
|
|
||||||
Object*
|
// Scan a relocation for stub generation.
|
||||||
do_make_elf_object(const std::string&, Input_file*, off_t,
|
void
|
||||||
const elfcpp::Ehdr<64, false>&)
|
scan_reloc_for_stub(const Relocate_info<32, big_endian>*, unsigned int,
|
||||||
{ gold_unreachable(); }
|
const Sized_symbol<32>*, unsigned int,
|
||||||
|
const Symbol_value<32>*,
|
||||||
|
elfcpp::Elf_types<32>::Elf_Swxword, Arm_address);
|
||||||
|
|
||||||
Object*
|
// Scan a relocation section for stub.
|
||||||
do_make_elf_object(const std::string&, Input_file*, off_t,
|
template<int sh_type>
|
||||||
const elfcpp::Ehdr<64, true>&)
|
void
|
||||||
{ gold_unreachable(); }
|
scan_reloc_section_for_stubs(
|
||||||
|
const Relocate_info<32, big_endian>* relinfo,
|
||||||
|
const unsigned char* prelocs,
|
||||||
|
size_t reloc_count,
|
||||||
|
Output_section* output_section,
|
||||||
|
bool needs_special_offset_handling,
|
||||||
|
const unsigned char* view,
|
||||||
|
elfcpp::Elf_types<32>::Elf_Addr view_address,
|
||||||
|
section_size_type);
|
||||||
|
|
||||||
// Information about this specific target which we pass to the
|
// Information about this specific target which we pass to the
|
||||||
// general Target structure.
|
// general Target structure.
|
||||||
|
@ -1558,6 +1610,8 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||||
bool may_use_blx_;
|
bool may_use_blx_;
|
||||||
// Whether we force PIC branch veneers.
|
// Whether we force PIC branch veneers.
|
||||||
bool should_force_pic_veneer_;
|
bool should_force_pic_veneer_;
|
||||||
|
// Map for locating Arm_input_sections.
|
||||||
|
Arm_input_section_map arm_input_section_map_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool big_endian>
|
template<bool big_endian>
|
||||||
|
@ -5119,6 +5173,429 @@ Target_arm<big_endian>::new_stub_table(Arm_input_section<big_endian>* owner)
|
||||||
return stub_table;
|
return stub_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan a relocation for stub generation.
|
||||||
|
|
||||||
|
template<bool big_endian>
|
||||||
|
void
|
||||||
|
Target_arm<big_endian>::scan_reloc_for_stub(
|
||||||
|
const Relocate_info<32, big_endian>* relinfo,
|
||||||
|
unsigned int r_type,
|
||||||
|
const Sized_symbol<32>* gsym,
|
||||||
|
unsigned int r_sym,
|
||||||
|
const Symbol_value<32>* psymval,
|
||||||
|
elfcpp::Elf_types<32>::Elf_Swxword addend,
|
||||||
|
Arm_address address)
|
||||||
|
{
|
||||||
|
typedef typename Target_arm<big_endian>::Relocate Relocate;
|
||||||
|
|
||||||
|
const Arm_relobj<big_endian>* arm_relobj =
|
||||||
|
Arm_relobj<big_endian>::as_arm_relobj(relinfo->object);
|
||||||
|
|
||||||
|
bool target_is_thumb;
|
||||||
|
Symbol_value<32> symval;
|
||||||
|
if (gsym != NULL)
|
||||||
|
{
|
||||||
|
// This is a global symbol. Determine if we use PLT and if the
|
||||||
|
// final target is THUMB.
|
||||||
|
if (gsym->use_plt_offset(Relocate::reloc_is_non_pic(r_type)))
|
||||||
|
{
|
||||||
|
// This uses a PLT, change the symbol value.
|
||||||
|
symval.set_output_value(this->plt_section()->address()
|
||||||
|
+ gsym->plt_offset());
|
||||||
|
psymval = &symval;
|
||||||
|
target_is_thumb = false;
|
||||||
|
}
|
||||||
|
else if (gsym->is_undefined())
|
||||||
|
// There is no need to generate a stub symbol is undefined.
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target_is_thumb =
|
||||||
|
((gsym->type() == elfcpp::STT_ARM_TFUNC)
|
||||||
|
|| (gsym->type() == elfcpp::STT_FUNC
|
||||||
|
&& !gsym->is_undefined()
|
||||||
|
&& ((psymval->value(arm_relobj, 0) & 1) != 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is a local symbol. Determine if the final target is THUMB.
|
||||||
|
target_is_thumb = arm_relobj->local_symbol_is_thumb_function(r_sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip LSB if this points to a THUMB target.
|
||||||
|
if (target_is_thumb
|
||||||
|
&& Target_arm<big_endian>::reloc_uses_thumb_bit(r_type)
|
||||||
|
&& ((psymval->value(arm_relobj, 0) & 1) != 0))
|
||||||
|
{
|
||||||
|
Arm_address stripped_value =
|
||||||
|
psymval->value(arm_relobj, 0) & ~static_cast<Arm_address>(1);
|
||||||
|
symval.set_output_value(stripped_value);
|
||||||
|
psymval = &symval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the symbol value.
|
||||||
|
Symbol_value<32>::Value value = psymval->value(arm_relobj, 0);
|
||||||
|
|
||||||
|
// Owing to pipelining, the PC relative branches below actually skip
|
||||||
|
// two instructions when the branch offset is 0.
|
||||||
|
Arm_address destination;
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
case elfcpp::R_ARM_CALL:
|
||||||
|
case elfcpp::R_ARM_JUMP24:
|
||||||
|
case elfcpp::R_ARM_PLT32:
|
||||||
|
// ARM branches.
|
||||||
|
destination = value + addend + 8;
|
||||||
|
break;
|
||||||
|
case elfcpp::R_ARM_THM_CALL:
|
||||||
|
case elfcpp::R_ARM_THM_XPC22:
|
||||||
|
case elfcpp::R_ARM_THM_JUMP24:
|
||||||
|
case elfcpp::R_ARM_THM_JUMP19:
|
||||||
|
// THUMB branches.
|
||||||
|
destination = value + addend + 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gold_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stub_type stub_type =
|
||||||
|
Reloc_stub::stub_type_for_reloc(r_type, address, destination,
|
||||||
|
target_is_thumb);
|
||||||
|
|
||||||
|
// This reloc does not need a stub.
|
||||||
|
if (stub_type == arm_stub_none)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Locate stub by destination.
|
||||||
|
Reloc_stub::Key stub_key(stub_type, gsym, arm_relobj, r_sym, addend);
|
||||||
|
|
||||||
|
// Create a stub if there is not one already
|
||||||
|
Reloc_stub* stub = stub_table->find_reloc_stub(stub_key);
|
||||||
|
if (stub == NULL)
|
||||||
|
{
|
||||||
|
// create a new stub and add it to stub table.
|
||||||
|
stub = this->stub_factory().make_reloc_stub(stub_type);
|
||||||
|
stub_table->add_reloc_stub(stub, stub_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the destination address.
|
||||||
|
stub->set_destination_address(destination
|
||||||
|
| (target_is_thumb ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function scans a relocation sections for stub generation.
|
||||||
|
// The template parameter Relocate must be a class type which provides
|
||||||
|
// a single function, relocate(), which implements the machine
|
||||||
|
// specific part of a relocation.
|
||||||
|
|
||||||
|
// BIG_ENDIAN is the endianness of the data. SH_TYPE is the section type:
|
||||||
|
// SHT_REL or SHT_RELA.
|
||||||
|
|
||||||
|
// PRELOCS points to the relocation data. RELOC_COUNT is the number
|
||||||
|
// of relocs. OUTPUT_SECTION is the output section.
|
||||||
|
// NEEDS_SPECIAL_OFFSET_HANDLING is true if input offsets need to be
|
||||||
|
// mapped to output offsets.
|
||||||
|
|
||||||
|
// VIEW is the section data, VIEW_ADDRESS is its memory address, and
|
||||||
|
// VIEW_SIZE is the size. These refer to the input section, unless
|
||||||
|
// NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
|
||||||
|
// the output section.
|
||||||
|
|
||||||
|
template<bool big_endian>
|
||||||
|
template<int sh_type>
|
||||||
|
void inline
|
||||||
|
Target_arm<big_endian>::scan_reloc_section_for_stubs(
|
||||||
|
const Relocate_info<32, big_endian>* relinfo,
|
||||||
|
const unsigned char* prelocs,
|
||||||
|
size_t reloc_count,
|
||||||
|
Output_section* output_section,
|
||||||
|
bool needs_special_offset_handling,
|
||||||
|
const unsigned char* view,
|
||||||
|
elfcpp::Elf_types<32>::Elf_Addr view_address,
|
||||||
|
section_size_type)
|
||||||
|
{
|
||||||
|
typedef typename Reloc_types<sh_type, 32, big_endian>::Reloc Reltype;
|
||||||
|
const int reloc_size =
|
||||||
|
Reloc_types<sh_type, 32, big_endian>::reloc_size;
|
||||||
|
|
||||||
|
Arm_relobj<big_endian>* arm_object =
|
||||||
|
Arm_relobj<big_endian>::as_arm_relobj(relinfo->object);
|
||||||
|
unsigned int local_count = arm_object->local_symbol_count();
|
||||||
|
|
||||||
|
Comdat_behavior comdat_behavior = CB_UNDETERMINED;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
|
||||||
|
{
|
||||||
|
Reltype reloc(prelocs);
|
||||||
|
|
||||||
|
typename elfcpp::Elf_types<32>::Elf_WXword r_info = reloc.get_r_info();
|
||||||
|
unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
|
||||||
|
unsigned int r_type = elfcpp::elf_r_type<32>(r_info);
|
||||||
|
|
||||||
|
r_type = this->get_real_reloc_type(r_type);
|
||||||
|
|
||||||
|
// Only a few relocation types need stubs.
|
||||||
|
if ((r_type != elfcpp::R_ARM_CALL)
|
||||||
|
&& (r_type != elfcpp::R_ARM_JUMP24)
|
||||||
|
&& (r_type != elfcpp::R_ARM_PLT32)
|
||||||
|
&& (r_type != elfcpp::R_ARM_THM_CALL)
|
||||||
|
&& (r_type != elfcpp::R_ARM_THM_XPC22)
|
||||||
|
&& (r_type != elfcpp::R_ARM_THM_JUMP24)
|
||||||
|
&& (r_type != elfcpp::R_ARM_THM_JUMP19))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
section_offset_type offset =
|
||||||
|
convert_to_section_size_type(reloc.get_r_offset());
|
||||||
|
|
||||||
|
if (needs_special_offset_handling)
|
||||||
|
{
|
||||||
|
offset = output_section->output_offset(relinfo->object,
|
||||||
|
relinfo->data_shndx,
|
||||||
|
offset);
|
||||||
|
if (offset == -1)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the addend.
|
||||||
|
Stub_addend_reader<sh_type, big_endian> stub_addend_reader;
|
||||||
|
elfcpp::Elf_types<32>::Elf_Swxword addend =
|
||||||
|
stub_addend_reader(r_type, view + offset, reloc);
|
||||||
|
|
||||||
|
const Sized_symbol<32>* sym;
|
||||||
|
|
||||||
|
Symbol_value<32> symval;
|
||||||
|
const Symbol_value<32> *psymval;
|
||||||
|
if (r_sym < local_count)
|
||||||
|
{
|
||||||
|
sym = NULL;
|
||||||
|
psymval = arm_object->local_symbol(r_sym);
|
||||||
|
|
||||||
|
// If the local symbol belongs to a section we are discarding,
|
||||||
|
// and that section is a debug section, try to find the
|
||||||
|
// corresponding kept section and map this symbol to its
|
||||||
|
// counterpart in the kept section. The symbol must not
|
||||||
|
// correspond to a section we are folding.
|
||||||
|
bool is_ordinary;
|
||||||
|
unsigned int shndx = psymval->input_shndx(&is_ordinary);
|
||||||
|
if (is_ordinary
|
||||||
|
&& shndx != elfcpp::SHN_UNDEF
|
||||||
|
&& !arm_object->is_section_included(shndx)
|
||||||
|
&& !(relinfo->symtab->is_section_folded(arm_object, shndx)))
|
||||||
|
{
|
||||||
|
if (comdat_behavior == CB_UNDETERMINED)
|
||||||
|
{
|
||||||
|
std::string name =
|
||||||
|
arm_object->section_name(relinfo->data_shndx);
|
||||||
|
comdat_behavior = get_comdat_behavior(name.c_str());
|
||||||
|
}
|
||||||
|
if (comdat_behavior == CB_PRETEND)
|
||||||
|
{
|
||||||
|
bool found;
|
||||||
|
typename elfcpp::Elf_types<32>::Elf_Addr value =
|
||||||
|
arm_object->map_to_kept_section(shndx, &found);
|
||||||
|
if (found)
|
||||||
|
symval.set_output_value(value + psymval->input_value());
|
||||||
|
else
|
||||||
|
symval.set_output_value(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
symval.set_output_value(0);
|
||||||
|
}
|
||||||
|
symval.set_no_output_symtab_entry();
|
||||||
|
psymval = &symval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const Symbol* gsym = arm_object->global_symbol(r_sym);
|
||||||
|
gold_assert(gsym != NULL);
|
||||||
|
if (gsym->is_forwarder())
|
||||||
|
gsym = relinfo->symtab->resolve_forwards(gsym);
|
||||||
|
|
||||||
|
sym = static_cast<const Sized_symbol<32>*>(gsym);
|
||||||
|
if (sym->has_symtab_index())
|
||||||
|
symval.set_output_symtab_index(sym->symtab_index());
|
||||||
|
else
|
||||||
|
symval.set_no_output_symtab_entry();
|
||||||
|
|
||||||
|
// We need to compute the would-be final value of this global
|
||||||
|
// symbol.
|
||||||
|
const Symbol_table* symtab = relinfo->symtab;
|
||||||
|
const Sized_symbol<32>* sized_symbol =
|
||||||
|
symtab->get_sized_symbol<32>(gsym);
|
||||||
|
Symbol_table::Compute_final_value_status status;
|
||||||
|
Arm_address value =
|
||||||
|
symtab->compute_final_value<32>(sized_symbol, &status);
|
||||||
|
|
||||||
|
// Skip this if the symbol has not output section.
|
||||||
|
if (status == Symbol_table::CFVS_NO_OUTPUT_SECTION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
symval.set_output_value(value);
|
||||||
|
psymval = &symval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If symbol is a section symbol, we don't know the actual type of
|
||||||
|
// destination. Give up.
|
||||||
|
if (psymval->is_section_symbol())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this->scan_reloc_for_stub(relinfo, r_type, sym, r_sym, psymval,
|
||||||
|
addend, view_address + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan an input section for stub generation.
|
||||||
|
|
||||||
|
template<bool big_endian>
|
||||||
|
void
|
||||||
|
Target_arm<big_endian>::scan_section_for_stubs(
|
||||||
|
const Relocate_info<32, big_endian>* relinfo,
|
||||||
|
unsigned int sh_type,
|
||||||
|
const unsigned char* prelocs,
|
||||||
|
size_t reloc_count,
|
||||||
|
Output_section* output_section,
|
||||||
|
bool needs_special_offset_handling,
|
||||||
|
const unsigned char* view,
|
||||||
|
Arm_address view_address,
|
||||||
|
section_size_type view_size)
|
||||||
|
{
|
||||||
|
if (sh_type == elfcpp::SHT_REL)
|
||||||
|
this->scan_reloc_section_for_stubs<elfcpp::SHT_REL>(
|
||||||
|
relinfo,
|
||||||
|
prelocs,
|
||||||
|
reloc_count,
|
||||||
|
output_section,
|
||||||
|
needs_special_offset_handling,
|
||||||
|
view,
|
||||||
|
view_address,
|
||||||
|
view_size);
|
||||||
|
else if (sh_type == elfcpp::SHT_RELA)
|
||||||
|
// We do not support RELA type relocations yet. This is provided for
|
||||||
|
// completeness.
|
||||||
|
this->scan_reloc_section_for_stubs<elfcpp::SHT_RELA>(
|
||||||
|
relinfo,
|
||||||
|
prelocs,
|
||||||
|
reloc_count,
|
||||||
|
output_section,
|
||||||
|
needs_special_offset_handling,
|
||||||
|
view,
|
||||||
|
view_address,
|
||||||
|
view_size);
|
||||||
|
else
|
||||||
|
gold_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group input sections for stub generation.
|
||||||
|
//
|
||||||
|
// We goup input sections in an output sections so that the total size,
|
||||||
|
// including any padding space due to alignment is smaller than GROUP_SIZE
|
||||||
|
// unless the only input section in group is bigger than GROUP_SIZE already.
|
||||||
|
// Then an ARM stub table is created to follow the last input section
|
||||||
|
// in group. For each group an ARM stub table is created an is placed
|
||||||
|
// after the last group. If STUB_ALWATS_AFTER_BRANCH is false, we further
|
||||||
|
// extend the group after the stub table.
|
||||||
|
|
||||||
|
template<bool big_endian>
|
||||||
|
void
|
||||||
|
Target_arm<big_endian>::group_sections(
|
||||||
|
Layout* layout,
|
||||||
|
section_size_type group_size,
|
||||||
|
bool stubs_always_after_branch)
|
||||||
|
{
|
||||||
|
// Group input sections and insert stub table
|
||||||
|
Layout::Section_list section_list;
|
||||||
|
layout->get_allocated_sections(§ion_list);
|
||||||
|
for (Layout::Section_list::const_iterator p = section_list.begin();
|
||||||
|
p != section_list.end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
Arm_output_section<big_endian>* output_section =
|
||||||
|
Arm_output_section<big_endian>::as_arm_output_section(*p);
|
||||||
|
output_section->group_sections(group_size, stubs_always_after_branch,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relaxation hook. This is where we do stub generation.
|
||||||
|
|
||||||
|
template<bool big_endian>
|
||||||
|
bool
|
||||||
|
Target_arm<big_endian>::do_relax(
|
||||||
|
int pass,
|
||||||
|
const Input_objects* input_objects,
|
||||||
|
Symbol_table* symtab,
|
||||||
|
Layout* layout)
|
||||||
|
{
|
||||||
|
// No need to generate stubs if this is a relocatable link.
|
||||||
|
gold_assert(!parameters->options().relocatable());
|
||||||
|
|
||||||
|
// If this is the first pass, we need to group input sections into
|
||||||
|
// stub groups.
|
||||||
|
if (pass == 1)
|
||||||
|
{
|
||||||
|
// Determine the stub group size. The group size is the absolute
|
||||||
|
// value of the parameter --stub-group-size. If --stub-group-size
|
||||||
|
// is passed a negative value, we restict stubs to be always after
|
||||||
|
// the stubbed branches.
|
||||||
|
int32_t stub_group_size_param =
|
||||||
|
parameters->options().stub_group_size();
|
||||||
|
bool stubs_always_after_branch = stub_group_size_param < 0;
|
||||||
|
section_size_type stub_group_size = abs(stub_group_size_param);
|
||||||
|
|
||||||
|
if (stub_group_size == 1)
|
||||||
|
{
|
||||||
|
// Default value.
|
||||||
|
// Thumb branch range is +-4MB has to be used as the default
|
||||||
|
// maximum size (a given section can contain both ARM and Thumb
|
||||||
|
// code, so the worst case has to be taken into account).
|
||||||
|
//
|
||||||
|
// This value is 24K less than that, which allows for 2025
|
||||||
|
// 12-byte stubs. If we exceed that, then we will fail to link.
|
||||||
|
// The user will have to relink with an explicit group size
|
||||||
|
// option.
|
||||||
|
stub_group_size = 4170000;
|
||||||
|
}
|
||||||
|
|
||||||
|
group_sections(layout, stub_group_size, stubs_always_after_branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear changed flags for all stub_tables
|
||||||
|
typedef typename Stub_table_list::iterator Stub_table_iterator;
|
||||||
|
for (Stub_table_iterator sp = this->stub_tables_.begin();
|
||||||
|
sp != this->stub_tables_.end();
|
||||||
|
++sp)
|
||||||
|
(*sp)->set_has_been_changed(false);
|
||||||
|
|
||||||
|
// scan relocs for stubs
|
||||||
|
for (Input_objects::Relobj_iterator op = input_objects->relobj_begin();
|
||||||
|
op != input_objects->relobj_end();
|
||||||
|
++op)
|
||||||
|
{
|
||||||
|
Arm_relobj<big_endian>* arm_relobj =
|
||||||
|
Arm_relobj<big_endian>::as_arm_relobj(*op);
|
||||||
|
arm_relobj->scan_sections_for_stubs(this, symtab, layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool any_stub_table_changed = false;
|
||||||
|
for (Stub_table_iterator sp = this->stub_tables_.begin();
|
||||||
|
(sp != this->stub_tables_.end()) && !any_stub_table_changed;
|
||||||
|
++sp)
|
||||||
|
{
|
||||||
|
if ((*sp)->has_been_changed())
|
||||||
|
any_stub_table_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return any_stub_table_changed;
|
||||||
|
}
|
||||||
|
|
||||||
// The selector for arm object files.
|
// The selector for arm object files.
|
||||||
|
|
||||||
template<bool big_endian>
|
template<bool big_endian>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue