* elf-bfd.h (struct elf_obj_tdata): Move find_line_info, local_stubs,
[binutils-gdb.git] / gold / object.h
index dc56136c18bf6b9d7f4a5648438d71ad41b03fb8..01c3c6fe2fbfe47a0f7bee08b87228fb5c46d6c0 100644 (file)
@@ -1,6 +1,7 @@
 // object.h -- support for an object file for linking in gold  -*- C++ -*-
 
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -47,7 +48,7 @@ class Pluginobj;
 class Dynobj;
 class Object_merge_map;
 class Relocatable_relocs;
-class Symbols_data;
+struct Symbols_data;
 
 template<typename Stringpool_char>
 class Stringpool_template;
@@ -332,12 +333,13 @@ class Object
     : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
       is_dynamic_(is_dynamic), is_needed_(false), uses_split_stack_(false),
       has_no_split_stack_(false), no_export_(false),
-      is_in_system_directory_(false), xindex_(NULL)
+      is_in_system_directory_(false), as_needed_(false), xindex_(NULL)
   {
     if (input_file != NULL)
       {
        input_file->file().add_object();
        this->is_in_system_directory_ = input_file->is_in_system_directory();
+       this->as_needed_ = input_file->options().as_needed();
       }
   }
 
@@ -347,7 +349,7 @@ class Object
       this->input_file_->file().remove_object();
   }
 
-  // Return the name of the object as we would report it to the tuser.
+  // Return the name of the object as we would report it to the user.
   const std::string&
   name() const
   { return this->name_; }
@@ -386,6 +388,12 @@ class Object
   has_no_split_stack() const
   { return this->has_no_split_stack_; }
 
+  // Returns NULL for Objects that are not dynamic objects.  This method
+  // is overridden in the Dynobj class.
+  Dynobj*
+  dynobj()
+  { return this->do_dynobj(); }
+
   // Returns NULL for Objects that are not plugin objects.  This method
   // is overridden in the Pluginobj class.
   Pluginobj*
@@ -688,6 +696,16 @@ class Object
   is_in_system_directory() const
   { return this->is_in_system_directory_; }
 
+  // Set flag that this object was linked with --as-needed.
+  void
+  set_as_needed()
+  { this->as_needed_ = true; }
+
+  // Return whether this object was linked with --as-needed.
+  bool
+  as_needed() const
+  { return this->as_needed_; }
+
   // Return whether we found this object by searching a directory.
   bool
   searched_for() const
@@ -708,6 +726,20 @@ class Object
                        section_size_type* uncompressed_size) const
   { return this->do_section_is_compressed(shndx, uncompressed_size); }
 
+  // Return a view of the decompressed contents of a section.  Set *PLEN
+  // to the size.  Set *IS_NEW to true if the contents need to be freed
+  // by the caller.
+  const unsigned char*
+  decompressed_section_contents(unsigned int shndx, section_size_type* plen,
+                               bool* is_cached)
+  { return this->do_decompressed_section_contents(shndx, plen, is_cached); }
+
+  // Discard any buffers of decompressed sections.  This is done
+  // at the end of the Add_symbols task.
+  void
+  discard_decompressed_sections()
+  { this->do_discard_decompressed_sections(); }
+
   // Return the index of the first incremental relocation for symbol SYMNDX.
   unsigned int
   get_incremental_reloc_base(unsigned int symndx) const
@@ -719,6 +751,12 @@ class Object
   { return this->do_get_incremental_reloc_count(symndx); }
 
  protected:
+  // Returns NULL for Objects that are not dynamic objects.  This method
+  // is overridden in the Dynobj class.
+  virtual Dynobj*
+  do_dynobj()
+  { return NULL; }
+
   // Returns NULL for Objects that are not plugin objects.  This method
   // is overridden in the Pluginobj class.
   virtual Pluginobj*
@@ -768,8 +806,9 @@ class Object
 
   // Return the location of the contents of a section.  Implemented by
   // child class.
-  virtual Location
-  do_section_contents(unsigned int shndx) = 0;
+  virtual const unsigned char*
+  do_section_contents(unsigned int shndx, section_size_type* plen,
+                     bool cache) = 0;
 
   // Get the size of a section--implemented by child class.
   virtual uint64_t
@@ -834,7 +873,7 @@ class Object
   set_shnum(int shnum)
   { this->shnum_ = shnum; }
 
-  // Functions used by both Sized_relobj and Sized_dynobj.
+  // Functions used by both Sized_relobj_file and Sized_dynobj.
 
   // Read the section data into a Read_symbols_data object.
   template<int size, bool big_endian>
@@ -869,6 +908,27 @@ class Object
   do_section_is_compressed(unsigned int, section_size_type*) const
   { return false; }
 
+  // Return a view of the decompressed contents of a section.  Set *PLEN
+  // to the size.  This default implementation simply returns the
+  // raw section contents and sets *IS_NEW to false to indicate
+  // that the contents do not need to be freed by the caller.
+  // This function must be overridden for any types of object files
+  // that might contain compressed sections.
+  virtual const unsigned char*
+  do_decompressed_section_contents(unsigned int shndx,
+                                  section_size_type* plen,
+                                  bool* is_new)
+  {
+    *is_new = false;
+    return this->do_section_contents(shndx, plen, false);
+  }
+
+  // Discard any buffers of decompressed sections.  This is done
+  // at the end of the Add_symbols task.
+  virtual void
+  do_discard_decompressed_sections()
+  { }
+
   // Return the index of the first incremental relocation for symbol SYMNDX--
   // implemented by child class.
   virtual unsigned int
@@ -911,12 +971,14 @@ class Object
   bool no_export_ : 1;
   // True if the object was found in a system directory.
   bool is_in_system_directory_ : 1;
+  // True if the object was linked with --as-needed.
+  bool as_needed_ : 1;
   // Many sections for objects with more than SHN_LORESERVE sections.
   Xindex* xindex_;
 };
 
 // A regular object (ET_REL).  This is an abstract base class itself.
-// The implementation is the template class Sized_relobj.
+// The implementation is the template class Sized_relobj_file.
 
 class Relobj : public Object
 {
@@ -929,7 +991,9 @@ class Relobj : public Object
       relocs_must_follow_section_writes_(false),
       sd_(NULL),
       reloc_counts_(NULL),
-      reloc_bases_(NULL)
+      reloc_bases_(NULL),
+      first_dyn_reloc_(0),
+      dyn_reloc_count_(0)
   { }
 
   // During garbage collection, the Read_symbols_data pass for 
@@ -982,6 +1046,44 @@ class Relobj : public Object
   scan_relocs(Symbol_table* symtab, Layout* layout, Read_relocs_data* rd)
   { return this->do_scan_relocs(symtab, layout, rd); }
 
+  // Return the value of the local symbol whose index is SYMNDX, plus
+  // ADDEND.  ADDEND is passed in so that we can correctly handle the
+  // section symbol for a merge section.
+  uint64_t
+  local_symbol_value(unsigned int symndx, uint64_t addend) const
+  { return this->do_local_symbol_value(symndx, addend); }
+
+  // Return the PLT offset for a local symbol.  It is an error to call
+  // this if it doesn't have one.
+  unsigned int
+  local_plt_offset(unsigned int symndx) const
+  { return this->do_local_plt_offset(symndx); }
+
+  // Return whether the local symbol SYMNDX has a GOT offset of type
+  // GOT_TYPE.
+  bool
+  local_has_got_offset(unsigned int symndx, unsigned int got_type) const
+  { return this->do_local_has_got_offset(symndx, got_type); }
+
+  // Return the GOT offset of type GOT_TYPE of the local symbol
+  // SYMNDX.  It is an error to call this if the symbol does not have
+  // a GOT offset of the specified type.
+  unsigned int
+  local_got_offset(unsigned int symndx, unsigned int got_type) const
+  { return this->do_local_got_offset(symndx, got_type); }
+
+  // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
+  // to GOT_OFFSET.
+  void
+  set_local_got_offset(unsigned int symndx, unsigned int got_type,
+                      unsigned int got_offset)
+  { this->do_set_local_got_offset(symndx, got_type, got_offset); }
+
+  // Return whether the local symbol SYMNDX is a TLS symbol.
+  bool
+  local_is_tls(unsigned int symndx) const
+  { return this->do_local_is_tls(symndx); }
+
   // The number of local symbols in the input symbol table.
   virtual unsigned int
   local_symbol_count() const
@@ -1022,6 +1124,25 @@ class Relobj : public Object
   set_local_dynsym_offset(off_t off)
   { return this->do_set_local_dynsym_offset(off); }
 
+  // Record a dynamic relocation against an input section from this object.
+  void
+  add_dyn_reloc(unsigned int index)
+  {
+    if (this->dyn_reloc_count_ == 0)
+      this->first_dyn_reloc_ = index;
+    ++this->dyn_reloc_count_;
+  }
+
+  // Return the index of the first dynamic relocation.
+  unsigned int
+  first_dyn_reloc() const
+  { return this->first_dyn_reloc_; }
+
+  // Return the count of dynamic relocations.
+  unsigned int
+  dyn_reloc_count() const
+  { return this->dyn_reloc_count_; }
+
   // Relocate the input sections and write out the local symbols.
   void
   relocate(const Symbol_table* symtab, const Layout* layout, Output_file* of)
@@ -1103,6 +1224,16 @@ class Relobj : public Object
   do_get_incremental_reloc_count(unsigned int symndx) const
   { return this->reloc_counts_[symndx]; }
 
+  // Return the word size of the object file.
+  int
+  elfsize() const
+  { return this->do_elfsize(); }
+
+  // Return TRUE if this is a big-endian object file.
+  bool
+  is_big_endian() const
+  { return this->do_is_big_endian(); }
+
  protected:
   // The output section to be used for each input section, indexed by
   // the input section number.  The output section is NULL if the
@@ -1121,6 +1252,32 @@ class Relobj : public Object
   virtual void
   do_scan_relocs(Symbol_table*, Layout*, Read_relocs_data*) = 0;
 
+  // Return the value of a local symbol.
+  virtual uint64_t
+  do_local_symbol_value(unsigned int symndx, uint64_t addend) const = 0;
+
+  // Return the PLT offset of a local symbol.
+  virtual unsigned int
+  do_local_plt_offset(unsigned int symndx) const = 0;
+
+  // Return whether a local symbol has a GOT offset of a given type.
+  virtual bool
+  do_local_has_got_offset(unsigned int symndx,
+                         unsigned int got_type) const = 0;
+
+  // Return the GOT offset of a given type of a local symbol.
+  virtual unsigned int
+  do_local_got_offset(unsigned int symndx, unsigned int got_type) const = 0;
+
+  // Set the GOT offset with a given type for a local symbol.
+  virtual void
+  do_set_local_got_offset(unsigned int symndx, unsigned int got_type,
+                         unsigned int got_offset) = 0;
+
+  // Return whether local symbol SYMNDX is a TLS symbol.
+  virtual bool
+  do_local_is_tls(unsigned int symndx) const = 0;
+
   // Return the number of local symbols--implemented by child class.
   virtual unsigned int
   do_local_symbol_count() const = 0;
@@ -1239,6 +1396,16 @@ class Relobj : public Object
     return this->reloc_bases_[symndx] + counter;
   }
 
+  // Return the word size of the object file--
+  // implemented by child class.
+  virtual int
+  do_elfsize() const = 0;
+
+  // Return TRUE if this is a big-endian object file--
+  // implemented by child class.
+  virtual bool
+  do_is_big_endian() const = 0;
+
  private:
   // Mapping from input sections to output section.
   Output_sections output_sections_;
@@ -1262,6 +1429,10 @@ class Relobj : public Object
   unsigned int* reloc_counts_;
   // Per-symbol base indexes of relocations, for incremental links.
   unsigned int* reloc_bases_;
+  // Index of the first dynamic relocation for this object.
+  unsigned int first_dyn_reloc_;
+  // Count of dynamic relocations for this object.
+  unsigned int dyn_reloc_count_;
 };
 
 // This class is used to handle relocations against a section symbol
@@ -1379,7 +1550,7 @@ class Symbol_value
   // symbol is defined, and ADDEND is an addend to add to the value.
   template<bool big_endian>
   Value
-  value(const Sized_relobj<size, big_endian>* object, Value addend) const
+  value(const Sized_relobj_file<size, big_endian>* object, Value addend) const
   {
     if (this->has_output_value_)
       return this->u_.value + addend;
@@ -1670,45 +1841,180 @@ class Reloc_symbol_changes
   std::vector<Symbol*> vec_;
 };
 
-// Type for mapping section index to uncompressed size.
+// Type for mapping section index to uncompressed size and contents.
 
-typedef std::map<unsigned int, section_size_type> Compressed_section_map;
+struct Compressed_section_info
+{
+  section_size_type size;
+  const unsigned char* contents;
+};
+typedef std::map<unsigned int, Compressed_section_info> Compressed_section_map;
 
 // Abstract base class for a regular object file, either a real object file
 // or an incremental (unchanged) object.  This is size and endian specific.
 
 template<int size, bool big_endian>
-class Sized_relobj_base : public Relobj
+class Sized_relobj : public Relobj
 {
  public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef Relobj::Symbols Symbols;
 
-  Sized_relobj_base(const std::string& name, Input_file* input_file)
-    : Relobj(name, input_file)
+  static const Address invalid_address = static_cast<Address>(0) - 1;
+
+  Sized_relobj(const std::string& name, Input_file* input_file)
+    : Relobj(name, input_file), local_got_offsets_(), section_offsets_()
   { }
 
-  Sized_relobj_base(const std::string& name, Input_file* input_file,
+  Sized_relobj(const std::string& name, Input_file* input_file,
                    off_t offset)
-    : Relobj(name, input_file, offset)
+    : Relobj(name, input_file, offset), local_got_offsets_(), section_offsets_()
   { }
 
-  ~Sized_relobj_base()
+  ~Sized_relobj()
   { }
 
+  // If this is a regular object, return a pointer to the Sized_relobj_file
+  // object.  Otherwise, return NULL.
+  virtual Sized_relobj_file<size, big_endian>*
+  sized_relobj()
+  { return NULL; }
+
+  const virtual Sized_relobj_file<size, big_endian>*
+  sized_relobj() const
+  { return NULL; }
+
+  // Checks if the offset of input section SHNDX within its output
+  // section is invalid.
+  bool
+  is_output_section_offset_invalid(unsigned int shndx) const
+  { return this->get_output_section_offset(shndx) == invalid_address; }
+
+  // Get the offset of input section SHNDX within its output section.
+  // This is -1 if the input section requires a special mapping, such
+  // as a merge section.  The output section can be found in the
+  // output_sections_ field of the parent class Relobj.
+  Address
+  get_output_section_offset(unsigned int shndx) const
+  {
+    gold_assert(shndx < this->section_offsets_.size());
+    return this->section_offsets_[shndx];
+  }
+
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  void
+  do_for_all_local_got_entries(Got_offset_list::Visitor* v) const;
+
  protected:
   typedef Relobj::Output_sections Output_sections;
 
+  // Clear the local symbol information.
+  void
+  clear_got_offsets()
+  { this->local_got_offsets_.clear(); }
+
+  // Return the vector of section offsets.
+  std::vector<Address>&
+  section_offsets()
+  { return this->section_offsets_; }
+
+  // Get the offset of a section.
+  uint64_t
+  do_output_section_offset(unsigned int shndx) const
+  {
+    Address off = this->get_output_section_offset(shndx);
+    if (off == invalid_address)
+      return -1ULL;
+    return off;
+  }
+
+  // Set the offset of a section.
+  void
+  do_set_section_offset(unsigned int shndx, uint64_t off)
+  {
+    gold_assert(shndx < this->section_offsets_.size());
+    this->section_offsets_[shndx] =
+      (off == static_cast<uint64_t>(-1)
+       ? invalid_address
+       : convert_types<Address, uint64_t>(off));
+  }
+
+  // Return whether the local symbol SYMNDX has a GOT offset of type
+  // GOT_TYPE.
+  bool
+  do_local_has_got_offset(unsigned int symndx, unsigned int got_type) const
+  {
+    Local_got_offsets::const_iterator p =
+        this->local_got_offsets_.find(symndx);
+    return (p != this->local_got_offsets_.end()
+            && p->second->get_offset(got_type) != -1U);
+  }
+
+  // Return the GOT offset of type GOT_TYPE of the local symbol
+  // SYMNDX.
+  unsigned int
+  do_local_got_offset(unsigned int symndx, unsigned int got_type) const
+  {
+    Local_got_offsets::const_iterator p =
+        this->local_got_offsets_.find(symndx);
+    gold_assert(p != this->local_got_offsets_.end());
+    unsigned int off = p->second->get_offset(got_type);
+    gold_assert(off != -1U);
+    return off;
+  }
+
+  // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
+  // to GOT_OFFSET.
+  void
+  do_set_local_got_offset(unsigned int symndx, unsigned int got_type,
+                         unsigned int got_offset)
+  {
+    Local_got_offsets::const_iterator p =
+        this->local_got_offsets_.find(symndx);
+    if (p != this->local_got_offsets_.end())
+      p->second->set_offset(got_type, got_offset);
+    else
+      {
+        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
+        std::pair<Local_got_offsets::iterator, bool> ins =
+            this->local_got_offsets_.insert(std::make_pair(symndx, g));
+        gold_assert(ins.second);
+      }
+  }
+
+  // Return the word size of the object file.
+  virtual int
+  do_elfsize() const
+  { return size; }
+
+  // Return TRUE if this is a big-endian object file.
+  virtual bool
+  do_is_big_endian() const
+  { return big_endian; }
+
  private:
+  // The GOT offsets of local symbols. This map also stores GOT offsets
+  // for tp-relative offsets for TLS symbols.
+  typedef Unordered_map<unsigned int, Got_offset_list*> Local_got_offsets;
+
+  // GOT offsets for local non-TLS symbols, and tp-relative offsets
+  // for TLS symbols, indexed by symbol number.
+  Local_got_offsets local_got_offsets_;
+  // For each input section, the offset of the input section in its
+  // output section.  This is INVALID_ADDRESS if the input section requires a
+  // special mapping.
+  std::vector<Address> section_offsets_;
 };
 
 // A regular object file.  This is size and endian specific.
 
 template<int size, bool big_endian>
-class Sized_relobj : public Sized_relobj_base<size, big_endian>
+class Sized_relobj_file : public Sized_relobj<size, big_endian>
 {
  public:
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
-  typedef typename Sized_relobj_base<size, big_endian>::Symbols Symbols;
+  typedef typename Sized_relobj<size, big_endian>::Symbols Symbols;
   typedef std::vector<Symbol_value<size> > Local_values;
 
   static const Address invalid_address = static_cast<Address>(0) - 1;
@@ -1723,22 +2029,32 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
     CFLV_DISCARDED
   };
 
-  Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
-              const typename elfcpp::Ehdr<size, big_endian>&);
+  Sized_relobj_file(const std::string& name,
+                   Input_file* input_file,
+                   off_t offset,
+                   const typename elfcpp::Ehdr<size, big_endian>&);
 
-  ~Sized_relobj();
-
-  // Checks if the offset of input section SHNDX within its output
-  // section is invalid. 
-  bool
-  is_output_section_offset_invalid(unsigned int shndx) const
-  { return this->get_output_section_offset(shndx) == invalid_address; }
+  ~Sized_relobj_file();
 
   // Set up the object file based on TARGET.
   void
   setup()
   { this->do_setup(); }
 
+  // Return a pointer to the Sized_relobj_file object.
+  Sized_relobj_file<size, big_endian>*
+  sized_relobj()
+  { return this; }
+
+  const Sized_relobj_file<size, big_endian>*
+  sized_relobj() const
+  { return this; }
+
+  // Return the ELF file type.
+  int
+  e_type() const
+  { return this->e_type_; }
+
   // Return the number of symbols.  This is only valid after
   // Object::add_symbols has been called.
   unsigned int
@@ -1818,70 +2134,19 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
     this->local_values_[sym].set_needs_output_dynsym_entry();
   }
 
-  // Return whether the local symbol SYMNDX has a GOT offset.
-  // For TLS symbols, the GOT entry will hold its tp-relative offset.
-  bool
-  local_has_got_offset(unsigned int symndx, unsigned int got_type) const
-  {
-    Local_got_offsets::const_iterator p =
-        this->local_got_offsets_.find(symndx);
-    return (p != this->local_got_offsets_.end()
-            && p->second->get_offset(got_type) != -1U);
-  }
-
-  // Return the GOT offset of the local symbol SYMNDX.
-  unsigned int
-  local_got_offset(unsigned int symndx, unsigned int got_type) const
-  {
-    Local_got_offsets::const_iterator p =
-        this->local_got_offsets_.find(symndx);
-    gold_assert(p != this->local_got_offsets_.end());
-    unsigned int off = p->second->get_offset(got_type);
-    gold_assert(off != -1U);
-    return off;
-  }
-
-  // Set the GOT offset of the local symbol SYMNDX to GOT_OFFSET.
-  void
-  set_local_got_offset(unsigned int symndx, unsigned int got_type,
-                       unsigned int got_offset)
-  {
-    Local_got_offsets::const_iterator p =
-        this->local_got_offsets_.find(symndx);
-    if (p != this->local_got_offsets_.end())
-      p->second->set_offset(got_type, got_offset);
-    else
-      {
-        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
-        std::pair<Local_got_offsets::iterator, bool> ins =
-            this->local_got_offsets_.insert(std::make_pair(symndx, g));
-        gold_assert(ins.second);
-      }
-  }
-
   // Return whether the local symbol SYMNDX has a PLT offset.
   bool
   local_has_plt_offset(unsigned int symndx) const;
 
-  // Return the PLT offset for a local symbol.  It is an error to call
-  // this if it doesn't have one.
-  unsigned int
-  local_plt_offset(unsigned int symndx) const;
-
   // Set the PLT offset of the local symbol SYMNDX.
   void
   set_local_plt_offset(unsigned int symndx, unsigned int plt_offset);
 
-  // Get the offset of input section SHNDX within its output section.
-  // This is -1 if the input section requires a special mapping, such
-  // as a merge section.  The output section can be found in the
-  // output_sections_ field of the parent class Relobj.
-  Address
-  get_output_section_offset(unsigned int shndx) const
-  {
-    gold_assert(shndx < this->section_offsets_.size());
-    return this->section_offsets_[shndx];
-  }
+  // Adjust this local symbol value.  Return false if the symbol
+  // should be discarded from the output file.
+  bool
+  adjust_local_symbol(Symbol_value<size>* lv) const
+  { return this->do_adjust_local_symbol(lv); }
 
   // Return the name of the symbol that spans the given offset in the
   // specified section in this object.  This is used only for error
@@ -1896,6 +2161,15 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   Address
   map_to_kept_section(unsigned int shndx, bool* found) const;
 
+  // Find the section header with the given NAME.  If HDR is non-NULL
+  // then it is a section header returned from a previous call to this
+  // function and the next section header with the same name will be
+  // returned.
+  const unsigned char*
+  find_shdr(const unsigned char* pshdrs, const char* name,
+           const char* names, section_size_type names_size,
+           const unsigned char* hdr) const;
+
   // Compute final local symbol value.  R_SYM is the local symbol index.
   // LV_IN points to a local symbol value containing the input value.
   // LV_OUT points to a local symbol value storing the final output value,
@@ -1913,7 +2187,7 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
                            const Symbol_table* symtab);
 
  protected:
-  typedef typename Sized_relobj_base<size, big_endian>::Output_sections
+  typedef typename Sized_relobj<size, big_endian>::Output_sections
       Output_sections;
 
   // Set up.
@@ -1924,6 +2198,24 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   void
   do_read_symbols(Read_symbols_data*);
 
+  // Return the value of a local symbol.
+  uint64_t
+  do_local_symbol_value(unsigned int symndx, uint64_t addend) const
+  {
+    const Symbol_value<size>* symval = this->local_symbol(symndx);
+    return symval->value(this, addend);
+  }
+
+  // Return the PLT offset for a local symbol.  It is an error to call
+  // this if it doesn't have one.
+  unsigned int
+  do_local_plt_offset(unsigned int symndx) const;
+
+  // Return whether local symbol SYMNDX is a TLS symbol.
+  bool
+  do_local_is_tls(unsigned int symndx) const
+  { return this->local_symbol(symndx)->is_tls_symbol(); }
+
   // Return the number of local symbols.
   unsigned int
   do_local_symbol_count() const
@@ -1961,11 +2253,6 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   do_for_all_global_symbols(Read_symbols_data* sd,
                            Library_base::Symbol_visitor_base* v);
 
-  // Iterate over local symbols, calling a visitor class V for each GOT offset
-  // associated with a local symbol.
-  void
-  do_for_all_local_got_entries(Got_offset_list::Visitor* v) const;
-
   // Read the relocs.
   void
   do_read_relocs(Read_relocs_data*);
@@ -2011,9 +2298,19 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   { return this->elf_file_.section_name(shndx); }
 
   // Return the location of the contents of a section.
-  Object::Location
-  do_section_contents(unsigned int shndx)
-  { return this->elf_file_.section_contents(shndx); }
+  const unsigned char*
+  do_section_contents(unsigned int shndx, section_size_type* plen,
+                     bool cache)
+  {
+    Object::Location loc(this->elf_file_.section_contents(shndx));
+    *plen = convert_to_section_size_type(loc.data_size);
+    if (*plen == 0)
+      {
+       static const unsigned char empty[1] = { '\0' };
+       return empty;
+      }
+    return this->get_view(loc.file_offset, *plen, true, cache);
+  }
 
   // Return section flags.
   uint64_t
@@ -2061,27 +2358,6 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   do_get_global_symbols() const
   { return &this->symbols_; }
 
-  // Get the offset of a section.
-  uint64_t
-  do_output_section_offset(unsigned int shndx) const
-  {
-    Address off = this->get_output_section_offset(shndx);
-    if (off == invalid_address)
-      return -1ULL;
-    return off;
-  }
-
-  // Set the offset of a section.
-  void
-  do_set_section_offset(unsigned int shndx, uint64_t off)
-  {
-    gold_assert(shndx < this->section_offsets_.size());
-    this->section_offsets_[shndx] =
-      (off == static_cast<uint64_t>(-1)
-       ? invalid_address
-       : convert_types<Address, uint64_t>(off));
-  }
-
   // Adjust a section index if necessary.
   unsigned int
   adjust_shndx(unsigned int shndx)
@@ -2125,16 +2401,28 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
     section_size_type view_size;
     bool is_input_output_view;
     bool is_postprocessing_view;
+    bool is_ctors_reverse_view;
   };
 
   typedef std::vector<View_size> Views;
 
+  // Stash away info for a number of special sections.
+  // Return true if any of the sections found require local symbols to be read.
+  virtual bool
+  do_find_special_sections(Read_symbols_data* sd);
+
   // This may be overriden by a child class.
   virtual void
   do_relocate_sections(const Symbol_table* symtab, const Layout* layout,
                       const unsigned char* pshdrs, Output_file* of,
                       Views* pviews);
 
+  // Adjust this local symbol value.  Return false if the symbol
+  // should be discarded from the output file.
+  virtual bool
+  do_adjust_local_symbol(Symbol_value<size>*) const
+  { return true; }
+
   // Allow a child to set output local symbol count.
   void
   set_output_local_symbol_count(unsigned int value)
@@ -2153,15 +2441,28 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
     if (p != this->compressed_sections_->end())
       {
        if (uncompressed_size != NULL)
-         *uncompressed_size = p->second;
+         *uncompressed_size = p->second.size;
        return true;
       }
     return false;
   }
 
+  // Return a view of the uncompressed contents of a section.  Set *PLEN
+  // to the size.  Set *IS_NEW to true if the contents need to be deleted
+  // by the caller.
+  const unsigned char*
+  do_decompressed_section_contents(unsigned int shndx,
+                                  section_size_type* plen,
+                                  bool* is_new);
+
+  // Discard any buffers of decompressed sections.  This is done
+  // at the end of the Add_symbols task.
+  void
+  do_discard_decompressed_sections();
+
  private:
   // For convenience.
-  typedef Sized_relobj<size, big_endian> This;
+  typedef Sized_relobj_file<size, big_endian> This;
   static const int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
   static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
   static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
@@ -2210,13 +2511,23 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   // Layout an input section.
   void
   layout_section(Layout* layout, unsigned int shndx, const char* name,
-                 typename This::Shdr& shdr, unsigned int reloc_shndx,
+                 const typename This::Shdr& shdr, unsigned int reloc_shndx,
                  unsigned int reloc_type);
 
+  // Layout an input .eh_frame section.
+  void
+  layout_eh_frame_section(Layout* layout, const unsigned char* symbols_data,
+                         section_size_type symbols_size,
+                         const unsigned char* symbol_names_data,
+                         section_size_type symbol_names_size,
+                         unsigned int shndx, const typename This::Shdr&,
+                         unsigned int reloc_shndx, unsigned int reloc_type);
+
   // Write section data to the output file.  Record the views and
   // sizes in VIEWS for use when relocating.
   void
-  write_sections(const unsigned char* pshdrs, Output_file*, Views*);
+  write_sections(const Layout*, const unsigned char* pshdrs, Output_file*,
+                Views*);
 
   // Relocate the sections in the output file.
   void
@@ -2225,6 +2536,11 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
                    Views* pviews)
   { this->do_relocate_sections(symtab, layout, pshdrs, of, pviews); }
 
+  // Reverse the words in a section.  Used for .ctors sections mapped
+  // to .init_array sections.
+  void
+  reverse_words(unsigned char*, section_size_type);
+
   // Scan the input relocations for --emit-relocs.
   void
   emit_relocs_scan(Symbol_table*, Layout*, const unsigned char* plocal_syms,
@@ -2239,27 +2555,6 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
                           const Read_relocs_data::Relocs_list::iterator&,
                           Relocatable_relocs*);
 
-  // Emit the relocs for --emit-relocs.
-  void
-  emit_relocs(const Relocate_info<size, big_endian>*, unsigned int,
-             unsigned int sh_type, const unsigned char* prelocs,
-             size_t reloc_count, Output_section*, Address output_offset,
-             unsigned char* view, Address address,
-             section_size_type view_size,
-             unsigned char* reloc_view, section_size_type reloc_view_size);
-
-  // Emit the relocs for --emit-relocs, templatized on the type of the
-  // relocation section.
-  template<int sh_type>
-  void
-  emit_relocs_reltype(const Relocate_info<size, big_endian>*, unsigned int,
-                     const unsigned char* prelocs, size_t reloc_count,
-                     Output_section*, Address output_offset,
-                     unsigned char* view, Address address,
-                     section_size_type view_size,
-                     unsigned char* reloc_view,
-                     section_size_type reloc_view_size);
-
   // Scan the input relocations for --incremental.
   void
   incremental_relocs_scan(const Read_relocs_data::Relocs_list::iterator&);
@@ -2369,10 +2664,6 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
                                     const std::vector<Address>& out_offsets,
                                     const Symbol_table* symtab);
 
-  // The GOT offsets of local symbols. This map also stores GOT offsets
-  // for tp-relative offsets for TLS symbols.
-  typedef Unordered_map<unsigned int, Got_offset_list*> Local_got_offsets;
-
   // The PLT offsets of local symbols.
   typedef Unordered_map<unsigned int, unsigned int> Local_plt_offsets;
 
@@ -2397,6 +2688,9 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
 
   // General access to the ELF file.
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
+  // Type of ELF file (ET_REL or ET_EXEC).  ET_EXEC files are allowed
+  // as input files only for the --just-symbols option.
+  int e_type_;
   // Index of SHT_SYMTAB section.
   unsigned int symtab_shndx_;
   // The number of local symbols.
@@ -2416,15 +2710,8 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   off_t local_dynsym_offset_;
   // Values of local symbols.
   Local_values local_values_;
-  // GOT offsets for local non-TLS symbols, and tp-relative offsets
-  // for TLS symbols, indexed by symbol number.
-  Local_got_offsets local_got_offsets_;
   // PLT offsets for local symbols.
   Local_plt_offsets local_plt_offsets_;
-  // For each input section, the offset of the input section in its
-  // output section.  This is INVALID_ADDRESS if the input section requires a
-  // special mapping.
-  std::vector<Address> section_offsets_;
   // Table mapping discarded comdat sections to corresponding kept sections.
   Kept_comdat_section_table kept_comdat_sections_;
   // Whether this object has a GNU style .eh_frame section.
@@ -2436,7 +2723,8 @@ class Sized_relobj : public Sized_relobj_base<size, big_endian>
   std::vector<Deferred_layout> deferred_layout_;
   // The list of relocation sections whose layout was deferred.
   std::vector<Deferred_layout> deferred_layout_relocs_;
-  // For compressed debug sections, map section index to uncompressed size.
+  // For compressed debug sections, map section index to uncompressed size
+  // and contents.
   Compressed_section_map* compressed_sections_;
 };
 
@@ -2548,7 +2836,7 @@ struct Relocate_info
   // Layout.
   const Layout* layout;
   // Object being relocated.
-  Sized_relobj<size, big_endian>* object;
+  Sized_relobj_file<size, big_endian>* object;
   // Section index of relocation section.
   unsigned int reloc_shndx;
   // Section header of relocation section.