PR ld/6430
[deliverable/binutils-gdb.git] / gold / layout.cc
index 8d0d5f79e01554e109ad5c4d5478b3aeba0bca6c..eae66794eb5b3d5c11ba0f503aa9f4577c211f9d 100644 (file)
@@ -90,6 +90,7 @@ Layout::Layout(const General_options& options, Script_options* script_options)
     special_output_list_(),
     section_headers_(NULL),
     tls_segment_(NULL),
+    relro_segment_(NULL),
     symtab_section_(NULL),
     symtab_xindex_(NULL),
     dynsym_section_(NULL),
@@ -503,7 +504,8 @@ Layout::layout_group(Symbol_table* symtab,
                     const char* group_section_name,
                     const char* signature,
                     const elfcpp::Shdr<size, big_endian>& shdr,
-                    const elfcpp::Elf_Word* contents)
+                    elfcpp::Elf_Word flags,
+                    std::vector<unsigned int>* shndxes)
 {
   gold_assert(parameters->options().relocatable());
   gold_assert(shdr.get_sh_type() == elfcpp::SHT_GROUP);
@@ -531,7 +533,8 @@ Layout::layout_group(Symbol_table* symtab,
   section_size_type entry_count =
     convert_to_section_size_type(shdr.get_sh_size() / 4);
   Output_section_data* posd =
-    new Output_data_group<size, big_endian>(object, entry_count, contents);
+    new Output_data_group<size, big_endian>(object, entry_count, flags,
+                                           shndxes);
   os->add_output_section_data(posd);
 }
 
@@ -635,9 +638,10 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
   return os;
 }
 
-// Add POSD to an output section using NAME, TYPE, and FLAGS.
+// Add POSD to an output section using NAME, TYPE, and FLAGS.  Return
+// the output section.
 
-void
+Output_section*
 Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
                                elfcpp::Elf_Xword flags,
                                Output_section_data* posd)
@@ -646,6 +650,7 @@ Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
                                                   false);
   if (os != NULL)
     os->add_output_section_data(posd);
+  return os;
 }
 
 // Map section flags to segment flags.
@@ -704,6 +709,23 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
          || strcmp(name, ".fini_array") == 0))
     os->set_may_sort_attached_input_sections();
 
+  // With -z relro, we have to recognize the special sections by name.
+  // There is no other way.
+  if (!this->script_options_->saw_sections_clause()
+      && parameters->options().relro()
+      && type == elfcpp::SHT_PROGBITS
+      && (flags & elfcpp::SHF_ALLOC) != 0
+      && (flags & elfcpp::SHF_WRITE) != 0)
+    {
+      if (strcmp(name, ".data.rel.ro") == 0)
+       os->set_is_relro();
+      else if (strcmp(name, ".data.rel.ro.local") == 0)
+       {
+         os->set_is_relro();
+         os->set_is_relro_local();
+       }
+    }
+
   // If we have already attached the sections to segments, then we
   // need to attach this one now.  This happens for sections created
   // directly by the linker.
@@ -829,6 +851,17 @@ Layout::attach_allocated_section_to_segment(Output_section* os)
                                                        seg_flags);
       this->tls_segment_->add_output_section(os, seg_flags);
     }
+
+  // If -z relro is in effect, and we see a relro section, we create a
+  // PT_GNU_RELRO segment.  There can only be one such segment.
+  if (os->is_relro() && parameters->options().relro())
+    {
+      gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W));
+      if (this->relro_segment_ == NULL)
+       this->relro_segment_ = this->make_output_segment(elfcpp::PT_GNU_RELRO,
+                                                        seg_flags);
+      this->relro_segment_->add_output_section(os, seg_flags);
+    }
 }
 
 // Make an output section for a script.
@@ -899,6 +932,7 @@ Layout::create_initial_dynamic_sections(Symbol_table* symtab)
                                                       (elfcpp::SHF_ALLOC
                                                        | elfcpp::SHF_WRITE),
                                                       false);
+  this->dynamic_section_->set_is_relro();
 
   symtab->define_in_output_data("_DYNAMIC", NULL, this->dynamic_section_, 0, 0,
                                elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
@@ -1506,12 +1540,25 @@ Layout::segment_precedes(const Output_segment* seg1,
   if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
     return false;
 
-  // We put the PT_TLS segment last, because that is where the dynamic
-  // linker expects to find it (this is just for efficiency; other
-  // positions would also work correctly).
-  if (type1 == elfcpp::PT_TLS && type2 != elfcpp::PT_TLS)
+  // We put the PT_TLS segment last except for the PT_GNU_RELRO
+  // segment, because that is where the dynamic linker expects to find
+  // it (this is just for efficiency; other positions would also work
+  // correctly).
+  if (type1 == elfcpp::PT_TLS
+      && type2 != elfcpp::PT_TLS
+      && type2 != elfcpp::PT_GNU_RELRO)
+    return false;
+  if (type2 == elfcpp::PT_TLS
+      && type1 != elfcpp::PT_TLS
+      && type1 != elfcpp::PT_GNU_RELRO)
+    return true;
+
+  // We put the PT_GNU_RELRO segment last, because that is where the
+  // dynamic linker expects to find it (as with PT_TLS, this is just
+  // for efficiency).
+  if (type1 == elfcpp::PT_GNU_RELRO && type2 != elfcpp::PT_GNU_RELRO)
     return false;
-  if (type2 == elfcpp::PT_TLS && type1 != elfcpp::PT_TLS)
+  if (type2 == elfcpp::PT_GNU_RELRO && type1 != elfcpp::PT_GNU_RELRO)
     return true;
 
   const elfcpp::Elf_Word flags1 = seg1->flags();
@@ -2477,7 +2524,7 @@ Layout::create_interp(const Target* target)
     {
       Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
                                                       elfcpp::PF_R);
-      oseg->add_initial_output_section(osec, elfcpp::PF_R);
+      oseg->add_output_section(osec, elfcpp::PF_R);
     }
 }
 
@@ -2492,8 +2539,8 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
       Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
                                                       (elfcpp::PF_R
                                                        | elfcpp::PF_W));
-      oseg->add_initial_output_section(this->dynamic_section_,
-                                      elfcpp::PF_R | elfcpp::PF_W);
+      oseg->add_output_section(this->dynamic_section_,
+                              elfcpp::PF_R | elfcpp::PF_W);
     }
 
   Output_data_dynamic* const odyn = this->dynamic_data_;
@@ -2632,7 +2679,8 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
 #define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
 const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
 {
-  MAPPING_INIT("d.rel.ro", ".data.rel.ro"),    // Must be before "d".
+  MAPPING_INIT("d.rel.ro.local", ".data.rel.ro.local"), // Before "d.rel.ro".
+  MAPPING_INIT("d.rel.ro", ".data.rel.ro"),            // Before "d".
   MAPPING_INIT("t", ".text"),
   MAPPING_INIT("r", ".rodata"),
   MAPPING_INIT("d", ".data"),
@@ -2734,6 +2782,9 @@ Layout::output_section_name(const char* name, size_t* plen)
   // initial '.', we use the name unchanged (i.e., "mysection" and
   // ".text" are unchanged).
 
+  // If the name starts with ".data.rel.ro.local" we use
+  // ".data.rel.ro.local".
+
   // If the name starts with ".data.rel.ro" we use ".data.rel.ro".
 
   // Otherwise, we drop the second '.' and everything that comes after
@@ -2747,6 +2798,13 @@ Layout::output_section_name(const char* name, size_t* plen)
   if (sdot == NULL)
     return name;
 
+  const char* const data_rel_ro_local = ".data.rel.ro.local";
+  if (strncmp(name, data_rel_ro_local, strlen(data_rel_ro_local)) == 0)
+    {
+      *plen = strlen(data_rel_ro_local);
+      return data_rel_ro_local;
+    }
+
   const char* const data_rel_ro = ".data.rel.ro";
   if (strncmp(name, data_rel_ro, strlen(data_rel_ro)) == 0)
     {
@@ -3258,7 +3316,8 @@ Layout::layout_group<32, false>(Symbol_table* symtab,
                                const char* group_section_name,
                                const char* signature,
                                const elfcpp::Shdr<32, false>& shdr,
-                               const elfcpp::Elf_Word* contents);
+                               elfcpp::Elf_Word flags,
+                               std::vector<unsigned int>* shndxes);
 #endif
 
 #ifdef HAVE_TARGET_32_BIG
@@ -3270,7 +3329,8 @@ Layout::layout_group<32, true>(Symbol_table* symtab,
                               const char* group_section_name,
                               const char* signature,
                               const elfcpp::Shdr<32, true>& shdr,
-                              const elfcpp::Elf_Word* contents);
+                              elfcpp::Elf_Word flags,
+                              std::vector<unsigned int>* shndxes);
 #endif
 
 #ifdef HAVE_TARGET_64_LITTLE
@@ -3282,7 +3342,8 @@ Layout::layout_group<64, false>(Symbol_table* symtab,
                                const char* group_section_name,
                                const char* signature,
                                const elfcpp::Shdr<64, false>& shdr,
-                               const elfcpp::Elf_Word* contents);
+                               elfcpp::Elf_Word flags,
+                               std::vector<unsigned int>* shndxes);
 #endif
 
 #ifdef HAVE_TARGET_64_BIG
@@ -3294,7 +3355,8 @@ Layout::layout_group<64, true>(Symbol_table* symtab,
                               const char* group_section_name,
                               const char* signature,
                               const elfcpp::Shdr<64, true>& shdr,
-                              const elfcpp::Elf_Word* contents);
+                              elfcpp::Elf_Word flags,
+                              std::vector<unsigned int>* shndxes);
 #endif
 
 #ifdef HAVE_TARGET_32_LITTLE
This page took 0.02619 seconds and 4 git commands to generate.