From 2fb7225c842271c7a7e7fd947658a4f9350aaa0c Mon Sep 17 00:00:00 2001 From: Doug Kwan Date: Sat, 9 Jan 2010 01:55:14 +0000 Subject: [PATCH] 2010-01-08 Doug Kwan * arm.cc (Stub_table::Stub_table): Initalize cortex_a8_stubs_, prev_data_size_ and prev_addralign_. Remove initializer for deleted data member has_been_changed_. (Stub_table::empty): Look at both reloc_stubs_ and cortex_a8_stubs_ to determine if the table is empty. (Stub_table::has_been_changed, Stub_table_set_has_been_changed): Remove. (Stub_table::add_reloc_stub): Define method in class definition instead of just declaring it there. (Stub_table::add_cortex_a8_stub): New method definition. (Stub_table::update_data_size_and_addralign): Ditto. (Stub_table::finalize_stubs): Ditto. (Stub_table::apply_cortex_a8_workaround_to_address_range): Ditto. (Stub_table::do_addralign_): Return address alignment in the (Stub_table::do_reset_address_and_file_offset): Define method in class definition instead of declaring it there. Set current data size to be the data size of the previous pass. (Stub_table::set_final_data_size): Use current data size as the final data size. (Stub_table::relocate_stub): Change parameter type of stub from Reloc_stub pointer to Stub pointer. (Stub_table::addralign_, Stub_table::has_been_changed_): Remove. (Stub_table::Cortex_a8_stub_list): New typedef. (Stub_table::cortex_a8_stubs_, Stub_table::prev_data_size_, Stub_table::prev_addralign_): New data member. (Arm_relobj::Arm_relobj): Initialize data member section_has_cortex_a8_workaround_. (Arm_relobj::section_has_cortex_a8_workaround, Arm_relobj::mark_section_for_cortex_a8_workaround): New method definitions. (Arm_relobj::section_has_cortex_a8_workaround_): New data member declarations. (Target_arm::relocate_stub): Change parameter type of stub from Reloc_stub pointer to Stub pointer. (Insn_template::size, Insn_template::alignment): Handle THUMB16_SPECIAL_TYPE. (Stub_table::remove_all_cortex_a8_stubs, Stub_table::finalize_stubs, Stub_table::update_data_size_and_addralign, Stub_table::apply_cortex_a8_workaround_to_address_range): New method definitions. (Stub_table::relocate_stubs): Handle Cortex-A8 stubs. (Stub_table::do_write): Ditto. (Target_arm::do_relax): Adjust code for changes in Stub_table. --- gold/ChangeLog | 46 +++++++ gold/arm.cc | 364 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 326 insertions(+), 84 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 37a28f11e61..18a465b96db 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,49 @@ +2010-01-08 Doug Kwan + + * arm.cc (Stub_table::Stub_table): Initalize cortex_a8_stubs_, + prev_data_size_ and prev_addralign_. Remove initializer for + deleted data member has_been_changed_. + (Stub_table::empty): Look at both reloc_stubs_ and cortex_a8_stubs_ + to determine if the table is empty. + (Stub_table::has_been_changed, Stub_table_set_has_been_changed): + Remove. + (Stub_table::add_reloc_stub): Define method in class definition + instead of just declaring it there. + (Stub_table::add_cortex_a8_stub): New method definition. + (Stub_table::update_data_size_and_addralign): Ditto. + (Stub_table::finalize_stubs): Ditto. + (Stub_table::apply_cortex_a8_workaround_to_address_range): Ditto. + (Stub_table::do_addralign_): Return address alignment in the + (Stub_table::do_reset_address_and_file_offset): Define method in + class definition instead of declaring it there. Set current data + size to be the data size of the previous pass. + (Stub_table::set_final_data_size): Use current data size as the + final data size. + (Stub_table::relocate_stub): Change parameter type of stub from + Reloc_stub pointer to Stub pointer. + (Stub_table::addralign_, Stub_table::has_been_changed_): Remove. + (Stub_table::Cortex_a8_stub_list): New typedef. + (Stub_table::cortex_a8_stubs_, Stub_table::prev_data_size_, + Stub_table::prev_addralign_): New data member. + (Arm_relobj::Arm_relobj): Initialize data member + section_has_cortex_a8_workaround_. + (Arm_relobj::section_has_cortex_a8_workaround, + Arm_relobj::mark_section_for_cortex_a8_workaround): New method + definitions. + (Arm_relobj::section_has_cortex_a8_workaround_): New data member + declarations. + (Target_arm::relocate_stub): Change parameter type of stub from + Reloc_stub pointer to Stub pointer. + (Insn_template::size, Insn_template::alignment): Handle + THUMB16_SPECIAL_TYPE. + (Stub_table::remove_all_cortex_a8_stubs, Stub_table::finalize_stubs, + Stub_table::update_data_size_and_addralign, + Stub_table::apply_cortex_a8_workaround_to_address_range): New method + definitions. + (Stub_table::relocate_stubs): Handle Cortex-A8 stubs. + (Stub_table::do_write): Ditto. + (Target_arm::do_relax): Adjust code for changes in Stub_table. + 2010-01-08 Ian Lance Taylor PR 11108 diff --git a/gold/arm.cc b/gold/arm.cc index 087979b4fe8..694ef93323e 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -798,8 +798,8 @@ class Stub_table : public Output_data { public: Stub_table(Arm_input_section* owner) - : Output_data(), addralign_(1), owner_(owner), has_been_changed_(false), - reloc_stubs_() + : Output_data(), owner_(owner), reloc_stubs_(), cortex_a8_stubs_(), + prev_data_size_(0), prev_addralign_(1) { } ~Stub_table() @@ -813,17 +813,7 @@ class Stub_table : public Output_data // Whether this stub table is empty. bool empty() const - { return this->reloc_stubs_.empty(); } - - // Whether this has been changed. - bool - has_been_changed() const - { return this->has_been_changed_; } - - // Set the has-been-changed flag. - void - set_has_been_changed(bool value) - { this->has_been_changed_ = value; } + { return this->reloc_stubs_.empty() && this->cortex_a8_stubs_.empty(); } // Return the current data size. off_t @@ -833,7 +823,26 @@ class Stub_table : public Output_data // Add a STUB with using KEY. Caller is reponsible for avoid adding // if already a STUB with the same key has been added. void - add_reloc_stub(Reloc_stub* stub, const Reloc_stub::Key& key); + add_reloc_stub(Reloc_stub* stub, const Reloc_stub::Key& key) + { + const Stub_template* stub_template = stub->stub_template(); + gold_assert(stub_template->type() == key.stub_type()); + this->reloc_stubs_[key] = stub; + } + + // Add a Cortex-A8 STUB that fixes up a THUMB branch at ADDRESS. + // Caller is reponsible for avoid adding if already a STUB with the same + // address has been added. + void + add_cortex_a8_stub(Arm_address address, Cortex_a8_stub* stub) + { + std::pair value(address, stub); + this->cortex_a8_stubs_.insert(value); + } + + // Remove all Cortex-A8 stubs. + void + remove_all_cortex_a8_stubs(); // Look up a relocation stub using KEY. Return NULL if there is none. Reloc_stub* @@ -849,6 +858,23 @@ class Stub_table : public Output_data Target_arm*, Output_section*, unsigned char*, Arm_address, section_size_type); + // Update data size and alignment at the end of a relaxation pass. Return + // true if either data size or alignment is different from that of the + // previous relaxation pass. + bool + update_data_size_and_addralign(); + + // Finalize stubs. Set the offsets of all stubs and mark input sections + // needing the Cortex-A8 workaround. + void + finalize_stubs(); + + // Apply Cortex-A8 workaround to an address range. + void + apply_cortex_a8_workaround_to_address_range(Target_arm*, + unsigned char*, Arm_address, + section_size_type); + protected: // Write out section contents. void @@ -857,33 +883,45 @@ class Stub_table : public Output_data // Return the required alignment. uint64_t do_addralign() const - { return this->addralign_; } - - // Finalize data size. - void - set_final_data_size() - { this->set_data_size(this->current_data_size_for_child()); } + { return this->prev_addralign_; } // Reset address and file offset. void - do_reset_address_and_file_offset(); + do_reset_address_and_file_offset() + { this->set_current_data_size_for_child(this->prev_data_size_); } + // Set final data size. + void + set_final_data_size() + { this->set_data_size(this->current_data_size()); } + private: - // Unordered map of stubs. + // Relocate one stub. + void + relocate_stub(Stub*, const Relocate_info<32, big_endian>*, + Target_arm*, Output_section*, + unsigned char*, Arm_address, section_size_type); + + // Unordered map of relocation stubs. typedef Unordered_map Reloc_stub_map; - // Address alignment - uint64_t addralign_; + // List of Cortex-A8 stubs ordered by addresses of branches being + // fixed up in output. + typedef std::map Cortex_a8_stub_list; + // Owner of this stub table. Arm_input_section* owner_; - // This is set to true during relaxiong if the size of the stub table - // has been changed. - bool has_been_changed_; // The relocation stubs. Reloc_stub_map reloc_stubs_; + // The cortex_a8_stubs. + Cortex_a8_stub_list cortex_a8_stubs_; + // data size of this in the previous pass. + off_t prev_data_size_; + // address alignment of this in the previous pass. + uint64_t prev_addralign_; }; // A class to wrap an ordinary input section containing executable code. @@ -1031,7 +1069,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> const typename elfcpp::Ehdr<32, big_endian>& ehdr) : Sized_relobj<32, big_endian>(name, input_file, offset, ehdr), stub_tables_(), local_symbol_is_thumb_function_(), - attributes_section_data_(NULL) + attributes_section_data_(NULL), section_has_cortex_a8_workaround_(NULL) { } ~Arm_relobj() @@ -1095,6 +1133,24 @@ class Arm_relobj : public Sized_relobj<32, big_endian> attributes_section_data() const { return this->attributes_section_data_; } + // Whether a section contains any Cortex-A8 workaround. + bool + section_has_cortex_a8_workaround(unsigned int shndx) const + { + return (this->section_has_cortex_a8_workaround_ != NULL + && (*this->section_has_cortex_a8_workaround_)[shndx]); + } + + // Mark a section that has Cortex-A8 workaround. + void + mark_section_for_cortex_a8_workaround(unsigned int shndx) + { + if (this->section_has_cortex_a8_workaround_ == NULL) + this->section_has_cortex_a8_workaround_ = + new std::vector(this->shnum(), false); + (*this->section_has_cortex_a8_workaround_)[shndx] = true; + } + protected: // Post constructor setup. void @@ -1133,6 +1189,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian> elfcpp::Elf_Word processor_specific_flags_; // Object attributes if there is an .ARM.attributes section or NULL. Attributes_section_data* attributes_section_data_; + // Bitmap to indicate sections with Cortex-A8 workaround or NULL. + std::vector* section_has_cortex_a8_workaround_; }; // Arm_dynobj class. @@ -1499,7 +1557,7 @@ class Target_arm : public Sized_target<32, big_endian> // Relocate a stub. void - relocate_stub(Reloc_stub*, const Relocate_info<32, big_endian>*, + relocate_stub(Stub*, const Relocate_info<32, big_endian>*, Output_section*, unsigned char*, Arm_address, section_size_type); @@ -2785,6 +2843,7 @@ Insn_template::size() const switch (this->type()) { case THUMB16_TYPE: + case THUMB16_SPECIAL_TYPE: return 2; case ARM_TYPE: case THUMB32_TYPE: @@ -2803,6 +2862,7 @@ Insn_template::alignment() const switch (this->type()) { case THUMB16_TYPE: + case THUMB16_SPECIAL_TYPE: case THUMB32_TYPE: return 2; case ARM_TYPE: @@ -3339,23 +3399,47 @@ Stub_factory::Stub_factory() // Stub_table methods. -// Add a STUB with using KEY. Caller is reponsible for avoid adding -// if already a STUB with the same key has been added. +// Removel all Cortex-A8 stub. template void -Stub_table::add_reloc_stub( - Reloc_stub* stub, - const Reloc_stub::Key& key) +Stub_table::remove_all_cortex_a8_stubs() +{ + for (Cortex_a8_stub_list::iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + delete p->second; + this->cortex_a8_stubs_.clear(); +} + +// Relocate one stub. This is a helper for Stub_table::relocate_stubs(). + +template +void +Stub_table::relocate_stub( + Stub* stub, + const Relocate_info<32, big_endian>* relinfo, + Target_arm* arm_target, + Output_section* output_section, + unsigned char* view, + Arm_address address, + section_size_type view_size) { const Stub_template* stub_template = stub->stub_template(); - gold_assert(stub_template->type() == key.stub_type()); - this->reloc_stubs_[key] = stub; - if (this->addralign_ < stub_template->alignment()) - this->addralign_ = stub_template->alignment(); - this->has_been_changed_ = true; + if (stub_template->reloc_count() != 0) + { + // Adjust view to cover the stub only. + section_size_type offset = stub->offset(); + section_size_type stub_size = stub_template->size(); + gold_assert(offset + stub_size <= view_size); + + arm_target->relocate_stub(stub, relinfo, output_section, view + offset, + address + offset, stub_size); + } } +// Relocate all stubs in this stub table. + template void Stub_table::relocate_stubs( @@ -3372,34 +3456,117 @@ Stub_table::relocate_stubs( && (view_size == static_cast(this->data_size()))); + // Relocate all relocation stubs. + for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); + p != this->reloc_stubs_.end(); + ++p) + this->relocate_stub(p->second, relinfo, arm_target, output_section, view, + address, view_size); + + // Relocate all Cortex-A8 stubs. + for (Cortex_a8_stub_list::iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + this->relocate_stub(p->second, relinfo, arm_target, output_section, view, + address, view_size); +} + +// Write out the stubs to file. + +template +void +Stub_table::do_write(Output_file* of) +{ + off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + // Write relocation stubs. for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); p != this->reloc_stubs_.end(); ++p) { Reloc_stub* stub = p->second; - const Stub_template* stub_template = stub->stub_template(); - if (stub_template->reloc_count() != 0) - { - // Adjust view to cover the stub only. - section_size_type offset = stub->offset(); - section_size_type stub_size = stub_template->size(); - gold_assert(offset + stub_size <= view_size); - - arm_target->relocate_stub(stub, relinfo, output_section, - view + offset, address + offset, - stub_size); - } + Arm_address address = this->address() + stub->offset(); + gold_assert(address + == align_address(address, + stub->stub_template()->alignment())); + stub->write(oview + stub->offset(), stub->stub_template()->size(), + big_endian); } + + // Write Cortex-A8 stubs. + for (Cortex_a8_stub_list::const_iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + { + Cortex_a8_stub* stub = p->second; + Arm_address address = this->address() + stub->offset(); + gold_assert(address + == align_address(address, + stub->stub_template()->alignment())); + stub->write(oview + stub->offset(), stub->stub_template()->size(), + big_endian); + } + + of->write_output_view(this->offset(), oview_size, oview); } -// Reset address and file offset. +// Update the data size and address alignment of the stub table at the end +// of a relaxation pass. Return true if either the data size or the +// alignment changed in this relaxation pass. + +template +bool +Stub_table::update_data_size_and_addralign() +{ + off_t size = 0; + unsigned addralign = 1; + + // Go over all stubs in table to compute data size and address alignment. + + for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); + p != this->reloc_stubs_.end(); + ++p) + { + const Stub_template* stub_template = p->second->stub_template(); + addralign = std::max(addralign, stub_template->alignment()); + size = (align_address(size, stub_template->alignment()) + + stub_template->size()); + } + + for (Cortex_a8_stub_list::const_iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + { + const Stub_template* stub_template = p->second->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. + // Update prev_data_size_ and prev_addralign_. These will be used + // as the current data size and address alignment for the next pass. + bool changed = size != this->prev_data_size_; + this->prev_data_size_ = size; + + if (addralign != this->prev_addralign_) + changed = true; + this->prev_addralign_ = addralign; + + return changed; +} + +// Finalize the stubs. This sets the offsets of the stubs within the stub +// table. It also marks all input sections needing Cortex-A8 workaround. template void -Stub_table::do_reset_address_and_file_offset() +Stub_table::finalize_stubs() { off_t off = 0; - uint64_t max_addralign = 1; for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); p != this->reloc_stubs_.end(); ++p) @@ -3407,41 +3574,65 @@ Stub_table::do_reset_address_and_file_offset() Reloc_stub* stub = p->second; const Stub_template* stub_template = stub->stub_template(); uint64_t stub_addralign = stub_template->alignment(); - max_addralign = std::max(max_addralign, stub_addralign); off = align_address(off, stub_addralign); stub->set_offset(off); - stub->reset_destination_address(); off += stub_template->size(); } - this->addralign_ = max_addralign; - this->set_current_data_size_for_child(off); + for (Cortex_a8_stub_list::const_iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + { + Cortex_a8_stub* stub = p->second; + const Stub_template* stub_template = stub->stub_template(); + uint64_t stub_addralign = stub_template->alignment(); + off = align_address(off, stub_addralign); + stub->set_offset(off); + off += stub_template->size(); + + // Mark input section so that we can determine later if a code section + // needs the Cortex-A8 workaround quickly. + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(stub->relobj()); + arm_relobj->mark_section_for_cortex_a8_workaround(stub->shndx()); + } + + gold_assert(off <= this->prev_data_size_); } -// Write out the stubs to file. +// Apply Cortex-A8 workaround to an address range between VIEW_ADDRESS +// and VIEW_ADDRESS + VIEW_SIZE - 1. VIEW points to the mapped address +// of the address range seen by the linker. template void -Stub_table::do_write(Output_file* of) +Stub_table::apply_cortex_a8_workaround_to_address_range( + Target_arm* arm_target, + unsigned char* view, + Arm_address view_address, + section_size_type view_size) { - off_t offset = this->offset(); - const section_size_type oview_size = - convert_to_section_size_type(this->data_size()); - unsigned char* const oview = of->get_output_view(offset, oview_size); - - for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); - p != this->reloc_stubs_.end(); - ++p) + // Cortex-A8 stubs are sorted by addresses of branches being fixed up. + for (Cortex_a8_stub_list::const_iterator p = + this->cortex_a8_stubs_.lower_bound(view_address); + ((p != this->cortex_a8_stubs_.end()) + && (p->first < (view_address + view_size))); + ++p) { - Reloc_stub* stub = p->second; - Arm_address address = this->address() + stub->offset(); - gold_assert(address - == align_address(address, - stub->stub_template()->alignment())); - stub->write(oview + stub->offset(), stub->stub_template()->size(), - big_endian); - } - of->write_output_view(this->offset(), oview_size, oview); + // We do not store the THUMB bit in the LSB of either the branch address + // or the stub offset. There is no need to strip the LSB. + Arm_address branch_address = p->first; + const Cortex_a8_stub* stub = p->second; + Arm_address stub_address = this->address() + stub->offset(); + + // Offset of the branch instruction relative to this view. + section_size_type offset = + convert_to_section_size_type(branch_address - view_address); + gold_assert((offset + 4) <= view_size); + + arm_target->apply_cortex_a8_workaround(stub, stub_address, + view + offset, branch_address); + } } // Arm_input_section methods. @@ -6998,12 +7189,7 @@ Target_arm::do_relax( 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(); @@ -7015,15 +7201,25 @@ Target_arm::do_relax( arm_relobj->scan_sections_for_stubs(this, symtab, layout); } + // Check all stub tables to see if any of them have their data sizes + // or addresses alignments changed. These are the only things that + // matter. 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()) + if ((*sp)->update_data_size_and_addralign()) any_stub_table_changed = true; } + // Finalize the stubs in the last relaxation pass. + if (!any_stub_table_changed) + for (Stub_table_iterator sp = this->stub_tables_.begin(); + (sp != this->stub_tables_.end()) && !any_stub_table_changed; + ++sp) + (*sp)->finalize_stubs(); + return any_stub_table_changed; } @@ -7032,7 +7228,7 @@ Target_arm::do_relax( template void Target_arm::relocate_stub( - Reloc_stub* stub, + Stub* stub, const Relocate_info<32, big_endian>* relinfo, Output_section* output_section, unsigned char* view, -- 2.30.2