aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Kwan <dougkwan@google.com>2009-10-21 18:33:18 +0000
committerDoug Kwan <dougkwan@google.com>2009-10-21 18:33:18 +0000
commit56ee5e00a8dd7d6821958b9e0c8e84e405e362ff (patch)
treeadb6fe142215d5545ada63f573eeeeaa3240d425
parent2b28d209243f5b7b19cd5adb37c535328334d3a0 (diff)
downloadgdb-56ee5e00a8dd7d6821958b9e0c8e84e405e362ff.zip
gdb-56ee5e00a8dd7d6821958b9e0c8e84e405e362ff.tar.gz
gdb-56ee5e00a8dd7d6821958b9e0c8e84e405e362ff.tar.bz2
2009-10-21 Doug Kwan <dougkwan@google.com>
* 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.
-rw-r--r--gold/ChangeLog9
-rw-r--r--gold/arm.cc209
2 files changed, 218 insertions, 0 deletions
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 <dougkwan@google.com>
+ * 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 <dougkwan@google.com>
+
* 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 <limits>
#include <cstdio>
#include <string>
+#include <algorithm>
#include "elfcpp.h"
#include "parameters.h"
@@ -55,6 +56,12 @@ template<bool big_endian>
class Output_data_plt_arm;
template<bool big_endian>
+class Stub_table;
+
+template<bool big_endian>
+class Arm_input_section;
+
+template<bool big_endian>
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<bool big_endian>
+class Stub_table : public Output_data
+{
+ public:
+ Stub_table(Arm_input_section<big_endian>* owner)
+ : Output_data(), addralign_(1), owner_(owner), has_been_changed_(false),
+ reloc_stubs_()
+ { }
+
+ ~Stub_table()
+ { }
+
+ // Owner of this stub table.
+ Arm_input_section<big_endian>*
+ 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<big_endian>*, 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::Key, Reloc_stub*, Reloc_stub::Key::hash,
+ Reloc_stub::Key::equal_to>
+ Reloc_stub_map;
+
+ // Address alignment
+ uint64_t addralign_;
+ // Owner of this stub table.
+ Arm_input_section<big_endian>* 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<bool big_endian>
+void
+Stub_table<big_endian>::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<bool big_endian>
+void
+Stub_table<big_endian>::relocate_stubs(
+ const Relocate_info<32, big_endian>* relinfo,
+ Target_arm<big_endian>* 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<section_size_type>(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<bool big_endian>
+void
+Stub_table<big_endian>::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<bool big_endian>
+void
+Stub_table<big_endian>::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<bool big_endian>