diff options
-rw-r--r-- | gold/ChangeLog | 19 | ||||
-rw-r--r-- | gold/layout.cc | 29 | ||||
-rw-r--r-- | gold/options.cc | 71 | ||||
-rw-r--r-- | gold/options.h | 12 | ||||
-rw-r--r-- | gold/output.cc | 10 | ||||
-rw-r--r-- | gold/output.h | 15 |
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 |