2010-03-22 Doug Kwan <dougkwan@google.com>
[binutils-gdb.git] / gold / output.h
index 21d80fb6aa5be69f0382e97c47ecc20f0e5ec165..a63f07c1a0c13241e6985268d63f5ae4c6db8e91 100644 (file)
@@ -47,62 +47,6 @@ class Sized_target;
 template<int size, bool big_endian>
 class Sized_relobj;
 
-// This class specifies an input section.  It is used as a key type
-// for maps.
-
-class Input_section_specifier
-{
- public:
-  Input_section_specifier(const Relobj* robj, unsigned int sec_shndx)
-    : relobj_(robj), shndx_(sec_shndx)
-  { }
-   
-  // Return Relobj of this.
-  const Relobj*
-  relobj() const
-  { return this->relobj_; }
-
-  // Return section index of this.
-  unsigned int
-  shndx() const
-  { return this->shndx_; }
-
-  // Whether this equals to another specifier ISS.
-  bool
-  eq(const Input_section_specifier& iss) const
-  { return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; }
-
-  // Compute a hash value of this.
-  size_t
-  hash_value() const
-  {
-     return (gold::string_hash<char>(this->relobj_->name().c_str())
-            ^ this->shndx_);
-   }
-
-  // Functors for containers.
-  struct equal_to
-  {
-    bool
-    operator()(const Input_section_specifier& iss1,
-              const Input_section_specifier& iss2) const
-    { return iss1.eq(iss2); }
-  };
-  struct hash
-  {
-    size_t
-    operator()(const Input_section_specifier& iss) const
-    { return iss.hash_value(); }
-  };
-
- private:
-  // An object.
-  const Relobj* relobj_;
-  // A section index. 
-  unsigned int shndx_;
-};
-
 // An abtract class for data which has to go into the output file.
 
 class Output_data
@@ -206,6 +150,10 @@ class Output_data
   output_section()
   { return this->do_output_section(); }
 
+  const Output_section*
+  output_section() const
+  { return this->do_output_section(); }
+
   // Return the output section index, if there is an output section.
   unsigned int
   out_shndx() const
@@ -358,6 +306,10 @@ class Output_data
   do_output_section()
   { return NULL; }
 
+  virtual const Output_section*
+  do_output_section() const
+  { return NULL; }
+
   // Return the output section index, if there is an output section.
   virtual unsigned int
   do_out_shndx() const
@@ -416,11 +368,11 @@ class Output_data
 
   // Set the size of the data.
   void
-  set_data_size(off_t datasize)
+  set_data_size(off_t data_size)
   {
     gold_assert(!this->is_data_size_valid_
                && !this->is_data_size_fixed_);
-    this->data_size_ = datasize;
+    this->data_size_ = data_size;
     this->is_data_size_valid_ = true;
   }
 
@@ -442,10 +394,10 @@ class Output_data
   // Set the current data size--this is for the convenience of
   // sections which build up their size over time.
   void
-  set_current_data_size_for_child(off_t datasize)
+  set_current_data_size_for_child(off_t data_size)
   {
     gold_assert(!this->is_data_size_valid_);
-    this->data_size_ = datasize;
+    this->data_size_ = data_size;
   }
 
   // Return default alignment for the target size.
@@ -639,17 +591,17 @@ class Output_file_header : public Output_data
 class Output_section_data : public Output_data
 {
  public:
-  Output_section_data(off_t datasize, uint64_t addr_align,
-                     bool is_datasize_fixed)
-    : Output_data(), output_section_(NULL), addralign_(addr_align)
+  Output_section_data(off_t data_size, uint64_t addralign,
+                     bool is_data_size_fixed)
+    : Output_data(), output_section_(NULL), addralign_(addralign)
   {
-    this->set_data_size(datasize);
-    if (is_datasize_fixed)
+    this->set_data_size(data_size);
+    if (is_data_size_fixed)
       this->fix_data_size();
   }
 
-  Output_section_data(uint64_t addr_align)
-    : Output_data(), output_section_(NULL), addralign_(addr_align)
+  Output_section_data(uint64_t addralign)
+    : Output_data(), output_section_(NULL), addralign_(addralign)
   { }
 
   // Return the output section.
@@ -675,9 +627,9 @@ class Output_section_data : public Output_data
   // this input offset is being discarded.
   bool
   output_offset(const Relobj* object, unsigned int shndx,
-               section_offset_type sec_offset,
+               section_offset_type offset,
                section_offset_type *poutput) const
-  { return this->do_output_offset(object, shndx, sec_offset, poutput); }
+  { return this->do_output_offset(object, shndx, offset, poutput); }
 
   // Return whether this is the merge section for the input section
   // SHNDX in OBJECT.  This should return true when output_offset
@@ -746,6 +698,10 @@ class Output_section_data : public Output_data
   do_output_section()
   { return this->output_section_; }
 
+  const Output_section*
+  do_output_section() const
+  { return this->output_section_; }
+
   // Return the section index of the output section.
   unsigned int
   do_out_shndx() const;
@@ -768,8 +724,8 @@ class Output_section_data : public Output_data
 class Output_section_data_build : public Output_section_data
 {
  public:
-  Output_section_data_build(uint64_t addr_align)
-    : Output_section_data(addr_align)
+  Output_section_data_build(uint64_t addralign)
+    : Output_section_data(addralign)
   { }
 
   // Get the current data size.
@@ -779,8 +735,8 @@ class Output_section_data_build : public Output_section_data
 
   // Set the current data size.
   void
-  set_current_data_size(off_t datasize)
-  { this->set_current_data_size_for_child(datasize); }
+  set_current_data_size(off_t data_size)
+  { this->set_current_data_size_for_child(data_size); }
 
  protected:
   // Set the final data size.
@@ -795,16 +751,16 @@ class Output_section_data_build : public Output_section_data
 class Output_data_const : public Output_section_data
 {
  public:
-  Output_data_const(const std::string& data, uint64_t addr_align)
-    : Output_section_data(data.size(), addr_align, true), data_(data)
+  Output_data_const(const std::string& data, uint64_t addralign)
+    : Output_section_data(data.size(), addralign, true), data_(data)
   { }
 
-  Output_data_const(const char* p, off_t len, uint64_t addr_align)
-    : Output_section_data(len, addr_align, true), data_(p, len)
+  Output_data_const(const char* p, off_t len, uint64_t addralign)
+    : Output_section_data(len, addralign, true), data_(p, len)
   { }
 
-  Output_data_const(const unsigned char* p, off_t len, uint64_t addr_align)
-    : Output_section_data(len, addr_align, true),
+  Output_data_const(const unsigned char* p, off_t len, uint64_t addralign)
+    : Output_section_data(len, addralign, true),
       data_(reinterpret_cast<const char*>(p), len)
   { }
 
@@ -834,8 +790,8 @@ class Output_data_const_buffer : public Output_section_data
 {
  public:
   Output_data_const_buffer(const unsigned char* p, off_t len,
-                          uint64_t addr_align, const char* map_name)
-    : Output_section_data(len, addr_align, true),
+                          uint64_t addralign, const char* map_name)
+    : Output_section_data(len, addralign, true),
       p_(p), map_name_(map_name)
   { }
 
@@ -868,9 +824,9 @@ class Output_data_const_buffer : public Output_section_data
 class Output_data_fixed_space : public Output_section_data
 {
  public:
-  Output_data_fixed_space(off_t datasize, uint64_t addr_align,
+  Output_data_fixed_space(off_t data_size, uint64_t addralign,
                          const char* map_name)
-    : Output_section_data(datasize, addr_align, true),
+    : Output_section_data(data_size, addralign, true),
       map_name_(map_name)
   { }
 
@@ -898,8 +854,8 @@ class Output_data_fixed_space : public Output_section_data
 class Output_data_space : public Output_section_data_build
 {
  public:
-  explicit Output_data_space(uint64_t addr_align, const char* map_name)
-    : Output_section_data_build(addr_align),
+  explicit Output_data_space(uint64_t addralign, const char* map_name)
+    : Output_section_data_build(addralign),
       map_name_(map_name)
   { }
 
@@ -932,8 +888,8 @@ class Output_data_space : public Output_section_data_build
 class Output_data_zero_fill : public Output_section_data
 {
  public:
-  Output_data_zero_fill(off_t datasize, uint64_t addr_align)
-    : Output_section_data(datasize, addr_align, true)
+  Output_data_zero_fill(off_t data_size, uint64_t addralign)
+    : Output_section_data(data_size, addralign, true)
   { }
 
  protected:
@@ -1018,23 +974,24 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   // A reloc against a global symbol.
 
   Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
-              Address address, bool is_relative);
+              Address address, bool is_relative, bool is_symbolless);
 
   Output_reloc(Symbol* gsym, unsigned int type,
                Sized_relobj<size, big_endian>* relobj,
-              unsigned int shndx, Address address, bool is_relative);
+              unsigned int shndx, Address address, bool is_relative,
+              bool is_symbolless);
 
   // A reloc against a local symbol or local section symbol.
 
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
               unsigned int local_sym_index, unsigned int type,
               Output_data* od, Address address, bool is_relative,
-               bool is_section_symbol);
+               bool is_symbolless, bool is_section_symbol);
 
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
               unsigned int local_sym_index, unsigned int type,
               unsigned int shndx, Address address, bool is_relative,
-               bool is_section_symbol);
+               bool is_symbolless, bool is_section_symbol);
 
   // A reloc against the STT_SECTION symbol of an output section.
 
@@ -1045,11 +1002,40 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
                Sized_relobj<size, big_endian>* relobj,
               unsigned int shndx, Address address);
 
-  // Return TRUE if this is a RELATIVE relocation.
+  // An absolute relocation with no symbol.
+
+  Output_reloc(unsigned int type, Output_data* od, Address address);
+
+  Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
+              unsigned int shndx, Address address);
+
+  // A target specific relocation.  The target will be called to get
+  // the symbol index, passing ARG.  The type and offset will be set
+  // as for other relocation types.
+
+  Output_reloc(unsigned int type, void* arg, Output_data* od,
+              Address address);
+
+  Output_reloc(unsigned int type, void* arg,
+              Sized_relobj<size, big_endian>* relobj,
+              unsigned int shndx, Address address);
+
+  // Return the reloc type.
+  unsigned int
+  type() const
+  { return this->type_; }
+
+  // Return whether this is a RELATIVE relocation.
   bool
   is_relative() const
   { return this->is_relative_; }
 
+  // Return whether this is a relocation which should not use
+  // a symbol, but which obtains its addend from a symbol.
+  bool
+  is_symbolless() const
+  { return this->is_symbolless_; }
+
   // Return whether this is against a local section symbol.
   bool
   is_local_section_symbol() const
@@ -1057,9 +1043,24 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
     return (this->local_sym_index_ != GSYM_CODE
             && this->local_sym_index_ != SECTION_CODE
             && this->local_sym_index_ != INVALID_CODE
+           && this->local_sym_index_ != TARGET_CODE
             && this->is_section_symbol_);
   }
 
+  // Return whether this is a target specific relocation.
+  bool
+  is_target_specific() const
+  { return this->local_sym_index_ == TARGET_CODE; }
+
+  // Return the argument to pass to the target for a target specific
+  // relocation.
+  void*
+  target_arg() const
+  {
+    gold_assert(this->local_sym_index_ == TARGET_CODE);
+    return this->u1_.arg;
+  }
+
   // For a local section symbol, return the offset of the input
   // section within the output section.  ADDEND is the addend being
   // applied to the input section.
@@ -1112,8 +1113,10 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
     GSYM_CODE = -1U,
     // Output section.
     SECTION_CODE = -2U,
+    // Target specific.
+    TARGET_CODE = -3U,
     // Invalid uninitialized entry.
-    INVALID_CODE = -3U
+    INVALID_CODE = -4U
   };
 
   union
@@ -1131,6 +1134,9 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
     // For a relocation against an output section
     // (this->local_sym_index_ == SECTION_CODE), the output section.
     Output_section* os;
+    // For a target specific relocation, an argument to pass to the
+    // target.
+    void* arg;
   } u1_;
   union
   {
@@ -1145,16 +1151,20 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   // The address offset within the input section or the Output_data.
   Address address_;
   // This is GSYM_CODE for a global symbol, or SECTION_CODE for a
-  // relocation against an output section, or INVALID_CODE for an
-  // uninitialized value.  Otherwise, for a local symbol
-  // (this->is_section_symbol_ is false), the local symbol index.  For
-  // a local section symbol (this->is_section_symbol_ is true), the
-  // section index in the input file.
+  // relocation against an output section, or TARGET_CODE for a target
+  // specific relocation, or INVALID_CODE for an uninitialized value.
+  // Otherwise, for a local symbol (this->is_section_symbol_ is
+  // false), the local symbol index.  For a local section symbol
+  // (this->is_section_symbol_ is true), the section index in the
+  // input file.
   unsigned int local_sym_index_;
   // The reloc type--a processor specific code.
-  unsigned int type_ : 30;
+  unsigned int type_ : 29;
   // True if the relocation is a RELATIVE relocation.
   bool is_relative_ : 1;
+  // True if the relocation is one which should not use
+  // a symbol, but which obtains its addend from a symbol.
+  bool is_symbolless_ : 1;
   // True if the relocation is against a section symbol.
   bool is_section_symbol_ : 1;
   // If the reloc address is an input section in an object, the
@@ -1181,50 +1191,93 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   // A reloc against a global symbol.
 
   Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
-              Address addr, Addend addend, bool is_relative)
-    : rel_(gsym, type, od, addr, is_relative), addend_(addend)
+              Address address, Addend addend, bool is_relative,
+              bool is_symbolless)
+    : rel_(gsym, type, od, address, is_relative, is_symbolless),
+      addend_(addend)
   { }
 
   Output_reloc(Symbol* gsym, unsigned int type,
                Sized_relobj<size, big_endian>* relobj,
-              unsigned int shndx, Address addr, Addend addend,
-              bool is_relative)
-    : rel_(gsym, type, relobj, shndx, addr, is_relative), addend_(addend)
+              unsigned int shndx, Address address, Addend addend,
+              bool is_relative, bool is_symbolless)
+    : rel_(gsym, type, relobj, shndx, address, is_relative,
+          is_symbolless), addend_(addend)
   { }
 
   // A reloc against a local symbol.
 
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
               unsigned int local_sym_index, unsigned int type,
-              Output_data* od, Address addr,
-              Addend addend, bool is_relative, bool is_section_symbol)
-    : rel_(relobj, local_sym_index, type, od, addr, is_relative,
-           is_section_symbol),
+              Output_data* od, Address address,
+              Addend addend, bool is_relative,
+              bool is_symbolless, bool is_section_symbol)
+    : rel_(relobj, local_sym_index, type, od, address, is_relative,
+           is_symbolless, is_section_symbol),
       addend_(addend)
   { }
 
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
               unsigned int local_sym_index, unsigned int type,
-              unsigned int shndx, Address addr,
-              Addend addend, bool is_relative, bool is_section_symbol)
-    : rel_(relobj, local_sym_index, type, shndx, addr, is_relative,
-           is_section_symbol),
+              unsigned int shndx, Address address,
+              Addend addend, bool is_relative,
+              bool is_symbolless, bool is_section_symbol)
+    : rel_(relobj, local_sym_index, type, shndx, address, is_relative,
+           is_symbolless, is_section_symbol),
       addend_(addend)
   { }
 
   // A reloc against the STT_SECTION symbol of an output section.
 
   Output_reloc(Output_section* os, unsigned int type, Output_data* od,
-              Address addr, Addend addend)
-    : rel_(os, type, od, addr), addend_(addend)
+              Address address, Addend addend)
+    : rel_(os, type, od, address), addend_(addend)
   { }
 
   Output_reloc(Output_section* os, unsigned int type,
                Sized_relobj<size, big_endian>* relobj,
-              unsigned int shndx, Address addr, Addend addend)
-    : rel_(os, type, relobj, shndx, addr), addend_(addend)
+              unsigned int shndx, Address address, Addend addend)
+    : rel_(os, type, relobj, shndx, address), addend_(addend)
+  { }
+
+  // An absolute relocation with no symbol.
+
+  Output_reloc(unsigned int type, Output_data* od, Address address,
+              Addend addend)
+    : rel_(type, od, address), addend_(addend)
   { }
 
+  Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
+              unsigned int shndx, Address address, Addend addend)
+    : rel_(type, relobj, shndx, address), addend_(addend)
+  { }
+
+  // A target specific relocation.  The target will be called to get
+  // the symbol index and the addend, passing ARG.  The type and
+  // offset will be set as for other relocation types.
+
+  Output_reloc(unsigned int type, void* arg, Output_data* od,
+              Address address, Addend addend)
+    : rel_(type, arg, od, address), addend_(addend)
+  { }
+
+  Output_reloc(unsigned int type, void* arg,
+              Sized_relobj<size, big_endian>* relobj,
+              unsigned int shndx, Address address, Addend addend)
+    : rel_(type, arg, relobj, shndx, address), addend_(addend)
+  { }
+
+  // Return whether this is a RELATIVE relocation.
+  bool
+  is_relative() const
+  { return this->rel_.is_relative(); }
+
+  // Return whether this is a relocation which should not use
+  // a symbol, but which obtains its addend from a symbol.
+  bool
+  is_symbolless() const
+  { return this->rel_.is_symbolless(); }
+
   // Write the reloc entry to an output view.
   void
   write(unsigned char* pov) const;
@@ -1251,6 +1304,43 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   Addend addend_;
 };
 
+// Output_data_reloc_generic is a non-template base class for
+// Output_data_reloc_base.  This gives the generic code a way to hold
+// a pointer to a reloc section.
+
+class Output_data_reloc_generic : public Output_section_data_build
+{
+ public:
+  Output_data_reloc_generic(int size, bool sort_relocs)
+    : Output_section_data_build(Output_data::default_alignment_for_size(size)),
+      relative_reloc_count_(0), sort_relocs_(sort_relocs)
+  { }
+
+  // Return the number of relative relocs in this section.
+  size_t
+  relative_reloc_count() const
+  { return this->relative_reloc_count_; }
+
+  // Whether we should sort the relocs.
+  bool
+  sort_relocs() const
+  { return this->sort_relocs_; }
+
+ protected:
+  // Note that we've added another relative reloc.
+  void
+  bump_relative_reloc_count()
+  { ++this->relative_reloc_count_; }
+
+ private:
+  // The number of relative relocs added to this section.  This is to
+  // support DT_RELCOUNT.
+  size_t relative_reloc_count_;
+  // Whether to sort the relocations when writing them out, to make
+  // the dynamic linker more efficient.
+  bool sort_relocs_;
+};
+
 // Output_data_reloc is used to manage a section containing relocs.
 // SH_TYPE is either elfcpp::SHT_REL or elfcpp::SHT_RELA.  DYNAMIC
 // indicates whether this is a dynamic relocation or a normal
@@ -1259,7 +1349,7 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 // the reloc type.
 
 template<int sh_type, bool dynamic, int size, bool big_endian>
-class Output_data_reloc_base : public Output_section_data_build
+class Output_data_reloc_base : public Output_data_reloc_generic
 {
  public:
   typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
@@ -1269,8 +1359,7 @@ class Output_data_reloc_base : public Output_section_data_build
 
   // Construct the section.
   Output_data_reloc_base(bool sort_relocs)
-    : Output_section_data_build(Output_data::default_alignment_for_size(size)),
-      sort_relocs_(sort_relocs)
+    : Output_data_reloc_generic(size, sort_relocs)
   { }
 
  protected:
@@ -1299,6 +1388,8 @@ class Output_data_reloc_base : public Output_section_data_build
     this->relocs_.push_back(reloc);
     this->set_current_data_size(this->relocs_.size() * reloc_size);
     od->add_dynamic_reloc();
+    if (reloc.is_relative())
+      this->bump_relative_reloc_count();
   }
 
  private:
@@ -1314,9 +1405,6 @@ class Output_data_reloc_base : public Output_section_data_build
 
   // 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.
@@ -1345,33 +1433,33 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   // Add a reloc against a global symbol.
 
   void
-  add_global(Symbol* gsym, unsigned int type, Output_data* od, Address addr)
-  { this->add(od, Output_reloc_type(gsym, type, od, addr, false)); }
+  add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, false, false)); }
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
              Sized_relobj<size, big_endian>* relobj,
-            unsigned int shndx, Address addr)
-  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
-                                    false)); }
+            unsigned int shndx, Address address)
+  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+                                    false, false)); }
 
   // These are to simplify the Copy_relocs class.
 
   void
-  add_global(Symbol* gsym, unsigned int type, Output_data* od, Address addr,
+  add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address,
             Address addend)
   {
     gold_assert(addend == 0);
-    this->add_global(gsym, type, od, addr);
+    this->add_global(gsym, type, od, address);
   }
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
              Sized_relobj<size, big_endian>* relobj,
-            unsigned int shndx, Address addr, Address addend)
+            unsigned int shndx, Address address, Address addend)
   {
     gold_assert(addend == 0);
-    this->add_global(gsym, type, od, relobj, shndx, addr);
+    this->add_global(gsym, type, od, relobj, shndx, address);
   }
 
   // Add a RELATIVE reloc against a global symbol.  The final relocation
@@ -1379,16 +1467,34 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
-                      Address addr)
-  { this->add(od, Output_reloc_type(gsym, type, od, addr, true)); }
+                      Address address)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, true, true)); }
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
                       Sized_relobj<size, big_endian>* relobj,
-                      unsigned int shndx, Address addr)
+                      unsigned int shndx, Address address)
   {
-    this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
-                                    true));
+    this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+                                    true, true));
+  }
+
+  // Add a global relocation which does not use a symbol for the relocation,
+  // but which gets its addend from a symbol.
+
+  void
+  add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+                              Output_data* od, Address address)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, false, true)); }
+
+  void
+  add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+                              Output_data* od,
+                              Sized_relobj<size, big_endian>* relobj,
+                              unsigned int shndx, Address address)
+  {
+    this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+                                    false, true));
   }
 
   // Add a reloc against a local symbol.
@@ -1396,19 +1502,19 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   void
   add_local(Sized_relobj<size, big_endian>* relobj,
            unsigned int local_sym_index, unsigned int type,
-           Output_data* od, Address addr)
+           Output_data* od, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
-                                    addr, false, false));
+                                    address, false, false, false));
   }
 
   void
   add_local(Sized_relobj<size, big_endian>* relobj,
            unsigned int local_sym_index, unsigned int type,
-           Output_data* od, unsigned int shndx, Address addr)
+           Output_data* od, unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-                                   addr, false, false));
+                                   address, false, false, false));
   }
 
   // Add a RELATIVE reloc against a local symbol.
@@ -1416,19 +1522,41 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   void
   add_local_relative(Sized_relobj<size, big_endian>* relobj,
                     unsigned int local_sym_index, unsigned int type,
-                    Output_data* od, Address addr)
+                    Output_data* od, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
-                                    addr, true, false));
+                                    address, true, true, false));
   }
 
   void
   add_local_relative(Sized_relobj<size, big_endian>* relobj,
                     unsigned int local_sym_index, unsigned int type,
-                    Output_data* od, unsigned int shndx, Address addr)
+                    Output_data* od, unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-                                   addr, true, false));
+                                   address, true, true, false));
+  }
+
+  // Add a local relocation which does not use a symbol for the relocation,
+  // but which gets its addend from a symbol.
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             unsigned int local_sym_index, unsigned int type,
+                             Output_data* od, Address address)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+                                    address, false, true, false));
+  }
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             unsigned int local_sym_index, unsigned int type,
+                             Output_data* od, unsigned int shndx,
+                             Address address)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+                                   address, false, true, false));
   }
 
   // Add a reloc against a local section symbol.  This will be
@@ -1438,19 +1566,19 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   void
   add_local_section(Sized_relobj<size, big_endian>* relobj,
                     unsigned int input_shndx, unsigned int type,
-                    Output_data* od, Address addr)
+                    Output_data* od, Address address)
   {
     this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
-                                    addr, false, true));
+                                    address, false, false, true));
   }
 
   void
   add_local_section(Sized_relobj<size, big_endian>* relobj,
                     unsigned int input_shndx, unsigned int type,
-                    Output_data* od, unsigned int shndx, Address addr)
+                    Output_data* od, unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
-                                    addr, false, true));
+                                    address, false, false, true));
   }
 
   // A reloc against the STT_SECTION symbol of an output section.
@@ -1459,14 +1587,40 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 
   void
   add_output_section(Output_section* os, unsigned int type,
-                    Output_data* od, Address addr)
-  { this->add(od, Output_reloc_type(os, type, od, addr)); }
+                    Output_data* od, Address address)
+  { this->add(od, Output_reloc_type(os, type, od, address)); }
 
   void
   add_output_section(Output_section* os, unsigned int type, Output_data* od,
                     Sized_relobj<size, big_endian>* relobj,
-                     unsigned int shndx, Address addr)
-  { this->add(od, Output_reloc_type(os, type, relobj, shndx, addr)); }
+                     unsigned int shndx, Address address)
+  { this->add(od, Output_reloc_type(os, type, relobj, shndx, address)); }
+
+  // Add an absolute relocation.
+
+  void
+  add_absolute(unsigned int type, Output_data* od, Address address)
+  { this->add(od, Output_reloc_type(type, od, address)); }
+
+  void
+  add_absolute(unsigned int type, Output_data* od,
+              Sized_relobj<size, big_endian>* relobj,
+              unsigned int shndx, Address address)
+  { this->add(od, Output_reloc_type(type, relobj, shndx, address)); }
+
+  // Add a target specific relocation.  A target which calls this must
+  // define the reloc_symbol_index and reloc_addend virtual functions.
+
+  void
+  add_target_specific(unsigned int type, void* arg, Output_data* od,
+                     Address address)
+  { this->add(od, Output_reloc_type(type, arg, od, address)); }
+
+  void
+  add_target_specific(unsigned int type, void* arg, Output_data* od,
+                     Sized_relobj<size, big_endian>* relobj,
+                     unsigned int shndx, Address address)
+  { this->add(od, Output_reloc_type(type, arg, relobj, shndx, address)); }
 };
 
 // The SHT_RELA version of Output_data_reloc.
@@ -1492,17 +1646,17 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
-            Address addr, Addend addend)
-  { this->add(od, Output_reloc_type(gsym, type, od, addr, addend,
-                                    false)); }
+            Address address, Addend addend)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+                                    false, false)); }
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
              Sized_relobj<size, big_endian>* relobj,
-            unsigned int shndx, Address addr,
+            unsigned int shndx, Address address,
             Addend addend)
-  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
-                                    addend, false)); }
+  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+                                    addend, false, false)); }
 
   // Add a RELATIVE reloc against a global symbol.  The final output
   // relocation will not reference the symbol, but we must keep the symbol
@@ -1511,35 +1665,53 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
-                     Address addr, Addend addend)
-  { this->add(od, Output_reloc_type(gsym, type, od, addr, addend, true)); }
+                     Address address, Addend addend)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true,
+                                   true)); }
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
                       Sized_relobj<size, big_endian>* relobj,
-                      unsigned int shndx, Address addr, Addend addend)
-  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, addr,
-                                    addend, true)); }
+                      unsigned int shndx, Address address, Addend addend)
+  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+                                    addend, true, true)); }
+
+  // Add a global relocation which does not use a symbol for the relocation,
+  // but which gets its addend from a symbol.
+
+  void
+  add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od,
+                              Address address, Addend addend)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+                                   false, true)); }
+
+  void
+  add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+                              Output_data* od,
+                              Sized_relobj<size, big_endian>* relobj,
+                              unsigned int shndx, Address address, Addend addend)
+  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+                                    addend, false, true)); }
 
   // Add a reloc against a local symbol.
 
   void
   add_local(Sized_relobj<size, big_endian>* relobj,
            unsigned int local_sym_index, unsigned int type,
-           Output_data* od, Address addr, Addend addend)
+           Output_data* od, Address address, Addend addend)
   {
-    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, addr,
-                                   addend, false, false));
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+                                   addend, false, false, false));
   }
 
   void
   add_local(Sized_relobj<size, big_endian>* relobj,
            unsigned int local_sym_index, unsigned int type,
-           Output_data* od, unsigned int shndx, Address addr,
+           Output_data* od, unsigned int shndx, Address address,
            Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-                                    addr, addend, false, false));
+                                    address, addend, false, false, false));
   }
 
   // Add a RELATIVE reloc against a local symbol.
@@ -1547,20 +1719,42 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   void
   add_local_relative(Sized_relobj<size, big_endian>* relobj,
                     unsigned int local_sym_index, unsigned int type,
-                    Output_data* od, Address addr, Addend addend)
+                    Output_data* od, Address address, Addend addend)
   {
-    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, addr,
-                                   addend, true, false));
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+                                   addend, true, true, false));
   }
 
   void
   add_local_relative(Sized_relobj<size, big_endian>* relobj,
                     unsigned int local_sym_index, unsigned int type,
-                    Output_data* od, unsigned int shndx, Address addr,
+                    Output_data* od, unsigned int shndx, Address address,
                     Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-                                    addr, addend, true, false));
+                                    address, addend, true, true, false));
+  }
+
+  // Add a local relocation which does not use a symbol for the relocation,
+  // but which gets it's addend from a symbol.
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             unsigned int local_sym_index, unsigned int type,
+                             Output_data* od, Address address, Addend addend)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+                                   addend, false, true, false));
+  }
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             unsigned int local_sym_index, unsigned int type,
+                             Output_data* od, unsigned int shndx,
+                             Address address, Addend addend)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+                                    address, addend, false, true, false));
   }
 
   // Add a reloc against a local section symbol.  This will be
@@ -1570,35 +1764,65 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   void
   add_local_section(Sized_relobj<size, big_endian>* relobj,
                     unsigned int input_shndx, unsigned int type,
-                    Output_data* od, Address addr, Addend addend)
+                    Output_data* od, Address address, Addend addend)
   {
-    this->add(od, Output_reloc_type(relobj, input_shndx, type, od, addr,
-                                   addend, false, true));
+    this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
+                                   addend, false, false, true));
   }
 
   void
   add_local_section(Sized_relobj<size, big_endian>* relobj,
                     unsigned int input_shndx, unsigned int type,
-                    Output_data* od, unsigned int shndx, Address addr,
+                    Output_data* od, unsigned int shndx, Address address,
                     Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
-                                    addr, addend, false, true));
+                                    address, addend, false, false, true));
   }
 
   // A reloc against the STT_SECTION symbol of an output section.
 
   void
   add_output_section(Output_section* os, unsigned int type, Output_data* od,
-                    Address addr, Addend addend)
-  { this->add(os, Output_reloc_type(os, type, od, addr, addend)); }
+                    Address address, Addend addend)
+  { this->add(os, Output_reloc_type(os, type, od, address, addend)); }
 
   void
   add_output_section(Output_section* os, unsigned int type,
                      Sized_relobj<size, big_endian>* relobj,
-                    unsigned int shndx, Address addr, Addend addend)
-  { this->add(os, Output_reloc_type(os, type, relobj, shndx, addr,
+                    unsigned int shndx, Address address, Addend addend)
+  { this->add(os, Output_reloc_type(os, type, relobj, shndx, address,
                                     addend)); }
+
+  // Add an absolute relocation.
+
+  void
+  add_absolute(unsigned int type, Output_data* od, Address address,
+              Addend addend)
+  { this->add(od, Output_reloc_type(type, od, address, addend)); }
+
+  void
+  add_absolute(unsigned int type, Output_data* od,
+              Sized_relobj<size, big_endian>* relobj,
+              unsigned int shndx, Address address, Addend addend)
+  { this->add(od, Output_reloc_type(type, relobj, shndx, address, addend)); }
+
+  // Add a target specific relocation.  A target which calls this must
+  // define the reloc_symbol_index and reloc_addend virtual functions.
+
+  void
+  add_target_specific(unsigned int type, void* arg, Output_data* od,
+                     Address address, Addend addend)
+  { this->add(od, Output_reloc_type(type, arg, od, address, addend)); }
+
+  void
+  add_target_specific(unsigned int type, void* arg, Output_data* od,
+                     Sized_relobj<size, big_endian>* relobj,
+                     unsigned int shndx, Address address, Addend addend)
+  {
+    this->add(od, Output_reloc_type(type, arg, relobj, shndx, address,
+                                   addend));
+  }
 };
 
 // Output_relocatable_relocs represents a relocation section in a
@@ -1866,14 +2090,20 @@ class Output_data_dynamic : public Output_section_data
   // plus a constant offset.
   void
   add_section_plus_offset(elfcpp::DT tag, const Output_data* od,
-                          unsigned int sec_offset)
-  { this->add_entry(Dynamic_entry(tag, od, sec_offset)); }
+                          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)
   { this->add_entry(Dynamic_entry(tag, od, true)); }
 
+  // Add a new dynamic entry with the total size of two output datas.
+  void
+  add_section_size(elfcpp::DT tag, const Output_data* od,
+                  const Output_data* od2)
+  { this->add_entry(Dynamic_entry(tag, od, od2)); }
+
   // Add a new dynamic entry with the address of a symbol.
   void
   add_symbol(elfcpp::DT tag, const Symbol* sym)
@@ -1912,32 +2142,44 @@ class Output_data_dynamic : public Output_section_data
   {
    public:
     // Create an entry with a fixed numeric value.
-    Dynamic_entry(elfcpp::DT etag, unsigned int val)
-      : tag_(etag), offset_(DYNAMIC_NUMBER)
+    Dynamic_entry(elfcpp::DT tag, unsigned int val)
+      : tag_(tag), offset_(DYNAMIC_NUMBER)
     { this->u_.val = val; }
 
     // Create an entry with the size or address of a section.
-    Dynamic_entry(elfcpp::DT etag, const Output_data* od, bool section_size)
-      : tag_(etag),
+    Dynamic_entry(elfcpp::DT tag, const Output_data* od, bool section_size)
+      : tag_(tag),
        offset_(section_size
                ? DYNAMIC_SECTION_SIZE
                : DYNAMIC_SECTION_ADDRESS)
-    { this->u_.od = od; }
+    {
+      this->u_.od = od;
+      this->od2 = NULL;
+    }
+
+    // Create an entry with the size of two sections.
+    Dynamic_entry(elfcpp::DT tag, const Output_data* od, const Output_data* od2)
+      : tag_(tag),
+       offset_(DYNAMIC_SECTION_SIZE)
+    {
+      this->u_.od = od;
+      this->od2 = od2;
+    }
 
     // Create an entry with the address of a section plus a constant offset.
-    Dynamic_entry(elfcpp::DT etag, const Output_data* od, unsigned int offset)
-      : tag_(etag),
+    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 etag, const Symbol* sym)
-      : tag_(etag), offset_(DYNAMIC_SYMBOL)
+    Dynamic_entry(elfcpp::DT tag, const Symbol* sym)
+      : tag_(tag), offset_(DYNAMIC_SYMBOL)
     { this->u_.sym = sym; }
 
     // Create an entry with a string.
-    Dynamic_entry(elfcpp::DT etag, const char* str)
-      : tag_(etag), offset_(DYNAMIC_STRING)
+    Dynamic_entry(elfcpp::DT tag, const char* str)
+      : tag_(tag), offset_(DYNAMIC_STRING)
     { this->u_.str = str; }
 
     // Return the tag of this entry.
@@ -1978,6 +2220,8 @@ class Output_data_dynamic : public Output_section_data
       // For DYNAMIC_STRING.
       const char* str;
     } u_;
+    // For DYNAMIC_SYMBOL with two sections.
+    const Output_data* od2;
     // The dynamic tag.
     elfcpp::DT tag_;
     // The type of entry (Classification) or offset within a section.
@@ -2050,9 +2294,9 @@ class Output_relaxed_input_section : public Output_section_data_build
   // We would like to call relobj->section_addralign(shndx) to get the
   // alignment but we do not want the constructor to fail.  So callers
   // are repsonsible for ensuring that.
-  Output_relaxed_input_section(Relobj* rel_obj, unsigned int sec_shndx,
-                              uint64_t addr_align)
-    : Output_section_data_build(addr_align), relobj_(rel_obj), shndx_(sec_shndx)
+  Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
+                              uint64_t addralign)
+    : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
   { }
  
   // Return the Relobj of this relaxed input section.
@@ -2132,9 +2376,9 @@ class Output_section : public Output_data
 
   // Set the load address.
   void
-  set_load_address(uint64_t load_addr)
+  set_load_address(uint64_t load_address)
   {
-    this->load_address_ = load_addr;
+    this->load_address_ = load_address;
     this->has_load_address_ = true;
   }
 
@@ -2351,6 +2595,35 @@ class Output_section : public Output_data
   set_is_relro_local()
   { this->is_relro_local_ = true; }
 
+  // True if this must be the last relro section.
+  bool
+  is_last_relro() const
+  { return this->is_last_relro_; }
+
+  // Record that this must be the last relro section.
+  void
+  set_is_last_relro()
+  {
+    gold_assert(this->is_relro_);
+    this->is_last_relro_ = true;
+  }
+
+  // True if this must be the first section following the relro sections.
+  bool
+  is_first_non_relro() const
+  {
+    gold_assert(!this->is_relro_);
+    return this->is_first_non_relro_;
+  }
+
+  // Record that this must be the first non-relro section.
+  void
+  set_is_first_non_relro()
+  {
+    gold_assert(!this->is_relro_);
+    this->is_first_non_relro_ = true;
+  }
+
   // True if this is a small section: a section which holds small
   // variables.
   bool
@@ -2502,11 +2775,11 @@ class Output_section : public Output_data
     static const unsigned int invalid_shndx = static_cast<unsigned int>(-1);
 
    public:
-    Simple_input_section(Relobj *rel_obj, unsigned int sec_shndx)
-      : shndx_(sec_shndx)
+    Simple_input_section(Relobj *relobj, unsigned int shndx)
+      : shndx_(shndx)
     {
-      gold_assert(sec_shndx != invalid_shndx);
-      this->u_.relobj = rel_obj;
+      gold_assert(shndx != invalid_shndx);
+      this->u_.relobj = relobj;
     }
  
     Simple_input_section(Output_relaxed_input_section* section)
@@ -2566,10 +2839,10 @@ class Output_section : public Output_data
   get_input_sections(uint64_t address, const std::string& fill,
                     std::list<Simple_input_section>*);
 
-  // Add an input section from a script.
+  // Add a simple input section.
   void
-  add_input_section_for_script(const Simple_input_section& input_section,
-                              off_t data_size, uint64_t addralign);
+  add_simple_input_section(const Simple_input_section& input_section,
+                          off_t data_size, uint64_t addralign);
 
   // Set the current size of the output section.
   void
@@ -2592,6 +2865,10 @@ class Output_section : public Output_data
   void
   restore_states();
 
+  // Discard states.
+  void
+  discard_states();
+
   // Convert existing input sections to relaxed input sections.
   void
   convert_input_sections_to_relaxed_sections(
@@ -2599,9 +2876,24 @@ class Output_section : public Output_data
 
   // Find a relaxed input section to an input section in OBJECT
   // with index SHNDX.  Return NULL if none is found.
-  const Output_section_data*
+  const Output_relaxed_input_section*
   find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
   
+  // Whether section offsets need adjustment due to relaxation.
+  bool
+  section_offsets_need_adjustment() const
+  { return this->section_offsets_need_adjustment_; }
+
+  // Set section_offsets_need_adjustment to be true.
+  void
+  set_section_offsets_need_adjustment()
+  { this->section_offsets_need_adjustment_ = true; }
+
+  // Adjust section offsets of input sections in this.  This is
+  // requires if relaxation caused some input sections to change sizes.
+  void
+  adjust_section_offsets();
+
   // Print merge statistics to stderr.
   void
   print_merge_stats();
@@ -2612,6 +2904,10 @@ class Output_section : public Output_data
   do_output_section()
   { return this; }
 
+  const Output_section*
+  do_output_section() const
+  { return this; }
+
   // Return the section index in the output file.
   unsigned int
   do_out_shndx() const
@@ -2676,8 +2972,8 @@ class Output_section : public Output_data
 
   // Return whether this is a section of the specified type.
   bool
-  do_is_section_type(elfcpp::Elf_Word sec_type) const
-  { return this->type_ == sec_type; }
+  do_is_section_type(elfcpp::Elf_Word type) const
+  { return this->type_ == type; }
 
   // Return whether the specified section flag is set.
   bool
@@ -2738,16 +3034,16 @@ class Output_section : public Output_data
     }
 
     // For an ordinary input section.
-    Input_section(Relobj* object, unsigned int sec_shndx, off_t datasize,
-                 uint64_t addr_align)
-      : shndx_(sec_shndx),
-       p2align_(ffsll(static_cast<long long>(addr_align)))
+    Input_section(Relobj* object, unsigned int shndx, off_t data_size,
+                 uint64_t addralign)
+      : shndx_(shndx),
+       p2align_(ffsll(static_cast<long long>(addralign)))
     {
-      gold_assert(sec_shndx != OUTPUT_SECTION_CODE
-                 && sec_shndx != MERGE_DATA_SECTION_CODE
-                 && sec_shndx != MERGE_STRING_SECTION_CODE
-                 && sec_shndx != RELAXED_INPUT_SECTION_CODE);
-      this->u1_.data_size = datasize;
+      gold_assert(shndx != OUTPUT_SECTION_CODE
+                 && shndx != MERGE_DATA_SECTION_CODE
+                 && shndx != MERGE_STRING_SECTION_CODE
+                 && shndx != RELAXED_INPUT_SECTION_CODE);
+      this->u1_.data_size = data_size;
       this->u2_.object = object;
     }
 
@@ -2807,13 +3103,13 @@ class Output_section : public Output_data
     // parameters.
     bool
     is_merge_section(bool is_string, uint64_t entsize,
-                     uint64_t addr_align) const
+                     uint64_t addralign) const
     {
       return (this->shndx_ == (is_string
                               ? MERGE_STRING_SECTION_CODE
                               : MERGE_DATA_SECTION_CODE)
              && this->u1_.entsize == entsize
-              && this->addralign() == addr_align);
+              && this->addralign() == addralign);
     }
 
     // Return whether this is a relaxed input section.
@@ -2896,11 +3192,11 @@ class Output_section : public Output_data
 
     // Add an input section, for SHF_MERGE sections.
     bool
-    add_input_section(Relobj* object, unsigned int sec_shndx)
+    add_input_section(Relobj* object, unsigned int shndx)
     {
       gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE
                  || this->shndx_ == MERGE_STRING_SECTION_CODE);
-      return this->u2_.posd->add_input_section(object, sec_shndx);
+      return this->u2_.posd->add_input_section(object, shndx);
     }
 
     // Given an input OBJECT, an input section index SHNDX within that
@@ -3000,15 +3296,15 @@ class Output_section : public Output_data
   class Checkpoint_output_section
   {
    public:
-    Checkpoint_output_section(uint64_t addr_align, elfcpp::Elf_Xword sflags,
-                             const Input_section_list& sinput_sections,
-                             off_t first_input_off,
-                             bool attached_input_sections_sorted)
-      : addralign_(addr_align), flags_(sflags),
-       input_sections_(sinput_sections),
+    Checkpoint_output_section(uint64_t addralign, elfcpp::Elf_Xword flags,
+                             const Input_section_list& input_sections,
+                             off_t first_input_offset,
+                             bool attached_input_sections_are_sorted)
+      : addralign_(addralign), flags_(flags),
+       input_sections_(input_sections),
        input_sections_size_(input_sections_.size()),
-       input_sections_copy_(), first_input_offset_(first_input_off),
-       attached_input_sections_are_sorted_(attached_input_sections_sorted)
+       input_sections_copy_(), first_input_offset_(first_input_offset),
+       attached_input_sections_are_sorted_(attached_input_sections_are_sorted)
     { }
 
     virtual
@@ -3082,7 +3378,7 @@ class Output_section : public Output_data
   // This class is used to sort the input sections.
   class Input_section_sort_entry;
 
-  // This is the sort comparison function.
+  // This is the sort comparison function for ctors and dtors.
   struct Input_section_sort_compare
   {
     bool
@@ -3090,6 +3386,14 @@ class Output_section : public Output_data
               const Input_section_sort_entry&) const;
   };
 
+  // This is the sort comparison function for .init_array and .fini_array.
+  struct Input_section_sort_init_fini_compare
+  {
+    bool
+    operator()(const Input_section_sort_entry&,
+              const Input_section_sort_entry&) const;
+  };
+
   // Fill data.  This is used to fill in data between input sections.
   // It is also used for data statements (BYTE, WORD, etc.) in linker
   // scripts.  When we have to keep track of the input sections, we
@@ -3098,9 +3402,9 @@ class Output_section : public Output_data
   class Fill
   {
    public:
-    Fill(off_t section_off, off_t len)
-      : section_offset_(section_off),
-       length_(convert_to_section_size_type(len))
+    Fill(off_t section_offset, off_t length)
+      : section_offset_(section_offset),
+       length_(convert_to_section_size_type(length))
     { }
 
     // Return section offset.
@@ -3184,19 +3488,20 @@ class Output_section : public Output_data
                        Merge_section_properties::equal_to>
     Merge_section_by_properties_map;
 
-  // Map that link Input_section_specifier to Output_section_data.
-  typedef Unordered_map<Input_section_specifier, Output_section_data*,
-                       Input_section_specifier::hash,
-                       Input_section_specifier::equal_to>
+  // Map that link Const_section_id to Output_section_data.
+  typedef Unordered_map<Const_section_id, Output_section_data*,
+                       Const_section_id_hash>
     Output_section_data_by_input_section_map;
 
+  // Map that link Const_section_id to Output_relaxed_input_section.
+  typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
+                       Const_section_id_hash>
+    Output_relaxed_input_section_by_input_section_map;
+
   // Map used during relaxation of existing sections.  This map
-  // an input section specifier to an input section list index.
-  // We assume that Input_section_list is a vector.
-  typedef Unordered_map<Input_section_specifier, size_t,
-                       Input_section_specifier::hash,
-                       Input_section_specifier::equal_to>
-    Relaxation_map;
+  // a section id an input section list index.  We assume that
+  // Input_section_list is a vector.
+  typedef Unordered_map<Section_id, size_t, Section_id_hash> Relaxation_map;
 
   // Add a new output section by Input_section.
   void
@@ -3335,6 +3640,10 @@ class Output_section : public Output_data
   bool is_relro_ : 1;
   // True if this section holds relro local data.
   bool is_relro_local_ : 1;
+  // True if this must be the last relro section.
+  bool is_last_relro_ : 1;
+  // True if this must be the first section after the relro sections.
+  bool is_first_non_relro_ : 1;
   // True if this is a small section.
   bool is_small_section_ : 1;
   // True if this is a large section.
@@ -3346,6 +3655,10 @@ class Output_section : public Output_data
   bool is_dynamic_linker_section_ : 1;
   // Whether code-fills are generated at write.
   bool generate_code_fills_at_write_ : 1;
+  // Whether the entry size field should be zero.
+  bool is_entsize_zero_ : 1;
+  // Whether section offsets need adjustment due to relaxation.
+  bool section_offsets_need_adjustment_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
@@ -3358,7 +3671,8 @@ class Output_section : public Output_data
   // Map from input sections to relaxed input sections.  This is mutable
   // because it is updated lazily.  We may need to update it in a
   // const qualified method.
-  mutable Output_section_data_by_input_section_map relaxed_input_section_map_;
+  mutable Output_relaxed_input_section_by_input_section_map
+    relaxed_input_section_map_;
   // Whether relaxed_input_section_map_ is valid.
   mutable bool is_relaxed_input_section_map_valid_;
 };
@@ -3441,8 +3755,8 @@ class Output_segment
   void
   remove_output_section(Output_section* os);
 
-  // Add an Output_data (which is not an Output_section) to the start
-  // of this segment.
+  // Add an Output_data (which need not be an Output_section) to the
+  // start of this segment.
   void
   add_initial_output_data(Output_data*);
 
@@ -3467,18 +3781,29 @@ class Output_segment
 
   // Set the addresses.
   void
-  set_addresses(uint64_t v_addr, uint64_t p_addr)
+  set_addresses(uint64_t vaddr, uint64_t paddr)
   {
-    this->vaddr_ = v_addr;
-    this->paddr_ = p_addr;
+    this->vaddr_ = vaddr;
+    this->paddr_ = paddr;
     this->are_addresses_set_ = true;
   }
 
+  // Update the flags for the flags of an output section added to this
+  // segment.
+  void
+  update_flags_for_output_section(elfcpp::Elf_Xword flags)
+  {
+    // The ELF ABI specifies that a PT_TLS segment should always have
+    // PF_R as the flags.
+    if (this->type() != elfcpp::PT_TLS)
+      this->flags_ |= flags;
+  }
+
   // Set the segment flags.  This is only used if we have a PHDRS
   // clause which explicitly specifies the flags.
   void
-  set_flags(elfcpp::Elf_Word seg_flags)
-  { this->flags_ = seg_flags; }
+  set_flags(elfcpp::Elf_Word flags)
+  { this->flags_ = flags; }
 
   // Set the address of the segment to ADDR and the offset to *POFF
   // and set the addresses and offsets of all contained output
@@ -3488,7 +3813,8 @@ class Output_segment
   // address of the immediately following segment.  Update *POFF and
   // *PSHNDX.  This should only be called for a PT_LOAD segment.
   uint64_t
-  set_section_addresses(const Layout*, bool reset, uint64_t addr, off_t* poff,
+  set_section_addresses(const Layout*, bool reset, uint64_t addr,
+                       unsigned int increase_relro, off_t* poff,
                        unsigned int* pshndx);
 
   // Set the minimum alignment of this segment.  This may be adjusted
@@ -3500,7 +3826,7 @@ class Output_segment
   // Set the offset of this segment based on the section.  This should
   // only be called for a non-PT_LOAD segment.
   void
-  set_offset();
+  set_offset(unsigned int increase);
 
   // Set the TLS offsets of the sections contained in the PT_TLS segment.
   void
@@ -3546,7 +3872,7 @@ class Output_segment
   uint64_t
   set_section_list_addresses(const Layout*, bool reset, Output_data_list*,
                              uint64_t addr, off_t* poff, unsigned int* pshndx,
-                             bool* in_tls, bool* in_relro);
+                             bool* in_tls);
 
   // Return the number of Output_sections in an Output_data_list.
   unsigned int