This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
gold patch committed: Add large section support
- From: Ian Lance Taylor <iant at google dot com>
- To: binutils at sourceware dot org
- Date: Sun, 21 Jun 2009 23:56:32 -0700
- Subject: gold patch committed: Add large section support
I committed this patch to gold to add large section support to the
x86_64 target. This supports the SHF_X86_64_LARGE section flag and
the SHN_X86_64_LCOMMON section index.
This patch should provide all the hooks needed for small section
support for other targets, although since none of the current set of
targets implements small sections I can't be completely sure that all
the required hooks are there.
Ian
gold/ChangeLog:
2009-06-21 Ian Lance Taylor <iant@google.com>
* 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.
elfcpp/ChangeLog:
2009-06-21 Ian Lance Taylor <iant@google.com>
* elfcpp.h (SHN_X86_64_LCOMMON): Define enum constant.
(enum SHT): Add SHT_X86_64_UNWIND.
(enum SHF): Add SHT_X86_64_LARGE.
Index: arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.6
diff -u -r1.6 arm.cc
--- arm.cc 4 Jun 2009 01:31:01 -0000 1.6
+++ arm.cc 22 Jun 2009 06:33:09 -0000
@@ -449,7 +449,11 @@
"/usr/lib/libc.so.1", // dynamic_linker
0x8000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
- 0x1000 // common_pagesize (overridable by -z common-page-size)
+ 0x1000, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
// Arm relocate functions class
Index: common.cc
===================================================================
RCS file: /cvs/src/src/gold/common.cc,v
retrieving revision 1.17
diff -u -r1.17 common.cc
--- common.cc 21 May 2008 21:37:44 -0000 1.17
+++ common.cc 22 Jun 2009 06:33:09 -0000
@@ -146,10 +146,18 @@
void
Symbol_table::do_allocate_commons(Layout* layout, Mapfile* mapfile)
{
- this->do_allocate_commons_list<size>(layout, false, &this->commons_,
- mapfile);
- this->do_allocate_commons_list<size>(layout, true, &this->tls_commons_,
- mapfile);
+ if (!this->commons_.empty())
+ this->do_allocate_commons_list<size>(layout, COMMONS_NORMAL,
+ &this->commons_, mapfile);
+ if (!this->tls_commons_.empty())
+ this->do_allocate_commons_list<size>(layout, COMMONS_TLS,
+ &this->tls_commons_, mapfile);
+ if (!this->small_commons_.empty())
+ this->do_allocate_commons_list<size>(layout, COMMONS_SMALL,
+ &this->small_commons_, mapfile);
+ if (!this->large_commons_.empty())
+ this->do_allocate_commons_list<size>(layout, COMMONS_LARGE,
+ &this->large_commons_, mapfile);
}
// Allocate the common symbols in a list. IS_TLS indicates whether
@@ -157,9 +165,11 @@
template<int size>
void
-Symbol_table::do_allocate_commons_list(Layout* layout, bool is_tls,
- Commons_type* commons,
- Mapfile* mapfile)
+Symbol_table::do_allocate_commons_list(
+ Layout* layout,
+ Commons_section_type commons_section_type,
+ Commons_type* commons,
+ Mapfile* mapfile)
{
typedef typename Sized_symbol<size>::Value_type Value_type;
typedef typename Sized_symbol<size>::Size_type Size_type;
@@ -198,20 +208,45 @@
Sort_commons<size>(this));
// Place them in a newly allocated BSS section.
-
- Output_data_space *poc = new Output_data_space(addralign,
- (is_tls
- ? "** tls common"
- : "** common"));
-
- const char* name = ".bss";
elfcpp::Elf_Xword flags = elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC;
- if (is_tls)
+ const char* name;
+ const char* ds_name;
+ switch (commons_section_type)
{
- name = ".tbss";
+ case COMMONS_NORMAL:
+ name = ".bss";
+ ds_name = "** common";
+ break;
+ case COMMONS_TLS:
flags |= elfcpp::SHF_TLS;
+ name = ".tbss";
+ ds_name = "** tls common";
+ break;
+ case COMMONS_SMALL:
+ flags |= parameters->target().small_common_section_flags();
+ name = ".sbss";
+ ds_name = "** small common";
+ break;
+ case COMMONS_LARGE:
+ flags |= parameters->target().large_common_section_flags();
+ name = ".lbss";
+ ds_name = "** large common";
+ break;
+ default:
+ gold_unreachable();
+ }
+
+ Output_data_space *poc = new Output_data_space(addralign, ds_name);
+ Output_section *os = layout->add_output_section_data(name,
+ elfcpp::SHT_NOBITS,
+ flags, poc);
+ if (os != NULL)
+ {
+ if (commons_section_type == COMMONS_SMALL)
+ os->set_is_small_section();
+ else if (commons_section_type == COMMONS_LARGE)
+ os->set_is_large_section();
}
- layout->add_output_section_data(name, elfcpp::SHT_NOBITS, flags, poc);
// Allocate them all.
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/gold/configure.ac,v
retrieving revision 1.43
diff -u -r1.43 configure.ac
--- configure.ac 15 May 2009 18:32:13 -0000 1.43
+++ configure.ac 22 Jun 2009 06:33:10 -0000
@@ -221,6 +221,9 @@
*) true;;
esac])
+dnl Whether we can test -mcmodel=medium.
+AM_CONDITIONAL(MCMODEL_MEDIUM, [test "$target_cpu" = "x86_64"])
+
dnl Test for __thread support.
AC_CACHE_CHECK([for thread support], [gold_cv_c_thread],
[AC_COMPILE_IFELSE([__thread int i = 1;],
Index: i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.87
diff -u -r1.87 i386.cc
--- i386.cc 5 Jun 2009 21:32:56 -0000 1.87
+++ i386.cc 22 Jun 2009 06:33:10 -0000
@@ -444,7 +444,11 @@
"/usr/lib/libc.so.1", // dynamic_linker
0x08048000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
- 0x1000 // common_pagesize (overridable by -z common-page-size)
+ 0x1000, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
// Get the GOT section, creating it if necessary.
Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.125
diff -u -r1.125 layout.cc
--- layout.cc 4 Jun 2009 21:14:11 -0000 1.125
+++ layout.cc 22 Jun 2009 06:33:11 -0000
@@ -788,6 +788,8 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
&& !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 @@
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 @@
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);
}
Index: object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.93
diff -u -r1.93 object.cc
--- object.cc 5 Jun 2009 21:32:56 -0000 1.93
+++ object.cc 22 Jun 2009 06:33:11 -0000
@@ -1554,7 +1554,7 @@
if (!is_ordinary)
{
- if (shndx == elfcpp::SHN_ABS || shndx == elfcpp::SHN_COMMON)
+ if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx))
lv.set_output_value(lv.input_value());
else
{
Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.90
diff -u -r1.90 output.cc
--- output.cc 24 Apr 2009 19:48:21 -0000 1.90
+++ output.cc 22 Jun 2009 06:33:11 -0000
@@ -1764,6 +1764,8 @@
attached_input_sections_are_sorted_(false),
is_relro_(false),
is_relro_local_(false),
+ is_small_section_(false),
+ is_large_section_(false),
tls_offset_(0)
{
// An unallocated section has no address. Forcing this means that
@@ -2613,7 +2615,8 @@
type_(type),
flags_(flags),
is_max_align_known_(false),
- are_addresses_set_(false)
+ are_addresses_set_(false),
+ is_large_data_segment_(false)
{
}
@@ -2625,6 +2628,7 @@
{
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());
// Update the segment flags.
this->flags_ |= seg_flags;
@@ -2732,6 +2736,69 @@
return;
}
+ // Small data sections go at the end of the list of data sections.
+ // If OS is not small, and there are small sections, we have to
+ // insert it before the first small section.
+ if (os->type() != elfcpp::SHT_NOBITS
+ && !os->is_small_section()
+ && !pdl->empty()
+ && pdl->back()->is_section()
+ && pdl->back()->output_section()->is_small_section())
+ {
+ for (Output_segment::Output_data_list::iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section()
+ && (*p)->output_section()->is_small_section())
+ {
+ pdl->insert(p, os);
+ return;
+ }
+ }
+ gold_unreachable();
+ }
+
+ // A small BSS section goes at the start of the BSS sections, after
+ // other small BSS sections.
+ if (os->type() == elfcpp::SHT_NOBITS && os->is_small_section())
+ {
+ for (Output_segment::Output_data_list::iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if (!(*p)->is_section()
+ || !(*p)->output_section()->is_small_section())
+ {
+ pdl->insert(p, os);
+ return;
+ }
+ }
+ }
+
+ // A large BSS section goes at the end of the BSS sections, which
+ // means that one that is not large must come before the first large
+ // one.
+ if (os->type() == elfcpp::SHT_NOBITS
+ && !os->is_large_section()
+ && !pdl->empty()
+ && pdl->back()->is_section()
+ && pdl->back()->output_section()->is_large_section())
+ {
+ for (Output_segment::Output_data_list::iterator p = pdl->begin();
+ p != pdl->end();
+ ++p)
+ {
+ if ((*p)->is_section()
+ && (*p)->output_section()->is_large_section())
+ {
+ pdl->insert(p, os);
+ return;
+ }
+ }
+ gold_unreachable();
+ }
+
pdl->push_back(os);
}
Index: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.78
diff -u -r1.78 output.h
--- output.h 24 Mar 2009 18:04:26 -0000 1.78
+++ output.h 22 Jun 2009 06:33:12 -0000
@@ -2195,6 +2195,33 @@
set_is_relro_local()
{ this->is_relro_local_ = true; }
+ // True if this is a small section: a section which holds small
+ // variables.
+ bool
+ is_small_section() const
+ { return this->is_small_section_; }
+
+ // Record that this is a small section.
+ void
+ set_is_small_section()
+ { this->is_small_section_ = true; }
+
+ // True if this is a large section: a section which holds large
+ // variables.
+ bool
+ is_large_section() const
+ { return this->is_large_section_; }
+
+ // Record that this is a large section.
+ void
+ set_is_large_section()
+ { this->is_large_section_ = true; }
+
+ // True if this is a large data (not BSS) section.
+ bool
+ is_large_data_section()
+ { return this->is_large_section_ && this->type_ != elfcpp::SHT_NOBITS; }
+
// Return whether this section should be written after all the input
// sections are complete.
bool
@@ -2808,6 +2835,10 @@
bool is_relro_ : 1;
// True if this section holds relro local data.
bool is_relro_local_ : 1;
+ // True if this is a small section.
+ bool is_small_section_ : 1;
+ // True if this is a large section.
+ bool is_large_section_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
@@ -2858,6 +2889,17 @@
offset() const
{ return this->offset_; }
+ // Whether this is a segment created to hold large data sections.
+ bool
+ is_large_data_segment() const
+ { return this->is_large_data_segment_; }
+
+ // Record that this is a segment created to hold large data
+ // sections.
+ void
+ set_is_large_data_segment()
+ { this->is_large_data_segment_ = true; }
+
// Return the maximum alignment of the Output_data.
uint64_t
maximum_alignment();
@@ -3040,6 +3082,8 @@
bool is_max_align_known_ : 1;
// Whether vaddr and paddr were set by a linker script.
bool are_addresses_set_ : 1;
+ // Whether this segment holds large data sections.
+ bool is_large_data_segment_ : 1;
};
// This class represents the output file.
Index: powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.12
diff -u -r1.12 powerpc.cc
--- powerpc.cc 27 Mar 2009 18:19:09 -0000 1.12
+++ powerpc.cc 22 Jun 2009 06:33:12 -0000
@@ -352,7 +352,11 @@
"/usr/lib/ld.so.1", // dynamic_linker
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
- 4 * 1024 // common_pagesize (overridable by -z common-page-size)
+ 4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
template<>
@@ -369,7 +373,11 @@
"/usr/lib/ld.so.1", // dynamic_linker
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
- 4 * 1024 // common_pagesize (overridable by -z common-page-size)
+ 4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
template<>
@@ -386,7 +394,11 @@
"/usr/lib/ld.so.1", // dynamic_linker
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
- 8 * 1024 // common_pagesize (overridable by -z common-page-size)
+ 8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
template<>
@@ -403,7 +415,11 @@
"/usr/lib/ld.so.1", // dynamic_linker
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
- 8 * 1024 // common_pagesize (overridable by -z common-page-size)
+ 8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
template<int size, bool big_endian>
Index: resolve.cc
===================================================================
RCS file: /cvs/src/src/gold/resolve.cc,v
retrieving revision 1.39
diff -u -r1.39 resolve.cc
--- resolve.cc 27 Feb 2009 19:57:46 -0000 1.39
+++ resolve.cc 22 Jun 2009 06:33:12 -0000
@@ -217,6 +217,8 @@
default:
if (type == elfcpp::STT_COMMON)
bits |= common_flag;
+ else if (!is_ordinary && Symbol::is_common_shndx(shndx))
+ bits |= common_flag;
else
bits |= def_flag;
break;
Index: sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.16
diff -u -r1.16 sparc.cc
--- sparc.cc 27 Mar 2009 18:19:09 -0000 1.16
+++ sparc.cc 22 Jun 2009 06:33:12 -0000
@@ -371,7 +371,11 @@
"/usr/lib/ld.so.1", // dynamic_linker
0x00010000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
- 8 * 1024 // common_pagesize (overridable by -z common-page-size)
+ 8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
template<>
@@ -388,7 +392,11 @@
"/usr/lib/sparcv9/ld.so.1", // dynamic_linker
0x100000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
- 8 * 1024 // common_pagesize (overridable by -z common-page-size)
+ 8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
// We have to take care here, even when operating in little-endian
Index: symtab.cc
===================================================================
RCS file: /cvs/src/src/gold/symtab.cc,v
retrieving revision 1.119
diff -u -r1.119 symtab.cc
--- symtab.cc 19 May 2009 22:14:17 -0000 1.119
+++ symtab.cc 22 Jun 2009 06:33:13 -0000
@@ -280,6 +280,16 @@
this->symsize_ = 0;
}
+// Return true if SHNDX represents a common symbol.
+
+bool
+Symbol::is_common_shndx(unsigned int shndx)
+{
+ return (shndx == elfcpp::SHN_COMMON
+ || shndx == parameters->target().small_common_shndx()
+ || shndx == parameters->target().large_common_shndx());
+}
+
// Allocate a common symbol.
template<int size>
@@ -477,7 +487,8 @@
Symbol_table::Symbol_table(unsigned int count,
const Version_script_info& version_script)
: saw_undefined_(0), offset_(0), table_(count), namepool_(),
- forwarders_(), commons_(), tls_commons_(), forced_locals_(), warnings_(),
+ forwarders_(), commons_(), tls_commons_(), small_commons_(),
+ large_commons_(), forced_locals_(), warnings_(),
version_script_(version_script), gc_(NULL)
{
namepool_.reserve(count);
@@ -975,10 +986,16 @@
// allocation.
if (!was_common && ret->is_common())
{
- if (ret->type() != elfcpp::STT_TLS)
- this->commons_.push_back(ret);
- else
+ if (ret->type() == elfcpp::STT_TLS)
this->tls_commons_.push_back(ret);
+ else if (!is_ordinary
+ && st_shndx == parameters->target().small_common_shndx())
+ this->small_commons_.push_back(ret);
+ else if (!is_ordinary
+ && st_shndx == parameters->target().large_common_shndx())
+ this->large_commons_.push_back(ret);
+ else
+ this->commons_.push_back(ret);
}
// If we're not doing a relocatable link, then any symbol with
@@ -2370,10 +2387,9 @@
bool is_ordinary;
unsigned int shndx = sym->shndx(&is_ordinary);
- // FIXME: We need some target specific support here.
if (!is_ordinary
&& shndx != elfcpp::SHN_ABS
- && shndx != elfcpp::SHN_COMMON)
+ && !Symbol::is_common_shndx(shndx))
{
gold_error(_("%s: unsupported symbol section 0x%x"),
sym->demangled_name().c_str(), shndx);
@@ -2394,7 +2410,8 @@
else if (shndx == elfcpp::SHN_UNDEF)
value = 0;
else if (!is_ordinary
- && (shndx == elfcpp::SHN_ABS || shndx == elfcpp::SHN_COMMON))
+ && (shndx == elfcpp::SHN_ABS
+ || Symbol::is_common_shndx(shndx)))
value = sym->value();
else
{
@@ -2597,10 +2614,9 @@
bool is_ordinary;
unsigned int in_shndx = sym->shndx(&is_ordinary);
- // FIXME: We need some target specific support here.
if (!is_ordinary
&& in_shndx != elfcpp::SHN_ABS
- && in_shndx != elfcpp::SHN_COMMON)
+ && !Symbol::is_common_shndx(in_shndx))
{
gold_error(_("%s: unsupported symbol section 0x%x"),
sym->demangled_name().c_str(), in_shndx);
@@ -2620,7 +2636,7 @@
else if (in_shndx == elfcpp::SHN_UNDEF
|| (!is_ordinary
&& (in_shndx == elfcpp::SHN_ABS
- || in_shndx == elfcpp::SHN_COMMON)))
+ || Symbol::is_common_shndx(in_shndx))))
shndx = in_shndx;
else
{
Index: symtab.h
===================================================================
RCS file: /cvs/src/src/gold/symtab.h,v
retrieving revision 1.88
diff -u -r1.88 symtab.h
--- symtab.h 25 Mar 2009 01:34:25 -0000 1.88
+++ symtab.h 22 Jun 2009 06:33:13 -0000
@@ -411,6 +411,11 @@
bool
final_value_is_known() const;
+ // Return true if SHNDX represents a common symbol. This depends on
+ // the target.
+ static bool
+ is_common_shndx(unsigned int shndx);
+
// Return whether this is a defined symbol (not undefined or
// common).
bool
@@ -422,7 +427,7 @@
unsigned int shndx = this->shndx(&is_ordinary);
return (is_ordinary
? shndx != elfcpp::SHN_UNDEF
- : shndx != elfcpp::SHN_COMMON);
+ : !Symbol::is_common_shndx(shndx));
}
// Return true if this symbol is from a dynamic object.
@@ -463,11 +468,13 @@
bool
is_common() const
{
+ if (this->type_ == elfcpp::STT_COMMON)
+ return true;
+ if (this->source_ != FROM_OBJECT)
+ return false;
bool is_ordinary;
- return (this->source_ == FROM_OBJECT
- && ((this->shndx(&is_ordinary) == elfcpp::SHN_COMMON
- && !is_ordinary)
- || this->type_ == elfcpp::STT_COMMON));
+ unsigned int shndx = this->shndx(&is_ordinary);
+ return !is_ordinary && Symbol::is_common_shndx(shndx);
}
// Return whether this symbol can be seen outside this object.
@@ -1505,6 +1512,16 @@
void
do_add_undefined_symbols_from_command_line();
+ // Types of common symbols.
+
+ enum Commons_section_type
+ {
+ COMMONS_NORMAL,
+ COMMONS_TLS,
+ COMMONS_SMALL,
+ COMMONS_LARGE
+ };
+
// Allocate the common symbols, sized version.
template<int size>
void
@@ -1513,7 +1530,8 @@
// Allocate the common symbols from one list.
template<int size>
void
- do_allocate_commons_list(Layout*, bool is_tls, Commons_type*, Mapfile*);
+ do_allocate_commons_list(Layout*, Commons_section_type, Commons_type*,
+ Mapfile*);
// Implement detect_odr_violations.
template<int size, bool big_endian>
@@ -1630,6 +1648,10 @@
// This is like the commons_ field, except that it holds TLS common
// symbols.
Commons_type tls_commons_;
+ // This is for small common symbols.
+ Commons_type small_commons_;
+ // This is for large common symbols.
+ Commons_type large_commons_;
// A list of symbols which have been forced to be local. We don't
// expect there to be very many of them, so we keep a list of them
// rather than walking the whole table to find them.
Index: target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.33
diff -u -r1.33 target.h
--- target.h 5 Jun 2009 21:32:56 -0000 1.33
+++ target.h 22 Jun 2009 06:33:13 -0000
@@ -141,6 +141,43 @@
wrap_char() const
{ return this->pti_->wrap_char; }
+ // Return the special section index which indicates a small common
+ // symbol. This will return SHN_UNDEF if there are no small common
+ // symbols.
+ elfcpp::Elf_Half
+ small_common_shndx() const
+ { return this->pti_->small_common_shndx; }
+
+ // Return values to add to the section flags for the section holding
+ // small common symbols.
+ elfcpp::Elf_Xword
+ small_common_section_flags() const
+ {
+ gold_assert(this->pti_->small_common_shndx != elfcpp::SHN_UNDEF);
+ return this->pti_->small_common_section_flags;
+ }
+
+ // Return the special section index which indicates a large common
+ // symbol. This will return SHN_UNDEF if there are no large common
+ // symbols.
+ elfcpp::Elf_Half
+ large_common_shndx() const
+ { return this->pti_->large_common_shndx; }
+
+ // Return values to add to the section flags for the section holding
+ // large common symbols.
+ elfcpp::Elf_Xword
+ large_common_section_flags() const
+ {
+ gold_assert(this->pti_->large_common_shndx != elfcpp::SHN_UNDEF);
+ return this->pti_->large_common_section_flags;
+ }
+
+ // This hook is called when an output section is created.
+ void
+ new_output_section(Output_section* os) const
+ { this->do_new_output_section(os); }
+
// This is called to tell the target to complete any sections it is
// handling. After this all sections must have their final size.
void
@@ -210,6 +247,16 @@
uint64_t abi_pagesize;
// The common page size used by actual implementations.
uint64_t common_pagesize;
+ // The special section index for small common symbols; SHN_UNDEF
+ // if none.
+ elfcpp::Elf_Half small_common_shndx;
+ // The special section index for large common symbols; SHN_UNDEF
+ // if none.
+ elfcpp::Elf_Half large_common_shndx;
+ // Section flags for small common section.
+ elfcpp::Elf_Xword small_common_section_flags;
+ // Section flags for large common section.
+ elfcpp::Elf_Xword large_common_section_flags;
};
Target(const Target_info* pti)
@@ -218,6 +265,11 @@
// Virtual function which may be implemented by the child class.
virtual void
+ do_new_output_section(Output_section*) const
+ { }
+
+ // Virtual function which may be implemented by the child class.
+ virtual void
do_finalize_sections(Layout*)
{ }
Index: x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.82
diff -u -r1.82 x86_64.cc
--- x86_64.cc 27 Apr 2009 16:23:57 -0000 1.82
+++ x86_64.cc 22 Jun 2009 06:33:13 -0000
@@ -67,6 +67,10 @@
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
+ // Hook for a new output section.
+ void
+ do_new_output_section(Output_section*) const;
+
// Scan the relocations to look for symbol adjustments.
void
gc_process_relocs(const General_options& options,
@@ -438,9 +442,23 @@
"/lib/ld64.so.1", // program interpreter
0x400000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
- 0x1000 // common_pagesize (overridable by -z common-page-size)
+ 0x1000, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE // large_common_section_flags
};
+// This is called when a new output section is created. This is where
+// we handle the SHF_X86_64_LARGE.
+
+void
+Target_x86_64::do_new_output_section(Output_section *os) const
+{
+ if ((os->flags() & elfcpp::SHF_X86_64_LARGE) != 0)
+ os->set_is_large_section();
+}
+
// Get the GOT section, creating it if necessary.
Output_data_got<64, false>*
Index: testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.93
diff -u -r1.93 Makefile.am
--- testsuite/Makefile.am 5 Jun 2009 21:32:57 -0000 1.93
+++ testsuite/Makefile.am 22 Jun 2009 06:33:14 -0000
@@ -1092,5 +1092,13 @@
discard_locals_test.o: discard_locals_test.c
$(COMPILE) -c -Wa,-L -o $@ $<
+if MCMODEL_MEDIUM
+check_PROGRAMS += large
+large_SOURCES = large.c
+large_CFLAGS = -mcmodel=medium
+large_DEPENDENCIES = gcctestdir/ld
+large_LDFLAGS = -Bgcctestdir/
+endif MCMODEL_MEDIUM
+
endif GCC
endif NATIVE_LINKER
Index: testsuite/large.c
===================================================================
RCS file: testsuite/large.c
diff -N testsuite/large.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/large.c 22 Jun 2009 06:33:14 -0000
@@ -0,0 +1,59 @@
+/* large.c -- a test case for gold
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@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. */
+
+#include <assert.h>
+
+/* Test large sections in gold. */
+
+int v1;
+int v2 = 1;
+int v3[0x10000];
+int v4[0x10000] = { 1 };
+const int v5[0x10000] = { 2 };
+int v6;
+int v7 = 1;
+
+int
+main (int argc __attribute__ ((unused)), char** argv __attribute ((unused)))
+{
+ assert (v1 == 0);
+ assert (v2 == 1);
+ assert (v3[0] == 0 && v3[0xffff] == 0);
+ assert (v4[0] == 1 && v4[0xffff] == 0);
+ assert (v5[0] == 2 && v5[0xffff] == 0);
+ assert (v6 == 0);
+ assert (v7 == 1);
+
+ /* The large symbols must follow the small ones. */
+ assert (&v1 < v3 && &v1 < v4 && &v1 < v5);
+ assert (&v2 < v3 && &v2 < v4 && &v2 < v5);
+ assert (&v6 < v3 && &v6 < v4 && &v6 < v5);
+ assert (&v7 < v3 && &v7 < v4 && &v7 < v5);
+
+ /* Large symbols should be BSS followed by read-only followed by
+ read-write. */
+ assert (v3 < v4);
+ assert (v3 < v5);
+ assert (v5 < v4);
+
+ return 0;
+}
Index: testsuite/testfile.cc
===================================================================
RCS file: /cvs/src/src/gold/testsuite/testfile.cc,v
retrieving revision 1.14
diff -u -r1.14 testfile.cc
--- testsuite/testfile.cc 28 Jan 2009 02:25:33 -0000 1.14
+++ testsuite/testfile.cc 22 Jun 2009 06:33:14 -0000
@@ -99,7 +99,11 @@
"/dummy", // dynamic_linker
0x08000000, // default_text_segment_address
0x1000, // abi_pagesize
- 0x1000 // common_pagesize
+ 0x1000, // common_pagesize
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
// The test targets.
Index: elfcpp.h
===================================================================
RCS file: /cvs/src/src/elfcpp/elfcpp.h,v
retrieving revision 1.23
diff -u -r1.23 elfcpp.h
--- elfcpp.h 27 May 2009 18:27:42 -0000 1.23
+++ elfcpp.h 22 Jun 2009 06:54:36 -0000
@@ -321,6 +321,9 @@
// with the SHF_LINK_ORDER and SHF_ORDERED section flags.
SHN_BEFORE = 0xff00,
SHN_AFTER = 0xff01,
+
+ // x86_64 specific large common symbol.
+ SHN_X86_64_LCOMMON = 0xff02
};
// The valid values found in the Shdr sh_type field.
@@ -382,6 +385,9 @@
SHT_ARM_DEBUGOVERLAY = 0x70000004,
SHT_ARM_OVERLAYSECTION = 0x70000005,
+ // x86_64 unwind information.
+ SHT_X86_64_UNWIND = 0x70000001,
+
// Link editor is to sort the entries in this section based on the
// address specified in the associated symbol table entry.
SHT_ORDERED = 0x7fffffff,
@@ -415,6 +421,9 @@
// executable or shared object. This flag is ignored if SHF_ALLOC
// is also set, or if relocations exist against the section.
SHF_EXCLUDE = 0x80000000,
+
+ // x86_64 specific large section.
+ SHF_X86_64_LARGE = 0x10000000
};
// Bit flags which appear in the first 32-bit word of the section data