Index: layout.cc =================================================================== RCS file: /cvs/src/src/gold/layout.cc,v retrieving revision 1.155 diff -p -u -r1.155 layout.cc --- layout.cc 31 Dec 2009 05:43:29 -0000 1.155 +++ layout.cc 6 Jan 2010 22:34:06 -0000 @@ -1025,7 +1025,9 @@ Layout::attach_allocated_section_to_segm 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_segm 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_segm 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: options.cc =================================================================== RCS file: /cvs/src/src/gold/options.cc,v retrieving revision 1.97 diff -p -u -r1.97 options.cc --- options.cc 30 Dec 2009 22:35:48 -0000 1.97 +++ options.cc 6 Jan 2010 22:34:06 -0000 @@ -398,6 +398,63 @@ General_options::parse_just_symbols(cons 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; Index: options.h =================================================================== RCS file: /cvs/src/src/gold/options.h,v retrieving revision 1.131 diff -p -u -r1.131 options.h --- options.h 6 Jan 2010 05:30:24 -0000 1.131 +++ options.h 6 Jan 2010 22:34:06 -0000 @@ -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 Index: output.cc =================================================================== RCS file: /cvs/src/src/gold/output.cc,v retrieving revision 1.111 diff -p -u -r1.111 output.cc --- output.cc 30 Dec 2009 19:29:20 -0000 1.111 +++ output.cc 6 Jan 2010 22:34:06 -0000 @@ -3081,11 +3081,7 @@ Output_segment::add_output_section(Outpu 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(Ou 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: output.h =================================================================== RCS file: /cvs/src/src/gold/output.h,v retrieving revision 1.93 diff -p -u -r1.93 output.h --- output.h 30 Dec 2009 06:57:17 -0000 1.93 +++ output.h 6 Jan 2010 22:34:06 -0000 @@ -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