Implement -Tdata and -Tbss.
authorIan Lance Taylor <iant@google.com>
Wed, 13 Feb 2008 22:47:28 +0000 (22:47 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 13 Feb 2008 22:47:28 +0000 (22:47 +0000)
gold/layout.cc
gold/options.cc
gold/options.h
gold/output.h

index b28682e..265dfb2 100644 (file)
@@ -621,11 +621,10 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
 
       elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
 
-      // The only thing we really care about for PT_LOAD segments is
-      // whether or not they are writable, so that is how we search
-      // for them.  People who need segments sorted on some other
-      // basis will have to wait until we implement a mechanism for
-      // them to describe the segments they want.
+      // 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 search for them.  People who need segments sorted on some
+      // other basis will have to use a linker script.
 
       Segment_list::const_iterator p;
       for (p = this->segment_list_.begin();
@@ -635,6 +634,15 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
          if ((*p)->type() == elfcpp::PT_LOAD
              && ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
            {
+             // If -Tbss was specified, we need to separate the data
+             // and BSS segments.
+             if (this->options_.user_set_bss_segment_address())
+               {
+                 if ((type == elfcpp::SHT_NOBITS)
+                     == (*p)->has_any_data_sections())
+                   continue;
+               }
+
              (*p)->add_output_section(os, seg_flags);
              break;
            }
@@ -1264,14 +1272,18 @@ Layout::segment_precedes(const Output_segment* seg1,
     return false;
 
   // We sort PT_LOAD segments based on the flags.  Readonly segments
-  // come before writable segments.  Then executable segments come
-  // before non-executable segments.  Then the unlikely case of a
-  // non-readable segment comes before the normal case of a readable
-  // segment.  If there are multiple segments with the same type and
-  // flags, we require that the address be set, and we sort by
-  // virtual address and then physical address.
+  // come before writable segments.  Then writable segments with data
+  // come before writable segments without data.  Then executable
+  // segments come before non-executable segments.  Then the unlikely
+  // case of a non-readable segment comes before the normal case of a
+  // readable segment.  If there are multiple segments with the same
+  // type and flags, we require that the address be set, and we sort
+  // by virtual address and then physical address.
   if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W))
     return (flags1 & elfcpp::PF_W) == 0;
+  if ((flags1 & elfcpp::PF_W) != 0
+      && seg1->has_any_data_sections() != seg2->has_any_data_sections())
+    return seg1->has_any_data_sections();
   if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X))
     return (flags1 & elfcpp::PF_X) != 0;
   if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R))
@@ -1298,7 +1310,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
   // and their section's addresses and offsets.
   uint64_t addr;
   if (this->options_.user_set_text_segment_address())
-    addr = options_.text_segment_address();
+    addr = this->options_.text_segment_address();
   else if (parameters->output_is_shared())
     addr = 0;
   else
@@ -1331,6 +1343,29 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
            gold_unreachable();
          load_seg = NULL;
 
+         bool are_addresses_set = (*p)->are_addresses_set();
+         if (are_addresses_set)
+           {
+             // When it comes to setting file offsets, we care about
+             // the physical address.
+             addr = (*p)->paddr();
+           }
+         else if (this->options_.user_set_data_segment_address()
+                  && ((*p)->flags() & elfcpp::PF_W) != 0
+                  && (!this->options_.user_set_bss_segment_address()
+                      || (*p)->has_any_data_sections()))
+           {
+             addr = this->options_.data_segment_address();
+             are_addresses_set = true;
+           }
+         else if (this->options_.user_set_bss_segment_address()
+                  && ((*p)->flags() & elfcpp::PF_W) != 0
+                  && !(*p)->has_any_data_sections())
+           {
+             addr = this->options_.bss_segment_address();
+             are_addresses_set = true;
+           }
+
          uint64_t orig_addr = addr;
          uint64_t orig_off = off;
 
@@ -1340,13 +1375,8 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
          // FIXME: This should depend on the -n and -N options.
          (*p)->set_minimum_p_align(target->common_pagesize());
 
-         bool are_addresses_set = (*p)->are_addresses_set();
          if (are_addresses_set)
            {
-             // When it comes to setting file offsets, we care about
-             // the physical address.
-             addr = (*p)->paddr();
-
              // Adjust the file offset to the same address modulo the
              // page size.
              uint64_t unsigned_off = off;
index db655a2..4d8f0b9 100644 (file)
@@ -541,10 +541,17 @@ options::Command_line_options::options[] =
                NULL, TWO_DASHES, &General_options::set_stats),
   GENERAL_ARG('\0', "sysroot", N_("Set target system root directory"),
              N_("--sysroot DIR"), TWO_DASHES, &General_options::set_sysroot),
-  GENERAL_ARG('\0', "Ttext", N_("Set the address of the .text section"),
+  GENERAL_ARG('\0', "Tbss", N_("Set the address of the bss segment"),
+              N_("-Tbss ADDRESS"), ONE_DASH,
+              &General_options::set_bss_segment_address),
+  GENERAL_ARG('\0', "Tdata", N_("Set the address of the data segment"),
+              N_("-Tdata ADDRESS"), ONE_DASH,
+              &General_options::set_data_segment_address),
+  GENERAL_ARG('\0', "Ttext", N_("Set the address of the text segment"),
               N_("-Ttext ADDRESS"), ONE_DASH,
               &General_options::set_text_segment_address),
-  // This must come after -Ttext since it's a prefix of it.
+  // This must come after -Ttext and friends since it's a prefix of
+  // them.
   SPECIAL('T', "script", N_("Read linker script"),
          N_("-T FILE, --script FILE"), TWO_DASHES,
          &invoke_script),
@@ -651,7 +658,9 @@ General_options::General_options(Script_options* script_options)
     is_static_(false),
     print_stats_(false),
     sysroot_(),
-    text_segment_address_(-1U),   // -1 indicates value not set by user
+    bss_segment_address_(-1U),   // -1 indicates value not set by user
+    data_segment_address_(-1U),
+    text_segment_address_(-1U),
     threads_(false),
     thread_count_initial_(0),
     thread_count_middle_(0),
index c484b55..ef8e26f 100644 (file)
@@ -260,6 +260,26 @@ class General_options
   version_script() const
   { return *this->script_options_->version_script_info(); }
 
+  // -Tbss: The address of the BSS segment
+  uint64_t
+  bss_segment_address() const
+  { return this->bss_segment_address_; }
+
+  // Whether -Tbss was used.
+  bool
+  user_set_bss_segment_address() const
+  { return this->bss_segment_address_ != -1U; }
+
+  // -Tdata: The address of the data segment
+  uint64_t
+  data_segment_address() const
+  { return this->data_segment_address_; }
+
+  // Whether -Tdata was used.
+  bool
+  user_set_data_segment_address() const
+  { return this->data_segment_address_ != -1U; }
+
   // -Ttext: The address of the .text section
   uint64_t
   text_segment_address() const
@@ -479,15 +499,26 @@ class General_options
   { this->sysroot_ = arg; }
 
   void
-  set_text_segment_address(const char* arg)
+  set_segment_address(const char* name, const char* arg, uint64_t* val)
   {
     char* endptr;
-    this->text_segment_address_ = strtoull(arg, &endptr, 0);
-    if (*endptr != '\0'
-       || this->text_segment_address_ == -1U)
-      gold_fatal(_("invalid argument to -Ttext: %s"), arg);
+    *val = strtoull(arg, &endptr, 0);
+    if (*endptr != '\0' || *val == -1U)
+      gold_fatal(_("invalid argument to %s: %s"), name, arg);
   }
 
+  void
+  set_bss_segment_address(const char* arg)
+  { this->set_segment_address("-Tbss", arg, &this->bss_segment_address_); }
+
+  void
+  set_data_segment_address(const char* arg)
+  { this->set_segment_address("-Tdata", arg, &this->data_segment_address_); }
+
+  void
+  set_text_segment_address(const char* arg)
+  { this->set_segment_address("-Ttext", arg, &this->text_segment_address_); }
+
   int
   parse_thread_count(const char* arg)
   {
@@ -582,6 +613,8 @@ class General_options
   bool is_static_;
   bool print_stats_;
   std::string sysroot_;
+  uint64_t bss_segment_address_;
+  uint64_t data_segment_address_;
   uint64_t text_segment_address_;
   bool threads_;
   int thread_count_initial_;
index 8f7a564..8d0a853 100644 (file)
@@ -2528,6 +2528,12 @@ class Output_segment
   void
   add_initial_output_data(Output_data*);
 
+  // Return true if this segment has any sections which hold actual
+  // data, rather than being a BSS section.
+  bool
+  has_any_data_sections() const
+  { return !this->output_data_.empty(); }
+
   // Return the number of dynamic relocations applied to this segment.
   unsigned int
   dynamic_reloc_count() const;