aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog19
-rw-r--r--gold/layout.cc29
-rw-r--r--gold/options.cc71
-rw-r--r--gold/options.h12
-rw-r--r--gold/output.cc10
-rw-r--r--gold/output.h15
6 files changed, 141 insertions, 15 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index e1c51e4..3dccb90 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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
diff --git a/gold/layout.cc b/gold/layout.cc
index c633d7b..13c7f7e 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -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())
{
diff --git a/gold/options.cc b/gold/options.cc
index 671f3d5..6c0fa04 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -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;
diff --git a/gold/options.h b/gold/options.h
index 817cac7..7e9c9f9 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -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
diff --git a/gold/output.cc b/gold/output.cc
index 8f1060e..63ab98c 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -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)
diff --git a/gold/output.h b/gold/output.h
index 7ce3202..98132e9 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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