Patch to do reorder text and data sections according to a user specified sequence.
Sriraman Tallam
tmsriram@google.com
Sat May 29 01:49:00 GMT 2010
Hi,
I fixed a bug Taras ran into. Here is the new patch.
* gold.h (is_wildcard_string): New function.
* layout.cc (Layout::layout): Pass this pointer to add_input_section.
(Layout::layout_eh_frame): Ditto.
(Layout::find_section_order_index): New method.
(Layout::read_layout_from_file): New method.
* layout.h (Layout::find_section_order_index): New method.
(Layout::read_layout_from_file): New method.
(Layout::input_section_position_): New private member.
(Layout::input_section_glob_): New private member.
* main.cc (main): Call read_layout_from_file here.
* options.h (--section-ordering-file): New option.
* output.cc (Output_section::input_section_order_specified_): New
member.
(Output_section::Output_section): Initialize new member.
(Output_section::add_input_section): Add new parameter.
Keep input sections when --section-ordering-file is used.
(Output_section::set_final_data_size): Sort input sections when
section ordering file is specified.
(Output_section::Input_section_sort_entry): Add new parameter.
Check sorting type.
(Output_section::Input_section_sort_entry::is_before_in_sequence):
New method.
(Output_section::Input_section_sort_compare::operator()): Change to
consider section_order_index.
(Output_section::Input_section_sort_init_fini_compare::operator()):
Change to consider section_order_index.
(Output_section::Input_section_sort_section_order_index_compare
::operator()): New method.
(Output_section::sort_attached_input_sections): Change to sort
according to section order when specified.
(Output_section::add_input_section<32, true>): Add new parameter.
(Output_section::add_input_section<64, true>): Add new parameter.
(Output_section::add_input_section<32, false>): Add new parameter.
(Output_section::add_input_section<64, false>): Add new parameter.
* output.h (Output_section::add_input_section): Add new parameter.
(Output_section::input_section_order_specified): New
method.
(Output_section::set_input_section_order_specified): New method.
(Input_section::Input_section): Initialize section_order_index_.
(Input_section::section_order_index): New method.
(Input_section::set_section_order_index): New method.
(Input_section::section_order_index_): New member.
(Input_section::Input_section_sort_section_order_index_compare): New
struct.
(Output_section::input_section_order_specified_): New member.
* script-sections.cc (is_wildcard_string): Delete and move modified
method to gold.h.
(Output_section_element_input::Output_section_element_input): Modify
call to is_wildcard_string.
(Output_section_element_input::Input_section_pattern
::Input_section_pattern): Ditto.
(Output_section_element_input::Output_section_element_input): Ditto.
* testsuite/Makefile.am (final_layout): New test case.
* testsuite/Makefile.in: Regenerate.
* testsuite/final_layout.cc: New file.
* testsuite/final_layout.sh: New file.
Thanks,
-Sri.
On Mon, May 24, 2010 at 12:26 PM, Taras Glek <tglek@mozilla.com> wrote:
> On 05/21/2010 06:41 PM, Sriraman Tallam wrote:
>>
>> Hi Taras,
>>
>> Did you get a chance to test the timings with the new patch ?
>>
>
> I've only tested it briefly on Friday. I'm having some problems with the new
> patch. It ranges from working perfectly to occasionally taking longer than
> the previous one and/or crashing. I'll let you know more once I have more
> time to play with it
>
> Taras
>>
>> Thanks,
>> -Sri.
>>
>> On Thu, May 13, 2010 at 5:58 PM, Sriraman Tallam<tmsriram@google.com>
>> wrote:
>>
>>>
>>> Hi Ian and Taras,
>>>
>>> Sorry for taking this long to get back. I have modified the patch
>>> to address Taras' timing issue. Basically, I split patterns specified
>>> into glob and non-glob by just looking for wild-card characters in the
>>> pattern. Non-glob look-ups are through a hash table and fast. Glob
>>> patterns are be searched linearly. So, if you specify non-glob symbol
>>> names in the section ordering file, the link should be faster than
>>> before.
>>>
>>> Further, I have prioritized non-glob patters over glob patterns.
>>> Let me explain with an example :
>>>
>>> If object main.o has sections .text._foov, .text._barv, and
>>> .text._zapv and the seection ordering file is :
>>> ===============================
>>> *bar*
>>> .text.*
>>> .text._barv
>>> ===============================
>>>
>>> Then, .text._barv will be the last section in .text even though it
>>> matches the first glob pattern.
>>>
>>>
>>> The changes are :
>>>
>>> * gold.h (is_wildcard_string): New function.
>>> * layout.cc (Layout::layout): Pass this pointer to
>>> add_input_section.
>>> (Layout::layout_eh_frame): Ditto.
>>> (Layout::find_section_order_index): New method.
>>> (Layout::read_layout_from_file): New method.
>>> * layout.h (Layout::find_section_order_index): New method.
>>> (Layout::read_layout_from_file): New method.
>>> (Layout::input_section_position_): New private member.
>>> (Layout::input_section_glob_): New private member.
>>> * main.cc (main): Call read_layout_from_file here.
>>> * options.h (--section-ordering-file): New option.
>>> * output.cc (Output_section::input_section_order_specified_): New
>>> member.
>>> (Output_section::Output_section): Initialize new member.
>>> (Output_section::add_input_section): Add new parameter.
>>> Keep input sections when --section-ordering-file is used.
>>> (Output_section::set_final_data_size): Sort input sections when
>>> section ordering file is specified.
>>> (Output_section::Input_section_sort_entry): Add new parameter.
>>> Check sorting type.
>>> (Output_section::Input_section_sort_entry::is_before_in_sequence):
>>> New method.
>>> (Output_section::Input_section_sort_compare::operator()): Change
>>> to
>>> consider section_order_index.
>>>
>>> (Output_section::Input_section_sort_init_fini_compare::operator()):
>>> Change to consider section_order_index.
>>> (Output_section::Input_section_sort_section_order_index_compare
>>> ::operator()): New method.
>>> (Output_section::sort_attached_input_sections): Change to sort
>>> according to section order when specified.
>>> (Output_section::add_input_section<32, true>): Add new parameter.
>>> (Output_section::add_input_section<64, true>): Add new parameter.
>>> (Output_section::add_input_section<32, false>): Add new parameter.
>>> (Output_section::add_input_section<64, false>): Add new parameter.
>>> * output.h (Output_section::add_input_section): Add new parameter.
>>> (Output_section::input_section_order_specified): New
>>> method.
>>> (Output_section::set_input_section_order_specified): New method.
>>> (Input_section::Input_section): Initialize section_order_index_.
>>> (Input_section::section_order_index): New method.
>>> (Input_section::set_section_order_index): New method.
>>> (Input_section::section_order_index_): New member.
>>> (Input_section::Input_section_sort_section_order_index_compare):
>>> New
>>> struct.
>>> (Output_section::input_section_order_specified_): New member.
>>> * script-sections.cc (is_wildcard_string): Delete and move
>>> modified
>>> method to gold.h.
>>> (Output_section_element_input::Output_section_element_input):
>>> Modify
>>> call to is_wildcard_string.
>>> (Output_section_element_input::Input_section_pattern
>>> ::Input_section_pattern): Ditto.
>>> (Output_section_element_input::Output_section_element_input):
>>> Ditto.
>>> * testsuite/Makefile.am (final_layout): New test case.
>>> * testsuite/Makefile.in: Regenerate.
>>> * testsuite/final_layout.cc: New file.
>>> * testsuite/final_layout.sh: New file.
>>>
>>> Please let me know what you think.
>>>
>>> Thanks,
>>> -Sri.
>>>
>>>
>>>
>>> On Tue, Mar 2, 2010 at 7:43 PM, Sriraman Tallam<tmsriram@google.com>
>>> wrote:
>>>
>>>>
>>>> Hi Ian,
>>>>
>>>> I finally got around to making the changes you specified. Please
>>>> take a look when you get a chance.
>>>>
>>>> * layout.cc (Layout::read_layout_from_file): New method.
>>>> (Layout::layout): Pass this pointer to add_input_section.
>>>> (Layout::layout_eh_frame): Ditto.
>>>> * layout.h (Layout::read_layout_from_file): New method.
>>>> (Layout::input_section_order): New method.
>>>> (Layout::input_section_order_): New private member.
>>>> * main.cc (main): Call read_layout_from_file here.
>>>> * options.h (--section-ordering-file): New option.
>>>> * output.cc (Output_section::input_section_order_specified_): New
>>>> member.
>>>> (Output_section::add_input_section): Add new parameter.
>>>> Keep input sections when --section-ordering-file is used.
>>>> (Output_section::set_final_data_size): Sort input sections when
>>>> section ordering file is specified.
>>>> (Output_section::Input_section_sort_entry::section_order_index_):
>>>> New
>>>> member.
>>>> (Output_section::Input_section_sort_entry::section_order_index):
>>>> New
>>>> method.
>>>> (Output_section::Input_section_sort_compare::operator()): Change
>>>> to
>>>> consider section_order_index.
>>>>
>>>> (Output_section::Input_section_sort_init_fini_compare::operator()):
>>>> Change to consider section_order_index.
>>>> (Output_section::Input_section_sort_section_order_index_compare
>>>> ::operator()): New method.
>>>> (Output_section::sort_attached_input_sections): Change to sort
>>>> according to section order when specified.
>>>> * output.h (Output_section::input_section_order_specified): New
>>>> method.
>>>> (Output_section::set_input_section_order_specified): New method.
>>>> (Input_section::glob_pattern_number): New method.
>>>> (Input_section::set_glob_pattern_number): New method.
>>>> (Input_section::glob_pattern_number_): New member.
>>>> (Input_section::Input_section_sort_section_order_index_compare):
>>>> New
>>>> struct.
>>>> (Output_section::input_section_order_specified_): New member.
>>>> * testsuite/Makefile.am (final_layout): New test case.
>>>> * testsuite/Makefile.in: Regenerate.
>>>> * testsuite/final_layout.cc: New file.
>>>> * testsuite/final_layout.sh: New file
>>>>
>>>>
>>>> Thanks,
>>>> -Sriraman.
>>>>
>>>>
>>>> On Thu, Feb 11, 2010 at 9:29 PM, Ian Lance Taylor<iant@google.com>
>>>> wrote:
>>>>
>>>>>
>>>>> Sriraman Tallam<tmsriram@google.com> writes:
>>>>>
>>>>>
>>>>>>
>>>>>> I have attached a patch to reorder text and data sections in the
>>>>>> linker according to a user specified sequence. I have added a new
>>>>>> option --final-layout to do this. Currently, this could be done using
>>>>>> linker scripts but this patch makes it really easy to do this. Let me
>>>>>> explain using a simple example.
>>>>>>
>>>>>> test.cc
>>>>>>
>>>>>> void foo()
>>>>>> { }
>>>>>>
>>>>>> void bar()
>>>>>> { }
>>>>>>
>>>>>> int main()
>>>>>> {
>>>>>> return 0;
>>>>>> }
>>>>>>
>>>>>> $ g++ -ffunction-sections test.cc
>>>>>> $ nm -n a.out
>>>>>> ...
>>>>>> 000000000040038c T _Z3foov
>>>>>> 0000000000400392 T _Z3barv
>>>>>> ....
>>>>>>
>>>>>> foo is laid to be before bar. Now, I can change this order as follows.
>>>>>>
>>>>>> $ (echo "_Z3barv"&& echo "_Z3foov")> sequence.txt
>>>>>> $ g++ -ffunction-sections test.cc -Wl,--final-layout,sequence.txt
>>>>>> $ nm -n a.out
>>>>>> ...
>>>>>> 0000000000400658 T _Z3barv
>>>>>> 000000000040065e T _Z3foov
>>>>>> ...
>>>>>>
>>>>>> The order is changed.
>>>>>>
>>>>>> This can be done for text or data sections.
>>>>>>
>>>>>
>>>>> As I understand it, in linker terms, you are sorting the sections by
>>>>> suffixes. When two input sections are in the same output section, and
>>>>> both input sections have suffixes which appear in the file, then the
>>>>> input sections are sorted in the order in which the suffixes appear in
>>>>> the file.
>>>>>
>>>>> I think it would be more natural to sort the input sections by name
>>>>> rather than by suffix. Since you don't want to fuss with writing
>>>>> ".text." all the time, suppose we say that we sort the input sections
>>>>> by name, and we match the input section names using glob patterns. We
>>>>> already use glob patterns in linker scripts, so that is not a big
>>>>> stretch.
>>>>>
>>>>> Just a few comments on the rest of the patch.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> +// Read the sequence of input sections from the file specified with
>>>>>> +// --final-layout.
>>>>>> +
>>>>>> +bool
>>>>>> +Layout::read_layout_from_file()
>>>>>> +{
>>>>>> + const char* filename = parameters->options().final_layout();
>>>>>> + char *buf = NULL;
>>>>>> + size_t len = 0;
>>>>>> + FILE* fp = fopen(filename, "r");
>>>>>> +
>>>>>> + if (fp == NULL)
>>>>>> + {
>>>>>> + gold_error(_("Error opening layout file : %s\n"), filename);
>>>>>> + gold_exit(false);
>>>>>> + }
>>>>>> +
>>>>>> + while (getline(&buf,&len, fp) != -1)
>>>>>> + {
>>>>>> + buf[strlen(buf) - 1] = 0;
>>>>>> + this->input_section_order_.push_back(std::string(buf));
>>>>>> + }
>>>>>> +
>>>>>> + if (buf != NULL)
>>>>>> + free(buf);
>>>>>> +
>>>>>> + fclose(fp);
>>>>>> + return true;
>>>>>> +}
>>>>>>
>>>>>
>>>>> The getline function is insufficient portable for use in gold. Search
>>>>> for std::getline in options.cc for an alternate approach you can use.
>>>>> Emulate the error message style you see there too--no capital letter,
>>>>> name the file, no space before colon, no \n. And if you really want
>>>>> to exit on failure, call gold_fatal.
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> +// If --final-layout option is used, reorder the input sections in
>>>>>> +// .text, .data, .bss and .rodata according to the specified
>>>>>> sequence.
>>>>>> +
>>>>>> +void
>>>>>> +Layout::section_reorder()
>>>>>> +{
>>>>>> + this->read_layout_from_file();
>>>>>> +
>>>>>> + for (Section_list::iterator p = this->section_list_.begin();
>>>>>> + p != this->section_list_.end();
>>>>>> + ++p)
>>>>>> + {
>>>>>> + if (strcmp(".text", (*p)->name()) == 0
>>>>>> + || strcmp(".data", (*p)->name()) == 0
>>>>>> + || strcmp(".bss", (*p)->name()) == 0
>>>>>> + || strcmp(".rodata", (*p)->name()) == 0)
>>>>>> + (*p)->reorder_layout(this);
>>>>>> + }
>>>>>> +}
>>>>>>
>>>>>
>>>>> Why restrict this to those output sections? Why not sort input
>>>>> sections in any output section?
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> + DEFINE_string(final_layout, options::TWO_DASHES, '\0', NULL,
>>>>>> + N_("Layout functions and data in the order specified."),
>>>>>> + N_("FILENAME"));
>>>>>>
>>>>>
>>>>> I'm not sure I care for --final-layout as the option name. Perhaps
>>>>> --section-ordering-file? Perhaps somebody else has a better idea.
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> + // the future, we keep track of the sections. If the
>>>>>> --final-layout
>>>>>> + // option is used to specify the order of sections, we need to keep
>>>>>> + // track of sections.
>>>>>> if (have_sections_script
>>>>>> || !this->input_sections_.empty()
>>>>>> || this->may_sort_attached_input_sections()
>>>>>> || this->must_sort_attached_input_sections()
>>>>>> || parameters->options().user_set_Map()
>>>>>> - || parameters->target().may_relax())
>>>>>> - this->input_sections_.push_back(Input_section(object, shndx,
>>>>>> - shdr.get_sh_size(),
>>>>>> - addralign));
>>>>>> + || parameters->target().may_relax()
>>>>>> + || parameters->options().final_layout())
>>>>>> + {
>>>>>> + Input_section isecn(object, shndx, shdr.get_sh_size(),
>>>>>> addralign);
>>>>>> + isecn.set_section_name(secname);
>>>>>> + this->input_sections_.push_back(isecn);
>>>>>> + }
>>>>>>
>>>>>
>>>>> Don't save the string here, that's just going to bloat memory usage.
>>>>> Instead, when you read the file, give each line a number. Then match
>>>>> the section name which you have here against the list of patterns. If
>>>>> you find a match, store the number in the Input_section structure.
>>>>> Also, if you find a match, set a flag in the output section. Then
>>>>> sort the sections, by number, in a function called from
>>>>> set_final_data_size.
>>>>>
>>>>> You will see that there is already some section ordering in that
>>>>> function, which is used to implement constructor/destructor priority
>>>>> ordering. I guess the priority ordering should take precedence.
>>>>> Maybe.
>>>>>
>>>>> Ian
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>
>
-------------- next part --------------
Index: gold.h
===================================================================
RCS file: /cvs/src/src/gold/gold.h,v
retrieving revision 1.43
diff -u -u -p -r1.43 gold.h
--- gold.h 18 May 2010 19:18:31 -0000 1.43
+++ gold.h 29 May 2010 01:44:54 -0000
@@ -401,6 +401,15 @@ string_hash(const Char_type* s)
return h;
}
+// Return whether STRING contains a wildcard character. This is used
+// to speed up matching.
+
+inline bool
+is_wildcard_string(const char* s)
+{
+ return strpbrk(s, "?*[") != NULL;
+}
+
} // End namespace gold.
#endif // !defined(GOLD_GOLD_H)
Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.169
diff -u -u -p -r1.169 layout.cc
--- layout.cc 24 Apr 2010 14:32:23 -0000 1.169
+++ layout.cc 29 May 2010 01:44:54 -0000
@@ -26,8 +26,10 @@
#include <cstring>
#include <algorithm>
#include <iostream>
+#include <fstream>
#include <utility>
#include <fcntl.h>
+#include <fnmatch.h>
#include <unistd.h>
#include "libiberty.h"
#include "md5.h"
@@ -669,7 +671,8 @@ Layout::layout(Sized_relobj<size, big_en
// FIXME: Handle SHF_LINK_ORDER somewhere.
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx,
- this->script_options_->saw_sections_clause());
+ this->script_options_->saw_sections_clause(),
+ this);
this->have_added_input_section_ = true;
return os;
@@ -887,7 +890,7 @@ Layout::layout_eh_frame(Sized_relobj<siz
// Add it as a normal section.
bool saw_sections_clause = this->script_options_->saw_sections_clause();
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx,
- saw_sections_clause);
+ saw_sections_clause, this);
this->have_added_input_section_ = true;
}
@@ -1642,6 +1645,65 @@ Layout::relaxation_loop_body(
return off;
}
+// Search the list of patterns and find the postion of the given section
+// name in the output section. If the section name matches a glob
+// pattern and a non-glob name, then the non-glob position takes
+// precedence. Return 0 if no match is found.
+
+unsigned int
+Layout::find_section_order_index(const std::string& section_name)
+{
+ std::map<std::string, unsigned int>::iterator map_it;
+ map_it = this->input_section_position_.find(section_name);
+ if (map_it != this->input_section_position_.end())
+ return map_it->second;
+
+ // Absolute match failed. Linear search the glob patterns.
+ std::vector<std::string>::iterator it;
+ for (it = this->input_section_glob_.begin();
+ it != this->input_section_glob_.end();
+ ++it)
+ {
+ if (fnmatch((*it).c_str(), section_name.c_str(), FNM_NOESCAPE) == 0)
+ {
+ map_it = this->input_section_position_.find(*it);
+ gold_assert(map_it != this->input_section_position_.end());
+ return map_it->second;
+ }
+ }
+ return 0;
+}
+
+// Read the sequence of input sections from the file specified with
+// --section-ordering-file.
+
+void
+Layout::read_layout_from_file()
+{
+ const char* filename = parameters->options().section_ordering_file();
+ std::ifstream in;
+ std::string line;
+
+ in.open(filename);
+ std::getline(in, line); // this chops off the trailing \n, if any
+ if (!in)
+ gold_fatal(_("unable to open --section-ordering-file file %s: %s"),
+ filename, strerror(errno));
+
+ unsigned int position = 1;
+ while (in)
+ {
+ if (!line.empty() && line[line.length() - 1] == '\r') // Windows
+ line.resize(line.length() - 1);
+ this->input_section_position_[line] = position;
+ // Store all glob patterns in a vector.
+ if (is_wildcard_string(line.c_str()))
+ this->input_section_glob_.push_back(line);
+ position++;
+ std::getline(in, line);
+ }
+}
+
// Finalize the layout. When this is called, we have created all the
// output sections and all the output segments which are based on
// input sections. We have several things to do, and we have to do
Index: layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.80
diff -u -u -p -r1.80 layout.h
--- layout.h 9 Apr 2010 17:32:58 -0000 1.80
+++ layout.h 29 May 2010 01:44:54 -0000
@@ -308,6 +308,12 @@ class Layout
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
+ unsigned int
+ find_section_order_index(const std::string&);
+
+ void
+ read_layout_from_file();
+
// Layout an input reloc section when doing a relocatable link. The
// section is RELOC_SHNDX in OBJECT, with data in SHDR.
// DATA_SECTION is the reloc section to which it refers. RR is the
@@ -1037,6 +1043,10 @@ class Layout
Segment_states* segment_states_;
// A relaxation debug checker. We only create one when in debugging mode.
Relaxation_debug_check* relaxation_debug_check_;
+ // Hash a pattern to its position in the section ordering file.
+ std::map<std::string, unsigned int> input_section_position_;
+ // Vector of glob only patterns in the section_ordering file.
+ std::vector<std::string> input_section_glob_;
};
// This task handles writing out data in output sections which is not
Index: main.cc
===================================================================
RCS file: /cvs/src/src/gold/main.cc,v
retrieving revision 1.38
diff -u -u -p -r1.38 main.cc
--- main.cc 22 Mar 2010 14:18:24 -0000 1.38
+++ main.cc 29 May 2010 01:44:54 -0000
@@ -234,6 +234,9 @@ main(int argc, char** argv)
layout.incremental_inputs()->report_inputs(command_line.inputs());
}
+ if (parameters->options().section_ordering_file())
+ layout.read_layout_from_file();
+
// Get the search path from the -L options.
Dirsearch search_path;
search_path.initialize(&workqueue, &command_line.options().library_path());
Index: options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.146
diff -u -u -p -r1.146 options.h
--- options.h 18 May 2010 18:08:03 -0000 1.146
+++ options.h 29 May 2010 01:44:54 -0000
@@ -892,6 +892,10 @@ class General_options
N_("Add DIR to link time shared library search path"),
N_("DIR"));
+ DEFINE_string(section_ordering_file, options::TWO_DASHES, '\0', NULL,
+ N_("Layout functions and data in the order specified."),
+ N_("FILENAME"));
+
DEFINE_special(section_start, options::TWO_DASHES, '\0',
N_("Set address of section"), N_("SECTION=ADDRESS"));
Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.126
diff -u -u -p -r1.126 output.cc
--- output.cc 23 May 2010 07:43:39 -0000 1.126
+++ output.cc 29 May 2010 01:44:54 -0000
@@ -1933,6 +1933,7 @@ Output_section::Output_section(const cha
found_in_sections_clause_(false),
has_load_address_(false),
info_uses_section_index_(false),
+ input_section_order_specified_(false),
may_sort_attached_input_sections_(false),
must_sort_attached_input_sections_(false),
attached_input_sections_are_sorted_(false),
@@ -1999,7 +2000,8 @@ Output_section::add_input_section(Sized_
const char* secname,
const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx,
- bool have_sections_script)
+ bool have_sections_script,
+ Layout* layout)
{
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
if ((addralign & (addralign - 1)) != 0)
@@ -2090,16 +2092,30 @@ Output_section::add_input_section(Sized_
// We need to keep track of this section if we are already keeping
// track of sections, or if we are relaxing. Also, if this is a
// section which requires sorting, or which may require sorting in
- // the future, we keep track of the sections.
+ // the future, we keep track of the sections. If the
+ // --section-ordering-file option is used to specify the order of
+ // sections, we need to keep track of sections.
if (have_sections_script
|| !this->input_sections_.empty()
|| this->may_sort_attached_input_sections()
|| this->must_sort_attached_input_sections()
|| parameters->options().user_set_Map()
- || parameters->target().may_relax())
- this->input_sections_.push_back(Input_section(object, shndx,
- shdr.get_sh_size(),
- addralign));
+ || parameters->target().may_relax()
+ || parameters->options().section_ordering_file())
+ {
+ Input_section isecn(object, shndx, shdr.get_sh_size(), addralign);
+ if (parameters->options().section_ordering_file())
+ {
+ unsigned int section_order_index =
+ layout->find_section_order_index(std::string(secname));
+ if (section_order_index)
+ {
+ isecn.set_section_order_index(section_order_index);
+ this->set_input_section_order_specified();
+ }
+ }
+ this->input_sections_.push_back(isecn);
+ }
return aligned_offset_in_section;
}
@@ -2623,7 +2639,8 @@ Output_section::set_final_data_size()
return;
}
- if (this->must_sort_attached_input_sections())
+ if (this->must_sort_attached_input_sections()
+ || this->input_section_order_specified())
this->sort_attached_input_sections();
uint64_t address = this->address();
@@ -2700,12 +2717,14 @@ class Output_section::Input_section_sort
{ }
Input_section_sort_entry(const Input_section& input_section,
- unsigned int index)
+ unsigned int index,
+ bool must_sort_attached_input_sections)
: input_section_(input_section), index_(index),
section_has_name_(input_section.is_input_section()
|| input_section.is_relaxed_input_section())
{
- if (this->section_has_name_)
+ if (this->section_has_name_
+ && must_sort_attached_input_sections)
{
// This is only called single-threaded from Layout::finalize,
// so it is OK to lock. Unfortunately we have no way to pass
@@ -2782,6 +2801,22 @@ class Output_section::Input_section_sort
return memcmp(base_name + base_len - 2, ".o", 2) == 0;
}
+ // Returns 0 if no order is specified. Returns 1 if "this" is the
+ // first section in order (is_before), returns 2 for s.
+ unsigned int
+ is_before_in_sequence(const Input_section_sort_entry& s) const
+ {
+ gold_assert(this->index_ != -1U);
+ if (this->input_section_.section_order_index() == 0
+ || s.input_section().section_order_index() == 0)
+ return 0;
+ if (this->input_section_.section_order_index()
+ < s.input_section().section_order_index())
+ return 1;
+ else
+ return 2;
+ }
+
private:
// The Input_section we are sorting.
Input_section input_section_;
@@ -2843,6 +2878,12 @@ Output_section::Input_section_sort_compa
if (!s1_has_priority && s2_has_priority)
return true;
+ // Check if a section order exists for these sections through a section
+ // ordering file. If sequence_num is 0, an order does not exist.
+ unsigned int sequence_num = s1.is_before_in_sequence(s2);
+ if (sequence_num)
+ return sequence_num == 1;
+
// Otherwise we sort by name.
int compare = s1.section_name().compare(s2.section_name());
if (compare != 0)
@@ -2879,6 +2920,12 @@ Output_section::Input_section_sort_init_
if (!s1_has_priority && s2_has_priority)
return false;
+ // Check if a section order exists for these sections through a section
+ // ordering file. If sequence_num is 0, an order does not exist.
+ unsigned int sequence_num = s1.is_before_in_sequence(s2);
+ if (sequence_num)
+ return sequence_num == 1;
+
// Otherwise we sort by name.
int compare = s1.section_name().compare(s2.section_name());
if (compare != 0)
@@ -2888,6 +2935,22 @@ Output_section::Input_section_sort_init_
return s1.index() < s2.index();
}
+// Return true if S1 should come before S2.
+bool
+Output_section::Input_section_sort_section_order_index_compare::operator()(
+ const Output_section::Input_section_sort_entry& s1,
+ const Output_section::Input_section_sort_entry& s2) const
+{
+ // Check if a section order exists for these sections through a section
+ // ordering file. If sequence_num is 0, an order does not exist.
+ unsigned int sequence_num = s1.is_before_in_sequence(s2);
+ if (sequence_num)
+ return sequence_num == 1;
+
+ // Otherwise we keep the input order.
+ return s1.index() < s2.index();
+}
+
// Sort the input sections attached to an output section.
void
@@ -2913,17 +2976,27 @@ Output_section::sort_attached_input_sect
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p, ++i)
- sort_list.push_back(Input_section_sort_entry(*p, i));
+ sort_list.push_back(Input_section_sort_entry(*p, i,
+ this->must_sort_attached_input_sections()));
// Sort the input sections.
- if (this->type() == elfcpp::SHT_PREINIT_ARRAY
- || this->type() == elfcpp::SHT_INIT_ARRAY
- || this->type() == elfcpp::SHT_FINI_ARRAY)
- std::sort(sort_list.begin(), sort_list.end(),
- Input_section_sort_init_fini_compare());
+ if (this->must_sort_attached_input_sections())
+ {
+ if (this->type() == elfcpp::SHT_PREINIT_ARRAY
+ || this->type() == elfcpp::SHT_INIT_ARRAY
+ || this->type() == elfcpp::SHT_FINI_ARRAY)
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_init_fini_compare());
+ else
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_compare());
+ }
else
- std::sort(sort_list.begin(), sort_list.end(),
- Input_section_sort_compare());
+ {
+ gold_assert(parameters->options().section_ordering_file());
+ std::sort(sort_list.begin(), sort_list.end(),
+ Input_section_sort_section_order_index_compare());
+ }
// Copy the sorted input sections back to our list.
this->input_sections_.clear();
@@ -2931,6 +3004,7 @@ Output_section::sort_attached_input_sect
p != sort_list.end();
++p)
this->input_sections_.push_back(p->input_section());
+ sort_list.clear();
// Remember that we sorted the input sections, since we might get
// called again.
@@ -4471,7 +4545,8 @@ Output_section::add_input_section<32, fa
const char* secname,
const elfcpp::Shdr<32, false>& shdr,
unsigned int reloc_shndx,
- bool have_sections_script);
+ bool have_sections_script,
+ Layout* layout);
#endif
#ifdef HAVE_TARGET_32_BIG
@@ -4483,7 +4558,8 @@ Output_section::add_input_section<32, tr
const char* secname,
const elfcpp::Shdr<32, true>& shdr,
unsigned int reloc_shndx,
- bool have_sections_script);
+ bool have_sections_script,
+ Layout* layout);
#endif
#ifdef HAVE_TARGET_64_LITTLE
@@ -4495,7 +4571,8 @@ Output_section::add_input_section<64, fa
const char* secname,
const elfcpp::Shdr<64, false>& shdr,
unsigned int reloc_shndx,
- bool have_sections_script);
+ bool have_sections_script,
+ Layout* layout);
#endif
#ifdef HAVE_TARGET_64_BIG
@@ -4507,7 +4584,8 @@ Output_section::add_input_section<64, tr
const char* secname,
const elfcpp::Shdr<64, true>& shdr,
unsigned int reloc_shndx,
- bool have_sections_script);
+ bool have_sections_script,
+ Layout* layout);
#endif
#ifdef HAVE_TARGET_32_LITTLE
Index: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.106
diff -u -u -p -r1.106 output.h
--- output.h 23 May 2010 07:43:39 -0000 1.106
+++ output.h 29 May 2010 01:44:54 -0000
@@ -2518,7 +2518,8 @@ class Output_section : public Output_dat
add_input_section(Sized_relobj<size, big_endian>* object, unsigned int shndx,
const char *name,
const elfcpp::Shdr<size, big_endian>& shdr,
- unsigned int reloc_shndx, bool have_sections_script);
+ unsigned int reloc_shndx, bool have_sections_script,
+ Layout* layout);
// Add generated data POSD to this output section.
void
@@ -2736,6 +2737,18 @@ class Output_section : public Output_dat
set_may_sort_attached_input_sections()
{ this->may_sort_attached_input_sections_ = true; }
+ // Returns true if input sections must be sorted according to the
+ // order in which their name appear in the --section-ordering-file.
+ bool
+ input_section_order_specified()
+ { return this->input_section_order_specified_; }
+
+ // Record that input sections must be sorted as some of their names
+ // match the patterns specified through --section-ordering-file.
+ void
+ set_input_section_order_specified()
+ { this->input_section_order_specified_ = true; }
+
// Return whether the input sections attached to this output section
// require sorting. This is used to handle constructor priorities
// compatibly with GNU ld.
@@ -2972,7 +2985,8 @@ class Output_section : public Output_dat
Input_section(Relobj* object, unsigned int shndx, off_t data_size,
uint64_t addralign)
: shndx_(shndx),
- p2align_(ffsll(static_cast<long long>(addralign)))
+ p2align_(ffsll(static_cast<long long>(addralign))),
+ section_order_index_(0)
{
gold_assert(shndx != OUTPUT_SECTION_CODE
&& shndx != MERGE_DATA_SECTION_CODE
@@ -2984,7 +2998,8 @@ class Output_section : public Output_dat
// For a non-merge output section.
Input_section(Output_section_data* posd)
- : shndx_(OUTPUT_SECTION_CODE), p2align_(0)
+ : shndx_(OUTPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
{
this->u1_.data_size = 0;
this->u2_.posd = posd;
@@ -2995,7 +3010,8 @@ class Output_section : public Output_dat
: shndx_(is_string
? MERGE_STRING_SECTION_CODE
: MERGE_DATA_SECTION_CODE),
- p2align_(0)
+ p2align_(0),
+ section_order_index_(0)
{
this->u1_.entsize = entsize;
this->u2_.posd = posd;
@@ -3003,12 +3019,25 @@ class Output_section : public Output_dat
// For a relaxed input section.
Input_section(Output_relaxed_input_section *psection)
- : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0)
+ : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0),
+ section_order_index_(0)
{
this->u1_.data_size = 0;
this->u2_.poris = psection;
}
+ unsigned int
+ section_order_index() const
+ {
+ return this->section_order_index_;
+ }
+
+ void
+ set_section_order_index(unsigned int number)
+ {
+ this->section_order_index_ = number;
+ }
+
// The required alignment.
uint64_t
addralign() const
@@ -3234,6 +3263,9 @@ class Output_section : public Output_dat
// For RELAXED_INPUT_SECTION_CODE, the data.
Output_relaxed_input_section* poris;
} u2_;
+ // The line number of the pattern it matches in the --section-ordering-file
+ // file. It is 0 if does not match any pattern.
+ unsigned int section_order_index_;
};
// Store the list of input sections for this Output_section into the
@@ -3540,6 +3572,15 @@ class Output_section : public Output_dat
const Input_section_sort_entry&) const;
};
+ // This is the sort comparison function when a section order is specified
+ // from an input file.
+ struct Input_section_sort_section_order_index_compare
+ {
+ bool
+ operator()(const Input_section_sort_entry&,
+ const Input_section_sort_entry&) const;
+ };
+
// Fill data. This is used to fill in data between input sections.
// It is also used for data statements (BYTE, WORD, etc.) in linker
// scripts. When we have to keep track of the input sections, we
@@ -3707,6 +3748,9 @@ class Output_section : public Output_dat
// section, false if it means the symbol index of the corresponding
// section symbol.
bool info_uses_section_index_ : 1;
+ // True if input sections attached to this output section have to be
+ // sorted according to a specified order.
+ bool input_section_order_specified_ : 1;
// True if the input sections attached to this output section may
// need sorting.
bool may_sort_attached_input_sections_ : 1;
Index: script-sections.cc
===================================================================
RCS file: /cvs/src/src/gold/script-sections.cc,v
retrieving revision 1.36
diff -u -u -p -r1.36 script-sections.cc
--- script-sections.cc 26 May 2010 15:15:05 -0000 1.36
+++ script-sections.cc 29 May 2010 01:44:54 -0000
@@ -983,15 +983,6 @@ class Output_section_element_fill : publ
Expression* val_;
};
-// Return whether STRING contains a wildcard character. This is used
-// to speed up matching.
-
-static inline bool
-is_wildcard_string(const std::string& s)
-{
- return strpbrk(s.c_str(), "?*[") != NULL;
-}
-
// An input section specification in an output section
class Output_section_element_input : public Output_section_element
@@ -1035,7 +1026,7 @@ class Output_section_element_input : pub
Input_section_pattern(const char* patterna, size_t patternlena,
Sort_wildcard sorta)
: pattern(patterna, patternlena),
- pattern_is_wildcard(is_wildcard_string(this->pattern)),
+ pattern_is_wildcard(is_wildcard_string(this->pattern.c_str())),
sort(sorta)
{ }
};
@@ -1102,7 +1093,7 @@ Output_section_element_input::Output_sec
if (spec->file.name.length != 1 || spec->file.name.value[0] != '*')
this->filename_pattern_.assign(spec->file.name.value,
spec->file.name.length);
- this->filename_is_wildcard_ = is_wildcard_string(this->filename_pattern_);
+ this->filename_is_wildcard_ = is_wildcard_string(this->filename_pattern_.c_str());
if (spec->input_sections.exclude != NULL)
{
@@ -1111,7 +1102,7 @@ Output_section_element_input::Output_sec
p != spec->input_sections.exclude->end();
++p)
{
- bool is_wildcard = is_wildcard_string(*p);
+ bool is_wildcard = is_wildcard_string((*p).c_str());
this->filename_exclusions_.push_back(std::make_pair(*p,
is_wildcard));
}
cvs diff: Diffing po
cvs diff: Diffing testsuite
Index: testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.135
diff -u -u -p -r1.135 Makefile.am
--- testsuite/Makefile.am 26 May 2010 15:47:39 -0000 1.135
+++ testsuite/Makefile.am 29 May 2010 01:44:54 -0000
@@ -193,6 +193,18 @@ icf_safe_so_test_1.stdout: icf_safe_so_t
icf_safe_so_test_2.stdout: icf_safe_so_test
$(TEST_READELF) -h icf_safe_so_test > icf_safe_so_test_2.stdout
+check_SCRIPTS += final_layout.sh
+check_DATA += final_layout.stdout
+MOSTLYCLEANFILES += final_layout
+final_layout.o: final_layout.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
+final_layout_sequence.txt:
+ (echo "*_Z3barv*" && echo ".text._Z3bazv" && echo "*_Z3foov*" && echo "*global_varb*" && echo "*global_vara*" && echo "*global_varc*") > final_layout_sequence.txt
+final_layout: final_layout.o final_layout_sequence.txt gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--section-ordering-file,final_layout_sequence.txt final_layout.o
+final_layout.stdout: final_layout
+ $(TEST_NM) final_layout > final_layout.stdout
+
check_PROGRAMS += icf_virtual_function_folding_test
MOSTLYCLEANFILES += icf_virtual_function_folding_test
icf_virtual_function_folding_test.o: icf_virtual_function_folding_test.cc
Index: testsuite/final_layout.cc
===================================================================
RCS file: testsuite/final_layout.cc
diff -N testsuite/final_layout.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/final_layout.cc 29 May 2010 01:44:55 -0000
@@ -0,0 +1,48 @@
+// final_layout.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// The goal of this program is to verify if --section-ordering-file orders
+// the .text and .data sections correctly as specified.
+
+int global_vara;
+int global_varb;
+int global_varc;
+
+int foo()
+{
+ return 1;
+}
+
+int bar()
+{
+ return 1;
+}
+
+int baz()
+{
+ return 1;
+}
+
+int main()
+{
+ return 1;
+}
Index: testsuite/final_layout.sh
===================================================================
RCS file: testsuite/final_layout.sh
diff -N testsuite/final_layout.sh
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/final_layout.sh 29 May 2010 01:44:55 -0000
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# final_layout.sh -- test --final-layout
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# The goal of this program is to verify if --section-ordering-file works as
+# intended. File final_layout.cc is in this test.
+
+check()
+{
+ func_addr_1=$((16#`grep $2 $1 | awk '{print $1}'`))
+ func_addr_2=$((16#`grep $3 $1 | awk '{print $1}'`))
+ if [ $func_addr_1 -gt $func_addr_2 ]
+ then
+ echo "final layout of" $2 "and" $3 "is not right."
+ exit 1
+ fi
+}
+
+check final_layout.stdout "_Z3barv" "_Z3bazv"
+check final_layout.stdout "_Z3bazv" "_Z3foov"
+check final_layout.stdout "global_varb" "global_vara"
+check final_layout.stdout "global_vara" "global_varc"
More information about the Binutils
mailing list