diff options
author | Ian Lance Taylor <ian@airs.com> | 2009-06-22 06:51:53 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2009-06-22 06:51:53 +0000 |
commit | 8a5e3e08a6faa0fdba3daa1fa4295b02c7ebe1eb (patch) | |
tree | 01736b6b47e8048239544872455cc12eb3d5bcc6 /gold/layout.cc | |
parent | 1998a8e0333f8ebc40a5387532d74f90f510591d (diff) | |
download | binutils-8a5e3e08a6faa0fdba3daa1fa4295b02c7ebe1eb.zip binutils-8a5e3e08a6faa0fdba3daa1fa4295b02c7ebe1eb.tar.gz binutils-8a5e3e08a6faa0fdba3daa1fa4295b02c7ebe1eb.tar.bz2 |
* layout.cc (Layout::make_output_section): Call
Target::new_output_section.
(Layout::attach_allocated_section_to_segment): Put large section
sections in a separate load segment with the large segment flag
set.
(Layout::segment_precedes): Sort large data segments after other
load segments.
(align_file_offset): New static function.
(Layout::set_segment_offsets): Use align_file_offset.
* output.h (class Output_section): Add is_small_section_ and
is_large_section_ fields.
(Output_section::is_small_section): New function.
(Output_section::set_is_small_section): New function.
(Output_section::is_large_section): New function.
(Output_section::set_is_large_section): New function.
(Output_section::is_large_data_section): New function.
(class Output_segment): Add is_large_data_segment_ field.
(Output_segment::is_large_data_segment): New function.
(Output_segment::set_is_large_data_segment): New function.
* output.cc (Output_section::Output_section): Initialize new
fields.
(Output_segment::Output_segment): Likewise.
(Output_segment::add_output_section): Add assertion that large
data sections always go in large data segments. Force small data
sections to the end of the list of data sections. Force small BSS
sections to the start of the list of BSS sections. For large BSS
sections to the end of the list of BSS sections.
* symtab.h (class Symbol): Declare is_common_shndx.
(Symbol::is_defined): Check Symbol::is_common_shndx.
(Symbol::is_common): Likewise.
(class Symbol_table): Define enum Commons_section_type. Update
declarations. Add small_commons_ and large_commons_ fields.
* symtab.cc (Symbol::is_common_shndx): New function.
(Symbol_table::Symbol_table): Initialize new fields.
(Symbol_table::add_from_object): Put small and large common
symbols in the right list.
(Symbol_table::sized_finalized_symbol): Check
Symbol::is_common_shndx.
(Symbol_table::sized_write_globals): Likewise.
* common.cc (Symbol_table::do_allocate_commons): Allocate new
common symbol lists. Don't call do_allocate_commons_list if the
list is empty.
(Symbol_table::do_allocate_commons_list): Remove is_tls
parameter. Add comons_section_type parameter. Change all
callers. Handle small and large common symbols.
* object.cc (Sized_relobj::do_finalize_local_symbols): Check
Symbol::is_common_shndx.
* resolve.cc (symbol_to_bits): Likewise.
* target.h (Target::small_common_shndx): New function.
(Target::small_common_section_flags): New function.
(Target::large_common_shndx): New function.
(Target::large_common_section_flags): New function.
(Target::new_output_section): New function.
(Target::Target_info): Add small_common_shndx, large_common_shndx,
small_common_section_flags, and large_common_section_flags
fields.
(Target::do_new_output_section): New virtual function.
* arm.cc (Target_arm::arm_info): Initialize new fields.
* i386.cc (Target_i386::i386_info): Likewise.
* powerpc.cc (Target_powerpc::powerpc_info) [all versions]:
Likewise.
* sparc.c (Target_sparc::sparc_info) [all versions]: Likewise.
* x86_64.cc (Target_x86_64::x86_64_info): Likewise.
(Target_x86_64::do_new_output_section): New function.
* configure.ac: Define conditional MCMODEL_MEDIUM.
* testsuite/Makefile.am (check_PROGRAMS): Add large.
(large_SOURCES, large_CFLAGS, large_DEPENDENCIES): Define.
(large_LDFLAGS): Define.
* testsuite/large.c: New file.
* testsuite/testfile.cc (Target_test::test_target_info):
Initialize new fields.
* configure, testsuite/Makefile.in: Rebuild.
Diffstat (limited to 'gold/layout.cc')
-rw-r--r-- | gold/layout.cc | 101 |
1 files changed, 61 insertions, 40 deletions
diff --git a/gold/layout.cc b/gold/layout.cc index 9dbcedc..c3020cd 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -788,6 +788,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, else os = new Output_section(name, type, flags); + parameters->target().new_output_section(os); + this->section_list_.push_back(os); // The GNU linker by default sorts some sections by priority, so we @@ -875,7 +877,8 @@ Layout::attach_allocated_section_to_segment(Output_section* os) // In general the only thing we really care about for PT_LOAD // segments is whether or not they are writable, so that is how we - // search for them. People who need segments sorted on some other + // search for them. Large data sections also go into their own + // PT_LOAD segment. People who need segments sorted on some other // basis will have to use a linker script. Segment_list::const_iterator p; @@ -883,28 +886,32 @@ Layout::attach_allocated_section_to_segment(Output_section* os) p != this->segment_list_.end(); ++p) { - if ((*p)->type() == elfcpp::PT_LOAD - && (parameters->options().omagic() - || ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))) - { - // If -Tbss was specified, we need to separate the data - // and BSS segments. - if (parameters->options().user_set_Tbss()) - { - if ((os->type() == elfcpp::SHT_NOBITS) - == (*p)->has_any_data_sections()) - continue; - } + if ((*p)->type() != elfcpp::PT_LOAD) + continue; + if (!parameters->options().omagic() + && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W)) + continue; + // If -Tbss was specified, we need to separate the data and BSS + // segments. + if (parameters->options().user_set_Tbss()) + { + if ((os->type() == elfcpp::SHT_NOBITS) + == (*p)->has_any_data_sections()) + continue; + } + if (os->is_large_data_section() && !(*p)->is_large_data_segment()) + continue; - (*p)->add_output_section(os, seg_flags); - break; - } + (*p)->add_output_section(os, seg_flags); + break; } if (p == this->segment_list_.end()) { Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD, seg_flags); + if (os->is_large_data_section()) + oseg->set_is_large_data_segment(); oseg->add_output_section(os, seg_flags); } @@ -1729,14 +1736,25 @@ Layout::segment_precedes(const Output_segment* seg1, else if (seg2->are_addresses_set()) return false; - // We sort PT_LOAD segments based on the flags. Readonly segments - // come before writable segments. Then writable segments with data - // come before writable segments without data. Then executable - // segments come before non-executable segments. Then the unlikely - // case of a non-readable segment comes before the normal case of a - // readable segment. If there are multiple segments with the same - // type and flags, we require that the address be set, and we sort - // by virtual address and then physical address. + // A segment which holds large data comes after a segment which does + // not hold large data. + if (seg1->is_large_data_segment()) + { + if (!seg2->is_large_data_segment()) + return false; + } + else if (seg2->is_large_data_segment()) + return true; + + // Otherwise, we sort PT_LOAD segments based on the flags. Readonly + // segments come before writable segments. Then writable segments + // with data come before writable segments without data. Then + // executable segments come before non-executable segments. Then + // the unlikely case of a non-readable segment comes before the + // normal case of a readable segment. If there are multiple + // segments with the same type and flags, we require that the + // address be set, and we sort by virtual address and then physical + // address. if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W)) return (flags1 & elfcpp::PF_W) == 0; if ((flags1 & elfcpp::PF_W) != 0 @@ -1752,6 +1770,19 @@ Layout::segment_precedes(const Output_segment* seg1, gold_unreachable(); } +// Increase OFF so that it is congruent to ADDR modulo ABI_PAGESIZE. + +static off_t +align_file_offset(off_t off, uint64_t addr, uint64_t abi_pagesize) +{ + uint64_t unsigned_off = off; + uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1)) + | (addr & (abi_pagesize - 1))); + if (aligned_off < unsigned_off) + aligned_off += abi_pagesize; + return aligned_off; +} + // Set the file offsets of all the segments, and all the sections they // contain. They have all been created. LOAD_SEG must be be laid out // first. Return the offset of the data to follow. @@ -1838,22 +1869,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, && !parameters->options().omagic()) (*p)->set_minimum_p_align(common_pagesize); - if (are_addresses_set) - { - if (!parameters->options().nmagic() - && !parameters->options().omagic()) - { - // Adjust the file offset to the same address modulo - // the page size. - uint64_t unsigned_off = off; - uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1)) - | (addr & (abi_pagesize - 1))); - if (aligned_off < unsigned_off) - aligned_off += abi_pagesize; - off = aligned_off; - } - } - else + if (!are_addresses_set) { // If the last segment was readonly, and this one is // not, then skip the address forward one page, @@ -1874,6 +1890,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); } + if (!parameters->options().nmagic() + && !parameters->options().omagic()) + off = align_file_offset(off, addr, abi_pagesize); + unsigned int shndx_hold = *pshndx; uint64_t new_addr = (*p)->set_section_addresses(this, false, addr, &off, pshndx); @@ -1900,6 +1920,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, addr = align_address(aligned_addr, common_pagesize); addr = align_address(addr, (*p)->maximum_alignment()); off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); + off = align_file_offset(off, addr, abi_pagesize); new_addr = (*p)->set_section_addresses(this, true, addr, &off, pshndx); } |