2009-10-22 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Thu, 22 Oct 2009 18:58:02 +0000 (18:58 +0000)
committerDoug Kwan <dougkwan@google.com>
Thu, 22 Oct 2009 18:58:02 +0000 (18:58 +0000)
* arm.cc (Arm_input_section): New class definition.
(Arm_input_section::init, Arm_input_section:do_write,
Arm_input_section::set_final_data_size,
Arm_input_section::do_reset_address_and_file_offset): New method
definitions.

gold/ChangeLog
gold/arm.cc

index bec5b3b4b46a04cb0dca5278a27ce60dcf9b9ebe..60ef9d004ea694374e976ff8dd85caa46f8ce081 100644 (file)
@@ -1,3 +1,11 @@
+2009-10-22  Doug Kwan  <dougkwan@google.com>
+
+       * arm.cc (Arm_input_section): New class definition.
+       (Arm_input_section::init, Arm_input_section:do_write,
+       Arm_input_section::set_final_data_size,
+       Arm_input_section::do_reset_address_and_file_offset): New method
+       definitions.
+
 2009-10-21  Doug Kwan  <dougkwan@google.com>
 
        * arm.cc (Stub_table, Arm_input_section): New forward class
index 718c21032ebc8263dcc6371769b1e0a1ce008755..b8bce33088e38fe90b1e2ab0a58e4e6c853316f2 100644 (file)
@@ -745,6 +745,95 @@ class Stub_table : public Output_data
   Reloc_stub_map reloc_stubs_;
 };
 
+// A class to wrap an ordinary input section containing executable code.
+
+template<bool big_endian>
+class Arm_input_section : public Output_relaxed_input_section
+{
+ public:
+  Arm_input_section(Relobj* relobj, unsigned int shndx)
+    : Output_relaxed_input_section(relobj, shndx, 1),
+      original_addralign_(1), original_size_(0), stub_table_(NULL)
+  { }
+
+  ~Arm_input_section()
+  { }
+
+  // Initialize.
+  void
+  init();
+  
+  // Whether this is a stub table owner.
+  bool
+  is_stub_table_owner() const
+  { return this->stub_table_ != NULL && this->stub_table_->owner() == this; }
+
+  // Return the stub table.
+  Stub_table<big_endian>*
+  stub_table() const
+  { return this->stub_table_; }
+
+  // Set the stub_table.
+  void
+  set_stub_table(Stub_table<big_endian>* stub_table)
+  { this->stub_table_ = stub_table; }
+
+ protected:
+  // Write data to output file.
+  void
+  do_write(Output_file*);
+
+  // Return required alignment of this.
+  uint64_t
+  do_addralign() const
+  {
+    if (this->is_stub_table_owner())
+      return std::max(this->stub_table_->addralign(),
+                     this->original_addralign_);
+    else
+      return this->original_addralign_;
+  }
+
+  // Finalize data size.
+  void
+  set_final_data_size();
+
+  // Reset address and file offset.
+  void
+  do_reset_address_and_file_offset();
+
+  // Output offset.
+  bool
+  do_output_offset(const Relobj* object, unsigned int shndx,
+                  section_offset_type offset,
+                   section_offset_type* poutput) const
+  {
+    if ((object == this->relobj())
+       && (shndx == this->shndx())
+       && (offset >= 0)
+       && (convert_types<uint64_t, section_offset_type>(offset)
+           <= this->original_size_))
+      {
+       *poutput = offset;
+       return true;
+      }
+    else
+      return false;
+  }
+
+ private:
+  // Copying is not allowed.
+  Arm_input_section(const Arm_input_section&);
+  Arm_input_section& operator=(const Arm_input_section&);
+
+  // Address alignment of the original input section.
+  uint64_t original_addralign_;
+  // Section size of the original input section.
+  uint64_t original_size_;
+  // Stub table.
+  Stub_table<big_endian>* stub_table_;
+};
+
 // Utilities for manipulating integers of up to 32-bits
 
 namespace utils
@@ -2470,6 +2559,96 @@ Stub_table<big_endian>::do_write(Output_file* of)
   of->write_output_view(this->offset(), oview_size, oview);
 }
 
+// Arm_input_section methods.
+
+// Initialize an Arm_input_section.
+
+template<bool big_endian>
+void
+Arm_input_section<big_endian>::init()
+{
+  Relobj* relobj = this->relobj();
+  unsigned int shndx = this->shndx();
+
+  // Cache these to speed up size and alignment queries.  It is too slow
+  // to call section_addraglin and section_size every time.
+  this->original_addralign_ = relobj->section_addralign(shndx);
+  this->original_size_ = relobj->section_size(shndx);
+
+  // We want to make this look like the original input section after
+  // output sections are finalized.
+  Output_section* os = relobj->output_section(shndx);
+  off_t offset = relobj->output_section_offset(shndx);
+  gold_assert(os != NULL && !relobj->is_output_section_offset_invalid(shndx));
+  this->set_address(os->address() + offset);
+  this->set_file_offset(os->offset() + offset);
+
+  this->set_current_data_size(this->original_size_);
+  this->finalize_data_size();
+}
+
+template<bool big_endian>
+void
+Arm_input_section<big_endian>::do_write(Output_file* of)
+{
+  // We have to write out the original section content.
+  section_size_type section_size;
+  const unsigned char* section_contents =
+    this->relobj()->section_contents(this->shndx(), &section_size, false); 
+  of->write(this->offset(), section_contents, section_size); 
+
+  // If this owns a stub table and it is not empty, write it.
+  if (this->is_stub_table_owner() && !this->stub_table_->empty())
+    this->stub_table_->write(of);
+}
+
+// Finalize data size.
+
+template<bool big_endian>
+void
+Arm_input_section<big_endian>::set_final_data_size()
+{
+  // If this owns a stub table, finalize its data size as well.
+  if (this->is_stub_table_owner())
+    {
+      uint64_t address = this->address();
+
+      // The stub table comes after the original section contents.
+      address += this->original_size_;
+      address = align_address(address, this->stub_table_->addralign());
+      off_t offset = this->offset() + (address - this->address());
+      this->stub_table_->set_address_and_file_offset(address, offset);
+      address += this->stub_table_->data_size();
+      gold_assert(address == this->address() + this->current_data_size());
+    }
+
+  this->set_data_size(this->current_data_size());
+}
+
+// Reset address and file offset.
+
+template<bool big_endian>
+void
+Arm_input_section<big_endian>::do_reset_address_and_file_offset()
+{
+  // Size of the original input section contents.
+  off_t off = convert_types<off_t, uint64_t>(this->original_size_);
+
+  // If this is a stub table owner, account for the stub table size.
+  if (this->is_stub_table_owner())
+    {
+      Stub_table<big_endian>* stub_table = this->stub_table_;
+
+      // Reset the stub table's address and file offset.  The
+      // current data size for child will be updated after that.
+      stub_table_->reset_address_and_file_offset();
+      off = align_address(off, stub_table_->addralign());
+      off += stub_table->current_data_size();
+    }
+
+  this->set_current_data_size(off);
+}
+
 // A class to handle the PLT data.
 
 template<bool big_endian>