This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
gold patch committed: Fix handling of odd PHDRS clauses
- From: Ian Lance Taylor <iant at google dot com>
- To: binutils at sourceware dot org
- Date: Tue, 28 Jun 2011 17:41:00 -0700
- Subject: gold patch committed: Fix handling of odd PHDRS clauses
This patch fixes gold to handle odd PHDRS clauses which define two
segments which can not be distinguished: same flags, same address.
According to PR 12898 this happens when building kvm. Committed to
mainline.
Ian
2011-06-28 Ian Lance Taylor <iant@google.com>
PR gold/12898
* layout.cc (Layout::segment_precedes): Don't crash if a linker
script create indistinguishable segments.
(Layout::set_segment_offsets): Use stable_sort when sorting
segments. Pass this to Compare_segments constructor.
* layout.h (class Layout): Make segment_precedes non-static.
(class Compare_segments): Change from struct to class. Add
layout_ field. Add constructor.
* script-sections.cc
(Script_sections::attach_sections_using_phdrs_clause): Rename
local orphan to is_orphan. Don't report failure to put empty
section in segment. On attachment failure, report name of
section, and attach to first PT_LOAD segment.
Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.206
diff -p -u -r1.206 layout.cc
--- layout.cc 25 Jun 2011 00:40:56 -0000 1.206
+++ layout.cc 29 Jun 2011 00:36:10 -0000
@@ -2751,7 +2751,7 @@ Layout::create_incremental_info_sections
// Return whether SEG1 should be before SEG2 in the output file. This
// is based entirely on the segment type and flags. When this is
-// called the segment addresses has normally not yet been set.
+// called the segment addresses have normally not yet been set.
bool
Layout::segment_precedes(const Output_segment* seg1,
@@ -2877,8 +2877,10 @@ Layout::segment_precedes(const Output_se
return (flags1 & elfcpp::PF_R) == 0;
// We shouldn't get here--we shouldn't create segments which we
- // can't distinguish.
- gold_unreachable();
+ // can't distinguish. Unless of course we are using a weird linker
+ // script.
+ gold_assert(this->script_options_->saw_phdrs_clause());
+ return false;
}
// Increase OFF so that it is congruent to ADDR modulo ABI_PAGESIZE.
@@ -2902,9 +2904,11 @@ off_t
Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
unsigned int* pshndx)
{
- // Sort them into the final order.
- std::sort(this->segment_list_.begin(), this->segment_list_.end(),
- Layout::Compare_segments());
+ // Sort them into the final order. We use a stable sort so that we
+ // don't randomize the order of indistinguishable segments created
+ // by linker scripts.
+ std::stable_sort(this->segment_list_.begin(), this->segment_list_.end(),
+ Layout::Compare_segments(this));
// Find the PT_LOAD segments, and set their addresses and offsets
// and their section's addresses and offsets.
Index: layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.94
diff -p -u -r1.94 layout.h
--- layout.h 25 Jun 2011 00:40:56 -0000 1.94
+++ layout.h 29 Jun 2011 00:36:10 -0000
@@ -1052,7 +1052,7 @@ class Layout
place_orphan_sections_in_script();
// Return whether SEG1 comes before SEG2 in the output file.
- static bool
+ bool
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
// Use to save and restore segments during relaxation.
@@ -1102,11 +1102,19 @@ class Layout
// A comparison class for segments.
- struct Compare_segments
+ class Compare_segments
{
+ public:
+ Compare_segments(Layout* layout)
+ : layout_(layout)
+ { }
+
bool
operator()(const Output_segment* seg1, const Output_segment* seg2)
- { return Layout::segment_precedes(seg1, seg2); }
+ { return this->layout_->segment_precedes(seg1, seg2); }
+
+ private:
+ Layout* layout_;
};
typedef std::vector<Output_section_data*> Output_section_data_list;
Index: script-sections.cc
===================================================================
RCS file: /cvs/src/src/gold/script-sections.cc,v
retrieving revision 1.52
diff -p -u -r1.52 script-sections.cc
--- script-sections.cc 19 Jun 2011 22:09:17 -0000 1.52
+++ script-sections.cc 29 Jun 2011 00:36:10 -0000
@@ -4050,15 +4050,37 @@ Script_sections::attach_sections_using_p
p != this->sections_elements_->end();
++p)
{
- bool orphan;
+ bool is_orphan;
String_list* old_phdr_names = phdr_names;
- Output_section* os = (*p)->allocate_to_segment(&phdr_names, &orphan);
+ Output_section* os = (*p)->allocate_to_segment(&phdr_names, &is_orphan);
if (os == NULL)
continue;
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment(os->flags());
+
if (phdr_names == NULL)
{
- gold_error(_("allocated section not in any segment"));
+ // Don't worry about empty orphan sections.
+ if (is_orphan && os->current_data_size() > 0)
+ gold_error(_("allocated section %s not in any segment"),
+ os->name());
+
+ // To avoid later crashes drop this section into the first
+ // PT_LOAD segment.
+ for (Phdrs_elements::const_iterator ppe =
+ this->phdrs_elements_->begin();
+ ppe != this->phdrs_elements_->end();
+ ++ppe)
+ {
+ Output_segment* oseg = (*ppe)->segment();
+ if (oseg->type() == elfcpp::PT_LOAD)
+ {
+ oseg->add_output_section_to_load(layout, os, seg_flags);
+ break;
+ }
+ }
+
continue;
}
@@ -4073,7 +4095,7 @@ Script_sections::attach_sections_using_p
// PT_INTERP segment will pick up following orphan sections,
// which does not make sense. If this is not an orphan section,
// we trust the linker script.
- if (orphan)
+ if (is_orphan)
{
// Enable PT_LOAD segments only filtering until we see another
// list of segment names.
@@ -4094,9 +4116,6 @@ Script_sections::attach_sections_using_p
&& r->second->type() != elfcpp::PT_LOAD)
continue;
- elfcpp::Elf_Word seg_flags =
- Layout::section_flags_to_segment(os->flags());
-
if (r->second->type() != elfcpp::PT_LOAD)
r->second->add_output_section_to_nonload(os, seg_flags);
else