This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: gold input section handling
David Miller <davem@davemloft.net> writes:
> From: Ian Lance Taylor <iant@google.com>
> Date: Mon, 14 Apr 2008 09:45:05 -0700
>
>> Because the Linux kernel is not reliable about setting section flags
>> in assembler source, gold has exceptions such that it will combine
>> sections with zero flags with sections with non-zero flags if they
>> have the same name.
>>
>> Because gcc uses an optimization for the .eh_frame section, making it
>> read-only possible and read-write when necessary, gold has an
>> exception for the .eh_frame section.
>
> I think the fact that gold needs two exceptions already, and we know
> of other cases that break, are good indications that it may not be
> tenable, in the end, to enforce this rule.
>
> There seems to be quite some precendence of using different section
> flags in different instances of a section.
I saw your later post, but this seems like a reasonable argument to
me. I changed gold so that it ignores SHF_WRITE and SHF_EXECINSTR
when merging sections. It still pays attention to SHF_ALLOC, except
for sections with zero flags.
I committed the attached patch.
Ian
2008-04-14 Ian Lance Taylor <iant@google.com>
* layout.cc (Layout::Layout): Initialize sections_are_attached_.
(Layout::get_output_section): Ignore SHF_WRITE and SHF_EXECINSTR
in the name/type/flags to section mapping. Don't call
allocate_output_section.
(Layout::choose_output_section): Change parameter from adjust_name
to is_input_section. Don't permit input sections after sections
are attached to segments. Don't call allocate_output_section.
(Layout::layout_eh_frame): Call update_flags_for_input_section,
not write_enable_output_section.
(Layout::make_output_section): Don't push to
unattached_section_list_ nor call attach_to_segment. Call
attach_section_to_segment if sections are attached.
(Layout::attach_sections_to_segments): New function.
(Layout::attach_section_to_segment): New function.
(Layout::attach_allocated_section_to_segment): Rename from
attach_to_segment. Remove flags parameter.
(Layout::allocate_output_section): Remove function.
(Layout::write_enable_output_section): Remove function.
* layout.h (class Layout): Update for above changes. Add new
field sections_are_attached_.
* output.h (Output_section::update_flags_for_input_section): New
function.
* output.cc (Output_section::add_input_section): Call
update_flags_for_input_section.
* gold.cc (queue_middle_tasks): Call attach_sections_to_segments.
Index: gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.51
diff -p -u -r1.51 gold.cc
--- gold.cc 4 Mar 2008 18:21:43 -0000 1.51
+++ gold.cc 15 Apr 2008 03:59:36 -0000
@@ -212,6 +212,9 @@ queue_middle_tasks(const General_options
// Define symbols from any linker scripts.
layout->define_script_symbols(symtab);
+ // Attach sections to segments.
+ layout->attach_sections_to_segments();
+
if (!parameters->options().relocatable())
{
// Predefine standard symbols.
Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.97
diff -p -u -r1.97 layout.cc
--- layout.cc 9 Apr 2008 00:26:48 -0000 1.97
+++ layout.cc 15 Apr 2008 03:59:36 -0000
@@ -79,10 +79,10 @@ Layout::Layout(const General_options& op
: options_(options), script_options_(script_options), namepool_(),
sympool_(), dynpool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_(),
- unattached_section_list_(), special_output_list_(),
- section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL),
- dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL),
- eh_frame_section_(NULL), eh_frame_data_(NULL),
+ unattached_section_list_(), sections_are_attached_(false),
+ special_output_list_(), section_headers_(NULL), tls_segment_(NULL),
+ symtab_section_(NULL), dynsym_section_(NULL), dynamic_section_(NULL),
+ dynamic_data_(NULL), eh_frame_section_(NULL), eh_frame_data_(NULL),
added_eh_frame_data_(false), eh_frame_hdr_section_(NULL),
build_id_note_(NULL), group_signatures_(), output_file_size_(-1),
input_requires_executable_stack_(false),
@@ -234,7 +234,15 @@ Output_section*
Layout::get_output_section(const char* name, Stringpool::Key name_key,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags)
{
- const Key key(name_key, std::make_pair(type, flags));
+ elfcpp::Elf_Xword lookup_flags = flags;
+
+ // Ignoring SHF_WRITE and SHF_EXECINSTR here means that we combine
+ // read-write with read-only sections. Some other ELF linkers do
+ // not do this. FIXME: Perhaps there should be an option
+ // controlling this.
+ lookup_flags &= ~(elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR);
+
+ const Key key(name_key, std::make_pair(type, lookup_flags));
const std::pair<Key, Output_section*> v(key, NULL);
std::pair<Section_name_map::iterator, bool> ins(
this->section_name_map_.insert(v));
@@ -268,11 +276,7 @@ Layout::get_output_section(const char* n
Section_name_map::iterator p =
this->section_name_map_.find(zero_key);
if (p != this->section_name_map_.end())
- {
- os = p->second;
- if ((flags & elfcpp::SHF_ALLOC) != 0)
- this->allocate_output_section(os, flags);
- }
+ os = p->second;
}
}
@@ -285,17 +289,22 @@ Layout::get_output_section(const char* n
// 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. ADJUST_NAME is true if we should apply the
-// standard name mappings in Layout::output_section_name. This will
-// return NULL if the input section should be discarded.
+// linker created section. IS_INPUT_SECTION is true if we are
+// choosing an output section for an input section found in a input
+// file. This will return NULL if the input section should be
+// discarded.
Output_section*
Layout::choose_output_section(const Relobj* relobj, const char* name,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
- bool adjust_name)
+ bool is_input_section)
{
- // We should ignore some flags. FIXME: This will need some
- // adjustment for ld -r.
+ // We should not see any input sections after we have attached
+ // 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_LINK_ORDER
| elfcpp::SHF_GROUP
@@ -324,17 +333,7 @@ Layout::choose_output_section(const Relo
if (output_section_slot != NULL)
{
if (*output_section_slot != NULL)
- {
- // If the output section was created unallocated, and we
- // are now allocating it, then we need to clear the
- // address set in the constructor and remove it from the
- // unattached section list.
- if (((*output_section_slot)->flags() & elfcpp::SHF_ALLOC) == 0
- && (flags & elfcpp::SHF_ALLOC) != 0)
- this->allocate_output_section(*output_section_slot, flags);
-
- return *output_section_slot;
- }
+ return *output_section_slot;
// We don't put sections found in the linker script into
// SECTION_NAME_MAP_. That keeps us from getting confused
@@ -356,7 +355,7 @@ Layout::choose_output_section(const Relo
// output section.
size_t len = strlen(name);
- if (adjust_name && !parameters->options().relocatable())
+ if (is_input_section && !parameters->options().relocatable())
name = Layout::output_section_name(name, &len);
Stringpool::Key name_key;
@@ -550,16 +549,6 @@ Layout::layout_eh_frame(Sized_relobj<siz
if (os == NULL)
return NULL;
- // On some targets gcc assumes that a read-only .eh_frame section
- // will be merged with a read-write .eh_frame section.
- if ((shdr.get_sh_flags() & elfcpp::SHF_WRITE) != 0
- && (os->flags() & elfcpp::SHF_WRITE) == 0)
- {
- elfcpp::Elf_Xword new_flags = os->flags() | elfcpp::SHF_WRITE;
- this->write_enable_output_section(os, new_flags);
- os->set_flags(new_flags);
- }
-
if (this->eh_frame_section_ == NULL)
{
this->eh_frame_section_ = os;
@@ -606,6 +595,8 @@ Layout::layout_eh_frame(Sized_relobj<siz
reloc_shndx,
reloc_type))
{
+ os->update_flags_for_input_section(shdr.get_sh_flags());
+
// We found a .eh_frame section we are going to optimize, so now
// we can add the set of optimized sections to the output
// section. We need to postpone adding this until we've found a
@@ -689,11 +680,6 @@ Layout::make_output_section(const char*
this->section_list_.push_back(os);
- if ((flags & elfcpp::SHF_ALLOC) == 0)
- this->unattached_section_list_.push_back(os);
- else
- this->attach_to_segment(os, flags);
-
// The GNU linker by default sorts some sections by priority, so we
// do the same. We need to know that this might happen before we
// attach any input sections.
@@ -704,14 +690,46 @@ Layout::make_output_section(const char*
|| strcmp(name, ".fini_array") == 0))
os->set_may_sort_attached_input_sections();
+ // If we have already attached the sections to segments, then we
+ // need to attach this one now. This happens for sections created
+ // directly by the linker.
+ if (this->sections_are_attached_)
+ this->attach_section_to_segment(os);
+
return os;
}
+// Attach output sections to segments. This is called after we have
+// seen all the input sections.
+
+void
+Layout::attach_sections_to_segments()
+{
+ for (Section_list::iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ this->attach_section_to_segment(*p);
+
+ this->sections_are_attached_ = true;
+}
+
+// Attach an output section to a segment.
+
+void
+Layout::attach_section_to_segment(Output_section* os)
+{
+ if ((os->flags() & elfcpp::SHF_ALLOC) == 0)
+ this->unattached_section_list_.push_back(os);
+ else
+ this->attach_allocated_section_to_segment(os);
+}
+
// Attach an allocated output section to a segment.
void
-Layout::attach_to_segment(Output_section* os, elfcpp::Elf_Xword flags)
+Layout::attach_allocated_section_to_segment(Output_section* os)
{
+ elfcpp::Elf_Xword flags = os->flags();
gold_assert((flags & elfcpp::SHF_ALLOC) != 0);
if (parameters->options().relocatable())
@@ -811,58 +829,6 @@ Layout::make_output_section_for_script(c
return os;
}
-// We have to move an existing output section from the unallocated
-// list to the allocated list.
-
-void
-Layout::allocate_output_section(Output_section* os, elfcpp::Elf_Xword flags)
-{
- os->reset_address_and_file_offset();
-
- Section_list::iterator p = std::find(this->unattached_section_list_.begin(),
- this->unattached_section_list_.end(),
- os);
- gold_assert(p != this->unattached_section_list_.end());
- this->unattached_section_list_.erase(p);
-
- this->attach_to_segment(os, flags);
-}
-
-// We have to move an existing output section from the read-only
-// segment to the writable segment.
-
-void
-Layout::write_enable_output_section(Output_section* os,
- elfcpp::Elf_Xword flags)
-{
- gold_assert((os->flags() & elfcpp::SHF_WRITE) == 0);
- gold_assert(os->type() == elfcpp::SHT_PROGBITS);
- gold_assert((flags & elfcpp::SHF_WRITE) != 0);
- gold_assert((flags & elfcpp::SHF_ALLOC) != 0);
-
- if (parameters->options().relocatable())
- return;
-
- if (this->script_options_->saw_sections_clause())
- return;
-
- Segment_list::iterator p;
- for (p = this->segment_list_.begin();
- p != this->segment_list_.end();
- ++p)
- {
- if ((*p)->type() == elfcpp::PT_LOAD
- && ((*p)->flags() & elfcpp::PF_W) == 0)
- {
- (*p)->remove_output_section(os);
- break;
- }
- }
- gold_assert(p != this->segment_list_.end());
-
- this->attach_to_segment(os, flags);
-}
-
// Return the number of segments we expect to see.
size_t
Index: layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.53
diff -p -u -r1.53 layout.h
--- layout.h 9 Apr 2008 00:26:48 -0000 1.53
+++ layout.h 15 Apr 2008 03:59:36 -0000
@@ -340,6 +340,10 @@ class Layout
static elfcpp::Elf_Word
section_flags_to_segment(elfcpp::Elf_Xword flags);
+ // Attach sections to segments.
+ void
+ attach_sections_to_segments();
+
private:
Layout(const Layout&);
Layout& operator=(const Layout&);
@@ -475,7 +479,7 @@ class Layout
Output_section*
choose_output_section(const Relobj* relobj, const char* name,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
- bool adjust_name);
+ bool is_input_section);
// Create a new Output_section.
Output_section*
@@ -484,15 +488,11 @@ class Layout
// Attach a section to a segment.
void
- attach_to_segment(Output_section*, elfcpp::Elf_Xword flags);
-
- // Allocate a previously unallocated output section.
- void
- allocate_output_section(Output_section*, elfcpp::Elf_Xword flags);
+ attach_section_to_segment(Output_section*);
- // Turn a read-only output section into a read-write output section.
+ // Attach an allocated section to a segment.
void
- write_enable_output_section(Output_section*, elfcpp::Elf_Xword flags);
+ attach_allocated_section_to_segment(Output_section*);
// Set the final file offsets of all the segments.
off_t
@@ -578,6 +578,8 @@ class Layout
// The list of output sections which are not attached to any output
// segment.
Section_list unattached_section_list_;
+ // Whether we have attached the sections to the segments.
+ bool sections_are_attached_;
// The list of unattached Output_data objects which require special
// handling because they are not Output_sections.
Data_list special_output_list_;
Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.71
diff -p -u -r1.71 output.cc
--- output.cc 11 Apr 2008 22:55:13 -0000 1.71
+++ output.cc 15 Apr 2008 03:59:37 -0000
@@ -1673,10 +1673,7 @@ Output_section::add_input_section(Sized_
this->addralign_ = addralign;
typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags();
- this->flags_ |= (sh_flags
- & (elfcpp::SHF_WRITE
- | elfcpp::SHF_ALLOC
- | elfcpp::SHF_EXECINSTR));
+ this->update_flags_for_input_section(sh_flags);
uint64_t entsize = shdr.get_sh_entsize();
Index: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.62
diff -p -u -r1.62 output.h
--- output.h 11 Apr 2008 22:55:13 -0000 1.62
+++ output.h 15 Apr 2008 03:59:37 -0000
@@ -1714,6 +1714,16 @@ class Output_section : public Output_dat
set_flags(elfcpp::Elf_Xword flags)
{ this->flags_ = flags; }
+ // Update the output section flags based on input section flags.
+ void
+ update_flags_for_input_section(elfcpp::Elf_Xword flags)
+ {
+ this->flags_ |= (flags
+ & (elfcpp::SHF_WRITE
+ | elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR));
+ }
+
// Return the entsize field.
uint64_t
entsize() const