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.
This commit is contained in:
parent
92a289b380
commit
16164a6b00
@ -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>
|
2012-08-22 Cary Coutant <ccoutant@google.com>
|
||||||
|
|
||||||
* layout.cc (Layout::include_section): Don't assert on GROUP
|
* layout.cc (Layout::include_section): Don't assert on GROUP
|
||||||
|
10
gold/gold.cc
10
gold/gold.cc
@ -530,11 +530,13 @@ queue_middle_tasks(const General_options& options,
|
|||||||
|
|
||||||
// Call Object::layout for the second time to determine the
|
// Call Object::layout for the second time to determine the
|
||||||
// output_sections for all referenced input sections. When
|
// output_sections for all referenced input sections. When
|
||||||
// --gc-sections or --icf is turned on, Object::layout is
|
// --gc-sections or --icf is turned on, or when certain input
|
||||||
// called twice. It is called the first time when the
|
// sections have to be mapped to unique segments, Object::layout
|
||||||
// symbols are added.
|
// is called twice. It is called the first time when symbols
|
||||||
|
// are added.
|
||||||
if (parameters->options().gc_sections()
|
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();
|
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
|
||||||
p != input_objects->relobj_end();
|
p != input_objects->relobj_end();
|
||||||
|
172
gold/layout.cc
172
gold/layout.cc
@ -408,12 +408,14 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
|
|||||||
resized_signatures_(false),
|
resized_signatures_(false),
|
||||||
have_stabstr_section_(false),
|
have_stabstr_section_(false),
|
||||||
section_ordering_specified_(false),
|
section_ordering_specified_(false),
|
||||||
|
unique_segment_for_sections_specified_(false),
|
||||||
incremental_inputs_(NULL),
|
incremental_inputs_(NULL),
|
||||||
record_output_section_data_from_script_(false),
|
record_output_section_data_from_script_(false),
|
||||||
script_output_section_data_list_(),
|
script_output_section_data_list_(),
|
||||||
segment_states_(NULL),
|
segment_states_(NULL),
|
||||||
relaxation_debug_check_(NULL),
|
relaxation_debug_check_(NULL),
|
||||||
section_order_map_(),
|
section_order_map_(),
|
||||||
|
section_segment_map_(),
|
||||||
input_section_position_(),
|
input_section_position_(),
|
||||||
input_section_glob_(),
|
input_section_glob_(),
|
||||||
incremental_base_(NULL),
|
incremental_base_(NULL),
|
||||||
@ -824,6 +826,27 @@ Layout::keep_input_section(const Relobj* relobj, const char* name)
|
|||||||
return name != NULL && keep;
|
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
|
// 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
|
// RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a
|
||||||
// linker created section. IS_INPUT_SECTION is true if we are
|
// 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.
|
// sections to segments.
|
||||||
gold_assert(!is_input_section || !this->sections_are_attached_);
|
gold_assert(!is_input_section || !this->sections_are_attached_);
|
||||||
|
|
||||||
// Some flags in the input section should not be automatically
|
flags = this->get_output_section_flags(flags);
|
||||||
// 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;
|
|
||||||
|
|
||||||
if (this->script_options_->saw_sections_clause())
|
if (this->script_options_->saw_sections_clause())
|
||||||
{
|
{
|
||||||
@ -1054,9 +1067,37 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
os = this->choose_output_section(object, name, sh_type,
|
// Plugins can choose to place one or more subsets of sections in
|
||||||
shdr.get_sh_flags(), true,
|
// unique segments and this is done by mapping these section subsets
|
||||||
ORDER_INVALID, false);
|
// 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)
|
if (os == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1116,6 +1157,15 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx,
|
|||||||
return os;
|
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.
|
// Handle a relocation section when doing a relocatable link.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
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);
|
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.
|
// Check for --section-start.
|
||||||
uint64_t addr;
|
uint64_t addr;
|
||||||
bool is_address_set = parameters->options().section_start(os->name(), &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.
|
// have to use a linker script.
|
||||||
|
|
||||||
Segment_list::const_iterator p;
|
Segment_list::const_iterator p;
|
||||||
for (p = this->segment_list_.begin();
|
if (!os->is_unique_segment())
|
||||||
p != this->segment_list_.end();
|
|
||||||
++p)
|
|
||||||
{
|
{
|
||||||
if ((*p)->type() != elfcpp::PT_LOAD)
|
for (p = this->segment_list_.begin();
|
||||||
continue;
|
p != this->segment_list_.end();
|
||||||
if (!parameters->options().omagic()
|
++p)
|
||||||
&& ((*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)
|
if ((*p)->type() != elfcpp::PT_LOAD)
|
||||||
== (*p)->has_any_data_sections())
|
continue;
|
||||||
continue;
|
if ((*p)->is_unique_segment())
|
||||||
}
|
continue;
|
||||||
if (os->is_large_data_section() && !(*p)->is_large_data_segment())
|
if (!parameters->options().omagic()
|
||||||
continue;
|
&& ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))
|
||||||
|
continue;
|
||||||
if (is_address_set)
|
if ((target->isolate_execinstr() || parameters->options().rosegment())
|
||||||
{
|
&& ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X))
|
||||||
if ((*p)->are_addresses_set())
|
continue;
|
||||||
continue;
|
// If -Tbss was specified, we need to separate the data and BSS
|
||||||
|
// segments.
|
||||||
(*p)->add_initial_output_data(os);
|
if (parameters->options().user_set_Tbss())
|
||||||
(*p)->update_flags_for_output_section(seg_flags);
|
{
|
||||||
(*p)->set_addresses(addr, addr);
|
if ((os->type() == elfcpp::SHT_NOBITS)
|
||||||
break;
|
== (*p)->has_any_data_sections())
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
(*p)->add_output_section_to_load(this, os, seg_flags);
|
if (os->is_large_data_section() && !(*p)->is_large_data_segment())
|
||||||
break;
|
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())
|
if (p == this->segment_list_.end()
|
||||||
|
|| os->is_unique_segment())
|
||||||
{
|
{
|
||||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
|
Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
|
||||||
seg_flags);
|
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);
|
oseg->add_output_section_to_load(this, os, seg_flags);
|
||||||
if (is_address_set)
|
if (is_address_set)
|
||||||
oseg->set_addresses(addr, addr);
|
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
|
// 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
|
// We shouldn't get here--we shouldn't create segments which we
|
||||||
// can't distinguish. Unless of course we are using a weird linker
|
// 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()
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,6 +528,31 @@ class Layout
|
|||||||
get_section_order_map()
|
get_section_order_map()
|
||||||
{ return &this->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
|
bool
|
||||||
is_section_ordering_specified()
|
is_section_ordering_specified()
|
||||||
{ return this->section_ordering_specified_; }
|
{ return this->section_ordering_specified_; }
|
||||||
@ -536,6 +561,14 @@ class Layout
|
|||||||
set_section_ordering_specified()
|
set_section_ordering_specified()
|
||||||
{ this->section_ordering_specified_ = true; }
|
{ 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
|
// For incremental updates, allocate a block of memory from the
|
||||||
// free list. Find a block starting at or after MINOFF.
|
// free list. Find a block starting at or after MINOFF.
|
||||||
off_t
|
off_t
|
||||||
@ -1070,6 +1103,11 @@ class Layout
|
|||||||
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
|
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
|
||||||
Output_section_order order, bool is_relro);
|
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.
|
// Choose the output section for NAME in RELOBJ.
|
||||||
Output_section*
|
Output_section*
|
||||||
choose_output_section(const Relobj* relobj, const char* name,
|
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
|
// True if the input sections in the output sections should be sorted
|
||||||
// as specified in a section ordering file.
|
// as specified in a section ordering file.
|
||||||
bool section_ordering_specified_;
|
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
|
// In incremental build, holds information check the inputs and build the
|
||||||
// .gnu_incremental_inputs section.
|
// .gnu_incremental_inputs section.
|
||||||
Incremental_inputs* incremental_inputs_;
|
Incremental_inputs* incremental_inputs_;
|
||||||
@ -1350,6 +1391,11 @@ class Layout
|
|||||||
// Plugins specify section_ordering using this map. This is set in
|
// Plugins specify section_ordering using this map. This is set in
|
||||||
// update_section_order in plugin.cc
|
// update_section_order in plugin.cc
|
||||||
std::map<Section_id, unsigned int> section_order_map_;
|
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.
|
// Hash a pattern to its position in the section ordering file.
|
||||||
Unordered_map<std::string, unsigned int> input_section_position_;
|
Unordered_map<std::string, unsigned int> input_section_position_;
|
||||||
// Vector of glob only patterns in the section_ordering file.
|
// Vector of glob only patterns in the section_ordering file.
|
||||||
|
110
gold/object.cc
110
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
|
// whether they should be included in the link. If they should, we
|
||||||
// pass them to the Layout object, which will return an output section
|
// pass them to the Layout object, which will return an output section
|
||||||
// and an offset.
|
// and an offset.
|
||||||
// During garbage collection (--gc-sections) and identical code folding
|
// This function is called twice sometimes, two passes, when mapping
|
||||||
// (--icf), this function is called twice. When it is called the first
|
// of input sections to output sections must be delayed.
|
||||||
// time, it is for setting up some sections as roots to a work-list for
|
// This is true for the following :
|
||||||
// --gc-sections and to do comdat processing. Actual layout happens the
|
// * Garbage collection (--gc-sections): Some input sections will be
|
||||||
// second time around after all the relevant sections have been determined.
|
// discarded and hence the assignment must wait until the second pass.
|
||||||
// The first time, is_worklist_ready or is_icf_ready is false. It is then
|
// In the first pass, it is for setting up some sections as roots to
|
||||||
// set to true after the garbage collection worklist or identical code
|
// a work-list for --gc-sections and to do comdat processing.
|
||||||
// folding is processed and the relevant sections to be kept are
|
// * Identical Code Folding (--icf=<safe,all>): Some input sections
|
||||||
// determined. Then, this function is called again to layout the 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>
|
template<int size, bool big_endian>
|
||||||
void
|
void
|
||||||
@ -1238,26 +1242,44 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||||||
Read_symbols_data* sd)
|
Read_symbols_data* sd)
|
||||||
{
|
{
|
||||||
const unsigned int shnum = this->shnum();
|
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()
|
/* Should this function be called twice? */
|
||||||
&& symtab->gc()->is_worklist_ready())
|
bool is_two_pass = (parameters->options().gc_sections()
|
||||||
|| (parameters->options().icf_enabled()
|
|| parameters->options().icf_enabled()
|
||||||
&& symtab->icf()->is_icf_ready()));
|
|| layout->is_unique_segment_for_sections_specified());
|
||||||
|
|
||||||
bool is_gc_or_icf = (parameters->options().gc_sections()
|
/* Only one of is_pass_one and is_pass_two is true. Both are false when
|
||||||
|| parameters->options().icf_enabled());
|
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.
|
Symbols_data* gc_sd = NULL;
|
||||||
gold_assert(!(is_gc_pass_one && is_gc_pass_two));
|
|
||||||
|
|
||||||
|
/* 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)
|
if (shnum == 0)
|
||||||
return;
|
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
|
// During garbage collection save the symbols data to use it when
|
||||||
// re-entering this function.
|
// 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->copy_symbols_data(gc_sd, sd, This::shdr_size * shnum);
|
||||||
this->set_symbols_data(gc_sd);
|
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;
|
const unsigned char* section_headers_data = NULL;
|
||||||
section_size_type section_names_size;
|
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;
|
const unsigned char* symbol_names_data = NULL;
|
||||||
section_size_type symbol_names_size;
|
section_size_type symbol_names_size;
|
||||||
|
|
||||||
if (is_gc_or_icf)
|
if (is_two_pass)
|
||||||
{
|
{
|
||||||
section_headers_data = gc_sd->section_headers_data;
|
section_headers_data = gc_sd->section_headers_data;
|
||||||
section_names_size = gc_sd->section_names_size;
|
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;
|
const unsigned char* pshdrs;
|
||||||
|
|
||||||
// Get the section names.
|
// Get the section names.
|
||||||
const unsigned char* pnamesu = (is_gc_or_icf)
|
const unsigned char* pnamesu = (is_two_pass
|
||||||
? gc_sd->section_names_data
|
? gc_sd->section_names_data
|
||||||
: sd->section_names->data();
|
: sd->section_names->data());
|
||||||
|
|
||||||
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
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());
|
Output_sections& out_sections(this->output_sections());
|
||||||
std::vector<Address>& out_section_offsets(this->section_offsets());
|
std::vector<Address>& out_section_offsets(this->section_offsets());
|
||||||
|
|
||||||
if (!is_gc_pass_two)
|
if (!is_pass_two)
|
||||||
{
|
{
|
||||||
out_sections.resize(shnum);
|
out_sections.resize(shnum);
|
||||||
out_section_offsets.resize(shnum);
|
out_section_offsets.resize(shnum);
|
||||||
@ -1365,7 +1383,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||||||
// do here.
|
// do here.
|
||||||
if (this->input_file()->just_symbols())
|
if (this->input_file()->just_symbols())
|
||||||
{
|
{
|
||||||
if (!is_gc_pass_two)
|
if (!is_pass_two)
|
||||||
{
|
{
|
||||||
delete sd->section_headers;
|
delete sd->section_headers;
|
||||||
sd->section_headers = NULL;
|
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();
|
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))
|
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)
|
if (this->is_section_name_included(name)
|
||||||
|| layout->keep_input_section (this, 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
|
&& strcmp(name, ".eh_frame") == 0
|
||||||
&& this->check_eh_frame_flags(&shdr))
|
&& this->check_eh_frame_flags(&shdr))
|
||||||
{
|
{
|
||||||
if (is_gc_pass_one)
|
if (is_pass_one)
|
||||||
{
|
{
|
||||||
out_sections[i] = reinterpret_cast<Output_section*>(1);
|
out_sections[i] = reinterpret_cast<Output_section*>(1);
|
||||||
out_section_offsets[i] = invalid_address;
|
out_section_offsets[i] = invalid_address;
|
||||||
@ -1552,7 +1570,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||||||
continue;
|
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
|
// This is executed during the second pass of garbage
|
||||||
// collection. do_layout has been called before and some
|
// 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)
|
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.
|
// should_defer_layout should be false.
|
||||||
if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
|
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,
|
this->deferred_layout_.push_back(Deferred_layout(i, name,
|
||||||
pshdrs,
|
pshdrs,
|
||||||
reloc_shndx[i],
|
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
|
// During gc_pass_two if a section that was previously deferred is
|
||||||
// found, do not layout the section as layout_deferred_sections will
|
// found, do not layout the section as layout_deferred_sections will
|
||||||
// do it later from gold.cc.
|
// do it later from gold.cc.
|
||||||
if (is_gc_pass_two
|
if (is_pass_two
|
||||||
&& (out_sections[i] == reinterpret_cast<Output_section*>(2)))
|
&& (out_sections[i] == reinterpret_cast<Output_section*>(2)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (is_gc_pass_one)
|
if (is_pass_one)
|
||||||
{
|
{
|
||||||
// This is during garbage collection. The out_sections are
|
// This is during garbage collection. The out_sections are
|
||||||
// assigned in the second call to this function.
|
// 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);
|
layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags, this);
|
||||||
|
|
||||||
// When doing a relocatable link handle the reloc sections at the
|
// 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)
|
if (emit_relocs)
|
||||||
this->size_relocatable_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();
|
for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin();
|
||||||
p != reloc_sections.end();
|
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.
|
// 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();
|
for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin();
|
||||||
p != eh_frame_sections.end();
|
p != eh_frame_sections.end();
|
||||||
++p)
|
++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
|
// When building a .gdb_index section, scan the .debug_info and
|
||||||
// .debug_types sections.
|
// .debug_types sections.
|
||||||
gold_assert(!is_gc_pass_one
|
gold_assert(!is_pass_one
|
||||||
|| (debug_info_sections.empty() && debug_types_sections.empty()));
|
|| (debug_info_sections.empty() && debug_types_sections.empty()));
|
||||||
for (std::vector<unsigned int>::const_iterator p
|
for (std::vector<unsigned int>::const_iterator p
|
||||||
= debug_info_sections.begin();
|
= 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]);
|
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_headers_data;
|
||||||
delete[] gc_sd->section_names_data;
|
delete[] gc_sd->section_names_data;
|
||||||
|
@ -2257,7 +2257,10 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
|||||||
always_keeps_input_sections_(false),
|
always_keeps_input_sections_(false),
|
||||||
has_fixed_layout_(false),
|
has_fixed_layout_(false),
|
||||||
is_patch_space_allowed_(false),
|
is_patch_space_allowed_(false),
|
||||||
|
is_unique_segment_(false),
|
||||||
tls_offset_(0),
|
tls_offset_(0),
|
||||||
|
extra_segment_flags_(0),
|
||||||
|
segment_alignment_(0),
|
||||||
checkpoint_(NULL),
|
checkpoint_(NULL),
|
||||||
lookup_maps_(new Output_section_lookup_maps),
|
lookup_maps_(new Output_section_lookup_maps),
|
||||||
free_list_(),
|
free_list_(),
|
||||||
@ -3991,7 +3994,8 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
|||||||
flags_(flags),
|
flags_(flags),
|
||||||
is_max_align_known_(false),
|
is_max_align_known_(false),
|
||||||
are_addresses_set_(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 ELF ABI specifies that a PT_TLS segment always has PF_R as
|
||||||
// the flags.
|
// the flags.
|
||||||
|
@ -3265,6 +3265,28 @@ class Output_section : public Output_data
|
|||||||
requires_postprocessing() const
|
requires_postprocessing() const
|
||||||
{ return this->requires_postprocessing_; }
|
{ 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.
|
// If a section requires postprocessing, return the buffer to use.
|
||||||
unsigned char*
|
unsigned char*
|
||||||
postprocessing_buffer() const
|
postprocessing_buffer() const
|
||||||
@ -4216,9 +4238,17 @@ class Output_section : public Output_data
|
|||||||
bool has_fixed_layout_ : 1;
|
bool has_fixed_layout_ : 1;
|
||||||
// True if we can add patch space to this section.
|
// True if we can add patch space to this section.
|
||||||
bool is_patch_space_allowed_ : 1;
|
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
|
// For SHT_TLS sections, the offset of this section relative to the base
|
||||||
// of the TLS segment.
|
// of the TLS segment.
|
||||||
uint64_t tls_offset_;
|
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.
|
// Saved checkpoint.
|
||||||
Checkpoint_output_section* checkpoint_;
|
Checkpoint_output_section* checkpoint_;
|
||||||
// Fast lookup maps for merged and relaxed input sections.
|
// Fast lookup maps for merged and relaxed input sections.
|
||||||
@ -4294,6 +4324,16 @@ class Output_segment
|
|||||||
set_is_large_data_segment()
|
set_is_large_data_segment()
|
||||||
{ this->is_large_data_segment_ = true; }
|
{ 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.
|
// Return the maximum alignment of the Output_data.
|
||||||
uint64_t
|
uint64_t
|
||||||
maximum_alignment();
|
maximum_alignment();
|
||||||
@ -4504,6 +4544,8 @@ class Output_segment
|
|||||||
bool are_addresses_set_ : 1;
|
bool are_addresses_set_ : 1;
|
||||||
// Whether this segment holds large data sections.
|
// Whether this segment holds large data sections.
|
||||||
bool is_large_data_segment_ : 1;
|
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.
|
// This class represents the output file.
|
||||||
|
@ -115,6 +115,15 @@ update_section_order(const struct ld_plugin_section *section_list,
|
|||||||
static enum ld_plugin_status
|
static enum ld_plugin_status
|
||||||
allow_section_ordering();
|
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
|
#endif // ENABLE_PLUGINS
|
||||||
@ -159,7 +168,7 @@ Plugin::load()
|
|||||||
sscanf(ver, "%d.%d", &major, &minor);
|
sscanf(ver, "%d.%d", &major, &minor);
|
||||||
|
|
||||||
// Allocate and populate a transfer vector.
|
// 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;
|
int tv_size = this->args_.size() + tv_fixed_size;
|
||||||
ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
|
ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
|
||||||
@ -272,6 +281,15 @@ Plugin::load()
|
|||||||
tv[i].tv_tag = LDPT_ALLOW_SECTION_ORDERING;
|
tv[i].tv_tag = LDPT_ALLOW_SECTION_ORDERING;
|
||||||
tv[i].tv_u.tv_allow_section_ordering = allow_section_ordering;
|
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;
|
++i;
|
||||||
tv[i].tv_tag = LDPT_NULL;
|
tv[i].tv_tag = LDPT_NULL;
|
||||||
tv[i].tv_u.tv_val = 0;
|
tv[i].tv_u.tv_val = 0;
|
||||||
@ -1685,6 +1703,64 @@ allow_section_ordering()
|
|||||||
return LDPS_OK;
|
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
|
#endif // ENABLE_PLUGINS
|
||||||
|
|
||||||
// Allocate a Pluginobj object of the appropriate size and endianness.
|
// Allocate a Pluginobj object of the appropriate size and endianness.
|
||||||
|
@ -1529,13 +1529,15 @@ unused.c:
|
|||||||
@cp /dev/null $@
|
@cp /dev/null $@
|
||||||
|
|
||||||
check_SCRIPTS += plugin_final_layout.sh
|
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
|
plugin_final_layout.o: plugin_final_layout.cc
|
||||||
$(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
|
$(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
|
||||||
plugin_final_layout: plugin_final_layout.o plugin_section_order.so gcctestdir/ld
|
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
|
$(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o
|
||||||
plugin_final_layout.stdout: plugin_final_layout
|
plugin_final_layout.stdout: plugin_final_layout
|
||||||
$(TEST_NM) -n plugin_final_layout > plugin_final_layout.stdout
|
$(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
|
plugin_section_order.so: plugin_section_order.o
|
||||||
$(LINK) -Bgcctestdir/ -shared plugin_section_order.o
|
$(LINK) -Bgcctestdir/ -shared plugin_section_order.o
|
||||||
|
@ -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.err \
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_7.syms \
|
@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_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.
|
# 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@am__append_36 = \
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_test_1.err \
|
@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@ $(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@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@ $(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@plugin_section_order.so: plugin_section_order.o
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_section_order.o
|
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_section_order.o
|
||||||
|
@ -56,5 +56,35 @@ END {
|
|||||||
}" $1
|
}" $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 "_Z3foov" "_Z3barv"
|
||||||
check plugin_final_layout.stdout "_Z3barv" "_Z3bazv"
|
check plugin_final_layout.stdout "_Z3barv" "_Z3bazv"
|
||||||
|
check_unique_segment plugin_final_layout_readelf.stdout ".text.plugin_created_unique"
|
||||||
|
@ -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_get_input_section_contents get_input_section_contents = NULL;
|
||||||
static ld_plugin_update_section_order update_section_order = 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_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 onload(struct ld_plugin_tv *tv);
|
||||||
enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
|
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)
|
switch (entry->tv_tag)
|
||||||
{
|
{
|
||||||
case LDPT_REGISTER_CLAIM_FILE_HOOK:
|
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;
|
break;
|
||||||
case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
|
case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
|
||||||
assert((*entry->tv_u.tv_register_all_symbols_read) (all_symbols_read_hook)
|
assert((*entry->tv_u.tv_register_all_symbols_read)
|
||||||
== LDPS_OK);
|
(all_symbols_read_hook)
|
||||||
|
== LDPS_OK);
|
||||||
break;
|
break;
|
||||||
case LDPT_GET_INPUT_SECTION_COUNT:
|
case LDPT_GET_INPUT_SECTION_COUNT:
|
||||||
get_input_section_count = *entry->tv_u.tv_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;
|
get_input_section_name = *entry->tv_u.tv_get_input_section_name;
|
||||||
break;
|
break;
|
||||||
case LDPT_GET_INPUT_SECTION_CONTENTS:
|
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;
|
break;
|
||||||
case LDPT_UPDATE_SECTION_ORDER:
|
case LDPT_UPDATE_SECTION_ORDER:
|
||||||
update_section_order = *entry->tv_u.tv_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:
|
case LDPT_ALLOW_SECTION_ORDERING:
|
||||||
allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
|
allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -86,7 +99,9 @@ onload(struct ld_plugin_tv *tv)
|
|||||||
|| get_input_section_name == NULL
|
|| get_input_section_name == NULL
|
||||||
|| get_input_section_contents == NULL
|
|| get_input_section_contents == NULL
|
||||||
|| update_section_order == 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");
|
fprintf(stderr, "Some interfaces are missing\n");
|
||||||
return LDPS_ERR;
|
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. */
|
/* Inform the linker to prepare for section reordering. */
|
||||||
(*allow_section_ordering)();
|
(*allow_section_ordering)();
|
||||||
|
/* Inform the linker to prepare to map some sections to unique
|
||||||
|
segments. */
|
||||||
|
(*allow_unique_segment_for_sections)();
|
||||||
is_ordering_specified = 1;
|
is_ordering_specified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,8 +178,11 @@ enum ld_plugin_status
|
|||||||
all_symbols_read_hook(void)
|
all_symbols_read_hook(void)
|
||||||
{
|
{
|
||||||
if (num_entries == 3)
|
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;
|
return LDPS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,13 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
2012-08-24 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
|
2012-08-24 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
|
||||||
|
|
||||||
* opcode/arm.h (ARM_CPU_IS_ANY): New define.
|
* opcode/arm.h (ARM_CPU_IS_ANY): New define.
|
||||||
|
@ -318,6 +318,33 @@ typedef
|
|||||||
enum ld_plugin_status
|
enum ld_plugin_status
|
||||||
(*ld_plugin_allow_section_ordering) (void);
|
(*ld_plugin_allow_section_ordering) (void);
|
||||||
|
|
||||||
|
/* The linker's interface for specifying that a subset of sections is
|
||||||
|
to be mapped to a unique segment. If the plugin wants to call
|
||||||
|
unique_segment_for_sections, it must call this function from a
|
||||||
|
claim_file_handler or when it is first loaded. */
|
||||||
|
|
||||||
|
typedef
|
||||||
|
enum ld_plugin_status
|
||||||
|
(*ld_plugin_allow_unique_segment_for_sections) (void);
|
||||||
|
|
||||||
|
/* The linker's interface for specifying that a specific set of sections
|
||||||
|
must be mapped to a unique segment. ELF segments do not have names
|
||||||
|
and the NAME is used as the name of the newly created output section
|
||||||
|
that is then placed in the unique PT_LOAD 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 that would be set by default is not possible. The
|
||||||
|
parameter SEGMENT_ALIGNMENT when non-zero will override the default. */
|
||||||
|
|
||||||
|
typedef
|
||||||
|
enum ld_plugin_status
|
||||||
|
(*ld_plugin_unique_segment_for_sections) (
|
||||||
|
const char* segment_name,
|
||||||
|
uint64_t segment_flags,
|
||||||
|
uint64_t segment_alignment,
|
||||||
|
const struct ld_plugin_section * section_list,
|
||||||
|
unsigned int num_sections);
|
||||||
|
|
||||||
enum ld_plugin_level
|
enum ld_plugin_level
|
||||||
{
|
{
|
||||||
LDPL_INFO,
|
LDPL_INFO,
|
||||||
@ -355,7 +382,9 @@ enum ld_plugin_tag
|
|||||||
LDPT_GET_INPUT_SECTION_CONTENTS,
|
LDPT_GET_INPUT_SECTION_CONTENTS,
|
||||||
LDPT_UPDATE_SECTION_ORDER,
|
LDPT_UPDATE_SECTION_ORDER,
|
||||||
LDPT_ALLOW_SECTION_ORDERING,
|
LDPT_ALLOW_SECTION_ORDERING,
|
||||||
LDPT_GET_SYMBOLS_V2
|
LDPT_GET_SYMBOLS_V2,
|
||||||
|
LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS,
|
||||||
|
LDPT_UNIQUE_SEGMENT_FOR_SECTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The plugin transfer vector. */
|
/* The plugin transfer vector. */
|
||||||
@ -385,6 +414,8 @@ struct ld_plugin_tv
|
|||||||
ld_plugin_get_input_section_contents tv_get_input_section_contents;
|
ld_plugin_get_input_section_contents tv_get_input_section_contents;
|
||||||
ld_plugin_update_section_order tv_update_section_order;
|
ld_plugin_update_section_order tv_update_section_order;
|
||||||
ld_plugin_allow_section_ordering tv_allow_section_ordering;
|
ld_plugin_allow_section_ordering tv_allow_section_ordering;
|
||||||
|
ld_plugin_allow_unique_segment_for_sections tv_allow_unique_segment_for_sections;
|
||||||
|
ld_plugin_unique_segment_for_sections tv_unique_segment_for_sections;
|
||||||
} tv_u;
|
} tv_u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user