PR 10980
authorIan Lance Taylor <ian@airs.com>
Wed, 6 Jan 2010 22:37:18 +0000 (22:37 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 6 Jan 2010 22:37:18 +0000 (22:37 +0000)
* options.cc (General_options::parse_section_start): New function.
(General_options::section_start): New function.
(General_options::General_options): Initialize all members.
* options.h: Include <map>
(class General_options): Add --section-start.  Add section_starts_
member.
* layout.cc (Layout::attach_allocated_section_to_segment): If
--section-start was used, set the address of the segment.  Remove
local sort_sections.
(Layout::relaxation_loop_body): If the address of the load segment
has been set by --section-start, don't use it.
* output.h (Output_segment::update_flags_for_output_section): New
function.
* output.cc (Output_segment::add_output_section): Call
update_flags_for_output_section.

gold/ChangeLog
gold/layout.cc
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h

index e1c51e4..3dccb90 100644 (file)
@@ -1,3 +1,22 @@
+2010-01-06  Ian Lance Taylor  <iant@google.com>
+
+       PR 10980
+       * options.cc (General_options::parse_section_start): New function.
+       (General_options::section_start): New function.
+       (General_options::General_options): Initialize all members.
+       * options.h: Include <map>
+       (class General_options): Add --section-start.  Add section_starts_
+       member.
+       * layout.cc (Layout::attach_allocated_section_to_segment): If
+       --section-start was used, set the address of the segment.  Remove
+       local sort_sections.
+       (Layout::relaxation_loop_body): If the address of the load segment
+       has been set by --section-start, don't use it.
+       * output.h (Output_segment::update_flags_for_output_section): New
+       function.
+       * output.cc (Output_segment::add_output_section): Call
+       update_flags_for_output_section.
+
 2010-01-05  Ian Lance Taylor  <iant@google.com>
 
        PR 10980
index c633d7b..13c7f7e 100644 (file)
@@ -1025,7 +1025,9 @@ Layout::attach_allocated_section_to_segment(Output_section* os)
 
   elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
 
-  bool sort_sections = !this->script_options_->saw_sections_clause();
+  // Check for --section-start.
+  uint64_t addr;
+  bool is_address_set = parameters->options().section_start(os->name(), &addr);
 
   // In general the only thing we really care about for PT_LOAD
   // segments is whether or not they are writable, so that is how we
@@ -1054,7 +1056,18 @@ Layout::attach_allocated_section_to_segment(Output_section* os)
       if (os->is_large_data_section() && !(*p)->is_large_data_segment())
        continue;
 
-      (*p)->add_output_section(os, seg_flags, sort_sections);
+      if (is_address_set)
+       {
+         if ((*p)->are_addresses_set())
+           continue;
+
+         (*p)->add_initial_output_data(os);
+         (*p)->update_flags_for_output_section(seg_flags);
+         (*p)->set_addresses(addr, addr);
+         break;
+       }
+
+      (*p)->add_output_section(os, seg_flags, true);
       break;
     }
 
@@ -1064,7 +1077,9 @@ Layout::attach_allocated_section_to_segment(Output_section* os)
                                                        seg_flags);
       if (os->is_large_data_section())
        oseg->set_is_large_data_segment();
-      oseg->add_output_section(os, seg_flags, sort_sections);
+      oseg->add_output_section(os, seg_flags, true);
+      if (is_address_set)
+       oseg->set_addresses(addr, addr);
     }
 
   // If we see a loadable SHT_NOTE section, we create a PT_NOTE
@@ -1492,6 +1507,14 @@ Layout::relaxation_loop_body(
              || load_seg != NULL
              || this->script_options_->saw_sections_clause());
 
+  // If the address of the load segment we found has been set by
+  // --section-start rather than by a script, then we don't want to
+  // use it for the file and segment headers.
+  if (load_seg != NULL
+      && load_seg->are_addresses_set()
+      && !this->script_options_->saw_sections_clause())
+    load_seg = NULL;
+
   // Lay out the segment headers.
   if (!parameters->options().relocatable())
     {
index 671f3d5..6c0fa04 100644 (file)
@@ -398,6 +398,63 @@ General_options::parse_just_symbols(const char*, const char* arg,
   cmdline->inputs().add_file(file);
 }
 
+// Handle --section-start.
+
+void
+General_options::parse_section_start(const char*, const char* arg,
+                                    Command_line*)
+{
+  const char* eq = strchr(arg, '=');
+  if (eq == NULL)
+    {
+      gold_error(_("invalid argument to --section-start; "
+                  "must be SECTION=ADDRESS"));
+      return;
+    }
+
+  std::string section_name(arg, eq - arg);
+
+  ++eq;
+  const char* val_start = eq;
+  if (eq[0] == '0' && (eq[1] == 'x' || eq[1] == 'X'))
+    eq += 2;
+  if (*eq == '\0')
+    {
+      gold_error(_("--section-start address missing"));
+      return;
+    }
+  uint64_t addr = 0;
+  hex_init();
+  for (; *eq != '\0'; ++eq)
+    {
+      if (!hex_p(*eq))
+       {
+         gold_error(_("--section-start argument %s is not a valid hex number"),
+                    val_start);
+         return;
+       }
+      addr <<= 4;
+      addr += hex_value(*eq);
+    }
+
+  this->section_starts_[section_name] = addr;
+}
+
+// Look up a --section-start value.
+
+bool
+General_options::section_start(const char* secname, uint64_t* paddr) const
+{
+  if (this->section_starts_.empty())
+    return false;
+  std::map<std::string, uint64_t>::const_iterator p =
+    this->section_starts_.find(secname);
+  if (p == this->section_starts_.end())
+    return false;
+  *paddr = p->second;
+  return true;
+}
+
 void
 General_options::parse_static(const char*, const char*, Command_line*)
 {
@@ -749,9 +806,17 @@ namespace gold
 
 General_options::General_options()
   : printed_version_(false),
-    execstack_status_(General_options::EXECSTACK_FROM_INPUT), static_(false),
-    do_demangle_(false), plugins_(),
-    incremental_disposition_(INCREMENTAL_CHECK), implicit_incremental_(false)
+    execstack_status_(EXECSTACK_FROM_INPUT),
+    icf_status_(ICF_NONE),
+    static_(false),
+    do_demangle_(false),
+    plugins_(NULL),
+    dynamic_list_(),
+    incremental_disposition_(INCREMENTAL_CHECK),
+    implicit_incremental_(false),
+    excluded_libs_(),
+    symbols_to_retain_(),
+    section_starts_()
 {
   // Turn off option registration once construction is complete.
   gold::options::ready_to_register = false;
index 817cac7..7e9c9f9 100644 (file)
@@ -39,6 +39,7 @@
 #include <cstdlib>
 #include <cstring>
 #include <list>
+#include <map>
 #include <string>
 #include <vector>
 
@@ -845,6 +846,9 @@ class General_options
                  N_("Add DIR to link time shared library search path"),
                  N_("DIR"));
 
+  DEFINE_special(section_start, options::TWO_DASHES, '\0',
+                N_("Set address of section"), N_("SECTION=ADDRESS"));
+
   DEFINE_optional_string(sort_common, options::TWO_DASHES, '\0', NULL,
                         N_("Sort common symbols by alignment"),
                         N_("[={ascending,descending}]"));
@@ -1174,6 +1178,12 @@ class General_options
   bool
   check_excluded_libs (const std::string &s) const;
 
+  // If an explicit start address was given for section SECNAME with
+  // the --section-start option, return true and set *PADDR to the
+  // address.  Otherwise return false.
+  bool
+  section_start(const char* secname, uint64_t* paddr) const;
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
@@ -1261,6 +1271,8 @@ class General_options
   Unordered_set<std::string> excluded_libs_;
   // List of symbol-names to keep, via -retain-symbol-info.
   Unordered_set<std::string> symbols_to_retain_;
+  // Map from section name to address from --section-start.
+  std::map<std::string, uint64_t> section_starts_;
 };
 
 // The position-dependent options.  We use this to store the state of
index 8f1060e..63ab98c 100644 (file)
@@ -3081,11 +3081,7 @@ Output_segment::add_output_section(Output_section* os,
   gold_assert(os->is_large_data_section() == this->is_large_data_segment());
   gold_assert(this->type() == elfcpp::PT_LOAD || !do_sort);
 
-  // Update the segment flags.  The ELF ABI specifies that a PT_TLS
-  // segment should always have PF_R as the flags, regardless of the
-  // associated sections.
-  if (this->type() != elfcpp::PT_TLS)
-    this->flags_ |= seg_flags;
+  this->update_flags_for_output_section(seg_flags);
 
   Output_segment::Output_data_list* pdl;
   if (os->type() == elfcpp::SHT_NOBITS)
@@ -3363,8 +3359,8 @@ Output_segment::remove_output_section(Output_section* os)
   gold_unreachable();
 }
 
-// Add an Output_data (which is not an Output_section) to the start of
-// a segment.
+// Add an Output_data (which need not be an Output_section) to the
+// start of a segment.
 
 void
 Output_segment::add_initial_output_data(Output_data* od)
index 7ce3202..98132e9 100644 (file)
@@ -3483,8 +3483,8 @@ class Output_segment
   void
   remove_output_section(Output_section* os);
 
-  // Add an Output_data (which is not an Output_section) to the start
-  // of this segment.
+  // Add an Output_data (which need not be an Output_section) to the
+  // start of this segment.
   void
   add_initial_output_data(Output_data*);
 
@@ -3516,6 +3516,17 @@ class Output_segment
     this->are_addresses_set_ = true;
   }
 
+  // Update the flags for the flags of an output section added to this
+  // segment.
+  void
+  update_flags_for_output_section(elfcpp::Elf_Xword flags)
+  {
+    // The ELF ABI specifies that a PT_TLS segment should always have
+    // PF_R as the flags.
+    if (this->type() != elfcpp::PT_TLS)
+      this->flags_ |= flags;
+  }
+
   // Set the segment flags.  This is only used if we have a PHDRS
   // clause which explicitly specifies the flags.
   void