coffcode.h handle_COMDAT tidy
[binutils-gdb.git] / gold / object.h
index 84fe5a64e0a9339611beadee316835167d37e92a..e7472893ca614daa5f4cd0e509ee060293874a57 100644 (file)
@@ -1,6 +1,6 @@
 // object.h -- support for an object file for linking in gold  -*- C++ -*-
 
-// Copyright (C) 2006-2017 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,6 +39,7 @@ class General_options;
 class Task;
 class Cref;
 class Layout;
+class Kept_section;
 class Output_data;
 class Output_section;
 class Output_section_data;
@@ -213,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()
@@ -235,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;
       }
@@ -265,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;
@@ -296,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.
@@ -306,12 +311,13 @@ 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_;
 };
 
@@ -321,15 +327,15 @@ class Got_offset_list
 class Local_got_entry_key
 {
  public:
-  Local_got_entry_key(unsigned int symndx, uint64_t addend)
-    : symndx_(symndx), addend_(addend)
+  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_ && this->addend_ == key.addend_);
+    return this->symndx_ == key.symndx_;
   }
 
   // Compute a hash value for this using 64-bit FNV-1a hash.
@@ -339,7 +345,6 @@ class Local_got_entry_key
     uint64_t h = 14695981039346656037ULL; // FNV offset basis.
     uint64_t prime = 1099511628211ULL;
     h = (h ^ static_cast<uint64_t>(this->symndx_)) * prime;
-    h = (h ^ static_cast<uint64_t>(this->addend_)) * prime;
     return h;
   }
 
@@ -362,8 +367,6 @@ class Local_got_entry_key
  private:
   // The local symbol index.
   unsigned int symndx_;
-  // The addend.
-  uint64_t addend_;
 };
 
 // Type for mapping section index to uncompressed size and contents.
@@ -372,6 +375,7 @@ 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;
@@ -382,6 +386,47 @@ 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).
@@ -807,7 +852,8 @@ class Object
 
   bool
   section_is_compressed(unsigned int shndx,
-                       section_size_type* uncompressed_size) const
+                       section_size_type* uncompressed_size,
+                       elfcpp::Elf_Xword* palign = NULL) const
   {
     if (this->compressed_sections_ == NULL)
       return false;
@@ -817,6 +863,8 @@ class Object
       {
        if (uncompressed_size != NULL)
          *uncompressed_size = p->second.size;
+       if (palign != NULL)
+         *palign = p->second.addralign;
        return true;
       }
     return false;
@@ -827,7 +875,7 @@ class Object
   // by the caller.
   const unsigned char*
   decompressed_section_contents(unsigned int shndx, section_size_type* plen,
-                               bool* 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.
@@ -1168,46 +1216,27 @@ 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.
-  bool
-  local_has_got_offset(unsigned int symndx, unsigned int got_type) const
-  { return this->do_local_has_got_offset(symndx, got_type, 0); }
-
-  // Return whether the local symbol SYMNDX plus ADDEND 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,
-                      uint64_t addend) const
+                      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.
-  unsigned int
-  local_got_offset(unsigned int symndx, unsigned int got_type) const
-  { return this->do_local_got_offset(symndx, got_type, 0); }
-
-  // Return the GOT offset of type GOT_TYPE of the local symbol
-  // SYMNDX plus ADDEND.  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,
-                      uint64_t addend) const
+                  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, 0); }
-
-  // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX
-  // plus ADDEND to GOT_OFFSET.
-  void
-  set_local_got_offset(unsigned int symndx, unsigned int got_type,
-                      unsigned int got_offset, uint64_t addend)
+                      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.
@@ -2084,11 +2113,11 @@ class Sized_relobj : public Relobj
   do_local_has_got_offset(unsigned int symndx, unsigned int got_type,
                          uint64_t addend) const
   {
-    Local_got_entry_key key(symndx, addend);
+    Local_got_entry_key key(symndx);
     Local_got_offsets::const_iterator p =
         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
@@ -2097,11 +2126,11 @@ class Sized_relobj : public Relobj
   do_local_got_offset(unsigned int symndx, unsigned int got_type,
                          uint64_t addend) const
   {
-    Local_got_entry_key key(symndx, addend);
+    Local_got_entry_key key(symndx);
     Local_got_offsets::const_iterator p =
         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;
   }
@@ -2112,14 +2141,14 @@ class Sized_relobj : public Relobj
   do_set_local_got_offset(unsigned int symndx, unsigned int got_type,
                          unsigned int got_offset, uint64_t addend)
   {
-    Local_got_entry_key key(symndx, addend);
+    Local_got_entry_key key(symndx);
     Local_got_offsets::const_iterator p =
         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(key, g));
         gold_assert(ins.second);
@@ -2200,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
@@ -2304,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.
@@ -2562,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
@@ -2584,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;
@@ -2628,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
@@ -2640,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
@@ -2739,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;
   }
 
@@ -2791,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];
@@ -2807,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_;
@@ -2835,9 +2904,6 @@ 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_;