diff options
Diffstat (limited to 'gold/layout.cc')
-rw-r--r-- | gold/layout.cc | 176 |
1 files changed, 123 insertions, 53 deletions
diff --git a/gold/layout.cc b/gold/layout.cc index db6b6ac..cadac87 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -408,12 +408,14 @@ Layout::Layout(int number_of_input_files, Script_options* script_options) resized_signatures_(false), have_stabstr_section_(false), section_ordering_specified_(false), + unique_segment_for_sections_specified_(false), incremental_inputs_(NULL), record_output_section_data_from_script_(false), script_output_section_data_list_(), segment_states_(NULL), relaxation_debug_check_(NULL), section_order_map_(), + section_segment_map_(), input_section_position_(), input_section_glob_(), incremental_base_(NULL), @@ -824,6 +826,27 @@ Layout::keep_input_section(const Relobj* relobj, const char* name) return name != NULL && keep; } +// Clear the input section flags that should not be copied to the +// output section. + +elfcpp::Elf_Xword +Layout::get_output_section_flags(elfcpp::Elf_Xword input_section_flags) +{ + // Some flags in the input section should not be automatically + // copied to the output section. + input_section_flags &= ~ (elfcpp::SHF_INFO_LINK + | elfcpp::SHF_GROUP + | elfcpp::SHF_MERGE + | elfcpp::SHF_STRINGS); + + // We only clear the SHF_LINK_ORDER flag in for + // a non-relocatable link. + if (!parameters->options().relocatable()) + input_section_flags &= ~elfcpp::SHF_LINK_ORDER; + + return input_section_flags; +} + // Pick the output section to use for section NAME, in input file // RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a // linker created section. IS_INPUT_SECTION is true if we are @@ -842,17 +865,7 @@ Layout::choose_output_section(const Relobj* relobj, const char* name, // sections to segments. gold_assert(!is_input_section || !this->sections_are_attached_); - // Some flags in the input section should not be automatically - // copied to the output section. - flags &= ~ (elfcpp::SHF_INFO_LINK - | elfcpp::SHF_GROUP - | elfcpp::SHF_MERGE - | elfcpp::SHF_STRINGS); - - // We only clear the SHF_LINK_ORDER flag in for - // a non-relocatable link. - if (!parameters->options().relocatable()) - flags &= ~elfcpp::SHF_LINK_ORDER; + flags = this->get_output_section_flags(flags); if (this->script_options_->saw_sections_clause()) { @@ -1054,9 +1067,37 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx, } else { - os = this->choose_output_section(object, name, sh_type, - shdr.get_sh_flags(), true, - ORDER_INVALID, false); + // Plugins can choose to place one or more subsets of sections in + // unique segments and this is done by mapping these section subsets + // to unique output sections. Check if this section needs to be + // remapped to a unique output section. + Section_segment_map::iterator it + = this->section_segment_map_.find(Const_section_id(object, shndx)); + if (it == this->section_segment_map_.end()) + { + os = this->choose_output_section(object, name, sh_type, + shdr.get_sh_flags(), true, + ORDER_INVALID, false); + } + else + { + // We know the name of the output section, directly call + // get_output_section here by-passing choose_output_section. + elfcpp::Elf_Xword flags + = this->get_output_section_flags(shdr.get_sh_flags()); + + const char* os_name = it->second->name; + Stringpool::Key name_key; + os_name = this->namepool_.add(os_name, true, &name_key); + os = this->get_output_section(os_name, name_key, sh_type, flags, + ORDER_INVALID, false); + if (!os->is_unique_segment()) + { + os->set_is_unique_segment(); + os->set_extra_segment_flags(it->second->flags); + os->set_segment_alignment(it->second->align); + } + } if (os == NULL) return NULL; } @@ -1116,6 +1157,15 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx, return os; } +// Maps section SECN to SEGMENT s. +void +Layout::insert_section_segment_map(Const_section_id secn, + Unique_segment_info *s) +{ + gold_assert(this->unique_segment_for_sections_specified_); + this->section_segment_map_[secn] = s; +} + // Handle a relocation section when doing a relocatable link. template<int size, bool big_endian> @@ -1718,6 +1768,10 @@ Layout::attach_allocated_section_to_segment(const Target* target, elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags); + // If this output section's segment has extra flags that need to be set, + // coming from a linker plugin, do that. + seg_flags |= os->extra_segment_flags(); + // Check for --section-start. uint64_t addr; bool is_address_set = parameters->options().section_start(os->name(), &addr); @@ -1730,45 +1784,51 @@ Layout::attach_allocated_section_to_segment(const Target* target, // have to use a linker script. Segment_list::const_iterator p; - for (p = this->segment_list_.begin(); - p != this->segment_list_.end(); - ++p) + if (!os->is_unique_segment()) { - if ((*p)->type() != elfcpp::PT_LOAD) - continue; - if (!parameters->options().omagic() - && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W)) - continue; - if ((target->isolate_execinstr() || parameters->options().rosegment()) - && ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X)) - continue; - // If -Tbss was specified, we need to separate the data and BSS - // segments. - if (parameters->options().user_set_Tbss()) - { - if ((os->type() == elfcpp::SHT_NOBITS) - == (*p)->has_any_data_sections()) - continue; - } - if (os->is_large_data_section() && !(*p)->is_large_data_segment()) - continue; - - if (is_address_set) + for (p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) { - 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_to_load(this, os, seg_flags); - break; - } - - if (p == this->segment_list_.end()) + if ((*p)->type() != elfcpp::PT_LOAD) + continue; + if ((*p)->is_unique_segment()) + continue; + if (!parameters->options().omagic() + && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W)) + continue; + if ((target->isolate_execinstr() || parameters->options().rosegment()) + && ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X)) + continue; + // If -Tbss was specified, we need to separate the data and BSS + // segments. + if (parameters->options().user_set_Tbss()) + { + if ((os->type() == elfcpp::SHT_NOBITS) + == (*p)->has_any_data_sections()) + continue; + } + if (os->is_large_data_section() && !(*p)->is_large_data_segment()) + continue; + + 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_to_load(this, os, seg_flags); + break; + } + } + + if (p == this->segment_list_.end() + || os->is_unique_segment()) { Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD, seg_flags); @@ -1777,6 +1837,14 @@ Layout::attach_allocated_section_to_segment(const Target* target, oseg->add_output_section_to_load(this, os, seg_flags); if (is_address_set) oseg->set_addresses(addr, addr); + // Check if segment should be marked unique. For segments marked + // unique by linker plugins, set the new alignment if specified. + if (os->is_unique_segment()) + { + oseg->set_is_unique_segment(); + if (os->segment_alignment() != 0) + oseg->set_minimum_p_align(os->segment_alignment()); + } } // If we see a loadable SHT_NOTE section, we create a PT_NOTE @@ -3121,9 +3189,11 @@ Layout::segment_precedes(const Output_segment* seg1, // We shouldn't get here--we shouldn't create segments which we // can't distinguish. Unless of course we are using a weird linker - // script or overlapping --section-start options. + // script or overlapping --section-start options. We could also get + // here if plugins want unique segments for subsets of sections. gold_assert(this->script_options_->saw_phdrs_clause() - || parameters->options().any_section_start()); + || parameters->options().any_section_start() + || this->is_unique_segment_for_sections_specified()); return false; } |