From a192ba05083cb72a218e7c7722f30eadb9973833 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 6 Jan 2010 22:37:18 +0000 Subject: [PATCH] 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 (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 | 19 +++++++++++++ gold/layout.cc | 29 +++++++++++++++++--- gold/options.cc | 71 ++++++++++++++++++++++++++++++++++++++++++++++--- gold/options.h | 12 +++++++++ gold/output.cc | 10 +++---- gold/output.h | 15 +++++++++-- 6 files changed, 141 insertions(+), 15 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index e1c51e4c74d..3dccb90500f 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,22 @@ +2010-01-06 Ian Lance Taylor + + 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 + (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 PR 10980 diff --git a/gold/layout.cc b/gold/layout.cc index c633d7be5fb..13c7f7eab0d 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 671f3d5db08..6c0fa041ec7 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::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 817cac7e65f..7e9c9f902ca 100644 --- a/gold/options.h +++ b/gold/options.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -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 excluded_libs_; // List of symbol-names to keep, via -retain-symbol-info. Unordered_set symbols_to_retain_; + // Map from section name to address from --section-start. + std::map 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 8f1060ed3f2..63ab98c96b6 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 7ce32026882..98132e9121d 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 -- 2.30.2