]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gold/layout.cc
Allow reference form for DW_AT_associated and DW_AT_allocated attributes
[thirdparty/binutils-gdb.git] / gold / layout.cc
index 9ce38c3ddef21642a2bec0baf0c86b447521b726..13e533aaf21393ac1717beab1aaeb73dc18f666f 100644 (file)
@@ -1,6 +1,6 @@
 // layout.cc -- lay out output file sections for gold
 
-// Copyright (C) 2006-2018 Free Software Foundation, Inc.
+// Copyright (C) 2006-2020 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -466,6 +466,7 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
     unique_segment_for_sections_specified_(false),
     incremental_inputs_(NULL),
     record_output_section_data_from_script_(false),
+    lto_slim_object_(false),
     script_output_section_data_list_(),
     segment_states_(NULL),
     relaxation_debug_check_(NULL),
@@ -1128,7 +1129,8 @@ Layout::special_ordering_of_input_section(const char* name)
     ".text.unlikely",
     ".text.exit",
     ".text.startup",
-    ".text.hot"
+    ".text.hot",
+    ".text.sorted"
   };
 
   for (size_t i = 0;
@@ -1181,11 +1183,11 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
       // All ".text.unlikely.*" sections can be moved to a unique
       // segment with --text-unlikely-segment option.
       bool text_unlikely_segment
-          = (parameters->options().text_unlikely_segment()
-             && is_prefix_of(".text.unlikely",
-                             object->section_name(shndx).c_str()));
+         = (parameters->options().text_unlikely_segment()
+            && is_prefix_of(".text.unlikely",
+                            object->section_name(shndx).c_str()));
       if (text_unlikely_segment)
-        {
+       {
          elfcpp::Elf_Xword flags
            = this->get_output_section_flags(shdr.get_sh_flags());
 
@@ -1194,11 +1196,11 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
                                                    &name_key);
          os = this->get_output_section(os_name, name_key, sh_type, flags,
                                        ORDER_INVALID, false);
-          // Map this output section to a unique segment.  This is done to
-          // separate "text" that is not likely to be executed from "text"
-          // that is likely executed.
+         // Map this output section to a unique segment.  This is done to
+         // separate "text" that is not likely to be executed from "text"
+         // that is likely executed.
          os->set_is_unique_segment();
-        }
+       }
       else
        {
          // Plugins can choose to place one or more subsets of sections in
@@ -1219,7 +1221,7 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
              // We know the name of the output section, directly call
              // get_output_section here by-passing choose_output_section.
              elfcpp::Elf_Xword flags
-               = this->get_output_section_flags(shdr.get_sh_flags());
+               = this->get_output_section_flags(shdr.get_sh_flags());
 
              const char* os_name = it->second->name;
              Stringpool::Key name_key;
@@ -1227,11 +1229,11 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
              os = this->get_output_section(os_name, name_key, sh_type, flags,
                                        ORDER_INVALID, false);
              if (!os->is_unique_segment())
-               {
-                 os->set_is_unique_segment();
-                 os->set_extra_segment_flags(it->second->flags);
-                 os->set_segment_alignment(it->second->align);
-               }
+               {
+                 os->set_is_unique_segment();
+                 os->set_extra_segment_flags(it->second->flags);
+                 os->set_segment_alignment(it->second->align);
+               }
            }
          }
       if (os == NULL)
@@ -1604,21 +1606,18 @@ Layout::add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
     }
 }
 
-// Remove .eh_frame information for a PLT.  FDEs using the CIE must
-// be removed in reverse order to the order they were added.
+// Remove all post-map .eh_frame information for a PLT.
 
 void
 Layout::remove_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
-                               size_t cie_length, const unsigned char* fde_data,
-                               size_t fde_length)
+                               size_t cie_length)
 {
   if (parameters->incremental())
     {
       // FIXME: Maybe this could work some day....
       return;
     }
-  this->eh_frame_data_->remove_ehframe_for_plt(plt, cie_data, cie_length,
-                                              fde_data, fde_length);
+  this->eh_frame_data_->remove_ehframe_for_plt(plt, cie_data, cie_length);
 }
 
 // Scan a .debug_info or .debug_types section, and add summary
@@ -2217,7 +2216,7 @@ read_sized_value(size_t size, const unsigned char* buf, bool is_big_endian,
     }
   else
     {
-      gold_warning(_("%s: in .note.gnu.properties section, "
+      gold_warning(_("%s: in .note.gnu.property section, "
                     "pr_datasz must be 4 or 8"),
                   object->name().c_str());
     }
@@ -2262,6 +2261,63 @@ Layout::layout_gnu_property(unsigned int note_type,
   // We currently support only the one note type.
   gold_assert(note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0);
 
+  if (pr_type >= elfcpp::GNU_PROPERTY_LOPROC
+      && pr_type < elfcpp::GNU_PROPERTY_HIPROC)
+    {
+      // Target-dependent property value; call the target to record.
+      const int size = parameters->target().get_size();
+      const bool is_big_endian = parameters->target().is_big_endian();
+      if (size == 32)
+       {
+         if (is_big_endian)
+           {
+#ifdef HAVE_TARGET_32_BIG
+             parameters->sized_target<32, true>()->
+                 record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
+                                     object);
+#else
+             gold_unreachable();
+#endif
+           }
+         else
+           {
+#ifdef HAVE_TARGET_32_LITTLE
+             parameters->sized_target<32, false>()->
+                 record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
+                                     object);
+#else
+             gold_unreachable();
+#endif
+           }
+       }
+      else if (size == 64)
+       {
+         if (is_big_endian)
+           {
+#ifdef HAVE_TARGET_64_BIG
+             parameters->sized_target<64, true>()->
+                 record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
+                                     object);
+#else
+             gold_unreachable();
+#endif
+           }
+         else
+           {
+#ifdef HAVE_TARGET_64_LITTLE
+             parameters->sized_target<64, false>()->
+                 record_gnu_property(note_type, pr_type, pr_datasz, pr_data,
+                                     object);
+#else
+             gold_unreachable();
+#endif
+           }
+       }
+      else
+       gold_unreachable();
+      return;
+    }
+
   Gnu_properties::iterator pprop = this->gnu_properties_.find(pr_type);
   if (pprop == this->gnu_properties_.end())
     {
@@ -2273,46 +2329,99 @@ Layout::layout_gnu_property(unsigned int note_type,
     }
   else
     {
-      if (pr_type >= elfcpp::GNU_PROPERTY_LOPROC
-         && pr_type < elfcpp::GNU_PROPERTY_HIPROC)
+      const bool is_big_endian = parameters->target().is_big_endian();
+      switch (pr_type)
        {
-         // Target-dependent property value; call the target to merge.
-         parameters->target().merge_gnu_property(note_type,
-                                                 pr_type,
-                                                 pr_datasz,
-                                                 pr_data,
-                                                 pprop->second.pr_datasz,
-                                                 pprop->second.pr_data,
-                                                 object);
+       case elfcpp::GNU_PROPERTY_STACK_SIZE:
+         // Record the maximum value seen.
+         {
+           uint64_t val1 = read_sized_value(pprop->second.pr_datasz,
+                                            pprop->second.pr_data,
+                                            is_big_endian, object);
+           uint64_t val2 = read_sized_value(pr_datasz, pr_data,
+                                            is_big_endian, object);
+           if (val2 > val1)
+             write_sized_value(val2, pprop->second.pr_datasz,
+                               pprop->second.pr_data, is_big_endian);
+         }
+         break;
+       case elfcpp::GNU_PROPERTY_NO_COPY_ON_PROTECTED:
+         // No data to merge.
+         break;
+       default:
+         gold_warning(_("%s: unknown program property type %d "
+                        "in .note.gnu.property section"),
+                      object->name().c_str(), pr_type);
+       }
+    }
+}
+
+// Merge per-object properties with program properties.
+// This lets the target identify objects that are missing certain
+// properties, in cases where properties must be ANDed together.
+
+void
+Layout::merge_gnu_properties(const Object* object)
+{
+  const int size = parameters->target().get_size();
+  const bool is_big_endian = parameters->target().is_big_endian();
+  if (size == 32)
+    {
+      if (is_big_endian)
+       {
+#ifdef HAVE_TARGET_32_BIG
+         parameters->sized_target<32, true>()->merge_gnu_properties(object);
+#else
+         gold_unreachable();
+#endif
        }
       else
        {
-         const bool is_big_endian = parameters->target().is_big_endian();
-         switch (pr_type)
-           {
-           case elfcpp::GNU_PROPERTY_STACK_SIZE:
-             // Record the maximum value seen.
-             {
-               uint64_t val1 = read_sized_value(pprop->second.pr_datasz,
-                                                pprop->second.pr_data,
-                                                is_big_endian, object);
-               uint64_t val2 = read_sized_value(pr_datasz, pr_data,
-                                                is_big_endian, object);
-               if (val2 > val1)
-                 write_sized_value(val2, pprop->second.pr_datasz,
-                                   pprop->second.pr_data, is_big_endian);
-             }
-             break;
-           case elfcpp::GNU_PROPERTY_NO_COPY_ON_PROTECTED:
-             // No data to merge.
-             break;
-           default:
-             gold_warning(_("%s: unknown program property type %d "
-                            "in .note.gnu.properties section"),
-                          object->name().c_str(), pr_type);
-           }
+#ifdef HAVE_TARGET_32_LITTLE
+         parameters->sized_target<32, false>()->merge_gnu_properties(object);
+#else
+         gold_unreachable();
+#endif
        }
     }
+  else if (size == 64)
+    {
+      if (is_big_endian)
+       {
+#ifdef HAVE_TARGET_64_BIG
+         parameters->sized_target<64, true>()->merge_gnu_properties(object);
+#else
+         gold_unreachable();
+#endif
+       }
+      else
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         parameters->sized_target<64, false>()->merge_gnu_properties(object);
+#else
+         gold_unreachable();
+#endif
+       }
+    }
+  else
+    gold_unreachable();
+}
+
+// Add a target-specific property for the output .note.gnu.property section.
+
+void
+Layout::add_gnu_property(unsigned int note_type,
+                        unsigned int pr_type,
+                        size_t pr_datasz,
+                        const unsigned char* pr_data)
+{
+  gold_assert(note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0);
+
+  Gnu_property prop;
+  prop.pr_datasz = pr_datasz;
+  prop.pr_data = new unsigned char[pr_datasz];
+  memcpy(prop.pr_data, pr_data, pr_datasz);
+  this->gnu_properties_[pr_type] = prop;
 }
 
 // Create automatic note sections.
@@ -2365,6 +2474,7 @@ Layout::create_initial_dynamic_sections(Symbol_table* symtab)
 void
 Layout::define_section_symbols(Symbol_table* symtab)
 {
+  const elfcpp::STV visibility = parameters->options().start_stop_visibility_enum();
   for (Section_list::const_iterator p = this->section_list_.begin();
        p != this->section_list_.end();
        ++p)
@@ -2386,7 +2496,7 @@ Layout::define_section_symbols(Symbol_table* symtab)
                                        0, // symsize
                                        elfcpp::STT_NOTYPE,
                                        elfcpp::STB_GLOBAL,
-                                       elfcpp::STV_PROTECTED,
+                                       visibility,
                                        0, // nonvis
                                        false, // offset_is_from_end
                                        true); // only_if_ref
@@ -2399,7 +2509,7 @@ Layout::define_section_symbols(Symbol_table* symtab)
                                        0, // symsize
                                        elfcpp::STT_NOTYPE,
                                        elfcpp::STB_GLOBAL,
-                                       elfcpp::STV_PROTECTED,
+                                       visibility,
                                        0, // nonvis
                                        true, // offset_is_from_end
                                        true); // only_if_ref
@@ -2812,6 +2922,8 @@ Layout::read_layout_from_file()
     gold_fatal(_("unable to open --section-ordering-file file %s: %s"),
               filename, strerror(errno));
 
+  File_read::record_file_read(filename);
+
   std::getline(in, line);   // this chops off the trailing \n, if any
   unsigned int position = 1;
   this->set_section_ordering_specified();
@@ -3144,12 +3256,14 @@ Layout::create_note(const char* name, int note_type,
   return os;
 }
 
-// Create a .note.gnu.properties section to record program properties
+// Create a .note.gnu.property section to record program properties
 // accumulated from the input files.
 
 void
 Layout::create_gnu_properties_note()
 {
+  parameters->target().finalize_gnu_properties(this);
+
   if (this->gnu_properties_.empty())
     return;
 
@@ -3168,7 +3282,7 @@ Layout::create_gnu_properties_note()
   // Create the note section.
   size_t trailing_padding;
   Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_PROPERTY_TYPE_0,
-                                        ".note.gnu.properties", descsz,
+                                        ".note.gnu.property", descsz,
                                         true, &trailing_padding);
   if (os == NULL)
     return;
@@ -3187,7 +3301,7 @@ Layout::create_gnu_properties_note()
       write_sized_value(datasz, 4, p + 4, is_big_endian);
       memcpy(p + 8, prop->second.pr_data, datasz);
       if (aligned_datasz > datasz)
-        memset(p + 8 + datasz, 0, aligned_datasz - datasz);
+       memset(p + 8 + datasz, 0, aligned_datasz - datasz);
       p += 8 + aligned_datasz;
     }
   Output_section_data* posd = new Output_data_const(desc, descsz, 4);
@@ -5240,6 +5354,8 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
     flags |= elfcpp::DF_1_NOW;
   if (parameters->options().Bgroup())
     flags |= elfcpp::DF_1_GROUP;
+  if (parameters->options().pie())
+    flags |= elfcpp::DF_1_PIE;
   if (flags != 0)
     odyn->add_constant(elfcpp::DT_FLAGS_1, flags);
 }
@@ -5317,6 +5433,7 @@ const Layout::Section_name_mapping Layout::section_name_mapping[] =
   MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
   MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
   MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
+  MAPPING_INIT(".gnu.build.attributes.", ".gnu.build.attributes"),
 };
 
 // Mapping for ".text" section prefixes with -z,keep-text-section-prefix.
@@ -6041,6 +6158,10 @@ Close_task_runner::run(Workqueue*, const Task*)
   if (this->options_->oformat_enum() != General_options::OBJECT_FORMAT_ELF)
     this->layout_->write_binary(this->of_);
 
+  if (this->options_->dependency_file())
+    File_read::write_dependency_file(this->options_->dependency_file(),
+                                    this->options_->output_file_name());
+
   this->of_->close();
 }