From 56ee5e00a8dd7d6821958b9e0c8e84e405e362ff Mon Sep 17 00:00:00 2001 From: Doug Kwan Date: Wed, 21 Oct 2009 18:33:18 +0000 Subject: 2009-10-21 Doug Kwan * arm.cc (Stub_table, Arm_input_section): New forward class declarations. (Stub_table): New class defintion. (Stub_table::add_reloc_stub, Stub_table::relocate_stubs Stub_table::do_reset_address_and_file_offset, Stub_table::do_write): New method definition. --- gold/ChangeLog | 9 +++ gold/arm.cc | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) (limited to 'gold') diff --git a/gold/ChangeLog b/gold/ChangeLog index 6431ee4..bec5b3b 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,14 @@ 2009-10-21 Doug Kwan + * arm.cc (Stub_table, Arm_input_section): New forward class + declarations. + (Stub_table): New class defintion. + (Stub_table::add_reloc_stub, Stub_table::relocate_stubs + Stub_table::do_reset_address_and_file_offset, Stub_table::do_write): + New method definition. + +2009-10-21 Doug Kwan + * arm.cc: Update copyright comments. (Target_arm): New forward class template declaration. (Arm_address): New type. diff --git a/gold/arm.cc b/gold/arm.cc index 4b225bf..718c210 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include "elfcpp.h" #include "parameters.h" @@ -55,6 +56,12 @@ template class Output_data_plt_arm; template +class Stub_table; + +template +class Arm_input_section; + +template class Target_arm; // For convenience. @@ -643,6 +650,101 @@ class Stub_factory const Stub_template* stub_templates_[arm_stub_type_last+1]; }; +// A class to hold stubs for the ARM target. + +template +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_() + { } + + ~Stub_table() + { } + + // Owner of this stub table. + Arm_input_section* + owner() const + { return this->owner_; } + + // 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 the current data size. + off_t + current_data_size() const + { return this->current_data_size_for_child(); } + + // 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); + + // Look up a relocation stub using KEY. Return NULL if there is none. + Reloc_stub* + find_reloc_stub(const Reloc_stub::Key& key) const + { + typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.find(key); + return (p != this->reloc_stubs_.end()) ? p->second : NULL; + } + + // Relocate stubs in this stub table. + void + relocate_stubs(const Relocate_info<32, big_endian>*, + Target_arm*, Output_section*, + unsigned char*, Arm_address, section_size_type); + + protected: + // Write out section contents. + void + do_write(Output_file*); + + // 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()); } + + // Reset address and file offset. + void + do_reset_address_and_file_offset(); + + private: + // Unordered map of stubs. + typedef + Unordered_map + Reloc_stub_map; + + // Address alignment + uint64_t addralign_; + // 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_; +}; + // Utilities for manipulating integers of up to 32-bits namespace utils @@ -2261,6 +2363,113 @@ Stub_factory::Stub_factory() #undef DEF_STUB } +// 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. + +template +void +Stub_table::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; + if (this->addralign_ < stub_template->alignment()) + this->addralign_ = stub_template->alignment(); + this->has_been_changed_ = true; +} + +template +void +Stub_table::relocate_stubs( + 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) +{ + // If we are passed a view bigger than the stub table's. we need to + // adjust the view. + gold_assert(address == this->address() + && (view_size + == static_cast(this->data_size()))); + + 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); + } + } +} + +// Reset address and file offset. + +template +void +Stub_table::do_reset_address_and_file_offset() +{ + 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) + { + 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); +} + +// 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); + + for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); + p != this->reloc_stubs_.end(); + ++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); +} + // A class to handle the PLT data. template -- cgit v1.1