Fix SIZEOF_HEADERS in gold. Gold undercounts the number of program headers it's going to add when initially evaluating the SIZEOF_HEADERS expression. As a result, scripts that use it end up skipping a page unnecessarily when the starting address is too low. The undercounting is because it doesn't count the PT_INTERP segment. Then, when finalizing symbols, gold overcounts the program headers: all segments have already been created, but we still count the headers we expected to add from the script. This patch fixes both problems. 2015-06-03 Cary Coutant gold/ * script-sections.cc (Script_sections::Script_sections): Initialize segments_created_. (Script_sections::create_note_and_tls_segments): Set flag when segments are created. (Script_sections::expected_segment_count): Count PT_INTERP. (Script_sections::attach_sections_using_phdrs_clause): Set flag when segments are created. * script-sections.h (Script_sections::segments_created_): New data member. diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 4f29c08..08c31e9 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -3200,7 +3200,8 @@ Script_sections::Script_sections() data_segment_align_start_(), saw_data_segment_align_(false), saw_relro_end_(false), - saw_segment_start_expression_(false) + saw_segment_start_expression_(false), + segments_created_(false) { } @@ -4007,8 +4008,8 @@ Script_sections::create_note_and_tls_segments( saw_tls = true; } - // If we are making a shared library, and we see a section named - // .interp then put the .interp section in a PT_INTERP segment. + // If we see a section named .interp then put the .interp section + // in a PT_INTERP segment. // This is for GNU ld compatibility. if (strcmp((*p)->name(), ".interp") == 0) { @@ -4019,6 +4020,8 @@ Script_sections::create_note_and_tls_segments( oseg->add_output_section_to_nonload(*p, seg_flags); } } + + this->segments_created_ = true; } // Add a program header. The PHDRS clause is syntactically distinct @@ -4046,6 +4049,10 @@ Script_sections::add_phdr(const char* name, size_t namelen, unsigned int type, size_t Script_sections::expected_segment_count(const Layout* layout) const { + // If we've already created the segments, we won't be adding any more. + if (this->segments_created_) + return 0; + if (this->saw_phdrs_clause()) return this->phdrs_elements_->size(); @@ -4057,6 +4064,7 @@ Script_sections::expected_segment_count(const Layout* layout) const bool saw_note = false; bool saw_tls = false; + bool saw_interp = false; for (Layout::Section_list::const_iterator p = sections.begin(); p != sections.end(); ++p) @@ -4080,6 +4088,15 @@ Script_sections::expected_segment_count(const Layout* layout) const saw_tls = true; } } + else if (strcmp((*p)->name(), ".interp") == 0) + { + // There can only be one PT_INTERP segment. + if (!saw_interp) + { + ++ret; + saw_interp = true; + } + } } return ret; @@ -4108,6 +4125,7 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout) p != this->phdrs_elements_->end(); ++p) name_to_segment[(*p)->name()] = (*p)->create_segment(layout); + this->segments_created_ = true; // Walk through the output sections and attach them to segments. // Output sections in the script which do not list segments are diff --git a/gold/script-sections.h b/gold/script-sections.h index 2e07aa2..e247ea5 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -319,6 +319,8 @@ class Script_sections bool saw_relro_end_; // Whether we have seen SEGMENT_START. bool saw_segment_start_expression_; + // Whether we have created all necessary segments. + bool segments_created_; }; // Attributes for memory regions.