diff options
author | Sriraman Tallam <tmsriram@google.com> | 2012-08-24 18:35:35 +0000 |
---|---|---|
committer | Sriraman Tallam <tmsriram@google.com> | 2012-08-24 18:35:35 +0000 |
commit | 16164a6b00372ebc0360f6aa71337e5613278817 (patch) | |
tree | 503893149fa2b29775eafe985a0a537cf7433132 /gold | |
parent | 92a289b3800274d15d440cea98c0df067da4c2ec (diff) | |
download | fsf-binutils-gdb-16164a6b00372ebc0360f6aa71337e5613278817.zip fsf-binutils-gdb-16164a6b00372ebc0360f6aa71337e5613278817.tar.gz fsf-binutils-gdb-16164a6b00372ebc0360f6aa71337e5613278817.tar.bz2 |
Patch adds support to allow plugins to map selected subset of sections to unique
segments.
2012-08-24 Sriraman Tallam <tmsriram@google.com>
* gold.cc (queue_middle_tasks): Call layout again when unique
segments for sections is desired.
* layout.cc (Layout::Layout): Initialize new members.
(Layout::get_output_section_flags): New function.
(Layout::choose_output_section): Call get_output_section_flags.
(Layout::layout): Make output section for mapping to a unique segment.
(Layout::insert_section_segment_map): New function.
(Layout::attach_allocated_section_to_segment): Make unique segment for
output sections marked so.
(Layout::segment_precedes): Check for unique segments when sorting.
* layout.h (Layout::Unique_segment_info): New struct.
(Layout::Section_segment_map): New typedef.
(Layout::insert_section_segment_map): New function.
(Layout::get_output_section_flags): New function.
(Layout::is_unique_segment_for_sections_specified): New function.
(Layout::set_unique_segment_for_sections_specified): New function.
(Layout::unique_segment_for_sections_specified_): New member.
(Layout::section_segment_map_): New member.
* object.cc (Sized_relobj_file<size, big_endian>::do_layout):
Rename is_gc_pass_one to is_pass_one.
Rename is_gc_pass_two to is_pass_two.
Rename is_gc_or_icf to is_two_pass.
Check for which pass based on whether symbols data is present.
Make it two pass when unique segments for sections is desired.
* output.cc (Output_section::Output_section): Initialize new
members.
* output.h (Output_section::is_unique_segment): New function.
(Output_section::set_is_unique_segment): New function.
(Output_section::is_unique_segment_): New member.
(Output_section::extra_segment_flags): New function.
(Output_section::set_extra_segment_flags): New function.
(Output_section::extra_segment_flags_): New member.
(Output_section::segment_alignment): New function.
(Output_section::set_segment_alignment): New function.
(Output_section::segment_alignment_): New member.
(Output_segment::Output_segment): Initialize is_unique_segment_.
(Output_segment::is_unique_segment): New function.
(Output_segment::set_is_unique_segment): New function.
(Output_segment::is_unique_segment_): New member.
* plugin.cc (allow_unique_segment_for_sections): New function.
(unique_segment_for_sections): New function.
(Plugin::load): Add new functions to transfer vector.
* Makefile.am (plugin_final_layout.readelf.stdout): Add readelf output.
* Makefile.in: Regenerate.
* testsuite/plugin_final_layout.sh: Check if unique segment
functionality works.
* testsuite/plugin_section_order.c (onload): Check if new interfaces
are available.
(allow_unique_segment_for_sections): New global.
(unique_segment_for_sections): New global.
(claim_file_hook): Call allow_unique_segment_for_sections.
(all_symbols_read_hook): Call unique_segment_for_sections.
2012-08-24 Sriraman Tallam <tmsriram@google.com>
* plugin-api.h (ld_plugin_allow_unique_segment_for_sections):
New interface.
(ld_plugin_unique_segment_for_sections): New interface.
(LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS): New enum val.
(LDPT_UNIQUE_SEGMENT_FOR_SECTIONS): New enum val.
(tv_allow_unique_segment_for_sections): New member.
(tv_unique_segment_for_sections): New member.
Diffstat (limited to 'gold')
-rw-r--r-- | gold/ChangeLog | 56 | ||||
-rw-r--r-- | gold/gold.cc | 10 | ||||
-rw-r--r-- | gold/layout.cc | 176 | ||||
-rw-r--r-- | gold/layout.h | 46 | ||||
-rw-r--r-- | gold/object.cc | 110 | ||||
-rw-r--r-- | gold/output.cc | 6 | ||||
-rw-r--r-- | gold/output.h | 42 | ||||
-rw-r--r-- | gold/plugin.cc | 78 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 4 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 5 | ||||
-rwxr-xr-x | gold/testsuite/plugin_final_layout.sh | 30 | ||||
-rw-r--r-- | gold/testsuite/plugin_section_order.c | 35 |
12 files changed, 484 insertions, 114 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 2f5fcb1..7ce8b69 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,59 @@ +2012-08-24 Sriraman Tallam <tmsriram@google.com> + + * gold.cc (queue_middle_tasks): Call layout again when unique + segments for sections is desired. + * layout.cc (Layout::Layout): Initialize new members. + (Layout::get_output_section_flags): New function. + (Layout::choose_output_section): Call get_output_section_flags. + (Layout::layout): Make output section for mapping to a unique segment. + (Layout::insert_section_segment_map): New function. + (Layout::attach_allocated_section_to_segment): Make unique segment for + output sections marked so. + (Layout::segment_precedes): Check for unique segments when sorting. + * layout.h (Layout::Unique_segment_info): New struct. + (Layout::Section_segment_map): New typedef. + (Layout::insert_section_segment_map): New function. + (Layout::get_output_section_flags): New function. + (Layout::is_unique_segment_for_sections_specified): New function. + (Layout::set_unique_segment_for_sections_specified): New function. + (Layout::unique_segment_for_sections_specified_): New member. + (Layout::section_segment_map_): New member. + * object.cc (Sized_relobj_file<size, big_endian>::do_layout): + Rename is_gc_pass_one to is_pass_one. + Rename is_gc_pass_two to is_pass_two. + Rename is_gc_or_icf to is_two_pass. + Check for which pass based on whether symbols data is present. + Make it two pass when unique segments for sections is desired. + * output.cc (Output_section::Output_section): Initialize new + members. + * output.h (Output_section::is_unique_segment): New function. + (Output_section::set_is_unique_segment): New function. + (Output_section::is_unique_segment_): New member. + (Output_section::extra_segment_flags): New function. + (Output_section::set_extra_segment_flags): New function. + (Output_section::extra_segment_flags_): New member. + (Output_section::segment_alignment): New function. + (Output_section::set_segment_alignment): New function. + (Output_section::segment_alignment_): New member. + (Output_segment::Output_segment): Initialize is_unique_segment_. + (Output_segment::is_unique_segment): New function. + (Output_segment::set_is_unique_segment): New function. + (Output_segment::is_unique_segment_): New member. + * plugin.cc (allow_unique_segment_for_sections): New function. + (unique_segment_for_sections): New function. + (Plugin::load): Add new functions to transfer vector. + * Makefile.am (plugin_final_layout.readelf.stdout): Add readelf output. + * Makefile.in: Regenerate. + * testsuite/plugin_final_layout.sh: Check if unique segment + functionality works. + * testsuite/plugin_section_order.c (onload): Check if new interfaces + are available. + (allow_unique_segment_for_sections): New global. + (unique_segment_for_sections): New global. + (claim_file_hook): Call allow_unique_segment_for_sections. + (all_symbols_read_hook): Call unique_segment_for_sections. + + 2012-08-22 Cary Coutant <ccoutant@google.com> * layout.cc (Layout::include_section): Don't assert on GROUP diff --git a/gold/gold.cc b/gold/gold.cc index dddf5ad..1b4badc 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -530,11 +530,13 @@ queue_middle_tasks(const General_options& options, // Call Object::layout for the second time to determine the // output_sections for all referenced input sections. When - // --gc-sections or --icf is turned on, Object::layout is - // called twice. It is called the first time when the - // symbols are added. + // --gc-sections or --icf is turned on, or when certain input + // sections have to be mapped to unique segments, Object::layout + // is called twice. It is called the first time when symbols + // are added. if (parameters->options().gc_sections() - || parameters->options().icf_enabled()) + || parameters->options().icf_enabled() + || layout->is_unique_segment_for_sections_specified()) { for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); p != input_objects->relobj_end(); 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; } diff --git a/gold/layout.h b/gold/layout.h index fe5c696..94745a6 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -528,6 +528,31 @@ class Layout get_section_order_map() { return &this->section_order_map_; } + // Struct to store segment info when mapping some input sections to + // unique segments using linker plugins. Mapping an input section to + // a unique segment is done by first placing such input sections in + // unique output sections and then mapping the output section to a + // unique segment. NAME is the name of the output section. FLAGS + // and ALIGN are the extra flags and alignment of the segment. + struct Unique_segment_info + { + // Identifier for the segment. ELF segments dont have names. This + // is used as the name of the output section mapped to the segment. + const char* name; + // Additional segment flags. + uint64_t flags; + // Segment alignment. + uint64_t align; + }; + + // Mapping from input section to segment. + typedef std::map<Const_section_id, Unique_segment_info*> + Section_segment_map; + + // Maps section SECN to SEGMENT s. + void + insert_section_segment_map(Const_section_id secn, Unique_segment_info *s); + bool is_section_ordering_specified() { return this->section_ordering_specified_; } @@ -536,6 +561,14 @@ class Layout set_section_ordering_specified() { this->section_ordering_specified_ = true; } + bool + is_unique_segment_for_sections_specified() const + { return this->unique_segment_for_sections_specified_; } + + void + set_unique_segment_for_sections_specified() + { this->unique_segment_for_sections_specified_ = true; } + // For incremental updates, allocate a block of memory from the // free list. Find a block starting at or after MINOFF. off_t @@ -1070,6 +1103,11 @@ class Layout elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, Output_section_order order, bool is_relro); + // Clear the input section flags that should not be copied to the + // output section. + elfcpp::Elf_Xword + get_output_section_flags (elfcpp::Elf_Xword input_section_flags); + // Choose the output section for NAME in RELOBJ. Output_section* choose_output_section(const Relobj* relobj, const char* name, @@ -1336,6 +1374,9 @@ class Layout // True if the input sections in the output sections should be sorted // as specified in a section ordering file. bool section_ordering_specified_; + // True if some input sections need to be mapped to a unique segment, + // after being mapped to a unique Output_section. + bool unique_segment_for_sections_specified_; // In incremental build, holds information check the inputs and build the // .gnu_incremental_inputs section. Incremental_inputs* incremental_inputs_; @@ -1350,6 +1391,11 @@ class Layout // Plugins specify section_ordering using this map. This is set in // update_section_order in plugin.cc std::map<Section_id, unsigned int> section_order_map_; + // This maps an input section to a unique segment. This is done by first + // placing such input sections in unique output sections and then mapping + // the output section to a unique segment. Unique_segment_info stores + // any additional flags and alignment of the new segment. + Section_segment_map section_segment_map_; // Hash a pattern to its position in the section ordering file. Unordered_map<std::string, unsigned int> input_section_position_; // Vector of glob only patterns in the section_ordering file. diff --git a/gold/object.cc b/gold/object.cc index 417ccfc..6c0c187 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1221,15 +1221,19 @@ Sized_relobj_file<size, big_endian>::layout_eh_frame_section( // whether they should be included in the link. If they should, we // pass them to the Layout object, which will return an output section // and an offset. -// During garbage collection (--gc-sections) and identical code folding -// (--icf), this function is called twice. When it is called the first -// time, it is for setting up some sections as roots to a work-list for -// --gc-sections and to do comdat processing. Actual layout happens the -// second time around after all the relevant sections have been determined. -// The first time, is_worklist_ready or is_icf_ready is false. It is then -// set to true after the garbage collection worklist or identical code -// folding is processed and the relevant sections to be kept are -// determined. Then, this function is called again to layout the sections. +// This function is called twice sometimes, two passes, when mapping +// of input sections to output sections must be delayed. +// This is true for the following : +// * Garbage collection (--gc-sections): Some input sections will be +// discarded and hence the assignment must wait until the second pass. +// In the first pass, it is for setting up some sections as roots to +// a work-list for --gc-sections and to do comdat processing. +// * Identical Code Folding (--icf=<safe,all>): Some input sections +// will be folded and hence the assignment must wait. +// * Using plugins to map some sections to unique segments: Mapping +// some sections to unique segments requires mapping them to unique +// output sections too. This can be done via plugins now and this +// information is not available in the first pass. template<int size, bool big_endian> void @@ -1238,26 +1242,44 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, Read_symbols_data* sd) { const unsigned int shnum = this->shnum(); - bool is_gc_pass_one = ((parameters->options().gc_sections() - && !symtab->gc()->is_worklist_ready()) - || (parameters->options().icf_enabled() - && !symtab->icf()->is_icf_ready())); - bool is_gc_pass_two = ((parameters->options().gc_sections() - && symtab->gc()->is_worklist_ready()) - || (parameters->options().icf_enabled() - && symtab->icf()->is_icf_ready())); + /* Should this function be called twice? */ + bool is_two_pass = (parameters->options().gc_sections() + || parameters->options().icf_enabled() + || layout->is_unique_segment_for_sections_specified()); - bool is_gc_or_icf = (parameters->options().gc_sections() - || parameters->options().icf_enabled()); + /* Only one of is_pass_one and is_pass_two is true. Both are false when + a two-pass approach is not needed. */ + bool is_pass_one = false; + bool is_pass_two = false; - // Both is_gc_pass_one and is_gc_pass_two should not be true. - gold_assert(!(is_gc_pass_one && is_gc_pass_two)); + Symbols_data* gc_sd = NULL; + /* Check if do_layout needs to be two-pass. If so, find out which pass + should happen. In the first pass, the data in sd is saved to be used + later in the second pass. */ + if (is_two_pass) + { + gc_sd = this->get_symbols_data(); + if (gc_sd == NULL) + { + gold_assert(sd != NULL); + is_pass_one = true; + } + else + { + if (parameters->options().gc_sections()) + gold_assert(symtab->gc()->is_worklist_ready()); + if (parameters->options().icf_enabled()) + gold_assert(symtab->icf()->is_icf_ready()); + is_pass_two = true; + } + } + if (shnum == 0) return; - Symbols_data* gc_sd = NULL; - if (is_gc_pass_one) + + if (is_pass_one) { // During garbage collection save the symbols data to use it when // re-entering this function. @@ -1265,10 +1287,6 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, this->copy_symbols_data(gc_sd, sd, This::shdr_size * shnum); this->set_symbols_data(gc_sd); } - else if (is_gc_pass_two) - { - gc_sd = this->get_symbols_data(); - } const unsigned char* section_headers_data = NULL; section_size_type section_names_size; @@ -1277,7 +1295,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, const unsigned char* symbol_names_data = NULL; section_size_type symbol_names_size; - if (is_gc_or_icf) + if (is_two_pass) { section_headers_data = gc_sd->section_headers_data; section_names_size = gc_sd->section_names_size; @@ -1303,9 +1321,9 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, const unsigned char* pshdrs; // Get the section names. - const unsigned char* pnamesu = (is_gc_or_icf) - ? gc_sd->section_names_data - : sd->section_names->data(); + const unsigned char* pnamesu = (is_two_pass + ? gc_sd->section_names_data + : sd->section_names->data()); const char* pnames = reinterpret_cast<const char*>(pnamesu); @@ -1355,7 +1373,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, Output_sections& out_sections(this->output_sections()); std::vector<Address>& out_section_offsets(this->section_offsets()); - if (!is_gc_pass_two) + if (!is_pass_two) { out_sections.resize(shnum); out_section_offsets.resize(shnum); @@ -1365,7 +1383,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, // do here. if (this->input_file()->just_symbols()) { - if (!is_gc_pass_two) + if (!is_pass_two) { delete sd->section_headers; sd->section_headers = NULL; @@ -1417,7 +1435,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, const char* name = pnames + shdr.get_sh_name(); - if (!is_gc_pass_two) + if (!is_pass_two) { if (this->handle_gnu_warning_section(name, i, symtab)) { @@ -1491,7 +1509,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, } } - if (is_gc_pass_one && parameters->options().gc_sections()) + if (is_pass_one && parameters->options().gc_sections()) { if (this->is_section_name_included(name) || layout->keep_input_section (this, name) @@ -1537,7 +1555,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, && strcmp(name, ".eh_frame") == 0 && this->check_eh_frame_flags(&shdr)) { - if (is_gc_pass_one) + if (is_pass_one) { out_sections[i] = reinterpret_cast<Output_section*>(1); out_section_offsets[i] = invalid_address; @@ -1552,7 +1570,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, continue; } - if (is_gc_pass_two && parameters->options().gc_sections()) + if (is_pass_two && parameters->options().gc_sections()) { // This is executed during the second pass of garbage // collection. do_layout has been called before and some @@ -1577,7 +1595,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, } } - if (is_gc_pass_two && parameters->options().icf_enabled()) + if (is_pass_two && parameters->options().icf_enabled()) { if (out_sections[i] == NULL) { @@ -1611,7 +1629,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, // should_defer_layout should be false. if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC)) { - gold_assert(!is_gc_pass_two); + gold_assert(!is_pass_two); this->deferred_layout_.push_back(Deferred_layout(i, name, pshdrs, reloc_shndx[i], @@ -1626,11 +1644,11 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, // During gc_pass_two if a section that was previously deferred is // found, do not layout the section as layout_deferred_sections will // do it later from gold.cc. - if (is_gc_pass_two + if (is_pass_two && (out_sections[i] == reinterpret_cast<Output_section*>(2))) continue; - if (is_gc_pass_one) + if (is_pass_one) { // This is during garbage collection. The out_sections are // assigned in the second call to this function. @@ -1661,7 +1679,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, } } - if (!is_gc_pass_two) + if (!is_pass_two) layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags, this); // When doing a relocatable link handle the reloc sections at the @@ -1670,7 +1688,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, if (emit_relocs) this->size_relocatable_relocs(); - gold_assert(!(is_gc_or_icf) || reloc_sections.empty()); + gold_assert(!is_two_pass || reloc_sections.empty()); for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin(); p != reloc_sections.end(); @@ -1717,7 +1735,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, } // Handle the .eh_frame sections at the end. - gold_assert(!is_gc_pass_one || eh_frame_sections.empty()); + gold_assert(!is_pass_one || eh_frame_sections.empty()); for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin(); p != eh_frame_sections.end(); ++p) @@ -1740,7 +1758,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, // When building a .gdb_index section, scan the .debug_info and // .debug_types sections. - gold_assert(!is_gc_pass_one + gold_assert(!is_pass_one || (debug_info_sections.empty() && debug_types_sections.empty())); for (std::vector<unsigned int>::const_iterator p = debug_info_sections.begin(); @@ -1761,7 +1779,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, i, reloc_shndx[i], reloc_type[i]); } - if (is_gc_pass_two) + if (is_pass_two) { delete[] gc_sd->section_headers_data; delete[] gc_sd->section_names_data; diff --git a/gold/output.cc b/gold/output.cc index 9556abf..2539aac 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -2257,7 +2257,10 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, always_keeps_input_sections_(false), has_fixed_layout_(false), is_patch_space_allowed_(false), + is_unique_segment_(false), tls_offset_(0), + extra_segment_flags_(0), + segment_alignment_(0), checkpoint_(NULL), lookup_maps_(new Output_section_lookup_maps), free_list_(), @@ -3991,7 +3994,8 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) flags_(flags), is_max_align_known_(false), are_addresses_set_(false), - is_large_data_segment_(false) + is_large_data_segment_(false), + is_unique_segment_(false) { // The ELF ABI specifies that a PT_TLS segment always has PF_R as // the flags. diff --git a/gold/output.h b/gold/output.h index 9b0f87f..25a6b89 100644 --- a/gold/output.h +++ b/gold/output.h @@ -3265,6 +3265,28 @@ class Output_section : public Output_data requires_postprocessing() const { return this->requires_postprocessing_; } + bool + is_unique_segment() const + { return this->is_unique_segment_; } + + void + set_is_unique_segment() + { this->is_unique_segment_ = true; } + + uint64_t extra_segment_flags() const + { return this->extra_segment_flags_; } + + void + set_extra_segment_flags(uint64_t flags) + { this->extra_segment_flags_ = flags; } + + uint64_t segment_alignment() const + { return this->segment_alignment_; } + + void + set_segment_alignment(uint64_t align) + { this->segment_alignment_ = align; } + // If a section requires postprocessing, return the buffer to use. unsigned char* postprocessing_buffer() const @@ -4216,9 +4238,17 @@ class Output_section : public Output_data bool has_fixed_layout_ : 1; // True if we can add patch space to this section. bool is_patch_space_allowed_ : 1; + // True if this output section goes into a unique segment. + bool is_unique_segment_ : 1; // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; + // Additional segment flags, specified via linker plugin, when mapping some + // input sections to unique segments. + uint64_t extra_segment_flags_; + // Segment alignment specified via linker plugin, when mapping some + // input sections to unique segments. + uint64_t segment_alignment_; // Saved checkpoint. Checkpoint_output_section* checkpoint_; // Fast lookup maps for merged and relaxed input sections. @@ -4294,6 +4324,16 @@ class Output_segment set_is_large_data_segment() { this->is_large_data_segment_ = true; } + bool + is_unique_segment() const + { return this->is_unique_segment_; } + + // Mark segment as unique, happens when linker plugins request that + // certain input sections be mapped to unique segments. + void + set_is_unique_segment() + { this->is_unique_segment_ = true; } + // Return the maximum alignment of the Output_data. uint64_t maximum_alignment(); @@ -4504,6 +4544,8 @@ class Output_segment bool are_addresses_set_ : 1; // Whether this segment holds large data sections. bool is_large_data_segment_ : 1; + // Whether this was marked as a unique segment via a linker plugin. + bool is_unique_segment_ : 1; }; // This class represents the output file. diff --git a/gold/plugin.cc b/gold/plugin.cc index 5aadc55..c39e11ec 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -115,6 +115,15 @@ update_section_order(const struct ld_plugin_section *section_list, static enum ld_plugin_status allow_section_ordering(); +static enum ld_plugin_status +allow_unique_segment_for_sections(); + +static enum ld_plugin_status +unique_segment_for_sections(const char* segment_name, + uint64_t flags, + uint64_t align, + const struct ld_plugin_section *section_list, + unsigned int num_sections); }; #endif // ENABLE_PLUGINS @@ -159,7 +168,7 @@ Plugin::load() sscanf(ver, "%d.%d", &major, &minor); // Allocate and populate a transfer vector. - const int tv_fixed_size = 24; + const int tv_fixed_size = 26; int tv_size = this->args_.size() + tv_fixed_size; ld_plugin_tv* tv = new ld_plugin_tv[tv_size]; @@ -273,6 +282,15 @@ Plugin::load() tv[i].tv_u.tv_allow_section_ordering = allow_section_ordering; ++i; + tv[i].tv_tag = LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS; + tv[i].tv_u.tv_allow_unique_segment_for_sections + = allow_unique_segment_for_sections; + + ++i; + tv[i].tv_tag = LDPT_UNIQUE_SEGMENT_FOR_SECTIONS; + tv[i].tv_u.tv_unique_segment_for_sections = unique_segment_for_sections; + + ++i; tv[i].tv_tag = LDPT_NULL; tv[i].tv_u.tv_val = 0; @@ -1685,6 +1703,64 @@ allow_section_ordering() return LDPS_OK; } +// Let the linker know that a subset of sections could be mapped +// to a unique segment. + +static enum ld_plugin_status +allow_unique_segment_for_sections() +{ + gold_assert(parameters->options().has_plugins()); + Layout* layout = parameters->options().plugins()->layout(); + layout->set_unique_segment_for_sections_specified(); + return LDPS_OK; +} + +// This function should map the list of sections specified in the +// SECTION_LIST to a unique segment. ELF segments do not have names +// and the NAME is used to identify Output Section which should contain +// the list of sections. This Output Section will then be mapped to +// a unique segment. FLAGS is used to specify if any additional segment +// flags need to be set. For instance, a specific segment flag can be +// set to identify this segment. Unsetting segment flags is not possible. +// ALIGN specifies the alignment of the segment. + +static enum ld_plugin_status +unique_segment_for_sections(const char* segment_name, + uint64_t flags, + uint64_t align, + const struct ld_plugin_section* section_list, + unsigned int num_sections) +{ + gold_assert(parameters->options().has_plugins()); + + if (num_sections == 0) + return LDPS_OK; + + if (section_list == NULL) + return LDPS_ERR; + + Layout* layout = parameters->options().plugins()->layout(); + gold_assert (layout != NULL); + + Layout::Unique_segment_info* s = new Layout::Unique_segment_info; + s->name = segment_name; + s->flags = flags; + s->align = align; + + for (unsigned int i = 0; i < num_sections; ++i) + { + Object* obj = parameters->options().plugins()->get_elf_object( + section_list[i].handle); + if (obj == NULL) + return LDPS_BAD_HANDLE; + unsigned int shndx = section_list[i].shndx; + Const_section_id secn_id(obj, shndx); + layout->insert_section_segment_map(secn_id, s); + } + + return LDPS_OK; +} + #endif // ENABLE_PLUGINS // Allocate a Pluginobj object of the appropriate size and endianness. diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 0e98e6a..146c7e0 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -1529,13 +1529,15 @@ unused.c: @cp /dev/null $@ check_SCRIPTS += plugin_final_layout.sh -check_DATA += plugin_final_layout.stdout +check_DATA += plugin_final_layout.stdout plugin_final_layout_readelf.stdout plugin_final_layout.o: plugin_final_layout.cc $(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $< plugin_final_layout: plugin_final_layout.o plugin_section_order.so gcctestdir/ld $(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o plugin_final_layout.stdout: plugin_final_layout $(TEST_NM) -n plugin_final_layout > plugin_final_layout.stdout +plugin_final_layout_readelf.stdout: plugin_final_layout + $(TEST_READELF) -Wl plugin_final_layout > plugin_final_layout_readelf.stdout plugin_section_order.so: plugin_section_order.o $(LINK) -Bgcctestdir/ -shared plugin_section_order.o diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index a3a4506..b937ff0 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -329,7 +329,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7.err \ @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7.syms \ @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_9.err \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_final_layout.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_final_layout.stdout \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_final_layout.readelf.stdout # Make a copy of two_file_test_1.o, which does not define the symbol _Z4t16av. @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_36 = \ @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \ @@ -4875,6 +4876,8 @@ uninstall-am: @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.stdout: plugin_final_layout @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_NM) -n plugin_final_layout > plugin_final_layout.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.readelf.stdout: plugin_final_layout +@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -Wl plugin_final_layout > plugin_final_layout_readelf.stdout @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_section_order.so: plugin_section_order.o @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_section_order.o diff --git a/gold/testsuite/plugin_final_layout.sh b/gold/testsuite/plugin_final_layout.sh index 600f8e2..75a40d3 100755 --- a/gold/testsuite/plugin_final_layout.sh +++ b/gold/testsuite/plugin_final_layout.sh @@ -56,5 +56,35 @@ END { }" $1 } +# With readelf -l, an ELF Section to Segment mapping is printed as : +############################################## +# Section to Segment mapping: +# Segment Sections... +# ... +# 0x .text.plugin_created_unique +# ... +############################################## +# Check of .text.plugin_created_unique is the only section in the segment. +check_unique_segment() +{ + awk " +BEGIN { saw_section = 0; saw_unique = 0; } +/$2/ { saw_section = 1; } +/[ ]*0[0-9][ ]*$2[ ]*\$/ { saw_unique = 1; } +END { + if (!saw_section) + { + printf \"Section $2 not seen in output\\n\"; + exit 1; + } + else if (!saw_unique) + { + printf \"Unique segment not seen for: $2\\n\"; + exit 1; + } + }" $1 +} + check plugin_final_layout.stdout "_Z3foov" "_Z3barv" check plugin_final_layout.stdout "_Z3barv" "_Z3bazv" +check_unique_segment plugin_final_layout_readelf.stdout ".text.plugin_created_unique" diff --git a/gold/testsuite/plugin_section_order.c b/gold/testsuite/plugin_section_order.c index 0e2079b..fdc6fe4 100644 --- a/gold/testsuite/plugin_section_order.c +++ b/gold/testsuite/plugin_section_order.c @@ -36,6 +36,9 @@ static ld_plugin_get_input_section_name get_input_section_name = NULL; static ld_plugin_get_input_section_contents get_input_section_contents = NULL; static ld_plugin_update_section_order update_section_order = NULL; static ld_plugin_allow_section_ordering allow_section_ordering = NULL; +static ld_plugin_allow_unique_segment_for_sections + allow_unique_segment_for_sections = NULL; +static ld_plugin_unique_segment_for_sections unique_segment_for_sections = NULL; enum ld_plugin_status onload(struct ld_plugin_tv *tv); enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file, @@ -52,11 +55,13 @@ onload(struct ld_plugin_tv *tv) switch (entry->tv_tag) { case LDPT_REGISTER_CLAIM_FILE_HOOK: - assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook) == LDPS_OK); + assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook) + == LDPS_OK); break; case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: - assert((*entry->tv_u.tv_register_all_symbols_read) (all_symbols_read_hook) - == LDPS_OK); + assert((*entry->tv_u.tv_register_all_symbols_read) + (all_symbols_read_hook) + == LDPS_OK); break; case LDPT_GET_INPUT_SECTION_COUNT: get_input_section_count = *entry->tv_u.tv_get_input_section_count; @@ -68,7 +73,8 @@ onload(struct ld_plugin_tv *tv) get_input_section_name = *entry->tv_u.tv_get_input_section_name; break; case LDPT_GET_INPUT_SECTION_CONTENTS: - get_input_section_contents = *entry->tv_u.tv_get_input_section_contents; + get_input_section_contents + = *entry->tv_u.tv_get_input_section_contents; break; case LDPT_UPDATE_SECTION_ORDER: update_section_order = *entry->tv_u.tv_update_section_order; @@ -76,6 +82,13 @@ onload(struct ld_plugin_tv *tv) case LDPT_ALLOW_SECTION_ORDERING: allow_section_ordering = *entry->tv_u.tv_allow_section_ordering; break; + case LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS: + allow_unique_segment_for_sections + = *entry->tv_u.tv_allow_unique_segment_for_sections; + case LDPT_UNIQUE_SEGMENT_FOR_SECTIONS: + unique_segment_for_sections + = *entry->tv_u.tv_unique_segment_for_sections; + break; default: break; } @@ -86,7 +99,9 @@ onload(struct ld_plugin_tv *tv) || get_input_section_name == NULL || get_input_section_contents == NULL || update_section_order == NULL - || allow_section_ordering == NULL) + || allow_section_ordering == NULL + || allow_unique_segment_for_sections == NULL + || unique_segment_for_sections == NULL) { fprintf(stderr, "Some interfaces are missing\n"); return LDPS_ERR; @@ -117,6 +132,9 @@ claim_file_hook(const struct ld_plugin_input_file *file, int *claimed) { /* Inform the linker to prepare for section reordering. */ (*allow_section_ordering)(); + /* Inform the linker to prepare to map some sections to unique + segments. */ + (*allow_unique_segment_for_sections)(); is_ordering_specified = 1; } @@ -160,8 +178,11 @@ enum ld_plugin_status all_symbols_read_hook(void) { if (num_entries == 3) - update_section_order(section_list, num_entries); + { + update_section_order(section_list, num_entries); + unique_segment_for_sections (".text.plugin_created_unique", 0, 0x1000, + section_list, num_entries); + } return LDPS_OK; } - |