| Index: binutils/gold/output.cc
|
| diff --git a/binutils/gold/output.cc b/binutils/gold/output.cc
|
| index e2d758520c28e29e07dd48d48a22f7860f20da27..84f59ae819467ae7135a577ce9b5ce8c28f31d39 100644
|
| --- a/binutils/gold/output.cc
|
| +++ b/binutils/gold/output.cc
|
| @@ -1800,13 +1800,15 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
| is_relro_local_(false),
|
| is_small_section_(false),
|
| is_large_section_(false),
|
| + is_interp_(false),
|
| + is_dynamic_linker_section_(false),
|
| + generate_code_fills_at_write_(false),
|
| tls_offset_(0),
|
| checkpoint_(NULL),
|
| merge_section_map_(),
|
| merge_section_by_properties_map_(),
|
| relaxed_input_section_map_(),
|
| - is_relaxed_input_section_map_valid_(true),
|
| - generate_code_fills_at_write_(false)
|
| + is_relaxed_input_section_map_valid_(true)
|
| {
|
| // An unallocated section has no address. Forcing this means that
|
| // we don't need special treatment for symbols defined in debug
|
| @@ -3045,11 +3047,13 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
|
|
| void
|
| Output_segment::add_output_section(Output_section* os,
|
| - elfcpp::Elf_Word seg_flags)
|
| + elfcpp::Elf_Word seg_flags,
|
| + bool do_sort)
|
| {
|
| gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
|
| gold_assert(!this->is_max_align_known_);
|
| gold_assert(os->is_large_data_section() == this->is_large_data_segment());
|
| + gold_assert(this->type() == elfcpp::PT_LOAD || !do_sort);
|
|
|
| // Update the segment flags.
|
| this->flags_ |= seg_flags;
|
| @@ -3060,19 +3064,12 @@ Output_segment::add_output_section(Output_section* os,
|
| else
|
| pdl = &this->output_data_;
|
|
|
| - // So that PT_NOTE segments will work correctly, we need to ensure
|
| - // that all SHT_NOTE sections are adjacent. This will normally
|
| - // happen automatically, because all the SHT_NOTE input sections
|
| - // will wind up in the same output section. However, it is possible
|
| - // for multiple SHT_NOTE input sections to have different section
|
| - // flags, and thus be in different output sections, but for the
|
| - // different section flags to map into the same segment flags and
|
| - // thus the same output segment.
|
| -
|
| // Note that while there may be many input sections in an output
|
| // section, there are normally only a few output sections in an
|
| - // output segment. This loop is expected to be fast.
|
| + // output segment. The loops below are expected to be fast.
|
|
|
| + // So that PT_NOTE segments will work correctly, we need to ensure
|
| + // that all SHT_NOTE sections are adjacent.
|
| if (os->type() == elfcpp::SHT_NOTE && !pdl->empty())
|
| {
|
| Output_segment::Output_data_list::iterator p = pdl->end();
|
| @@ -3094,8 +3091,8 @@ Output_segment::add_output_section(Output_section* os,
|
| // case: we group the SHF_TLS/SHT_NOBITS sections right after the
|
| // SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS
|
| // correctly. SHF_TLS sections get added to both a PT_LOAD segment
|
| - // and the PT_TLS segment -- we do this grouping only for the
|
| - // PT_LOAD segment.
|
| + // and the PT_TLS segment; we do this grouping only for the PT_LOAD
|
| + // segment.
|
| if (this->type_ != elfcpp::PT_TLS
|
| && (os->flags() & elfcpp::SHF_TLS) != 0)
|
| {
|
| @@ -3225,6 +3222,68 @@ Output_segment::add_output_section(Output_section* os,
|
| gold_unreachable();
|
| }
|
|
|
| + // We do some further output section sorting in order to make the
|
| + // generated program run more efficiently. We should only do this
|
| + // when not using a linker script, so it is controled by the DO_SORT
|
| + // parameter.
|
| + if (do_sort)
|
| + {
|
| + // FreeBSD requires the .interp section to be in the first page
|
| + // of the executable. That is a more efficient location anyhow
|
| + // for any OS, since it means that the kernel will have the data
|
| + // handy after it reads the program headers.
|
| + if (os->is_interp() && !pdl->empty())
|
| + {
|
| + pdl->insert(pdl->begin(), os);
|
| + return;
|
| + }
|
| +
|
| + // Put loadable non-writable notes immediately after the .interp
|
| + // sections, so that the PT_NOTE segment is on the first page of
|
| + // the executable.
|
| + if (os->type() == elfcpp::SHT_NOTE
|
| + && (os->flags() & elfcpp::SHF_WRITE) == 0
|
| + && !pdl->empty())
|
| + {
|
| + Output_segment::Output_data_list::iterator p = pdl->begin();
|
| + if ((*p)->is_section() && (*p)->output_section()->is_interp())
|
| + ++p;
|
| + pdl->insert(p, os);
|
| + return;
|
| + }
|
| +
|
| + // If this section is used by the dynamic linker, and it is not
|
| + // writable, then put it first, after the .interp section and
|
| + // any loadable notes. This makes it more likely that the
|
| + // dynamic linker will have to read less data from the disk.
|
| + if (os->is_dynamic_linker_section()
|
| + && !pdl->empty()
|
| + && (os->flags() & elfcpp::SHF_WRITE) == 0)
|
| + {
|
| + bool is_reloc = (os->type() == elfcpp::SHT_REL
|
| + || os->type() == elfcpp::SHT_RELA);
|
| + Output_segment::Output_data_list::iterator p = pdl->begin();
|
| + while (p != pdl->end()
|
| + && (*p)->is_section()
|
| + && ((*p)->output_section()->is_dynamic_linker_section()
|
| + || (*p)->output_section()->type() == elfcpp::SHT_NOTE))
|
| + {
|
| + // Put reloc sections after the other ones. Putting the
|
| + // dynamic reloc sections first confuses BFD, notably
|
| + // objcopy and strip.
|
| + if (!is_reloc
|
| + && ((*p)->output_section()->type() == elfcpp::SHT_REL
|
| + || (*p)->output_section()->type() == elfcpp::SHT_RELA))
|
| + break;
|
| + ++p;
|
| + }
|
| + pdl->insert(p, os);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + // If there were no constraints on the output section, just add it
|
| + // to the end of the list.
|
| pdl->push_back(os);
|
| }
|
|
|
| @@ -3503,15 +3562,20 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
|
| else
|
| {
|
| Output_section* os = (*p)->output_section();
|
| +
|
| + // Cast to unsigned long long to avoid format warnings.
|
| + unsigned long long previous_dot =
|
| + static_cast<unsigned long long>(addr + (off - startoff));
|
| + unsigned long long dot =
|
| + static_cast<unsigned long long>((*p)->address());
|
| +
|
| if (os == NULL)
|
| gold_error(_("dot moves backward in linker script "
|
| - "from 0x%llx to 0x%llx"),
|
| - addr + (off - startoff), (*p)->address());
|
| + "from 0x%llx to 0x%llx"), previous_dot, dot);
|
| else
|
| gold_error(_("address of section '%s' moves backward "
|
| "from 0x%llx to 0x%llx"),
|
| - os->name(), addr + (off - startoff),
|
| - (*p)->address());
|
| + os->name(), previous_dot, dot);
|
| }
|
| }
|
| (*p)->set_file_offset(off);
|
|
|