]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gold/object.h
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gold / object.h
index 38b06f01fa99a2e380d3d6ee1f699c16991cee2b..e7472893ca614daa5f4cd0e509ee060293874a57 100644 (file)
@@ -1,6 +1,6 @@
 // object.h -- support for an object file for linking in gold  -*- C++ -*-
 
-// Copyright (C) 2006-2014 Free Software Foundation, Inc.
+// Copyright (C) 2006-2023 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -39,8 +39,10 @@ class General_options;
 class Task;
 class Cref;
 class Layout;
+class Kept_section;
 class Output_data;
 class Output_section;
+class Output_section_data;
 class Output_file;
 class Output_symtab_xindex;
 class Pluginobj;
@@ -212,11 +214,13 @@ class Got_offset_list
 {
  public:
   Got_offset_list()
-    : got_type_(-1U), got_offset_(0), got_next_(NULL)
+    : got_type_(-1U), got_offset_(0), addend_(0), got_next_(NULL)
   { }
 
-  Got_offset_list(unsigned int got_type, unsigned int got_offset)
-    : got_type_(got_type), got_offset_(got_offset), got_next_(NULL)
+  Got_offset_list(unsigned int got_type, unsigned int got_offset,
+                 uint64_t addend)
+    : got_type_(got_type), got_offset_(got_offset), addend_(addend),
+      got_next_(NULL)
   { }
 
   ~Got_offset_list()
@@ -234,29 +238,31 @@ class Got_offset_list
   {
     this->got_type_ = -1U;
     this->got_offset_ = 0;
+    this->addend_ = 0;
     this->got_next_ = NULL;
   }
 
   // Set the offset for the GOT entry of type GOT_TYPE.
   void
-  set_offset(unsigned int got_type, unsigned int got_offset)
+  set_offset(unsigned int got_type, unsigned int got_offset, uint64_t addend)
   {
     if (this->got_type_ == -1U)
       {
         this->got_type_ = got_type;
         this->got_offset_ = got_offset;
+        this->addend_ = addend;
       }
     else
       {
         for (Got_offset_list* g = this; g != NULL; g = g->got_next_)
           {
-            if (g->got_type_ == got_type)
+            if (g->got_type_ == got_type && g->addend_ == addend)
               {
                 g->got_offset_ = got_offset;
                 return;
               }
           }
-        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
+        Got_offset_list* g = new Got_offset_list(got_type, got_offset, addend);
         g->got_next_ = this->got_next_;
         this->got_next_ = g;
       }
@@ -264,11 +270,11 @@ class Got_offset_list
 
   // Return the offset for a GOT entry of type GOT_TYPE.
   unsigned int
-  get_offset(unsigned int got_type) const
+  get_offset(unsigned int got_type, uint64_t addend) const
   {
     for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
       {
-        if (g->got_type_ == got_type)
+        if (g->got_type_ == got_type && g->addend_ == addend)
           return g->got_offset_;
       }
     return -1U;
@@ -295,7 +301,7 @@ class Got_offset_list
     { }
 
     virtual void
-    visit(unsigned int, unsigned int) = 0;
+    visit(unsigned int, unsigned int, uint64_t) = 0;
   };
 
   // Loop over all GOT offset entries, calling a visitor class V for each.
@@ -305,15 +311,122 @@ class Got_offset_list
     if (this->got_type_ == -1U)
       return;
     for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
-      v->visit(g->got_type_, g->got_offset_);
+      v->visit(g->got_type_, g->got_offset_, g->addend_);
   }
 
  private:
   unsigned int got_type_;
   unsigned int got_offset_;
+  uint64_t addend_;
   Got_offset_list* got_next_;
 };
 
+// The Local_got_entry_key used to index the GOT offsets for local
+// non-TLS symbols, and tp-relative offsets for TLS symbols.
+
+class Local_got_entry_key
+{
+ public:
+  Local_got_entry_key(unsigned int symndx)
+    : symndx_(symndx)
+  {}
+
+  // Whether this equals to another Local_got_entry_key.
+  bool
+  eq(const Local_got_entry_key& key) const
+  {
+    return this->symndx_ == key.symndx_;
+  }
+
+  // Compute a hash value for this using 64-bit FNV-1a hash.
+  size_t
+  hash_value() const
+  {
+    uint64_t h = 14695981039346656037ULL; // FNV offset basis.
+    uint64_t prime = 1099511628211ULL;
+    h = (h ^ static_cast<uint64_t>(this->symndx_)) * prime;
+    return h;
+  }
+
+  // Functors for associative containers.
+  struct equal_to
+  {
+    bool
+    operator()(const Local_got_entry_key& key1,
+               const Local_got_entry_key& key2) const
+    { return key1.eq(key2); }
+  };
+
+  struct hash
+  {
+    size_t
+    operator()(const Local_got_entry_key& key) const
+    { return key.hash_value(); }
+  };
+
+ private:
+  // The local symbol index.
+  unsigned int symndx_;
+};
+
+// Type for mapping section index to uncompressed size and contents.
+
+struct Compressed_section_info
+{
+  section_size_type size;
+  elfcpp::Elf_Xword flag;
+  uint64_t addralign;
+  const unsigned char* contents;
+};
+typedef std::map<unsigned int, Compressed_section_info> Compressed_section_map;
+
+template<int size, bool big_endian>
+Compressed_section_map*
+build_compressed_section_map(const unsigned char* pshdrs, unsigned int shnum,
+                            const char* names, section_size_type names_size,
+                            Object* obj, bool decompress_if_needed);
+
+// Osabi represents the EI_OSABI field from the ELF header.
+
+class Osabi
+{
+ public:
+  Osabi(unsigned char ei_osabi)
+    : ei_osabi_(static_cast<elfcpp::ELFOSABI>(ei_osabi))
+  { }
+
+  bool
+  has_shf_retain(elfcpp::Elf_Xword sh_flags) const
+  {
+    switch (this->ei_osabi_)
+      {
+      case elfcpp::ELFOSABI_GNU:
+      case elfcpp::ELFOSABI_FREEBSD:
+       return (sh_flags & elfcpp::SHF_GNU_RETAIN) != 0;
+      default:
+        break;
+      }
+    return false;
+  }
+
+  elfcpp::Elf_Xword
+  ignored_sh_flags() const
+  {
+    switch (this->ei_osabi_)
+      {
+      case elfcpp::ELFOSABI_GNU:
+      case elfcpp::ELFOSABI_FREEBSD:
+       return elfcpp::SHF_GNU_RETAIN;
+      default:
+        break;
+      }
+    return 0;
+  }
+
+ private:
+  elfcpp::ELFOSABI ei_osabi_;
+};
+
 // Object is an abstract base class which represents either a 32-bit
 // or a 64-bit input object.  This can be a regular object file
 // (ET_REL) or a shared object (ET_DYN).
@@ -332,7 +445,8 @@ 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), as_needed_(false), xindex_(NULL)
+      is_in_system_directory_(false), as_needed_(false), xindex_(NULL),
+      compressed_sections_(NULL)
   {
     if (input_file != NULL)
       {
@@ -363,6 +477,12 @@ class Object
   is_dynamic() const
   { return this->is_dynamic_; }
 
+  // Return the word size of the object file.
+  virtual int elfsize() const = 0;
+
+  // Return TRUE if this is a big-endian object file.
+  virtual bool is_big_endian() const = 0;
+
   // Return whether this object is needed--true if it is a dynamic
   // object which defines some symbol referenced by a regular object.
   // We keep the flag here rather than in Dynobj for convenience when
@@ -507,7 +627,7 @@ class Object
 
   // Return the name of a section given a section index.
   std::string
-  section_name(unsigned int shndx)
+  section_name(unsigned int shndx) const
   { return this->do_section_name(shndx); }
 
   // Return the section flags given a section index.
@@ -707,6 +827,11 @@ class Object
   set_as_needed()
   { this->as_needed_ = true; }
 
+  // Clear flag that this object was linked with --as-needed.
+  void
+  clear_as_needed()
+  { this->as_needed_ = false; }
+
   // Return whether this object was linked with --as-needed.
   bool
   as_needed() const
@@ -725,26 +850,37 @@ class Object
   set_no_export(bool value)
   { this->no_export_ = value; }
 
-  // Return TRUE if the section is a compressed debug section, and set
-  // *UNCOMPRESSED_SIZE to the size of the uncompressed data.
   bool
   section_is_compressed(unsigned int shndx,
-                       section_size_type* uncompressed_size) const
-  { return this->do_section_is_compressed(shndx, uncompressed_size); }
+                       section_size_type* uncompressed_size,
+                       elfcpp::Elf_Xword* palign = NULL) const
+  {
+    if (this->compressed_sections_ == NULL)
+      return false;
+    Compressed_section_map::const_iterator p =
+        this->compressed_sections_->find(shndx);
+    if (p != this->compressed_sections_->end())
+      {
+       if (uncompressed_size != NULL)
+         *uncompressed_size = p->second.size;
+       if (palign != NULL)
+         *palign = p->second.addralign;
+       return true;
+      }
+    return false;
+  }
 
   // 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); }
+                               bool* is_cached, uint64_t* palign = NULL);
 
   // 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(); }
+  discard_decompressed_sections();
 
   // Return the index of the first incremental relocation for symbol SYMNDX.
   unsigned int
@@ -756,6 +892,11 @@ class Object
   get_incremental_reloc_count(unsigned int symndx) const
   { return this->do_get_incremental_reloc_count(symndx); }
 
+  // Return the output view for section SHNDX.
+  unsigned char*
+  get_output_view(unsigned int shndx, section_size_type* plen) const
+  { return this->do_get_output_view(shndx, plen); }
+
  protected:
   // Returns NULL for Objects that are not dynamic objects.  This method
   // is overridden in the Dynobj class.
@@ -822,7 +963,7 @@ class Object
 
   // Get the name of a section--implemented by child class.
   virtual std::string
-  do_section_name(unsigned int shndx) = 0;
+  do_section_name(unsigned int shndx) const = 0;
 
   // Get section flags--implemented by child class.
   virtual uint64_t
@@ -923,27 +1064,6 @@ class Object
   bool
   handle_split_stack_section(const char* name);
 
-  // Return TRUE if the section is a compressed debug section, and set
-  // *UNCOMPRESSED_SIZE to the size of the uncompressed data.
-  virtual bool
-  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
@@ -962,6 +1082,19 @@ class Object
   do_get_incremental_reloc_count(unsigned int) const
   { gold_unreachable(); }
 
+  // Return the output view for a section.
+  virtual unsigned char*
+  do_get_output_view(unsigned int, section_size_type*) const
+  { gold_unreachable(); }
+
+  void
+  set_compressed_sections(Compressed_section_map* compressed_sections)
+  { this->compressed_sections_ = compressed_sections; }
+
+  Compressed_section_map*
+  compressed_sections()
+  { return this->compressed_sections_; }
+
  private:
   // This class may not be copied.
   Object(const Object&);
@@ -996,6 +1129,9 @@ class Object
   bool as_needed_ : 1;
   // Many sections for objects with more than SHN_LORESERVE sections.
   Xindex* xindex_;
+  // For compressed debug sections, map section index to uncompressed size
+  // and contents.
+  Compressed_section_map* compressed_sections_;
 };
 
 // A regular object (ET_REL).  This is an abstract base class itself.
@@ -1080,25 +1216,28 @@ class Relobj : public Object
   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.
+  // Return whether there is a GOT entry of type GOT_TYPE for the
+  // local symbol SYMNDX with given ADDEND.
   bool
-  local_has_got_offset(unsigned int symndx, unsigned int got_type) const
-  { return this->do_local_has_got_offset(symndx, got_type); }
+  local_has_got_offset(unsigned int symndx, unsigned int got_type,
+                      uint64_t addend = 0) const
+  { return this->do_local_has_got_offset(symndx, got_type, addend); }
 
-  // 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.
+  // Return the GOT offset of the GOT entry with type GOT_TYPE for the
+  // local symbol SYMNDX with given ADDEND.  It is an error to call
+  // this function if the symbol does not have such a GOT entry.
   unsigned int
-  local_got_offset(unsigned int symndx, unsigned int got_type) const
-  { return this->do_local_got_offset(symndx, got_type); }
+  local_got_offset(unsigned int symndx, unsigned int got_type,
+                  uint64_t addend = 0) const
+  { return this->do_local_got_offset(symndx, got_type, addend); }
 
-  // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
-  // to GOT_OFFSET.
+  // Set the GOT offset for a GOT entry with type GOT_TYPE for the
+  // local symbol SYMNDX with ADDEND to GOT_OFFSET.  Create such an
+  // entry if none exists.
   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); }
+                      unsigned int got_offset, uint64_t addend = 0)
+  { this->do_set_local_got_offset(symndx, got_type, got_offset, addend); }
 
   // Return whether the local symbol SYMNDX is a TLS symbol.
   bool
@@ -1200,18 +1339,28 @@ class Relobj : public Object
   relocs_must_follow_section_writes() const
   { return this->relocs_must_follow_section_writes_; }
 
-  // Return the object merge map.
   Object_merge_map*
-  merge_map() const
-  { return this->object_merge_map_; }
+  get_or_create_merge_map();
 
-  // Set the object merge map.
+  template<int size>
   void
-  set_merge_map(Object_merge_map* object_merge_map)
-  {
-    gold_assert(this->object_merge_map_ == NULL);
-    this->object_merge_map_ = object_merge_map;
-  }
+  initialize_input_to_output_map(unsigned int shndx,
+      typename elfcpp::Elf_types<size>::Elf_Addr starting_address,
+      Unordered_map<section_offset_type,
+           typename elfcpp::Elf_types<size>::Elf_Addr>* output_address) const;
+
+  void
+  add_merge_mapping(Output_section_data *output_data,
+                    unsigned int shndx, section_offset_type offset,
+                    section_size_type length,
+                    section_offset_type output_offset);
+
+  bool
+  merge_output_offset(unsigned int shndx, section_offset_type offset,
+                      section_offset_type *poutput) const;
+
+  const Output_section_data*
+  find_merge_section(unsigned int shndx) const;
 
   // Record the relocatable reloc info for an input reloc section.
   void
@@ -1281,19 +1430,21 @@ class Relobj : public Object
   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.
+  // Return whether a local symbol plus addend has a GOT offset
+  // of a given type.
   virtual bool
   do_local_has_got_offset(unsigned int symndx,
-                         unsigned int got_type) const = 0;
+                         unsigned int got_type, uint64_t addend) const = 0;
 
-  // Return the GOT offset of a given type of a local symbol.
+  // Return the GOT offset of a given type of a local symbol plus addend.
   virtual unsigned int
-  do_local_got_offset(unsigned int symndx, unsigned int got_type) const = 0;
+  do_local_got_offset(unsigned int symndx, unsigned int got_type,
+                     uint64_t addend) const = 0;
 
-  // Set the GOT offset with a given type for a local symbol.
+  // Set the GOT offset with a given type for a local symbol plus addend.
   virtual void
   do_set_local_got_offset(unsigned int symndx, unsigned int got_type,
-                         unsigned int got_offset) = 0;
+                         unsigned int got_offset, uint64_t addend) = 0;
 
   // Return whether local symbol SYMNDX is a TLS symbol.
   virtual bool
@@ -1862,15 +2013,6 @@ class Reloc_symbol_changes
   std::vector<Symbol*> vec_;
 };
 
-// Type for mapping section index to uncompressed size and contents.
-
-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.
 
@@ -1965,45 +2107,50 @@ class Sized_relobj : public Relobj
        : convert_types<Address, uint64_t>(off));
   }
 
-  // Return whether the local symbol SYMNDX has a GOT offset of type
-  // GOT_TYPE.
+  // Return whether the local symbol SYMNDX plus ADDEND has a GOT offset
+  // of type GOT_TYPE.
   bool
-  do_local_has_got_offset(unsigned int symndx, unsigned int got_type) const
+  do_local_has_got_offset(unsigned int symndx, unsigned int got_type,
+                         uint64_t addend) const
   {
+    Local_got_entry_key key(symndx);
     Local_got_offsets::const_iterator p =
-        this->local_got_offsets_.find(symndx);
+        this->local_got_offsets_.find(key);
     return (p != this->local_got_offsets_.end()
-            && p->second->get_offset(got_type) != -1U);
+            && p->second->get_offset(got_type, addend) != -1U);
   }
 
   // Return the GOT offset of type GOT_TYPE of the local symbol
-  // SYMNDX.
+  // SYMNDX plus ADDEND.
   unsigned int
-  do_local_got_offset(unsigned int symndx, unsigned int got_type) const
+  do_local_got_offset(unsigned int symndx, unsigned int got_type,
+                         uint64_t addend) const
   {
+    Local_got_entry_key key(symndx);
     Local_got_offsets::const_iterator p =
-        this->local_got_offsets_.find(symndx);
+        this->local_got_offsets_.find(key);
     gold_assert(p != this->local_got_offsets_.end());
-    unsigned int off = p->second->get_offset(got_type);
+    unsigned int off = p->second->get_offset(got_type, addend);
     gold_assert(off != -1U);
     return off;
   }
 
   // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
-  // to GOT_OFFSET.
+  // plus ADDEND to GOT_OFFSET.
   void
   do_set_local_got_offset(unsigned int symndx, unsigned int got_type,
-                         unsigned int got_offset)
+                         unsigned int got_offset, uint64_t addend)
   {
+    Local_got_entry_key key(symndx);
     Local_got_offsets::const_iterator p =
-        this->local_got_offsets_.find(symndx);
+        this->local_got_offsets_.find(key);
     if (p != this->local_got_offsets_.end())
-      p->second->set_offset(got_type, got_offset);
+      p->second->set_offset(got_type, got_offset, addend);
     else
       {
-        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
+       Got_offset_list* g = new Got_offset_list(got_type, got_offset, addend);
         std::pair<Local_got_offsets::iterator, bool> ins =
-            this->local_got_offsets_.insert(std::make_pair(symndx, g));
+            this->local_got_offsets_.insert(std::make_pair(key, g));
         gold_assert(ins.second);
       }
   }
@@ -2021,10 +2168,12 @@ class Sized_relobj : public Relobj
  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;
+  typedef Unordered_map<Local_got_entry_key, Got_offset_list*,
+                        Local_got_entry_key::hash,
+                        Local_got_entry_key::equal_to> Local_got_offsets;
 
   // GOT offsets for local non-TLS symbols, and tp-relative offsets
-  // for TLS symbols, indexed by symbol number.
+  // for TLS symbols, indexed by local got entry key class.
   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
@@ -2080,6 +2229,11 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   e_type() const
   { return this->e_type_; }
 
+  // Return the EI_OSABI.
+  const Osabi&
+  osabi() const
+  { return this->osabi_; }
+
   // Return the number of symbols.  This is only valid after
   // Object::add_symbols has been called.
   unsigned int
@@ -2184,7 +2338,17 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   // and return its output address.  This is used only for relocations in
   // debugging sections.
   Address
-  map_to_kept_section(unsigned int shndx, bool* found) const;
+  map_to_kept_section(unsigned int shndx, std::string& section_name,
+                     bool* found) const;
+
+  // Look for a kept section corresponding to the given discarded section,
+  // and return its object file.
+  Relobj*
+  find_kept_section_object(unsigned int shndx, unsigned int* symndx_p) const;
+
+  // Return the name of symbol SYMNDX.
+  const char*
+  get_symbol_name(unsigned int symndx);
 
   // Compute final local symbol value.  R_SYM is the local symbol index.
   // LV_IN points to a local symbol value containing the input value.
@@ -2202,6 +2366,10 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
                            Symbol_value<size>* lv_out,
                            const Symbol_table* symtab);
 
+  // Return true if the layout for this object was deferred.
+  bool is_deferred_layout() const
+  { return this->is_deferred_layout_; }
+
  protected:
   typedef typename Sized_relobj<size, big_endian>::Output_sections
       Output_sections;
@@ -2214,6 +2382,11 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   void
   do_read_symbols(Read_symbols_data*);
 
+  // Read the symbols.  This is common code for all target-specific
+  // overrides of do_read_symbols.
+  void
+  base_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
@@ -2310,7 +2483,7 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
 
   // Get the name of a section.
   std::string
-  do_section_name(unsigned int shndx)
+  do_section_name(unsigned int shndx) const
   { return this->elf_file_.section_name(shndx); }
 
   // Return the location of the contents of a section.
@@ -2433,6 +2606,13 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
                       const unsigned char* pshdrs, Output_file* of,
                       Views* pviews);
 
+  // Relocate section data for a range of sections.
+  void
+  relocate_section_range(const Symbol_table* symtab, const Layout* layout,
+                        const unsigned char* pshdrs, Output_file* of,
+                        Views* pviews, unsigned int start_shndx,
+                        unsigned int end_shndx);
+
   // Adjust this local symbol value.  Return false if the symbol
   // should be discarded from the output file.
   virtual bool
@@ -2444,37 +2624,9 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   set_output_local_symbol_count(unsigned int value)
   { this->output_local_symbol_count_ = value; }
 
-  // Return TRUE if the section is a compressed debug section, and set
-  // *UNCOMPRESSED_SIZE to the size of the uncompressed data.
-  bool
-  do_section_is_compressed(unsigned int shndx,
-                          section_size_type* uncompressed_size) const
-  {
-    if (this->compressed_sections_ == NULL)
-      return false;
-    Compressed_section_map::const_iterator p =
-        this->compressed_sections_->find(shndx);
-    if (p != this->compressed_sections_->end())
-      {
-       if (uncompressed_size != NULL)
-         *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();
+  // Return the output view for a section.
+  unsigned char*
+  do_get_output_view(unsigned int, section_size_type*) const;
 
  private:
   // For convenience.
@@ -2483,17 +2635,22 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
   static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
   typedef elfcpp::Shdr<size, big_endian> Shdr;
+  typedef elfcpp::Shdr_write<size, big_endian> Shdr_write;
 
   // To keep track of discarded comdat sections, we need to map a member
   // section index to the object and section index of the corresponding
   // kept section.
   struct Kept_comdat_section
   {
-    Kept_comdat_section(Relobj* a_object, unsigned int a_shndx)
-      : object(a_object), shndx(a_shndx)
+    Kept_comdat_section(uint64_t a_sh_size, Kept_section* a_kept_section,
+                       unsigned int a_symndx, bool a_is_comdat)
+      : sh_size(a_sh_size), kept_section(a_kept_section),
+       symndx (a_symndx), is_comdat(a_is_comdat)
     { }
-    Relobj* object;
-    unsigned int shndx;
+    uint64_t sh_size;          // Section size
+    Kept_section* kept_section;        // Kept section info
+    unsigned int symndx;       // Index of key symbol
+    bool is_comdat;            // True if comdat group, false if linkonce
   };
   typedef std::map<unsigned int, Kept_comdat_section>
       Kept_comdat_section_table;
@@ -2527,8 +2684,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   // Layout an input section.
   void
   layout_section(Layout* layout, unsigned int shndx, const char* name,
-                 const typename This::Shdr& shdr, unsigned int reloc_shndx,
-                 unsigned int reloc_type);
+                 const typename This::Shdr& shdr, unsigned int sh_type,
+                 unsigned int reloc_shndx, unsigned int reloc_type);
 
   // Layout an input .eh_frame section.
   void
@@ -2539,6 +2696,10 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
                          unsigned int shndx, const typename This::Shdr&,
                          unsigned int reloc_shndx, unsigned int reloc_type);
 
+  // Layout an input .note.gnu.property section.
+  void
+  layout_gnu_property_section(Layout* layout, unsigned int shndx);
+
   // Write section data to the output file.  Record the views and
   // sizes in VIEWS for use when relocating.
   void
@@ -2609,7 +2770,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
                     unsigned int sh_type, unsigned int shndx,
                     const unsigned char* prelocs, size_t reloc_count,
                     unsigned char* view, section_size_type view_size,
-                    Reloc_symbol_changes** reloc_map);
+                    Reloc_symbol_changes** reloc_map,
+                    const Sized_target<size, big_endian>* target);
 
   template<int sh_type>
   void
@@ -2617,7 +2779,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
                             unsigned int shndx, const unsigned char* prelocs,
                             size_t reloc_count, unsigned char* view,
                             section_size_type view_size,
-                            Reloc_symbol_changes** reloc_map);
+                            Reloc_symbol_changes** reloc_map,
+                            const Sized_target<size, big_endian>* target);
 
   // Find all functions in a section.
   void
@@ -2636,25 +2799,29 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   // Record a mapping from discarded section SHNDX to the corresponding
   // kept section.
   void
-  set_kept_comdat_section(unsigned int shndx, Relobj* kept_object,
-                         unsigned int kept_shndx)
+  set_kept_comdat_section(unsigned int shndx, bool is_comdat,
+                         unsigned int symndx, uint64_t sh_size,
+                         Kept_section* kept_section)
   {
-    Kept_comdat_section kept(kept_object, kept_shndx);
+    Kept_comdat_section kept(sh_size, kept_section, symndx, is_comdat);
     this->kept_comdat_sections_.insert(std::make_pair(shndx, kept));
   }
 
   // Find the kept section corresponding to the discarded section
   // SHNDX.  Return true if found.
   bool
-  get_kept_comdat_section(unsigned int shndx, Relobj** kept_object,
-                         unsigned int* kept_shndx) const
+  get_kept_comdat_section(unsigned int shndx, bool* is_comdat,
+                         unsigned int *symndx, uint64_t* sh_size,
+                         Kept_section** kept_section) const
   {
     typename Kept_comdat_section_table::const_iterator p =
       this->kept_comdat_sections_.find(shndx);
     if (p == this->kept_comdat_sections_.end())
       return false;
-    *kept_object = p->second.object;
-    *kept_shndx = p->second.shndx;
+    *is_comdat = p->second.is_comdat;
+    *symndx = p->second.symndx;
+    *sh_size = p->second.sh_size;
+    *kept_section = p->second.kept_section;
     return true;
   }
 
@@ -2688,15 +2855,18 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   {
     static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
     Deferred_layout(unsigned int shndx, const char* name,
+                    unsigned int sh_type,
                     const unsigned char* pshdr,
                     unsigned int reloc_shndx, unsigned int reloc_type)
-      : shndx_(shndx), name_(name), reloc_shndx_(reloc_shndx),
+      : name_(name), shndx_(shndx), reloc_shndx_(reloc_shndx),
         reloc_type_(reloc_type)
     {
+      typename This::Shdr_write shdr(this->shdr_data_);
       memcpy(this->shdr_data_, pshdr, shdr_size);
+      shdr.put_sh_type(sh_type);
     }
-    unsigned int shndx_;
     std::string name_;
+    unsigned int shndx_;
     unsigned int reloc_shndx_;
     unsigned int reloc_type_;
     unsigned char shdr_data_[shdr_size];
@@ -2704,6 +2874,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
 
   // General access to the ELF file.
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
+  // The EI_OSABI.
+  const Osabi osabi_;
   // 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_;
@@ -2732,16 +2904,15 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   Kept_comdat_section_table kept_comdat_sections_;
   // Whether this object has a GNU style .eh_frame section.
   bool has_eh_frame_;
-  // If this object has a GNU style .eh_frame section that is discarded in
-  // output, record the index here.  Otherwise it is -1U.
-  unsigned int discarded_eh_frame_shndx_;
+  // True if the layout of this object was deferred, waiting for plugin
+  // replacement files.
+  bool is_deferred_layout_;
   // The list of sections whose layout was deferred.
   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
-  // and contents.
-  Compressed_section_map* compressed_sections_;
+  // Pointer to the list of output views; valid only during do_relocate().
+  const Views* output_views_;
 };
 
 // A class to manage the list of all objects.
@@ -2836,7 +3007,7 @@ class Input_objects
   // The list of dynamic objects included in the link.
   Dynobj_list dynobj_list_;
   // SONAMEs that we have seen.
-  Unordered_set<std::string> sonames_;
+  Unordered_map<std::string, Object*> sonames_;
   // Manage cross-references if requested.
   Cref* cref_;
 };
@@ -2857,6 +3028,8 @@ struct Relocate_info
   unsigned int reloc_shndx;
   // Section header of relocation section.
   const unsigned char* reloc_shdr;
+  // Info about how relocs should be handled
+  Relocatable_relocs* rr;
   // Section index of section being relocated.
   unsigned int data_shndx;
   // Section header of data section.
@@ -2870,11 +3043,11 @@ struct Relocate_info
 
 // This is used to represent a section in an object and is used as the
 // key type for various section maps.
-typedef std::pair<Object*, unsigned int> Section_id;
+typedef std::pair<Relobj*, unsigned int> Section_id;
 
 // This is similar to Section_id but is used when the section
 // pointers are const.
-typedef std::pair<const Object*, unsigned int> Const_section_id;
+typedef std::pair<const Relobj*, unsigned int> Const_section_id;
 
 // The hash value is based on the address of an object in memory during
 // linking.  It is okay to use this for looking up sections but never use