2008-05-05 Ian Lance Taylor <iant@google.com>
[binutils-gdb.git] / gold / output.h
index e69777554930691f8e227b569bf03a5a1f75cf8e..89c6eeb4487affa4a085fa97b9ad72fc083028a3 100644 (file)
@@ -384,7 +384,8 @@ class Output_section_headers : public Output_data
                         const Layout::Segment_list*,
                         const Layout::Section_list*,
                         const Layout::Section_list*,
-                        const Stringpool*);
+                        const Stringpool*,
+                        const Output_section*);
 
  protected:
   // Write the data to the file.
@@ -407,6 +408,7 @@ class Output_section_headers : public Output_data
   const Layout::Section_list* section_list_;
   const Layout::Section_list* unattached_section_list_;
   const Stringpool* secnamepool_;
+  const Output_section* shstrtab_section_;
 };
 
 // Output the segment headers.
@@ -595,8 +597,7 @@ class Output_section_data : public Output_data
 
   // Set the alignment.
   void
-  set_addralign(uint64_t addralign)
-  { this->addralign_ = addralign; }
+  set_addralign(uint64_t addralign);
 
  private:
   // The output section for this section.
@@ -854,6 +855,19 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   template<typename Write_rel>
   void write_rel(Write_rel*) const;
 
+  // This is used when sorting dynamic relocs.  Return -1 to sort this
+  // reloc before R2, 0 to sort the same as R2, 1 to sort after R2.
+  int
+  compare(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>& r2)
+    const;
+
+  // Return whether this reloc should be sorted before the argument
+  // when sorting dynamic relocs.
+  bool
+  sort_before(const Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>&
+             r2) const
+  { return this->compare(r2) < 0; }
+
  private:
   // Record that we need a dynamic symbol index.
   void
@@ -863,6 +877,10 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   unsigned int
   get_symbol_index() const;
 
+  // Return the output address.
+  section_offset_type
+  get_address() const;
+
   // Codes for local_sym_index_.
   enum
   {
@@ -985,6 +1003,21 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   void
   write(unsigned char* pov) const;
 
+  // Return whether this reloc should be sorted before the argument
+  // when sorting dynamic relocs.
+  bool
+  sort_before(const Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>&
+             r2) const
+  {
+    int i = this->rel_.compare(r2.rel_);
+    if (i < 0)
+      return false;
+    else if (i > 0)
+      return true;
+    else
+      return this->addend_ < r2.addend_;
+  }
+
  private:
   // The basic reloc.
   Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
@@ -1009,8 +1042,9 @@ class Output_data_reloc_base : public Output_section_data_build
     Reloc_types<sh_type, size, big_endian>::reloc_size;
 
   // Construct the section.
-  Output_data_reloc_base()
-    : Output_section_data_build(Output_data::default_alignment_for_size(size))
+  Output_data_reloc_base(bool sort_relocs)
+    : Output_section_data_build(Output_data::default_alignment_for_size(size)),
+      sort_relocs_(sort_relocs)
   { }
 
  protected:
@@ -1034,7 +1068,19 @@ class Output_data_reloc_base : public Output_section_data_build
  private:
   typedef std::vector<Output_reloc_type> Relocs;
 
+  // The class used to sort the relocations.
+  struct Sort_relocs_comparison
+  {
+    bool
+    operator()(const Output_reloc_type& r1, const Output_reloc_type& r2) const
+    { return r1.sort_before(r2); }
+  };
+
+  // The relocations in this section.
   Relocs relocs_;
+  // Whether to sort the relocations when writing them out, to make
+  // the dynamic linker more efficient.
+  bool sort_relocs_;
 };
 
 // The class which callers actually create.
@@ -1056,8 +1102,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   typedef typename Base::Output_reloc_type Output_reloc_type;
   typedef typename Output_reloc_type::Address Address;
 
-  Output_data_reloc()
-    : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>()
+  Output_data_reloc(bool sr)
+    : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>(sr)
   { }
 
   // Add a reloc against a global symbol.
@@ -1072,6 +1118,24 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
                                     false)); }
 
+  // These are to simplify the Copy_relocs class.
+
+  void
+  add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address,
+            Address addend)
+  {
+    gold_assert(addend == 0);
+    this->add_global(gsym, type, od, address);
+  }
+
+  void
+  add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+            unsigned int shndx, Address address, Address addend)
+  {
+    gold_assert(addend == 0);
+    this->add_global(gsym, type, od, relobj, shndx, address);
+  }
+
   // Add a RELATIVE reloc against a global symbol.  The final relocation
   // will not reference the symbol.
 
@@ -1180,8 +1244,8 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   typedef typename Output_reloc_type::Address Address;
   typedef typename Output_reloc_type::Addend Addend;
 
-  Output_data_reloc()
-    : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>()
+  Output_data_reloc(bool sr)
+    : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>(sr)
   { }
 
   // Add a reloc against a global symbol.
@@ -1327,9 +1391,11 @@ template<int size, bool big_endian>
 class Output_data_group : public Output_section_data
 {
  public:
+  // The constructor clears *INPUT_SHNDXES.
   Output_data_group(Sized_relobj<size, big_endian>* relobj,
                    section_size_type entry_count,
-                   const elfcpp::Elf_Word* contents);
+                   elfcpp::Elf_Word flags,
+                   std::vector<unsigned int>* input_shndxes);
 
   void
   do_write(Output_file*);
@@ -1340,7 +1406,7 @@ class Output_data_group : public Output_section_data
   // The group flag word.
   elfcpp::Elf_Word flags_;
   // The section indexes of the input sections in this group.
-  std::vector<unsigned int> input_sections_;
+  std::vector<unsigned int> input_shndxes_;
 };
 
 // Output_data_got is used to manage a GOT.  Each entry in the GOT is
@@ -1534,6 +1600,13 @@ class Output_data_dynamic : public Output_section_data
   add_section_address(elfcpp::DT tag, const Output_data* od)
   { this->add_entry(Dynamic_entry(tag, od, false)); }
 
+  // Add a new dynamic entry with the address of output data
+  // plus a constant offset.
+  void
+  add_section_plus_offset(elfcpp::DT tag, const Output_data* od,
+                          unsigned int offset)
+  { this->add_entry(Dynamic_entry(tag, od, offset)); }
+
   // Add a new dynamic entry with the size of output data.
   void
   add_section_size(elfcpp::DT tag, const Output_data* od)
@@ -1573,25 +1646,31 @@ class Output_data_dynamic : public Output_section_data
    public:
     // Create an entry with a fixed numeric value.
     Dynamic_entry(elfcpp::DT tag, unsigned int val)
-      : tag_(tag), classification_(DYNAMIC_NUMBER)
+      : tag_(tag), offset_(DYNAMIC_NUMBER)
     { this->u_.val = val; }
 
     // Create an entry with the size or address of a section.
     Dynamic_entry(elfcpp::DT tag, const Output_data* od, bool section_size)
       : tag_(tag),
-       classification_(section_size
-                       ? DYNAMIC_SECTION_SIZE
-                       : DYNAMIC_SECTION_ADDRESS)
+       offset_(section_size
+               ? DYNAMIC_SECTION_SIZE
+               : DYNAMIC_SECTION_ADDRESS)
+    { this->u_.od = od; }
+
+    // Create an entry with the address of a section plus a constant offset.
+    Dynamic_entry(elfcpp::DT tag, const Output_data* od, unsigned int offset)
+      : tag_(tag),
+       offset_(offset)
     { this->u_.od = od; }
 
     // Create an entry with the address of a symbol.
     Dynamic_entry(elfcpp::DT tag, const Symbol* sym)
-      : tag_(tag), classification_(DYNAMIC_SYMBOL)
+      : tag_(tag), offset_(DYNAMIC_SYMBOL)
     { this->u_.sym = sym; }
 
     // Create an entry with a string.
     Dynamic_entry(elfcpp::DT tag, const char* str)
-      : tag_(tag), classification_(DYNAMIC_STRING)
+      : tag_(tag), offset_(DYNAMIC_STRING)
     { this->u_.str = str; }
 
     // Write the dynamic entry to an output view.
@@ -1600,25 +1679,27 @@ class Output_data_dynamic : public Output_section_data
     write(unsigned char* pov, const Stringpool*) const;
 
    private:
+    // Classification is encoded in the OFFSET field.
     enum Classification
     {
-      // Number.
-      DYNAMIC_NUMBER,
       // Section address.
-      DYNAMIC_SECTION_ADDRESS,
+      DYNAMIC_SECTION_ADDRESS = 0,
+      // Number.
+      DYNAMIC_NUMBER = -1U,
       // Section size.
-      DYNAMIC_SECTION_SIZE,
+      DYNAMIC_SECTION_SIZE = -2U,
       // Symbol adress.
-      DYNAMIC_SYMBOL,
+      DYNAMIC_SYMBOL = -3U,
       // String.
-      DYNAMIC_STRING
+      DYNAMIC_STRING = -4U
+      // Any other value indicates a section address plus OFFSET.
     };
 
     union
     {
       // For DYNAMIC_NUMBER.
       unsigned int val;
-      // For DYNAMIC_SECTION_ADDRESS and DYNAMIC_SECTION_SIZE.
+      // For DYNAMIC_SECTION_SIZE and section address plus OFFSET.
       const Output_data* od;
       // For DYNAMIC_SYMBOL.
       const Symbol* sym;
@@ -1627,8 +1708,8 @@ class Output_data_dynamic : public Output_section_data
     } u_;
     // The dynamic tag.
     elfcpp::DT tag_;
-    // The type of entry.
-    Classification classification_;
+    // The type of entry (Classification) or offset within a section.
+    unsigned int offset_;
   };
 
   // Add an entry to the list.
@@ -1650,6 +1731,41 @@ class Output_data_dynamic : public Output_section_data
   Stringpool* pool_;
 };
 
+// Output_symtab_xindex is used to handle SHT_SYMTAB_SHNDX sections,
+// which may be required if the object file has more than
+// SHN_LORESERVE sections.
+
+class Output_symtab_xindex : public Output_section_data
+{
+ public:
+  Output_symtab_xindex(size_t symcount)
+    : Output_section_data(symcount * 4, 4),
+      entries_()
+  { }
+
+  // Add an entry: symbol number SYMNDX has section SHNDX.
+  void
+  add(unsigned int symndx, unsigned int shndx)
+  { this->entries_.push_back(std::make_pair(symndx, shndx)); }
+
+ protected:
+  void
+  do_write(Output_file*);
+
+ private:
+  template<bool big_endian>
+  void
+  endian_do_write(unsigned char*);
+
+  // It is likely that most symbols will not require entries.  Rather
+  // than keep a vector for all symbols, we keep pairs of symbol index
+  // and section index.
+  typedef std::vector<std::pair<unsigned int, unsigned int> > Xindex_entries;
+
+  // The entries we need.
+  Xindex_entries entries_;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -1700,6 +1816,16 @@ class Output_section : public Output_data
   set_flags(elfcpp::Elf_Xword flags)
   { this->flags_ = flags; }
 
+  // Update the output section flags based on input section flags.
+  void
+  update_flags_for_input_section(elfcpp::Elf_Xword flags)
+  {
+    this->flags_ |= (flags
+                    & (elfcpp::SHF_WRITE
+                       | elfcpp::SHF_ALLOC
+                       | elfcpp::SHF_EXECINSTR));
+  }
+
   // Return the entsize field.
   uint64_t
   entsize() const
@@ -1819,6 +1945,11 @@ class Output_section : public Output_data
   set_addralign(uint64_t v)
   { this->addralign_ = v; }
 
+  // Whether the output section index has been set.
+  bool
+  has_out_shndx() const
+  { return this->out_shndx_ != -1U; }
+
   // Indicate that we need a symtab index.
   void
   set_needs_symtab_index()