diff options
-rw-r--r-- | gold/ChangeLog | 75 | ||||
-rw-r--r-- | gold/Makefile.in | 2 | ||||
-rw-r--r-- | gold/arm.cc | 6 | ||||
-rw-r--r-- | gold/common.cc | 69 | ||||
-rwxr-xr-x | gold/configure | 22 | ||||
-rw-r--r-- | gold/configure.ac | 3 | ||||
-rw-r--r-- | gold/i386.cc | 6 | ||||
-rw-r--r-- | gold/layout.cc | 101 | ||||
-rw-r--r-- | gold/object.cc | 2 | ||||
-rw-r--r-- | gold/output.cc | 69 | ||||
-rw-r--r-- | gold/output.h | 44 | ||||
-rw-r--r-- | gold/powerpc.cc | 24 | ||||
-rw-r--r-- | gold/resolve.cc | 2 | ||||
-rw-r--r-- | gold/sparc.cc | 12 | ||||
-rw-r--r-- | gold/symtab.cc | 36 | ||||
-rw-r--r-- | gold/symtab.h | 34 | ||||
-rw-r--r-- | gold/target.h | 52 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 8 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 68 | ||||
-rw-r--r-- | gold/testsuite/large.c | 59 | ||||
-rw-r--r-- | gold/testsuite/testfile.cc | 6 | ||||
-rw-r--r-- | gold/x86_64.cc | 20 |
22 files changed, 622 insertions, 98 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 02ee8fa..308441a 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,78 @@ +2009-06-21 Ian Lance Taylor <ian@airs.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. + 2009-06-05 Doug Kwan <dougkwan@google.com> * Makefile.am (CCFILES): Add target.cc. diff --git a/gold/Makefile.in b/gold/Makefile.in index 0a3245f..a32de6b 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -213,6 +213,8 @@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ +MCMODEL_MEDIUM_FALSE = @MCMODEL_MEDIUM_FALSE@ +MCMODEL_MEDIUM_TRUE = @MCMODEL_MEDIUM_TRUE@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGMERGE = @MSGMERGE@ diff --git a/gold/arm.cc b/gold/arm.cc index 76538de..491f254 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -449,7 +449,11 @@ const Target::Target_info Target_arm<big_endian>::arm_info = "/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 diff --git a/gold/common.cc b/gold/common.cc index 632a20b..f90ae40 100644 --- a/gold/common.cc +++ b/gold/common.cc @@ -146,10 +146,18 @@ template<int size> 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 @@ Symbol_table::do_allocate_commons(Layout* layout, Mapfile* mapfile) 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 @@ Symbol_table::do_allocate_commons_list(Layout* layout, bool is_tls, 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. diff --git a/gold/configure b/gold/configure index 8a6e728..0ada4cf 100755 --- a/gold/configure +++ b/gold/configure @@ -309,7 +309,7 @@ ac_includes_default="\ # include <unistd.h> #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE PLUGINS_TRUE PLUGINS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE OMP_SUPPORT_TRUE OMP_SUPPORT_FALSE TLS_GNU2_DIALECT_TRUE TLS_GNU2_DIALECT_FALSE TLS_DESCRIPTORS_TRUE TLS_DESCRIPTORS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE RANDOM_SEED_CFLAGS WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE PLUGINS_TRUE PLUGINS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE MCMODEL_MEDIUM_TRUE MCMODEL_MEDIUM_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE OMP_SUPPORT_TRUE OMP_SUPPORT_FALSE TLS_GNU2_DIALECT_TRUE TLS_GNU2_DIALECT_FALSE TLS_DESCRIPTORS_TRUE TLS_DESCRIPTORS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE RANDOM_SEED_CFLAGS WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS' ac_subst_files='' ac_pwd=`pwd` @@ -4603,6 +4603,17 @@ else fi + + +if test "$target_cpu" = "x86_64"; then + MCMODEL_MEDIUM_TRUE= + MCMODEL_MEDIUM_FALSE='#' +else + MCMODEL_MEDIUM_TRUE='#' + MCMODEL_MEDIUM_FALSE= +fi + + echo "$as_me:$LINENO: checking for thread support" >&5 echo $ECHO_N "checking for thread support... $ECHO_C" >&6 if test "${gold_cv_c_thread+set}" = set; then @@ -7651,6 +7662,13 @@ echo "$as_me: error: conditional \"FN_PTRS_IN_SO_WITHOUT_PIC\" was never defined Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi +if test -z "${MCMODEL_MEDIUM_TRUE}" && test -z "${MCMODEL_MEDIUM_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"MCMODEL_MEDIUM\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"MCMODEL_MEDIUM\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi if test -z "${TLS_TRUE}" && test -z "${TLS_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"TLS\" was never defined. Usually this means the macro was only invoked conditionally." >&5 @@ -8335,6 +8353,8 @@ s,@GCC_TRUE@,$GCC_TRUE,;t t s,@GCC_FALSE@,$GCC_FALSE,;t t s,@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@,$FN_PTRS_IN_SO_WITHOUT_PIC_TRUE,;t t s,@FN_PTRS_IN_SO_WITHOUT_PIC_FALSE@,$FN_PTRS_IN_SO_WITHOUT_PIC_FALSE,;t t +s,@MCMODEL_MEDIUM_TRUE@,$MCMODEL_MEDIUM_TRUE,;t t +s,@MCMODEL_MEDIUM_FALSE@,$MCMODEL_MEDIUM_FALSE,;t t s,@TLS_TRUE@,$TLS_TRUE,;t t s,@TLS_FALSE@,$TLS_FALSE,;t t s,@STATIC_TLS_TRUE@,$STATIC_TLS_TRUE,;t t diff --git a/gold/configure.ac b/gold/configure.ac index cf59a6a..c249ae4 100644 --- a/gold/configure.ac +++ b/gold/configure.ac @@ -221,6 +221,9 @@ AM_CONDITIONAL(FN_PTRS_IN_SO_WITHOUT_PIC, [ *) 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;], diff --git a/gold/i386.cc b/gold/i386.cc index 11204f4..0b68613 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -444,7 +444,11 @@ const Target::Target_info Target_i386::i386_info = "/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. 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); } diff --git a/gold/object.cc b/gold/object.cc index 88b6028..c3c9c7bcf 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1554,7 +1554,7 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index, 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 { diff --git a/gold/output.cc b/gold/output.cc index b532136..911a49a 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1764,6 +1764,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, 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 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) 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 @@ Output_segment::add_output_section(Output_section* os, { 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 @@ Output_segment::add_output_section(Output_section* os, 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); } diff --git a/gold/output.h b/gold/output.h index 5d2c62f..3e46ad8 100644 --- a/gold/output.h +++ b/gold/output.h @@ -2195,6 +2195,33 @@ class Output_section : public Output_data 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 @@ class Output_section : public Output_data 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 @@ class Output_segment 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 @@ class Output_segment 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. diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 9e3d327..a940fd8 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -352,7 +352,11 @@ Target::Target_info Target_powerpc<32, true>::powerpc_info = "/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 @@ Target::Target_info Target_powerpc<32, false>::powerpc_info = "/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 @@ Target::Target_info Target_powerpc<64, true>::powerpc_info = "/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 @@ Target::Target_info Target_powerpc<64, false>::powerpc_info = "/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> diff --git a/gold/resolve.cc b/gold/resolve.cc index bd327e8..9da963f 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -217,6 +217,8 @@ symbol_to_bits(elfcpp::STB binding, bool is_dynamic, 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; diff --git a/gold/sparc.cc b/gold/sparc.cc index d15b833..34288de 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -371,7 +371,11 @@ Target::Target_info Target_sparc<32, true>::sparc_info = "/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 @@ Target::Target_info Target_sparc<64, true>::sparc_info = "/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 diff --git a/gold/symtab.cc b/gold/symtab.cc index 3d179ef..daf9daf 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -280,6 +280,16 @@ Sized_symbol<size>::init_undefined(const char* name, const char* version, 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::set_output_section(Output_section* os) 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 @@ Symbol_table::add_from_object(Object* object, // 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 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) 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 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym) 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 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, 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 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, 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 { diff --git a/gold/symtab.h b/gold/symtab.h index 660fc4d..be6bc12 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -411,6 +411,11 @@ class Symbol 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 @@ class Symbol 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 @@ class Symbol 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 @@ class Symbol_table 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 @@ class Symbol_table // 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 @@ class Symbol_table // 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. diff --git a/gold/target.h b/gold/target.h index 2a28105..597a4f9 100644 --- a/gold/target.h +++ b/gold/target.h @@ -141,6 +141,43 @@ class Target 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 @@ class Target 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 @@ class Target // 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*) { } diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 3bb5bd3..5afd4b0 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -1092,5 +1092,13 @@ discard_locals_test.syms: discard_locals_test 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 diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 1bc579e..c108274 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -48,7 +48,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \ $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \ $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15) \ - $(am__EXEEXT_16) $(am__EXEEXT_17) + $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) # Test --detect-odr-violations @@ -330,6 +330,20 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_2.a \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libexclude_libs_test_3.a \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms +@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_28 = large +@GCC_FALSE@large_DEPENDENCIES = libgoldtest.a ../libgold.a \ +@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \ +@GCC_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +@MCMODEL_MEDIUM_FALSE@large_DEPENDENCIES = libgoldtest.a ../libgold.a \ +@MCMODEL_MEDIUM_FALSE@ ../../libiberty/libiberty.a \ +@MCMODEL_MEDIUM_FALSE@ $(am__DEPENDENCIES_1) \ +@MCMODEL_MEDIUM_FALSE@ $(am__DEPENDENCIES_1) \ +@MCMODEL_MEDIUM_FALSE@ $(am__DEPENDENCIES_1) +@NATIVE_LINKER_FALSE@large_DEPENDENCIES = libgoldtest.a ../libgold.a \ +@NATIVE_LINKER_FALSE@ ../../libiberty/libiberty.a \ +@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \ +@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \ +@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) subdir = testsuite DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -438,6 +452,7 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS) @GCC_TRUE@@NATIVE_LINKER_TRUE@ exclude_libs_test$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test$(EXEEXT) +@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_18 = large$(EXEEXT) basic_pic_test_SOURCES = basic_pic_test.c basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT) basic_pic_test_LDADD = $(LDADD) @@ -589,6 +604,10 @@ am__justsyms_SOURCES_DIST = justsyms_1.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms_1.$(OBJEXT) justsyms_OBJECTS = $(am_justsyms_OBJECTS) justsyms_LDADD = $(LDADD) +am__large_SOURCES_DIST = large.c +@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am_large_OBJECTS = large-large.$(OBJEXT) +large_OBJECTS = $(am_large_OBJECTS) +large_LDADD = $(LDADD) local_labels_test_SOURCES = local_labels_test.c local_labels_test_OBJECTS = local_labels_test.$(OBJEXT) local_labels_test_LDADD = $(LDADD) @@ -923,15 +942,16 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(exclude_libs_test_SOURCES) \ flagstest_compress_debug_sections.c flagstest_o_specialfile.c \ flagstest_o_specialfile_and_compress_debug_sections.c \ - $(initpri1_SOURCES) $(justsyms_SOURCES) local_labels_test.c \ - many_sections_r_test.c $(many_sections_test_SOURCES) \ - $(object_unittest_SOURCES) plugin_test_1.c plugin_test_2.c \ - plugin_test_3.c plugin_test_4.c $(protected_1_SOURCES) \ - $(protected_2_SOURCES) $(relro_script_test_SOURCES) \ - $(relro_test_SOURCES) $(script_test_1_SOURCES) \ - $(script_test_2_SOURCES) script_test_3.c \ - $(thin_archive_test_1_SOURCES) $(thin_archive_test_2_SOURCES) \ - $(tls_pic_test_SOURCES) $(tls_shared_gd_to_ie_test_SOURCES) \ + $(initpri1_SOURCES) $(justsyms_SOURCES) $(large_SOURCES) \ + local_labels_test.c many_sections_r_test.c \ + $(many_sections_test_SOURCES) $(object_unittest_SOURCES) \ + plugin_test_1.c plugin_test_2.c plugin_test_3.c \ + plugin_test_4.c $(protected_1_SOURCES) $(protected_2_SOURCES) \ + $(relro_script_test_SOURCES) $(relro_test_SOURCES) \ + $(script_test_1_SOURCES) $(script_test_2_SOURCES) \ + script_test_3.c $(thin_archive_test_1_SOURCES) \ + $(thin_archive_test_2_SOURCES) $(tls_pic_test_SOURCES) \ + $(tls_shared_gd_to_ie_test_SOURCES) \ $(tls_shared_gnu2_gd_to_ie_test_SOURCES) \ $(tls_shared_gnu2_test_SOURCES) $(tls_shared_ie_test_SOURCES) \ $(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \ @@ -979,8 +999,8 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ flagstest_compress_debug_sections.c flagstest_o_specialfile.c \ flagstest_o_specialfile_and_compress_debug_sections.c \ $(am__initpri1_SOURCES_DIST) $(am__justsyms_SOURCES_DIST) \ - local_labels_test.c many_sections_r_test.c \ - $(am__many_sections_test_SOURCES_DIST) \ + $(am__large_SOURCES_DIST) local_labels_test.c \ + many_sections_r_test.c $(am__many_sections_test_SOURCES_DIST) \ $(object_unittest_SOURCES) plugin_test_1.c plugin_test_2.c \ plugin_test_3.c plugin_test_4.c \ $(am__protected_1_SOURCES_DIST) \ @@ -1086,6 +1106,8 @@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ +MCMODEL_MEDIUM_FALSE = @MCMODEL_MEDIUM_FALSE@ +MCMODEL_MEDIUM_TRUE = @MCMODEL_MEDIUM_TRUE@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGMERGE = @MSGMERGE@ @@ -1546,6 +1568,10 @@ binary_unittest_SOURCES = binary_unittest.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test_SOURCES = discard_locals_test.c @GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test_LDFLAGS = -Bgcctestdir/ -Wl,--discard-locals +@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_SOURCES = large.c +@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_CFLAGS = -mcmodel=medium +@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_DEPENDENCIES = gcctestdir/ld +@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_LDFLAGS = -Bgcctestdir/ all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am @@ -1689,6 +1715,9 @@ initpri1$(EXEEXT): $(initpri1_OBJECTS) $(initpri1_DEPENDENCIES) justsyms$(EXEEXT): $(justsyms_OBJECTS) $(justsyms_DEPENDENCIES) @rm -f justsyms$(EXEEXT) $(CXXLINK) $(justsyms_LDFLAGS) $(justsyms_OBJECTS) $(justsyms_LDADD) $(LIBS) +large$(EXEEXT): $(large_OBJECTS) $(large_DEPENDENCIES) + @rm -f large$(EXEEXT) + $(LINK) $(large_LDFLAGS) $(large_OBJECTS) $(large_LDADD) $(LIBS) @GCC_FALSE@local_labels_test$(EXEEXT): $(local_labels_test_OBJECTS) $(local_labels_test_DEPENDENCIES) @GCC_FALSE@ @rm -f local_labels_test$(EXEEXT) @GCC_FALSE@ $(LINK) $(local_labels_test_LDFLAGS) $(local_labels_test_OBJECTS) $(local_labels_test_LDADD) $(LIBS) @@ -1928,6 +1957,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile_and_compress_debug_sections.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initpri1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/justsyms_1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/large-large.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_labels_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_r_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_test.Po@am__quote@ @@ -1980,6 +2010,20 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +large-large.o: large.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -MT large-large.o -MD -MP -MF "$(DEPDIR)/large-large.Tpo" -c -o large-large.o `test -f 'large.c' || echo '$(srcdir)/'`large.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/large-large.Tpo" "$(DEPDIR)/large-large.Po"; else rm -f "$(DEPDIR)/large-large.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='large.c' object='large-large.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -c -o large-large.o `test -f 'large.c' || echo '$(srcdir)/'`large.c + +large-large.obj: large.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -MT large-large.obj -MD -MP -MF "$(DEPDIR)/large-large.Tpo" -c -o large-large.obj `if test -f 'large.c'; then $(CYGPATH_W) 'large.c'; else $(CYGPATH_W) '$(srcdir)/large.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/large-large.Tpo" "$(DEPDIR)/large-large.Po"; else rm -f "$(DEPDIR)/large-large.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='large.c' object='large-large.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(large_CFLAGS) $(CFLAGS) -c -o large-large.obj `if test -f 'large.c'; then $(CYGPATH_W) 'large.c'; else $(CYGPATH_W) '$(srcdir)/large.c'; fi` + .cc.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi diff --git a/gold/testsuite/large.c b/gold/testsuite/large.c new file mode 100644 index 0000000..796242a --- /dev/null +++ b/gold/testsuite/large.c @@ -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; +} diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc index a2a45be..2532307 100644 --- a/gold/testsuite/testfile.cc +++ b/gold/testsuite/testfile.cc @@ -99,7 +99,11 @@ const Target::Target_info Target_test<size, big_endian>::test_target_info = "/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. diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 611c37e..91b542e 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -67,6 +67,10 @@ class Target_x86_64 : public Target_freebsd<64, false> 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 @@ const Target::Target_info Target_x86_64::x86_64_info = "/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>* |