PR 6048
[binutils-gdb.git] / gold / script-sections.cc
index 39aa9bd03dbaea66c5ef62fc16d522831add8058..13c97710d29d8a187ad6b92493a931985b8531c4 100644 (file)
@@ -105,13 +105,27 @@ class Sections_element
 
   // Get the list of segments to use for an allocated section when
   // using a PHDRS clause.  If this is an allocated section, return
-  // the Output_section, and set *PHDRS_LIST to the list of PHDRS to
-  // which it should be attached.  If the PHDRS were not specified,
-  // don't change *PHDRS_LIST.
+  // the Output_section, and set *PHDRS_LIST (the first parameter) to
+  // the list of PHDRS to which it should be attached.  If the PHDRS
+  // were not specified, don't change *PHDRS_LIST.  When not returning
+  // NULL, set *ORPHAN (the second parameter) according to whether
+  // this is an orphan section--one that is not mentioned in the
+  // linker script.
   virtual Output_section*
-  allocate_to_segment(String_list**)
+  allocate_to_segment(String_list**, bool*)
   { return NULL; }
 
+  // Look for an output section by name and return the address, the
+  // load address, the alignment, and the size.  This is used when an
+  // expression refers to an output section which was not actually
+  // created.  This returns true if the section was found, false
+  // otherwise.  The only real definition is for
+  // Output_section_definition.
+  virtual bool
+  get_output_section_info(const char*, uint64_t*, uint64_t*, uint64_t*,
+                          uint64_t*) const
+  { return false; }
+
   // Print the element for debugging purposes.
   virtual void
   print(FILE* f) const = 0;
@@ -412,7 +426,7 @@ Output_section_element_dot_assignment::set_section_addresses(
                                                              - *dot_value);
       Output_section_data* posd;
       if (fill->empty())
-       posd = new Output_data_fixed_space(length, 0);
+       posd = new Output_data_zero_fill(length, 0);
       else
        {
          std::string this_fill = this->get_fill_string(fill, length);
@@ -468,6 +482,11 @@ class Output_data_expression : public Output_section_data
   void
   do_write_to_buffer(unsigned char*);
 
+  // Write to a map file.
+  void
+  do_print_to_mapfile(Mapfile* mapfile) const
+  { mapfile->print_output_data(this, _("** expression")); }
+
  private:
   template<bool big_endian>
   void
@@ -1252,12 +1271,18 @@ class Output_section_definition : public Sections_element
   alternate_constraint(Output_section_definition*, Section_constraint);
 
   // Get the list of segments to use for an allocated section when
-  // using a PHDRS clause.  If this is an allocated section, return
-  // the Output_section, and set *PHDRS_LIST to the list of PHDRS to
-  // which it should be attached.  If the PHDRS were not specified,
-  // don't change *PHDRS_LIST.
+  // using a PHDRS clause.
   Output_section*
-  allocate_to_segment(String_list** phdrs_list);
+  allocate_to_segment(String_list** phdrs_list, bool* orphan);
+
+  // Look for an output section by name and return the address, the
+  // load address, the alignment, and the size.  This is used when an
+  // expression refers to an output section which was not actually
+  // created.  This returns true if the section was found, false
+  // otherwise.
+  bool
+  get_output_section_info(const char*, uint64_t*, uint64_t*, uint64_t*,
+                          uint64_t*) const;
 
   // Print the contents to the FILE.  This is for debugging.
   void
@@ -1288,6 +1313,12 @@ class Output_section_definition : public Sections_element
   // The Output_section created for this definition.  This will be
   // NULL if none was created.
   Output_section* output_section_;
+  // The address after it has been evaluated.
+  uint64_t evaluated_address_;
+  // The load address after it has been evaluated.
+  uint64_t evaluated_load_address_;
+  // The alignment after it has been evaluated.
+  uint64_t evaluated_addralign_;
 };
 
 // Constructor.
@@ -1648,13 +1679,20 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
       && (this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0)
     this->output_section_->set_address(address);
 
-  if (this->load_address_ != NULL && this->output_section_ != NULL)
+  this->evaluated_address_ = address;
+  this->evaluated_addralign_ = align;
+
+  if (this->load_address_ == NULL)
+    this->evaluated_load_address_ = address;
+  else
     {
       Output_section* dummy;
       uint64_t load_address =
        this->load_address_->eval_with_dot(symtab, layout, true, *dot_value,
                                           this->output_section_, &dummy);
-      this->output_section_->set_load_address(load_address);
+      if (this->output_section_ != NULL)
+        this->output_section_->set_load_address(load_address);
+      this->evaluated_load_address_ = load_address;
     }
 
   uint64_t subalign;
@@ -1801,23 +1839,59 @@ Output_section_definition::alternate_constraint(
 }
 
 // Get the list of segments to use for an allocated section when using
-// a PHDRS clause.  If this is an allocated section, return the
-// Output_section, and set *PHDRS_LIST to the list of PHDRS to which
-// it should be attached.  If the PHDRS were not specified, don't
-// change *PHDRS_LIST.
+// a PHDRS clause.
 
 Output_section*
-Output_section_definition::allocate_to_segment(String_list** phdrs_list)
+Output_section_definition::allocate_to_segment(String_list** phdrs_list,
+                                              bool* orphan)
 {
   if (this->output_section_ == NULL)
     return NULL;
   if ((this->output_section_->flags() & elfcpp::SHF_ALLOC) == 0)
     return NULL;
+  *orphan = false;
   if (this->phdrs_ != NULL)
     *phdrs_list = this->phdrs_;
   return this->output_section_;
 }
 
+// Look for an output section by name and return the address, the load
+// address, the alignment, and the size.  This is used when an
+// expression refers to an output section which was not actually
+// created.  This returns true if the section was found, false
+// otherwise.
+
+bool
+Output_section_definition::get_output_section_info(const char* name,
+                                                   uint64_t* address,
+                                                   uint64_t* load_address,
+                                                   uint64_t* addralign,
+                                                   uint64_t* size) const
+{
+  if (this->name_ != name)
+    return false;
+
+  if (this->output_section_ != NULL)
+    {
+      *address = this->output_section_->address();
+      if (this->output_section_->has_load_address())
+        *load_address = this->output_section_->load_address();
+      else
+        *load_address = *address;
+      *addralign = this->output_section_->addralign();
+      *size = this->output_section_->current_data_size();
+    }
+  else
+    {
+      *address = this->evaluated_address_;
+      *load_address = this->evaluated_load_address_;
+      *addralign = this->evaluated_addralign_;
+      *size = 0;
+    }
+
+  return true;
+}
+
 // Print for debugging.
 
 void
@@ -1901,10 +1975,9 @@ class Orphan_output_section : public Sections_element
   set_section_addresses(Symbol_table*, Layout*, uint64_t*, uint64_t*);
 
   // Get the list of segments to use for an allocated section when
-  // using a PHDRS clause.  If this is an allocated section, return
-  // the Output_section.
+  // using a PHDRS clause.
   Output_section*
-  allocate_to_segment(String_list**);
+  allocate_to_segment(String_list**, bool*);
 
   // Print for debugging.
   void
@@ -1993,10 +2066,11 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
 // Output_section.  We don't change the list of segments.
 
 Output_section*
-Orphan_output_section::allocate_to_segment(String_list**)
+Orphan_output_section::allocate_to_segment(String_list**, bool* orphan)
 {
   if ((this->os_->flags() & elfcpp::SHF_ALLOC) == 0)
     return NULL;
+  *orphan = true;
   return this->os_;
 }
 
@@ -2349,7 +2423,7 @@ Script_sections::place_orphan(Output_section* os)
        p != this->sections_elements_->end();
        ++p)
     {
-      bool exact;
+      bool exact = false;
       if ((*p)->place_orphan_here(os, &exact))
        {
          place = p;
@@ -2583,7 +2657,8 @@ Script_sections::create_segments(Layout* layout)
          need_new_segment = true;
        }
       else if (is_current_seg_readonly
-              && ((*p)->flags() & elfcpp::SHF_WRITE) != 0)
+              && ((*p)->flags() & elfcpp::SHF_WRITE) != 0
+              && !parameters->options().omagic())
        {
          // Don't put a writable section in the same segment as a
          // non-writable section.
@@ -2637,18 +2712,17 @@ Script_sections::create_segments(Layout* layout)
 
   size_t sizeof_headers = this->total_header_size(layout);
 
-  if ((first_seg->paddr() & (abi_pagesize - 1)) >= sizeof_headers)
-    {
-      first_seg->set_addresses(first_seg->vaddr() - sizeof_headers,
-                              first_seg->paddr() - sizeof_headers);
-      return first_seg;
-    }
-
   uint64_t vma = first_seg->vaddr();
   uint64_t lma = first_seg->paddr();
 
   uint64_t subtract = this->header_size_adjustment(lma, sizeof_headers);
 
+  if ((lma & (abi_pagesize - 1)) >= sizeof_headers)
+    {
+      first_seg->set_addresses(vma - subtract, lma - subtract);
+      return first_seg;
+    }
+
   // If there is no room to squeeze in the headers, then punt.  The
   // resulting executable probably won't run on GNU/Linux, but we
   // trust that the user knows what they are doing.
@@ -2820,7 +2894,8 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
        p != this->sections_elements_->end();
        ++p)
     {
-      Output_section* os = (*p)->allocate_to_segment(&phdr_names);
+      bool orphan;
+      Output_section* os = (*p)->allocate_to_segment(&phdr_names, &orphan);
       if (os == NULL)
        continue;
 
@@ -2830,6 +2905,27 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
          continue;
        }
 
+      // If this is an orphan section--one that was not explicitly
+      // mentioned in the linker script--then it should not inherit
+      // any segment type other than PT_LOAD.  Otherwise, e.g., the
+      // PT_INTERP segment will pick up following orphan sections,
+      // which does not make sense.  If this is not an orphan section,
+      // we trust the linker script.
+      if (orphan)
+       {
+         String_list::iterator q = phdr_names->begin();
+         while (q != phdr_names->end())
+           {
+             Name_to_segment::const_iterator r = name_to_segment.find(*q);
+             // We give errors about unknown segments below.
+             if (r == name_to_segment.end()
+                 || r->second->type() == elfcpp::PT_LOAD)
+               ++q;
+             else
+               q = phdr_names->erase(q);
+           }
+       }
+
       bool in_load_segment = false;
       for (String_list::const_iterator q = phdr_names->begin();
           q != phdr_names->end();
@@ -2971,6 +3067,29 @@ Script_sections::put_headers_in_phdrs(Output_data* file_header,
     }
 }
 
+// Look for an output section by name and return the address, the load
+// address, the alignment, and the size.  This is used when an
+// expression refers to an output section which was not actually
+// created.  This returns true if the section was found, false
+// otherwise.
+
+bool
+Script_sections::get_output_section_info(const char* name, uint64_t* address,
+                                         uint64_t* load_address,
+                                         uint64_t* addralign,
+                                         uint64_t* size) const
+{
+  if (!this->saw_sections_clause_)
+    return false;
+  for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+       p != this->sections_elements_->end();
+       ++p)
+    if ((*p)->get_output_section_info(name, address, load_address, addralign,
+                                      size))
+      return true;
+  return false;
+}
+
 // Print the SECTIONS clause to F for debugging.
 
 void