]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
* object.cc (Xindex::initialize_symtab_xindex): New function.
authorIan Lance Taylor <ian@airs.com>
Sat, 19 Apr 2008 18:30:58 +0000 (18:30 +0000)
committerIan Lance Taylor <ian@airs.com>
Sat, 19 Apr 2008 18:30:58 +0000 (18:30 +0000)
(Xindex::read_symtab_xindex): New function.
(Xindex::sym_xindex_to_shndx): New function.
(Sized_relobj::find_symtab): Pick up SHT_SYMTAB_SHNDX section if
available.
(Sized_relobj::do_initialize_xindex): New function.
(Sized_relobj::do_read_symbols): Adjust section links.
(Sized_relobj::symbol_section_and_value): Add is_ordinary
parameter.  Change all callers.
(Sized_relobj::include_section_group): Adjust section links and
symbol section indexes.
(Sized_relobj::do_layout): Adjust section links.
(Sized_relobj::do_count_local_symbols): Adjust section links and
symbol section indexes.
(Sized_relobj::do_finalize_local_symbols): Distinguish between
ordinary and special symbols.
(Sized_relobj::write_local_symbols): Add symtab_xindex and
dynsym_xindex parameters.  Change all callers.  Adjust section
links.  Use SHN_XINDEX when needed.
(Sized_relobj::get_symbol_location_info): Adjust section links.
Don't get fooled by special symbols.
* object.h (class Xindex): Define.
(class Object): Add xindex_ parameter.  Declare virtual functoin
do_initialize_xindex.
(Object::adjust_sym_shndx): New function.
(Object::set_xindex): New protected function.
(class Symbol_value): Add is_ordinary_shndx_ field.
(Symbol_value::Symbol_value): Initialize is_ordinary_shndx_.
(Symbol_value::value): Assert ordinary section.
(Symbol_value::initialize_input_to_output_map): Likewise.
(Symbol_value::set_input_shndx): Add is_ordinary parameter.
Change all callers.
(Symbol_value::input_shndx): Add is_ordinary parameter.  Change
all callers.
(class Sized_relobj): Update declarations.
(Sized_relobj::local_symbol_input_shndx): Add is_ordinary
parameter.  Change all callers.
(Sized_relobj::adjust_shndx): New function.
* dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize dynsym_shndx_
field.
(Sized_dynobj::find_dynsym_sections): Remove pdynsym_shndx
parameter.  Change all callers.  Pick up SHT_DYNSYM_SHNDX section
for SHT_DYNSYM section if available.  Set dynsym_shndx_ field.
(Sized_dynobj::read_dynsym_section): Adjust section links.
(Sized_dynobj::read_dynamic): Likewise.
(Sized_dynobj::do_read_symbols): Use dynsym_shndx_ field.  Adjust
section links.
(Sized_dynobj::do_initialize_xindex): New function.
* dynobj.h (class Sized_dynobj): Add dynsym_shndx_ field.  Declare
do_initialize_xindex.
(Sized_dynobj::adjust_shndx): New function.
* layout.cc (Layout::Layout): Initialize symtab_xindex_ and
dynsym_xindex_ fields.
(Layout::finalize): Add a call to set_section_indexes before
creating the symtab sections.
(Layout::set_section_indexes): Don't do anything if the section
already has a section index.
(Layout::create_symtab_sections): Add shnum parameter.  Change
caller.  Create .symtab_shndx section if needed.
(Layout::create_shdrs): Add shstrtab_section parameter.  Change
caller.
(Layout::allocated_output_section_count): New function.
(Layout::create_dynamic_symtab): Create .dynsym_shndx section if
needed.
* layout.h (class Layout): Add symtab_xindex_ and dynsym_xindex_
fields.  Update declarations.
(Layout::symtab_xindex): New function.
(Layout::dynsym_xindex): New function.
(class Write_symbols_task): Add layout_ field.
(Write_symbols_task::Write_symbols_task): Add layout parameter.
Change caller.
* output.cc (Output_section_headers::Output_section_headers): Add
shstrtab_section parameter.  Change all callers.
(Output_section_headers::do_sized_write): Store overflow values
for section count and section string table section index in
section header zero.
(Output_file_header::do_sized_write): Check for overflow of
section count and section string table section index.
(Output_symtab_xindex::do_write): New function.
(Output_symtab_xindex::endian_do_write): New function.
* output.h (class Output_section_headers): Add shstrtab_section_.
Update declarations.
(class Output_symtab_xindex): Define.
(Output_section::has_out_shndx): New function.
* symtab.cc (Symbol::init_fields): Initialize is_ordinary_shndx_
field.
(Symbol::init_base): Add st_shndx and is_ordinary parameters.
Change all callers.
(Sized_symbol::init): Likewise.
(Symbol::output_section): Check for ordinary symbol.
(Symbol_table::add_from_object): Remove orig_sym parameter.  Add
st_shndx, is_ordinary, and orig_st_shndx parameters.  Change all
callers.
(Symbol_table::add_from_relobj): Add symndx_offset parameter.
Change all callers.  Simplify handling of symbols from sections
not included in the link.
(Symbol_table::add_from_dynobj): Handle ordinary symbol
distinction.
(Weak_alias_sorter::operator()): Assert that symbols are
ordinary.
(Symbol_table::sized_finalize_symbol): Handle ordinary symbol
distinction.
(Symbol_table::write_globals): Add symtab_xindex and dynsym_xindex
parameters.  Change all callers.
(Symbol_table::sized_write_globals): Likewise.  Handle ordinary
symbol distinction.  Use SHN_XINDEX when needed.
(Symbol_table::write_section_symbol): Add symtab_xindex
parameter.  Change all callers.
(Symbol_table::sized_write_section_symbol): Likewise.  Use
SHN_XINDEX when needed.
* symtab.h (class Symbol): Add is_ordinary_shndx_ field.  Update
declarations.
(Symbol::shndx): Add is_ordinary parameter.  Change all callers.
(Symbol::is_defined): Check is_ordinary.
(Symbol::is_undefined, Symbol::is_weak_undefined): Likewise.
(Symbol::is_absolute, Symbol::is_common): Likewise.
(class Sized_symbol): Update declarations.
(class Symbol_table): Update declarations.
* resolve.cc (Symbol::override_base): Add st_shndx and is_ordinary
parameters.  Change all callers.
(Sized_symbol::override): Likewise.
(Symbol_table::override): Likewise.
(symbol_to_bits): Add is_ordinary parameter.  Change all callers.
(Symbol_table::resolve): Remove orig_sym parameter.  Add st_shndx,
is_ordinary, and orig_st_shndx parameters.  Change all callers.
* copy-relocs.cc (Copy_relocs::emit_copy_reloc): Require symbol
to be in an ordinary section.
* dwarf_reader.cc (Sized_dwarf_line_info::symbol_section): Add
object and is_ordinary parameters.  Change all callers.
(Sized_dwarf_line_info::read_relocs): Add object parameter.
Change all callers.  Don't add undefined or non-ordinary symbols
to reloc_map_.
(Sized_dwarf_line_info::read_line_mappings): Add object parameter.
Change all callers.
* dwarf_reader.h (class Sized_dwarf_line_info): Update
declarations.
* ehframe.cc (Eh_frame::read_fde): Check for ordinary symbol.
* reloc.cc (Sized_relobj::do_read_relocs): Adjust section links.
(Sized_relobj::relocate_sections): Likewise.
* target-reloc.h (scan_relocs): Adjust section symbol index.
(scan_relocatable_relocs): Likewise.
* i386.cc (Scan::local): Check for ordinary symbols.
* sparc.cc (Scan::local): Likewise.
* x86_64.cc (Scan::local): Likewise.
* testsuite/binary_unittest.cc (Sized_binary_test): Update calls
to symbol_section_and_value.
* testsuite/many_sections_test.cc: New file.
* testsuite/Makefile.am (BUILT_SOURCES): Define.
(check_PROGRAMS): Add many_sections_test.
(many_sections_test_SOURCES): Define.
(many_sections_test_DEPENDENCIES): Define.
(many_sections_test_LDFLAGS): Define.
(BUILT_SOURCES): Add many_sections_define.h.
(many_sections_define.h): New target.
(BUILT_SOURCES): Add many_sections_check.h.
(many_sections_check.h): New target.
(check_PROGRAMS): Add many_sections_r_test.
(many_sections_r_test_SOURCES): Define.
(many_sections_r_test_DEPENDENCIES): Define.
(many_sections_r_test_LDFLAGS): Define.
(many_sections_r_test_LDADD): Define.
(many_sections_r_test.o): New target.
* testsuite/Makefile.in: Rebuild.

26 files changed:
gold/ChangeLog
gold/copy-relocs.cc
gold/dwarf_reader.cc
gold/dwarf_reader.h
gold/dynobj.cc
gold/dynobj.h
gold/ehframe.cc
gold/gold.cc
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/output.cc
gold/output.h
gold/reloc.cc
gold/resolve.cc
gold/sparc.cc
gold/symtab.cc
gold/symtab.h
gold/target-reloc.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/binary_unittest.cc
gold/testsuite/many_sections_test.cc [new file with mode: 0644]
gold/x86_64.cc

index a230f5965671876725308803780e10a41ddfdc96..877d82826da6b3c75ce08dcb6ed5d371626a088e 100644 (file)
@@ -1,3 +1,169 @@
+2008-04-19  Ian Lance Taylor  <iant@google.com>
+
+       * object.cc (Xindex::initialize_symtab_xindex): New function.
+       (Xindex::read_symtab_xindex): New function.
+       (Xindex::sym_xindex_to_shndx): New function.
+       (Sized_relobj::find_symtab): Pick up SHT_SYMTAB_SHNDX section if
+       available.
+       (Sized_relobj::do_initialize_xindex): New function.
+       (Sized_relobj::do_read_symbols): Adjust section links.
+       (Sized_relobj::symbol_section_and_value): Add is_ordinary
+       parameter.  Change all callers.
+       (Sized_relobj::include_section_group): Adjust section links and
+       symbol section indexes.
+       (Sized_relobj::do_layout): Adjust section links.
+       (Sized_relobj::do_count_local_symbols): Adjust section links and
+       symbol section indexes.
+       (Sized_relobj::do_finalize_local_symbols): Distinguish between
+       ordinary and special symbols.
+       (Sized_relobj::write_local_symbols): Add symtab_xindex and
+       dynsym_xindex parameters.  Change all callers.  Adjust section
+       links.  Use SHN_XINDEX when needed.
+       (Sized_relobj::get_symbol_location_info): Adjust section links.
+       Don't get fooled by special symbols.
+       * object.h (class Xindex): Define.
+       (class Object): Add xindex_ parameter.  Declare virtual functoin
+       do_initialize_xindex.
+       (Object::adjust_sym_shndx): New function.
+       (Object::set_xindex): New protected function.
+       (class Symbol_value): Add is_ordinary_shndx_ field.
+       (Symbol_value::Symbol_value): Initialize is_ordinary_shndx_.
+       (Symbol_value::value): Assert ordinary section.
+       (Symbol_value::initialize_input_to_output_map): Likewise.
+       (Symbol_value::set_input_shndx): Add is_ordinary parameter.
+       Change all callers.
+       (Symbol_value::input_shndx): Add is_ordinary parameter.  Change
+       all callers.
+       (class Sized_relobj): Update declarations.
+       (Sized_relobj::local_symbol_input_shndx): Add is_ordinary
+       parameter.  Change all callers.
+       (Sized_relobj::adjust_shndx): New function.
+       * dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize dynsym_shndx_
+       field.
+       (Sized_dynobj::find_dynsym_sections): Remove pdynsym_shndx
+       parameter.  Change all callers.  Pick up SHT_DYNSYM_SHNDX section
+       for SHT_DYNSYM section if available.  Set dynsym_shndx_ field.
+       (Sized_dynobj::read_dynsym_section): Adjust section links.
+       (Sized_dynobj::read_dynamic): Likewise.
+       (Sized_dynobj::do_read_symbols): Use dynsym_shndx_ field.  Adjust
+       section links.
+       (Sized_dynobj::do_initialize_xindex): New function.
+       * dynobj.h (class Sized_dynobj): Add dynsym_shndx_ field.  Declare
+       do_initialize_xindex.
+       (Sized_dynobj::adjust_shndx): New function.
+       * layout.cc (Layout::Layout): Initialize symtab_xindex_ and
+       dynsym_xindex_ fields.
+       (Layout::finalize): Add a call to set_section_indexes before
+       creating the symtab sections.
+       (Layout::set_section_indexes): Don't do anything if the section
+       already has a section index.
+       (Layout::create_symtab_sections): Add shnum parameter.  Change
+       caller.  Create .symtab_shndx section if needed.
+       (Layout::create_shdrs): Add shstrtab_section parameter.  Change
+       caller.
+       (Layout::allocated_output_section_count): New function.
+       (Layout::create_dynamic_symtab): Create .dynsym_shndx section if
+       needed.
+       * layout.h (class Layout): Add symtab_xindex_ and dynsym_xindex_
+       fields.  Update declarations.
+       (Layout::symtab_xindex): New function.
+       (Layout::dynsym_xindex): New function.
+       (class Write_symbols_task): Add layout_ field.
+       (Write_symbols_task::Write_symbols_task): Add layout parameter.
+       Change caller.
+       * output.cc (Output_section_headers::Output_section_headers): Add
+       shstrtab_section parameter.  Change all callers.
+       (Output_section_headers::do_sized_write): Store overflow values
+       for section count and section string table section index in
+       section header zero.
+       (Output_file_header::do_sized_write): Check for overflow of
+       section count and section string table section index.
+       (Output_symtab_xindex::do_write): New function.
+       (Output_symtab_xindex::endian_do_write): New function.
+       * output.h (class Output_section_headers): Add shstrtab_section_.
+       Update declarations.
+       (class Output_symtab_xindex): Define.
+       (Output_section::has_out_shndx): New function.
+       * symtab.cc (Symbol::init_fields): Initialize is_ordinary_shndx_
+       field.
+       (Symbol::init_base): Add st_shndx and is_ordinary parameters.
+       Change all callers.
+       (Sized_symbol::init): Likewise.
+       (Symbol::output_section): Check for ordinary symbol.
+       (Symbol_table::add_from_object): Remove orig_sym parameter.  Add
+       st_shndx, is_ordinary, and orig_st_shndx parameters.  Change all
+       callers.
+       (Symbol_table::add_from_relobj): Add symndx_offset parameter.
+       Change all callers.  Simplify handling of symbols from sections
+       not included in the link.
+       (Symbol_table::add_from_dynobj): Handle ordinary symbol
+       distinction.
+       (Weak_alias_sorter::operator()): Assert that symbols are
+       ordinary.
+       (Symbol_table::sized_finalize_symbol): Handle ordinary symbol
+       distinction.
+       (Symbol_table::write_globals): Add symtab_xindex and dynsym_xindex
+       parameters.  Change all callers.
+       (Symbol_table::sized_write_globals): Likewise.  Handle ordinary
+       symbol distinction.  Use SHN_XINDEX when needed.
+       (Symbol_table::write_section_symbol): Add symtab_xindex
+       parameter.  Change all callers.
+       (Symbol_table::sized_write_section_symbol): Likewise.  Use
+       SHN_XINDEX when needed.
+       * symtab.h (class Symbol): Add is_ordinary_shndx_ field.  Update
+       declarations.
+       (Symbol::shndx): Add is_ordinary parameter.  Change all callers.
+       (Symbol::is_defined): Check is_ordinary.
+       (Symbol::is_undefined, Symbol::is_weak_undefined): Likewise.
+       (Symbol::is_absolute, Symbol::is_common): Likewise.
+       (class Sized_symbol): Update declarations.
+       (class Symbol_table): Update declarations.
+       * resolve.cc (Symbol::override_base): Add st_shndx and is_ordinary
+       parameters.  Change all callers.
+       (Sized_symbol::override): Likewise.
+       (Symbol_table::override): Likewise.
+       (symbol_to_bits): Add is_ordinary parameter.  Change all callers.
+       (Symbol_table::resolve): Remove orig_sym parameter.  Add st_shndx,
+       is_ordinary, and orig_st_shndx parameters.  Change all callers.
+       * copy-relocs.cc (Copy_relocs::emit_copy_reloc): Require symbol
+       to be in an ordinary section.
+       * dwarf_reader.cc (Sized_dwarf_line_info::symbol_section): Add
+       object and is_ordinary parameters.  Change all callers.
+       (Sized_dwarf_line_info::read_relocs): Add object parameter.
+       Change all callers.  Don't add undefined or non-ordinary symbols
+       to reloc_map_.
+       (Sized_dwarf_line_info::read_line_mappings): Add object parameter.
+       Change all callers.
+       * dwarf_reader.h (class Sized_dwarf_line_info): Update
+       declarations.
+       * ehframe.cc (Eh_frame::read_fde): Check for ordinary symbol.
+       * reloc.cc (Sized_relobj::do_read_relocs): Adjust section links.
+       (Sized_relobj::relocate_sections): Likewise.
+       * target-reloc.h (scan_relocs): Adjust section symbol index.
+       (scan_relocatable_relocs): Likewise.
+       * i386.cc (Scan::local): Check for ordinary symbols.
+       * sparc.cc (Scan::local): Likewise.
+       * x86_64.cc (Scan::local): Likewise.
+       * testsuite/binary_unittest.cc (Sized_binary_test): Update calls
+       to symbol_section_and_value.
+       * testsuite/many_sections_test.cc: New file.
+       * testsuite/Makefile.am (BUILT_SOURCES): Define.
+       (check_PROGRAMS): Add many_sections_test.
+       (many_sections_test_SOURCES): Define.
+       (many_sections_test_DEPENDENCIES): Define.
+       (many_sections_test_LDFLAGS): Define.
+       (BUILT_SOURCES): Add many_sections_define.h.
+       (many_sections_define.h): New target.
+       (BUILT_SOURCES): Add many_sections_check.h.
+       (many_sections_check.h): New target.
+       (check_PROGRAMS): Add many_sections_r_test.
+       (many_sections_r_test_SOURCES): Define.
+       (many_sections_r_test_DEPENDENCIES): Define.
+       (many_sections_r_test_LDFLAGS): Define.
+       (many_sections_r_test_LDADD): Define.
+       (many_sections_r_test.o): New target.
+       * testsuite/Makefile.in: Rebuild.
+
 2008-04-17  Cary Coutant  <ccoutant@google.com>
 
        * errors.cc (Errors::info): New function.
index 1e9705ef3490eb1d03643780b0c01f13d59e90e4..3df50c8c67de3d45a0452bac67b5d828b6ef066c 100644 (file)
@@ -118,8 +118,11 @@ Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc(
   // that.  Then we reduce that alignment if the symbol is not aligned
   // within the section.
   gold_assert(sym->is_from_dynobj());
+  bool is_ordinary;
+  unsigned int shndx = sym->shndx(&is_ordinary);
+  gold_assert(is_ordinary);
   typename elfcpp::Elf_types<size>::Elf_WXword addralign =
-    sym->object()->section_addralign(sym->shndx());
+    sym->object()->section_addralign(shndx);
 
   typename Sized_symbol<size>::Value_type value = sym->value();
   while ((value & (addralign - 1)) != 0)
index e345ff8eccf8b90ca93053375458f4f9d2a8aa60..d3faeebea631d8adc3a11382edf87e8f91086057 100644 (file)
@@ -175,7 +175,7 @@ Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info(Object* object,
   // Now that we have successfully read all the data, parse the debug
   // info.
   this->data_valid_ = true;
-  this->read_line_mappings(read_shndx);
+  this->read_line_mappings(object, read_shndx);
 }
 
 // Read the DWARF header.
@@ -542,21 +542,23 @@ Sized_dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr
 template<int size, bool big_endian>
 unsigned int
 Sized_dwarf_line_info<size, big_endian>::symbol_section(
+    Object* object,
     unsigned int sym,
-    typename elfcpp::Elf_types<size>::Elf_Addr* value)
+    typename elfcpp::Elf_types<size>::Elf_Addr* value,
+    bool* is_ordinary)
 {
   const int symsize = elfcpp::Elf_sizes<size>::sym_size;
   gold_assert(sym * symsize < this->symtab_buffer_size_);
   elfcpp::Sym<size, big_endian> elfsym(this->symtab_buffer_ + sym * symsize);
   *value = elfsym.get_st_value();
-  return elfsym.get_st_shndx();
+  return object->adjust_sym_shndx(sym, elfsym.get_st_shndx(), is_ordinary);
 }
 
 // Read the relocations into a Reloc_map.
 
 template<int size, bool big_endian>
 void
-Sized_dwarf_line_info<size, big_endian>::read_relocs()
+Sized_dwarf_line_info<size, big_endian>::read_relocs(Object* object)
 {
   if (this->symtab_buffer_ == NULL)
     return;
@@ -566,8 +568,16 @@ Sized_dwarf_line_info<size, big_endian>::read_relocs()
   while ((reloc_offset = this->track_relocs_.next_offset()) != -1)
     {
       const unsigned int sym = this->track_relocs_.next_symndx();
-      const unsigned int shndx = this->symbol_section(sym, &value);
-      this->reloc_map_[reloc_offset] = std::make_pair(shndx, value);
+
+      bool is_ordinary;
+      const unsigned int shndx = this->symbol_section(object, sym, &value,
+                                                     &is_ordinary);
+
+      // There is no reason to record non-ordinary section indexes, or
+      // SHN_UNDEF, because they will never match the real section.
+      if (is_ordinary && shndx != elfcpp::SHN_UNDEF)
+       this->reloc_map_[reloc_offset] = std::make_pair(shndx, value);
+
       this->track_relocs_.advance(reloc_offset + 1);
     }
 }
@@ -576,11 +586,12 @@ Sized_dwarf_line_info<size, big_endian>::read_relocs()
 
 template<int size, bool big_endian>
 void
-Sized_dwarf_line_info<size, big_endian>::read_line_mappings(off_t shndx)
+Sized_dwarf_line_info<size, big_endian>::read_line_mappings(Object* object,
+                                                           off_t shndx)
 {
   gold_assert(this->data_valid_ == true);
 
-  read_relocs();
+  this->read_relocs(object);
   while (this->buffer_ < this->buffer_end_)
     {
       const unsigned char* lineptr = this->buffer_;
index 2d857654457920ae6154170c51273b737dfb60cf..9c6b175839d24a2c1232db337d6beec880d884b4 100644 (file)
@@ -101,17 +101,18 @@ class Sized_dwarf_line_info : public Dwarf_line_info
   // If SHNDX is non-negative, only store debug information that
   // pertains to the specified section.
   void
-  read_line_mappings(off_t shndx);
+  read_line_mappings(Object*, off_t shndx);
 
   // Reads the relocation section associated with .debug_line and
   // stores relocation information in reloc_map_.
   void
-  read_relocs();
+  read_relocs(Object*);
 
   // Looks in the symtab to see what section a symbol is in.
   unsigned int
-  symbol_section(unsigned int sym,
-                 typename elfcpp::Elf_types<size>::Elf_Addr* value);
+  symbol_section(Object*, unsigned int sym,
+                 typename elfcpp::Elf_types<size>::Elf_Addr* value,
+                bool* is_ordinary);
 
   // Reads the DWARF2/3 header for this line info.  Each takes as input
   // a starting buffer position, and returns the ending position.
index e593b8948de44f6d6f0c55f1a5c4ef7c6cf02167..89186adecbc84cfcaf8c2119487a7a824e217a73 100644 (file)
@@ -72,7 +72,8 @@ Sized_dynobj<size, big_endian>::Sized_dynobj(
     off_t offset,
     const elfcpp::Ehdr<size, big_endian>& ehdr)
   : Dynobj(name, input_file, offset),
-    elf_file_(this, ehdr)
+    elf_file_(this, ehdr),
+    dynsym_shndx_(-1U)
 {
 }
 
@@ -98,18 +99,18 @@ template<int size, bool big_endian>
 void
 Sized_dynobj<size, big_endian>::find_dynsym_sections(
     const unsigned char* pshdrs,
-    unsigned int* pdynsym_shndx,
     unsigned int* pversym_shndx,
     unsigned int* pverdef_shndx,
     unsigned int* pverneed_shndx,
     unsigned int* pdynamic_shndx)
 {
-  *pdynsym_shndx = -1U;
   *pversym_shndx = -1U;
   *pverdef_shndx = -1U;
   *pverneed_shndx = -1U;
   *pdynamic_shndx = -1U;
 
+  unsigned int xindex_shndx = 0;
+  unsigned int xindex_link = 0;
   const unsigned int shnum = this->shnum();
   const unsigned char* p = pshdrs;
   for (unsigned int i = 0; i < shnum; ++i, p += This::shdr_size)
@@ -120,7 +121,15 @@ Sized_dynobj<size, big_endian>::find_dynsym_sections(
       switch (shdr.get_sh_type())
        {
        case elfcpp::SHT_DYNSYM:
-         pi = pdynsym_shndx;
+         this->dynsym_shndx_ = i;
+         if (xindex_shndx > 0 && xindex_link == i)
+           {
+             Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+             xindex->read_symtab_xindex<size, big_endian>(this, xindex_shndx,
+                                                          pshdrs);
+             this->set_xindex(xindex);
+           }
+         pi = NULL;
          break;
        case elfcpp::SHT_GNU_versym:
          pi = pversym_shndx;
@@ -134,6 +143,18 @@ Sized_dynobj<size, big_endian>::find_dynsym_sections(
        case elfcpp::SHT_DYNAMIC:
          pi = pdynamic_shndx;
          break;
+       case elfcpp::SHT_SYMTAB_SHNDX:
+         xindex_shndx = i;
+         xindex_link = this->adjust_shndx(shdr.get_sh_link());
+         if (xindex_link == this->dynsym_shndx_)
+           {
+             Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+             xindex->read_symtab_xindex<size, big_endian>(this, xindex_shndx,
+                                                          pshdrs);
+             this->set_xindex(xindex);
+           }
+         pi = NULL;
+         break;
        default:
          pi = NULL;
          break;
@@ -178,9 +199,9 @@ Sized_dynobj<size, big_endian>::read_dynsym_section(
 
   gold_assert(shdr.get_sh_type() == type);
 
-  if (shdr.get_sh_link() != link)
+  if (this->adjust_shndx(shdr.get_sh_link()) != link)
     this->error(_("unexpected link in section %u header: %u != %u"),
-               shndx, shdr.get_sh_link(), link);
+               shndx, this->adjust_shndx(shdr.get_sh_link()), link);
 
   *view = this->get_lasting_view(shdr.get_sh_offset(), shdr.get_sh_size(),
                                 true, false);
@@ -210,7 +231,7 @@ Sized_dynobj<size, big_endian>::read_dynamic(const unsigned char* pshdrs,
   const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(),
                                                 dynamic_size, true, false);
 
-  const unsigned int link = dynamicshdr.get_sh_link();
+  const unsigned int link = this->adjust_shndx(dynamicshdr.get_sh_link());
   if (link != strtab_shndx)
     {
       if (link >= this->shnum())
@@ -291,13 +312,12 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
 
   const unsigned char* const pshdrs = sd->section_headers->data();
 
-  unsigned int dynsym_shndx;
   unsigned int versym_shndx;
   unsigned int verdef_shndx;
   unsigned int verneed_shndx;
   unsigned int dynamic_shndx;
-  this->find_dynsym_sections(pshdrs, &dynsym_shndx, &versym_shndx,
-                            &verdef_shndx, &verneed_shndx, &dynamic_shndx);
+  this->find_dynsym_sections(pshdrs, &versym_shndx, &verdef_shndx,
+                            &verneed_shndx, &dynamic_shndx);
 
   unsigned int strtab_shndx = -1U;
 
@@ -307,10 +327,11 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
   sd->symbol_names = NULL;
   sd->symbol_names_size = 0;
 
-  if (dynsym_shndx != -1U)
+  if (this->dynsym_shndx_ != -1U)
     {
       // Get the dynamic symbols.
-      typename This::Shdr dynsymshdr(pshdrs + dynsym_shndx * This::shdr_size);
+      typename This::Shdr dynsymshdr(pshdrs
+                                    + this->dynsym_shndx_ * This::shdr_size);
       gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
 
       sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(),
@@ -320,7 +341,7 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
        convert_to_section_size_type(dynsymshdr.get_sh_size());
 
       // Get the symbol names.
-      strtab_shndx = dynsymshdr.get_sh_link();
+      strtab_shndx = this->adjust_shndx(dynsymshdr.get_sh_link());
       if (strtab_shndx >= this->shnum())
        {
          this->error(_("invalid dynamic symbol table name index: %u"),
@@ -346,8 +367,8 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
 
       unsigned int dummy;
       this->read_dynsym_section(pshdrs, versym_shndx, elfcpp::SHT_GNU_versym,
-                               dynsym_shndx, &sd->versym, &sd->versym_size,
-                               &dummy);
+                               this->dynsym_shndx_,
+                               &sd->versym, &sd->versym_size, &dummy);
 
       // We require that the version definition and need section link
       // to the same string table as the dynamic symbol table.  This
@@ -375,6 +396,19 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
                       sd->symbol_names_size);
 }
 
+// Return the Xindex structure to use for object with lots of
+// sections.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_dynobj<size, big_endian>::do_initialize_xindex()
+{
+  gold_assert(this->dynsym_shndx_ != -1U);
+  Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+  xindex->initialize_symtab_xindex<size, big_endian>(this, this->dynsym_shndx_);
+  return xindex;
+}
+
 // Lay out the input sections for a dynamic object.  We don't want to
 // include sections from a dynamic object, so all that we actually do
 // here is check for .gnu.warning sections.
index bab15cd32509d74724df272060a56dc2deb6a366..bd5e12dc5e1bacc72192b2c6c05bf757a3611f74 100644 (file)
@@ -221,6 +221,10 @@ class Sized_dynobj : public Dynobj
   do_section_addralign(unsigned int shndx)
   { return this->elf_file_.section_addralign(shndx); }
 
+  // Return the Xindex structure to use.
+  Xindex*
+  do_initialize_xindex();
+
  private:
   // For convenience.
   typedef Sized_dynobj<size, big_endian> This;
@@ -230,11 +234,19 @@ class Sized_dynobj : public Dynobj
   typedef elfcpp::Shdr<size, big_endian> Shdr;
   typedef elfcpp::Dyn<size, big_endian> Dyn;
 
+  // Adjust a section index if necessary.
+  unsigned int
+  adjust_shndx(unsigned int shndx)
+  {
+    if (shndx >= elfcpp::SHN_LORESERVE)
+      shndx += this->elf_file_.large_shndx_offset();
+    return shndx;
+  }
+
   // Find the dynamic symbol table and the version sections, given the
   // section headers.
   void
   find_dynsym_sections(const unsigned char* pshdrs,
-                      unsigned int* pdynshm_shndx,
                       unsigned int* pversym_shndx,
                       unsigned int* pverdef_shndx,
                       unsigned int* pverneed_shndx,
@@ -274,6 +286,8 @@ class Sized_dynobj : public Dynobj
 
   // General access to the ELF file.
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
+  // The section index of the dynamic symbol table.
+  unsigned int dynsym_shndx_;
 };
 
 // A base class for Verdef and Verneed_version which just handles the
index 4ec29f6b97f7694b7762dbe7198ad7d6e33bdd07..5061f80764ea760fcb892ad04ace660574a63e52 100644 (file)
@@ -971,9 +971,12 @@ Eh_frame::read_fde(Sized_relobj<size, big_endian>* object,
   if (symndx >= symbols_size / sym_size)
     return false;
   elfcpp::Sym<size, big_endian> sym(symbols + symndx * sym_size);
-  fde_shndx = sym.get_st_shndx();
+  bool is_ordinary;
+  fde_shndx = object->adjust_sym_shndx(symndx, sym.get_st_shndx(),
+                                      &is_ordinary);
 
-  if (fde_shndx != elfcpp::SHN_UNDEF
+  if (is_ordinary
+      && fde_shndx != elfcpp::SHN_UNDEF
       && fde_shndx < object->shnum()
       && !object->is_section_included(fde_shndx))
     {
index d150db76d997b6aae306e744f876f91e37f884dd..54b082823e50c2876bf27a10d6394790be0d8e4a 100644 (file)
@@ -310,7 +310,8 @@ queue_final_tasks(const General_options& options,
 
   // Queue a task to write out the symbol table.
   final_blocker->add_blocker();
-  workqueue->queue(new Write_symbols_task(symtab,
+  workqueue->queue(new Write_symbols_task(layout,
+                                         symtab,
                                          input_objects,
                                          layout->sympool(),
                                          layout->dynpool(),
index 3e2483664dca0814c099bb23c2a4a3e3d436bead..dcd4c03ef9c7e5f489062335048a2feb4a23343b 100644 (file)
@@ -881,18 +881,24 @@ Target_i386::Scan::local(const General_options&,
       if (parameters->options().output_is_position_independent())
         {
           Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+         unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
           if (lsym.get_st_type() != elfcpp::STT_SECTION)
-            {
-              unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
-              rel_dyn->add_local(object, r_sym, r_type, output_section,
-                                 data_shndx, reloc.get_r_offset());
-            }
+           rel_dyn->add_local(object, r_sym, r_type, output_section,
+                              data_shndx, reloc.get_r_offset());
           else
             {
               gold_assert(lsym.get_st_value() == 0);
-              rel_dyn->add_local_section(object, lsym.get_st_shndx(),
-                                         r_type, output_section,
-                                         data_shndx, reloc.get_r_offset());
+             unsigned int shndx = lsym.get_st_shndx();
+             bool is_ordinary;
+             shndx = object->adjust_sym_shndx(r_sym, shndx,
+                                              &is_ordinary);
+             if (!is_ordinary)
+               object->error(_("section symbol %u has bad shndx %u"),
+                             r_sym, shndx);
+             else
+               rel_dyn->add_local_section(object, shndx,
+                                          r_type, output_section,
+                                          data_shndx, reloc.get_r_offset());
             }
         }
       break;
@@ -975,11 +981,17 @@ Target_i386::Scan::local(const General_options&,
                 Output_data_got<32, false>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
-                got->add_local_pair_with_rel(object, r_sym, 
-                                             lsym.get_st_shndx(),
-                                             GOT_TYPE_TLS_PAIR,
-                                             target->rel_dyn_section(layout),
-                                             elfcpp::R_386_TLS_DTPMOD32, 0);
+               unsigned int shndx = lsym.get_st_shndx();
+               bool is_ordinary;
+               shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+               if (!is_ordinary)
+                 object->error(_("local symbol %u has bad shndx %u"),
+                             r_sym, shndx);
+                else
+                 got->add_local_pair_with_rel(object, r_sym, shndx,
+                                              GOT_TYPE_TLS_PAIR,
+                                              target->rel_dyn_section(layout),
+                                              elfcpp::R_386_TLS_DTPMOD32, 0);
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
@@ -993,11 +1005,17 @@ Target_i386::Scan::local(const General_options&,
                 Output_data_got<32, false>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
-                got->add_local_pair_with_rel(object, r_sym, 
-                                             lsym.get_st_shndx(),
-                                             GOT_TYPE_TLS_DESC,
-                                             target->rel_dyn_section(layout),
-                                             elfcpp::R_386_TLS_DESC, 0);
+               unsigned int shndx = lsym.get_st_shndx();
+               bool is_ordinary;
+               shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+               if (!is_ordinary)
+                 object->error(_("local symbol %u has bad shndx %u"),
+                             r_sym, shndx);
+                else
+                 got->add_local_pair_with_rel(object, r_sym, shndx,
+                                              GOT_TYPE_TLS_DESC,
+                                              target->rel_dyn_section(layout),
+                                              elfcpp::R_386_TLS_DESC, 0);
               }
             else if (optimized_type != tls::TLSOPT_TO_LE)
               unsupported_reloc_local(object, r_type);
index fa0d4c8598300fe77c9d853cb2bee556e749055f..a3bcf2135698fa9f49c0f28354314ad9f819c42a 100644 (file)
@@ -76,15 +76,33 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
 // Layout methods.
 
 Layout::Layout(const General_options& options, Script_options* script_options)
-  : options_(options), script_options_(script_options), namepool_(),
-    sympool_(), dynpool_(), signatures_(),
-    section_name_map_(), segment_list_(), section_list_(),
-    unattached_section_list_(), sections_are_attached_(false),
-    special_output_list_(), section_headers_(NULL), tls_segment_(NULL),
-    symtab_section_(NULL), dynsym_section_(NULL), dynamic_section_(NULL),
-    dynamic_data_(NULL), eh_frame_section_(NULL), eh_frame_data_(NULL),
-    added_eh_frame_data_(false), eh_frame_hdr_section_(NULL),
-    build_id_note_(NULL), group_signatures_(), output_file_size_(-1),
+  : options_(options),
+    script_options_(script_options),
+    namepool_(),
+    sympool_(),
+    dynpool_(),
+    signatures_(),
+    section_name_map_(),
+    segment_list_(),
+    section_list_(),
+    unattached_section_list_(),
+    sections_are_attached_(false),
+    special_output_list_(),
+    section_headers_(NULL),
+    tls_segment_(NULL),
+    symtab_section_(NULL),
+    symtab_xindex_(NULL),
+    dynsym_section_(NULL),
+    dynsym_xindex_(NULL),
+    dynamic_section_(NULL),
+    dynamic_data_(NULL),
+    eh_frame_section_(NULL),
+    eh_frame_data_(NULL),
+    added_eh_frame_data_(false),
+    eh_frame_hdr_section_(NULL),
+    build_id_note_(NULL),
+    group_signatures_(),
+    output_file_size_(-1),
     input_requires_executable_stack_(false),
     input_with_gnu_stack_note_(false),
     input_without_gnu_stack_note_(false),
@@ -1149,8 +1167,12 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   // sections.
   off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS);
 
+  // Set the section indexes of all unallocated sections seen so far,
+  // in case any of them are somehow referenced by a symbol.
+  shndx = this->set_section_indexes(shndx);
+
   // Create the symbol table sections.
-  this->create_symtab_sections(input_objects, symtab, &off);
+  this->create_symtab_sections(input_objects, symtab, shndx, &off);
   if (!parameters->doing_static_link())
     this->assign_local_dynsym_offsets(input_objects);
 
@@ -1165,11 +1187,12 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   // don't have to wait for the input sections.
   off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS);
 
-  // Now that all sections have been created, set the section indexes.
+  // Now that all sections have been created, set the section indexes
+  // for any sections which haven't been done yet.
   shndx = this->set_section_indexes(shndx);
 
   // Create the section table header.
-  this->create_shdrs(&off);
+  this->create_shdrs(shstrtab_section, &off);
 
   // If there are no sections which require postprocessing, we can
   // handle the section names now, and avoid a resize later.
@@ -1816,18 +1839,15 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
 unsigned int
 Layout::set_section_indexes(unsigned int shndx)
 {
-  const bool output_is_object = parameters->options().relocatable();
   for (Section_list::iterator p = this->unattached_section_list_.begin();
        p != this->unattached_section_list_.end();
        ++p)
     {
-      // In a relocatable link, we already did group sections.
-      if (output_is_object
-         && (*p)->type() == elfcpp::SHT_GROUP)
-       continue;
-
-      (*p)->set_out_shndx(shndx);
-      ++shndx;
+      if (!(*p)->has_out_shndx())
+       {
+         (*p)->set_out_shndx(shndx);
+         ++shndx;
+       }
     }
   return shndx;
 }
@@ -1893,11 +1913,12 @@ Layout::count_local_symbols(const Task* task,
 
 // Create the symbol table sections.  Here we also set the final
 // values of the symbols.  At this point all the loadable sections are
-// fully laid out.
+// fully laid out.  SHNUM is the number of sections so far.
 
 void
 Layout::create_symtab_sections(const Input_objects* input_objects,
                               Symbol_table* symtab,
+                              unsigned int shnum,
                               off_t* poff)
 {
   int symsize;
@@ -1988,6 +2009,38 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
                                                             align);
       osymtab->add_output_section_data(pos);
 
+      // We generate a .symtab_shndx section if we have more than
+      // SHN_LORESERVE sections.  Technically it is possible that we
+      // don't need one, because it is possible that there are no
+      // symbols in any of sections with indexes larger than
+      // SHN_LORESERVE.  That is probably unusual, though, and it is
+      // easier to always create one than to compute section indexes
+      // twice (once here, once when writing out the symbols).
+      if (shnum >= elfcpp::SHN_LORESERVE)
+       {
+         const char* symtab_xindex_name = this->namepool_.add(".symtab_shndx",
+                                                              false, NULL);
+         Output_section* osymtab_xindex =
+           this->make_output_section(symtab_xindex_name,
+                                     elfcpp::SHT_SYMTAB_SHNDX, 0);
+
+         size_t symcount = (off - startoff) / symsize;
+         this->symtab_xindex_ = new Output_symtab_xindex(symcount);
+
+         osymtab_xindex->add_output_section_data(this->symtab_xindex_);
+
+         osymtab_xindex->set_link_section(osymtab);
+         osymtab_xindex->set_addralign(4);
+         osymtab_xindex->set_entsize(4);
+
+         osymtab_xindex->set_after_input_sections();
+
+         // This tells the driver code to wait until the symbol table
+         // has written out before writing out the postprocessing
+         // sections, including the .symtab_shndx section.
+         this->any_postprocessing_sections_ = true;
+       }
+
       const char* strtab_name = this->namepool_.add(".strtab", false, NULL);
       Output_section* ostrtab = this->make_output_section(strtab_name,
                                                          elfcpp::SHT_STRTAB,
@@ -2035,14 +2088,15 @@ Layout::create_shstrtab()
 // offset.
 
 void
-Layout::create_shdrs(off_t* poff)
+Layout::create_shdrs(const Output_section* shstrtab_section, off_t* poff)
 {
   Output_section_headers* oshdrs;
   oshdrs = new Output_section_headers(this,
                                      &this->segment_list_,
                                      &this->section_list_,
                                      &this->unattached_section_list_,
-                                     &this->namepool_);
+                                     &this->namepool_,
+                                     shstrtab_section);
   off_t off = align_address(*poff, oshdrs->addralign());
   oshdrs->set_address_and_file_offset(0, off);
   off += oshdrs->data_size();
@@ -2050,6 +2104,19 @@ Layout::create_shdrs(off_t* poff)
   this->section_headers_ = oshdrs;
 }
 
+// Count the allocated sections.
+
+size_t
+Layout::allocated_output_section_count() const
+{
+  size_t section_count = 0;
+  for (Segment_list::const_iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    section_count += (*p)->output_section_count();
+  return section_count;
+}
+
 // Create the dynamic symbol table.
 
 void
@@ -2093,8 +2160,6 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
   unsigned int local_symcount = index;
   *plocal_dynamic_count = local_symcount;
 
-  // FIXME: We have to tell set_dynsym_indexes whether the
-  // -E/--export-dynamic option was used.
   index = symtab->set_dynsym_indexes(index, pdynamic_symbols,
                                     &this->dynpool_, pversions);
 
@@ -2135,6 +2200,37 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
   odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
   odyn->add_constant(elfcpp::DT_SYMENT, symsize);
 
+  // If there are more than SHN_LORESERVE allocated sections, we
+  // create a .dynsym_shndx section.  It is possible that we don't
+  // need one, because it is possible that there are no dynamic
+  // symbols in any of the sections with indexes larger than
+  // SHN_LORESERVE.  This is probably unusual, though, and at this
+  // time we don't know the actual section indexes so it is
+  // inconvenient to check.
+  if (this->allocated_output_section_count() >= elfcpp::SHN_LORESERVE)
+    {
+      Output_section* dynsym_xindex =
+       this->choose_output_section(NULL, ".dynsym_shndx",
+                                   elfcpp::SHT_SYMTAB_SHNDX,
+                                   elfcpp::SHF_ALLOC,
+                                   false);
+
+      this->dynsym_xindex_ = new Output_symtab_xindex(index);
+
+      dynsym_xindex->add_output_section_data(this->dynsym_xindex_);
+
+      dynsym_xindex->set_link_section(dynsym);
+      dynsym_xindex->set_addralign(4);
+      dynsym_xindex->set_entsize(4);
+
+      dynsym_xindex->set_after_input_sections();
+
+      // This tells the driver code to wait until the symbol table has
+      // written out before writing out the postprocessing sections,
+      // including the .dynsym_shndx section.
+      this->any_postprocessing_sections_ = true;
+    }
+
   // Create the dynamic string table section.
 
   Output_section* dynstr = this->choose_output_section(NULL, ".dynstr",
@@ -2766,7 +2862,7 @@ Layout::write_data(const Symbol_table* symtab, Output_file* of) const
              gold_assert(index > 0 && index != -1U);
              off_t off = (symtab_section->offset()
                           + index * symtab_section->entsize());
-             symtab->write_section_symbol(*p, of, off);
+             symtab->write_section_symbol(*p, this->symtab_xindex_, of, off);
            }
        }
     }
@@ -2783,7 +2879,7 @@ Layout::write_data(const Symbol_table* symtab, Output_file* of) const
          gold_assert(index > 0 && index != -1U);
          off_t off = (dynsym_section->offset()
                       + index * dynsym_section->entsize());
-         symtab->write_section_symbol(*p, of, off);
+         symtab->write_section_symbol(*p, this->dynsym_xindex_, of, off);
        }
     }
 
@@ -3014,7 +3110,8 @@ void
 Write_symbols_task::run(Workqueue*)
 {
   this->symtab_->write_globals(this->input_objects_, this->sympool_,
-                              this->dynpool_, this->of_);
+                              this->dynpool_, this->layout_->symtab_xindex(),
+                              this->layout_->dynsym_xindex(), this->of_);
 }
 
 // Write_after_input_sections_task methods.
index 13fafd60705784e1657252ea2bae15f3d4ae8b1c..efa8b61d5aa3c03d32a9bb6c42db156648cb7429 100644 (file)
@@ -46,6 +46,7 @@ class Output_section_headers;
 class Output_segment;
 class Output_data;
 class Output_data_dynamic;
+class Output_symtab_xindex;
 class Eh_frame;
 class Target;
 
@@ -193,6 +194,18 @@ class Layout
   dynpool() const
   { return &this->dynpool_; }
 
+  // Return the symtab_xindex section used to hold large section
+  // indexes for the normal symbol table.
+  Output_symtab_xindex*
+  symtab_xindex() const
+  { return this->symtab_xindex_; }
+
+  // Return the dynsym_xindex section used to hold large section
+  // indexes for the dynamic symbol table.
+  Output_symtab_xindex*
+  dynsym_xindex() const
+  { return this->dynsym_xindex_; }
+
   // Return whether a section is a .gnu.linkonce section, given the
   // section name.
   static inline bool
@@ -407,7 +420,8 @@ class Layout
 
   // Create the output sections for the symbol table.
   void
-  create_symtab_sections(const Input_objects*, Symbol_table*, off_t*);
+  create_symtab_sections(const Input_objects*, Symbol_table*,
+                        unsigned int, off_t*);
 
   // Create the .shstrtab section.
   Output_section*
@@ -415,7 +429,7 @@ class Layout
 
   // Create the section header table.
   void
-  create_shdrs(off_t*);
+  create_shdrs(const Output_section* shstrtab_section, off_t*);
 
   // Create the dynamic symbol table.
   void
@@ -470,6 +484,10 @@ class Layout
   static const char*
   linkonce_output_name(const char* name, size_t* plen);
 
+  // Return the number of allocated output sections.
+  size_t
+  allocated_output_section_count() const;
+
   // Return the output section for NAME, TYPE and FLAGS.
   Output_section*
   get_output_section(const char* name, Stringpool::Key name_key,
@@ -589,8 +607,12 @@ class Layout
   Output_segment* tls_segment_;
   // The SHT_SYMTAB output section.
   Output_section* symtab_section_;
+  // The SHT_SYMTAB_SHNDX for the regular symbol table if there is one.
+  Output_symtab_xindex* symtab_xindex_;
   // The SHT_DYNSYM output section if there is one.
   Output_section* dynsym_section_;
+  // The SHT_SYMTAB_SHNDX for the dynamic symbol table if there is one.
+  Output_symtab_xindex* dynsym_xindex_;
   // The SHT_DYNAMIC output section if there is one.
   Output_section* dynamic_section_;
   // The dynamic data which goes into dynamic_section_.
@@ -702,12 +724,13 @@ class Write_data_task : public Task
 class Write_symbols_task : public Task
 {
  public:
-  Write_symbols_task(const Symbol_table* symtab,
+  Write_symbols_task(const Layout* layout, const Symbol_table* symtab,
                     const Input_objects* input_objects,
                     const Stringpool* sympool, const Stringpool* dynpool,
                     Output_file* of, Task_token* final_blocker)
-    : symtab_(symtab), input_objects_(input_objects), sympool_(sympool),
-      dynpool_(dynpool), of_(of), final_blocker_(final_blocker)
+    : layout_(layout), symtab_(symtab), input_objects_(input_objects),
+      sympool_(sympool), dynpool_(dynpool), of_(of),
+      final_blocker_(final_blocker)
   { }
 
   // The standard Task methods.
@@ -726,6 +749,7 @@ class Write_symbols_task : public Task
   { return "Write_symbols_task"; }
 
  private:
+  const Layout* layout_;
   const Symbol_table* symtab_;
   const Input_objects* input_objects_;
   const Stringpool* sympool_;
index 2849093bd31c2a9d2aac2e849b8523d320df26dc..19d9185c44b7aa4db2da070038de6b9440a14943 100644 (file)
 namespace gold
 {
 
+// Class Xindex.
+
+// Initialize the symtab_xindex_ array.  Find the SHT_SYMTAB_SHNDX
+// section and read it in.  SYMTAB_SHNDX is the index of the symbol
+// table we care about.
+
+template<int size, bool big_endian>
+void
+Xindex::initialize_symtab_xindex(Object* object, unsigned int symtab_shndx)
+{
+  if (!this->symtab_xindex_.empty())
+    return;
+
+  gold_assert(symtab_shndx != 0);
+
+  // Look through the sections in reverse order, on the theory that it
+  // is more likely to be near the end than the beginning.
+  unsigned int i = object->shnum();
+  while (i > 0)
+    {
+      --i;
+      if (object->section_type(i) == elfcpp::SHT_SYMTAB_SHNDX
+         && this->adjust_shndx(object->section_link(i)) == symtab_shndx)
+       {
+         this->read_symtab_xindex<size, big_endian>(object, i, NULL);
+         return;
+       }
+    }
+
+  object->error(_("missing SHT_SYMTAB_SHNDX section"));
+}
+
+// Read in the symtab_xindex_ array, given the section index of the
+// SHT_SYMTAB_SHNDX section.  If PSHDRS is not NULL, it points at the
+// section headers.
+
+template<int size, bool big_endian>
+void
+Xindex::read_symtab_xindex(Object* object, unsigned int xindex_shndx,
+                          const unsigned char* pshdrs)
+{
+  section_size_type bytecount;
+  const unsigned char* contents;
+  if (pshdrs == NULL)
+    contents = object->section_contents(xindex_shndx, &bytecount, false);
+  else
+    {
+      const unsigned char* p = (pshdrs
+                               + (xindex_shndx
+                                  * elfcpp::Elf_sizes<size>::shdr_size));
+      typename elfcpp::Shdr<size, big_endian> shdr(p);
+      bytecount = convert_to_section_size_type(shdr.get_sh_size());
+      contents = object->get_view(shdr.get_sh_offset(), bytecount, true, false);
+    }
+
+  gold_assert(this->symtab_xindex_.empty());
+  this->symtab_xindex_.reserve(bytecount / 4);
+  for (section_size_type i = 0; i < bytecount; i += 4)
+    {
+      unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(contents + i);
+      // We preadjust the section indexes we save.
+      this->symtab_xindex_.push_back(this->adjust_shndx(shndx));
+    }
+}
+
+// Symbol symndx has a section of SHN_XINDEX; return the real section
+// index.
+
+unsigned int
+Xindex::sym_xindex_to_shndx(Object* object, unsigned int symndx)
+{
+  if (symndx >= this->symtab_xindex_.size())
+    {
+      object->error(_("symbol %u out of range for SHT_SYMTAB_SHNDX section"),
+                   symndx);
+      return elfcpp::SHN_UNDEF;
+    }
+  unsigned int shndx = this->symtab_xindex_[symndx];
+  if (shndx < elfcpp::SHN_LORESERVE || shndx >= object->shnum())
+    {
+      object->error(_("extended index for symbol %u out of range: %u"),
+                   symndx, shndx);
+      return elfcpp::SHN_UNDEF;
+    }
+  return shndx;
+}
+
 // Class Object.
 
 // Set the target based on fields in the ELF file header.
@@ -204,6 +291,8 @@ Sized_relobj<size, big_endian>::find_symtab(const unsigned char* pshdrs)
       // to put the symbol table at the end.
       const unsigned char* p = pshdrs + shnum * This::shdr_size;
       unsigned int i = shnum;
+      unsigned int xindex_shndx = 0;
+      unsigned int xindex_link = 0;
       while (i > 0)
        {
          --i;
@@ -212,12 +301,43 @@ Sized_relobj<size, big_endian>::find_symtab(const unsigned char* pshdrs)
          if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
            {
              this->symtab_shndx_ = i;
+             if (xindex_shndx > 0 && xindex_link == i)
+               {
+                 Xindex* xindex =
+                   new Xindex(this->elf_file_.large_shndx_offset());
+                 xindex->read_symtab_xindex<size, big_endian>(this,
+                                                              xindex_shndx,
+                                                              pshdrs);
+                 this->set_xindex(xindex);
+               }
              break;
            }
+
+         // Try to pick up the SHT_SYMTAB_SHNDX section, if there is
+         // one.  This will work if it follows the SHT_SYMTAB
+         // section.
+         if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB_SHNDX)
+           {
+             xindex_shndx = i;
+             xindex_link = this->adjust_shndx(shdr.get_sh_link());
+           }
        }
     }
 }
 
+// Return the Xindex structure to use for object with lots of
+// sections.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_relobj<size, big_endian>::do_initialize_xindex()
+{
+  gold_assert(this->symtab_shndx_ != -1U);
+  Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset());
+  xindex->initialize_symtab_xindex<size, big_endian>(this, this->symtab_shndx_);
+  return xindex;
+}
+
 // Return whether SHDR has the right type and flags to be a GNU
 // .eh_frame section.
 
@@ -323,7 +443,7 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
   File_view* fvsymtab = this->get_lasting_view(readoff, readsize, true, false);
 
   // Read the section header for the symbol names.
-  unsigned int strtab_shndx = symtabshdr.get_sh_link();
+  unsigned int strtab_shndx = this->adjust_shndx(symtabshdr.get_sh_link());
   if (strtab_shndx >= this->shnum())
     {
       this->error(_("invalid symbol table name index: %u"), strtab_shndx);
@@ -351,14 +471,17 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
 }
 
 // Return the section index of symbol SYM.  Set *VALUE to its value in
-// the object file.  Note that for a symbol which is not defined in
-// this object file, this will set *VALUE to 0 and return SHN_UNDEF;
-// it will not return the final value of the symbol in the link.
+// the object file.  Set *IS_ORDINARY if this is an ordinary section
+// index.  not a special cod between SHN_LORESERVE and SHN_HIRESERVE.
+// Note that for a symbol which is not defined in this object file,
+// this will set *VALUE to 0 and return SHN_UNDEF; it will not return
+// the final value of the symbol in the link.
 
 template<int size, bool big_endian>
 unsigned int
 Sized_relobj<size, big_endian>::symbol_section_and_value(unsigned int sym,
-                                                        Address* value)
+                                                        Address* value,
+                                                        bool* is_ordinary)
 {
   section_size_type symbols_size;
   const unsigned char* symbols = this->section_contents(this->symtab_shndx_,
@@ -370,8 +493,8 @@ Sized_relobj<size, big_endian>::symbol_section_and_value(unsigned int sym,
 
   elfcpp::Sym<size, big_endian> elfsym(symbols + sym * This::sym_size);
   *value = elfsym.get_st_value();
-  // FIXME: Handle SHN_XINDEX.
-  return elfsym.get_st_shndx();
+
+  return this->adjust_sym_shndx(sym, elfsym.get_st_shndx(), is_ordinary);
 }
 
 // Return whether to include a section group in the link.  LAYOUT is
@@ -408,17 +531,18 @@ Sized_relobj<size, big_endian>::include_section_group(
 
   // Get the appropriate symbol table header (this will normally be
   // the single SHT_SYMTAB section, but in principle it need not be).
-  const unsigned int link = shdr.get_sh_link();
+  const unsigned int link = this->adjust_shndx(shdr.get_sh_link());
   typename This::Shdr symshdr(this, this->elf_file_.section_header(link));
 
   // Read the symbol table entry.
-  if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size)
+  unsigned int symndx = shdr.get_sh_info();
+  if (symndx >= symshdr.get_sh_size() / This::sym_size)
     {
       this->error(_("section group %u info %u out of range"),
-                 index, shdr.get_sh_info());
+                 index, symndx);
       return false;
     }
-  off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
+  off_t symoff = symshdr.get_sh_offset() + symndx * This::sym_size;
   const unsigned char* psym = this->get_view(symoff, This::sym_size, true,
                                             false);
   elfcpp::Sym<size, big_endian> sym(psym);
@@ -426,15 +550,15 @@ Sized_relobj<size, big_endian>::include_section_group(
   // Read the symbol table names.
   section_size_type symnamelen;
   const unsigned char* psymnamesu;
-  psymnamesu = this->section_contents(symshdr.get_sh_link(), &symnamelen,
-                                     true);
+  psymnamesu = this->section_contents(this->adjust_shndx(symshdr.get_sh_link()),
+                                     &symnamelen, true);
   const char* psymnames = reinterpret_cast<const char*>(psymnamesu);
 
   // Get the section group signature.
   if (sym.get_st_name() >= symnamelen)
     {
       this->error(_("symbol %u name offset %u out of range"),
-                 shdr.get_sh_info(), sym.get_st_name());
+                 symndx, sym.get_st_name());
       return false;
     }
 
@@ -443,11 +567,20 @@ Sized_relobj<size, big_endian>::include_section_group(
   // It seems that some versions of gas will create a section group
   // associated with a section symbol, and then fail to give a name to
   // the section symbol.  In such a case, use the name of the section.
-  // FIXME.
   std::string secname;
   if (signature[0] == '\0' && sym.get_st_type() == elfcpp::STT_SECTION)
     {
-      secname = this->section_name(sym.get_st_shndx());
+      bool is_ordinary;
+      unsigned int sym_shndx = this->adjust_sym_shndx(symndx,
+                                                     sym.get_st_shndx(),
+                                                     &is_ordinary);
+      if (!is_ordinary || sym_shndx >= this->shnum())
+       {
+         this->error(_("symbol %u invalid section index %u"),
+                     symndx, sym_shndx);
+         return false;
+       }
+      secname = this->section_name(sym_shndx);
       signature = secname.c_str();
     }
 
@@ -559,7 +692,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
       unsigned int sh_type = shdr.get_sh_type();
       if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA)
        {
-         unsigned int target_shndx = shdr.get_sh_info();
+         unsigned int target_shndx = this->adjust_shndx(shdr.get_sh_info());
          if (target_shndx == 0 || target_shndx >= shnum)
            {
              this->error(_("relocation section %u has bad info %u"),
@@ -723,7 +856,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
       pshdr = sd->section_headers->data() + i * This::shdr_size;
       typename This::Shdr shdr(pshdr);
 
-      unsigned int data_shndx = shdr.get_sh_info();
+      unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info());
       if (data_shndx >= shnum)
        {
          // We already warned about this above.
@@ -813,7 +946,11 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
     reinterpret_cast<const char*>(sd->symbol_names->data());
   symtab->add_from_relobj(this,
                          sd->symbols->data() + sd->external_symbols_offset,
-                         symcount, sym_names, sd->symbol_names_size,
+                         symcount,
+                         (sd->external_symbols_offset == 0
+                          ? this->local_symbol_count_
+                          : 0),
+                         sym_names, sd->symbol_names_size,
                          &this->symbols_);
 
   delete sd->symbols;
@@ -855,7 +992,8 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
                                              locsize, true, true);
 
   // Read the symbol names.
-  const unsigned int strtab_shndx = symtabshdr.get_sh_link();
+  const unsigned int strtab_shndx =
+    this->adjust_shndx(symtabshdr.get_sh_link());
   section_size_type strtab_size;
   const unsigned char* pnamesu = this->section_contents(strtab_shndx,
                                                        &strtab_size,
@@ -876,8 +1014,10 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
 
       Symbol_value<size>& lv(this->local_values_[i]);
 
-      unsigned int shndx = sym.get_st_shndx();
-      lv.set_input_shndx(shndx);
+      bool is_ordinary;
+      unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(),
+                                                 &is_ordinary);
+      lv.set_input_shndx(shndx, is_ordinary);
 
       if (sym.get_st_type() == elfcpp::STT_SECTION)
        lv.set_is_section_symbol();
@@ -937,7 +1077,7 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
 template<int size, bool big_endian>
 unsigned int
 Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
-                                                          off_t off)
+                                                         off_t off)
 {
   gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
 
@@ -951,17 +1091,17 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
     {
       Symbol_value<size>& lv(this->local_values_[i]);
 
-      unsigned int shndx = lv.input_shndx();
+      bool is_ordinary;
+      unsigned int shndx = lv.input_shndx(&is_ordinary);
 
       // Set the output symbol value.
       
-      if (shndx >= elfcpp::SHN_LORESERVE)
+      if (!is_ordinary)
        {
          if (shndx == elfcpp::SHN_ABS || shndx == elfcpp::SHN_COMMON)
            lv.set_output_value(lv.input_value());
          else
            {
-             // FIXME: Handle SHN_XINDEX.
              this->error(_("unknown section index %u for local symbol %u"),
                          shndx, i);
              lv.set_output_value(0);
@@ -1062,7 +1202,9 @@ void
 Sized_relobj<size, big_endian>::write_local_symbols(
     Output_file* of,
     const Stringpool* sympool,
-    const Stringpool* dynpool)
+    const Stringpool* dynpool,
+    Output_symtab_xindex* symtab_xindex,
+    Output_symtab_xindex* dynsym_xindex)
 {
   if (parameters->options().strip_all()
       && this->output_local_dynsym_count_ == 0)
@@ -1090,7 +1232,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(
                                              locsize, true, false);
 
   // Read the symbol names.
-  const unsigned int strtab_shndx = symtabshdr.get_sh_link();
+  const unsigned int strtab_shndx =
+    this->adjust_shndx(symtabshdr.get_sh_link());
   section_size_type strtab_size;
   const unsigned char* pnamesu = this->section_contents(strtab_shndx,
                                                        &strtab_size,
@@ -1121,18 +1264,30 @@ Sized_relobj<size, big_endian>::write_local_symbols(
     {
       elfcpp::Sym<size, big_endian> isym(psyms);
 
-      unsigned int st_shndx = isym.get_st_shndx();
-      if (st_shndx < elfcpp::SHN_LORESERVE)
+      Symbol_value<size>& lv(this->local_values_[i]);
+
+      bool is_ordinary;
+      unsigned int st_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+                                                    &is_ordinary);
+      if (is_ordinary)
        {
          gold_assert(st_shndx < mo.size());
          if (mo[st_shndx].output_section == NULL)
            continue;
          st_shndx = mo[st_shndx].output_section->out_shndx();
+         if (st_shndx >= elfcpp::SHN_LORESERVE)
+           {
+             if (lv.needs_output_symtab_entry())
+               symtab_xindex->add(lv.output_symtab_index(), st_shndx);
+             if (lv.needs_output_dynsym_entry())
+               dynsym_xindex->add(lv.output_dynsym_index(), st_shndx);
+             st_shndx = elfcpp::SHN_XINDEX;
+           }
        }
 
       // Write the symbol to the output symbol table.
       if (!parameters->options().strip_all()
-         && this->local_values_[i].needs_output_symtab_entry())
+         && lv.needs_output_symtab_entry())
         {
           elfcpp::Sym_write<size, big_endian> osym(ov);
 
@@ -1149,7 +1304,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(
         }
 
       // Write the symbol to the output dynamic symbol table.
-      if (this->local_values_[i].needs_output_dynsym_entry())
+      if (lv.needs_output_dynsym_entry())
         {
           gold_assert(dyn_ov < dyn_oview + dyn_output_size);
           elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
@@ -1201,7 +1356,8 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
                                                        &symbols_size,
                                                        false);
 
-  unsigned int symbol_names_shndx = this->section_link(this->symtab_shndx_);
+  unsigned int symbol_names_shndx =
+    this->adjust_shndx(this->section_link(this->symtab_shndx_));
   section_size_type names_size;
   const unsigned char* symbol_names_u =
     this->section_contents(symbol_names_shndx, &names_size, false);
@@ -1221,11 +1377,17 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
            info->source_file = "(invalid)";
          else
            info->source_file = symbol_names + sym.get_st_name();
+         continue;
        }
-      else if (sym.get_st_shndx() == shndx
-               && static_cast<off_t>(sym.get_st_value()) <= offset
-               && (static_cast<off_t>(sym.get_st_value() + sym.get_st_size())
-                   > offset))
+
+      bool is_ordinary;
+      unsigned int st_shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(),
+                                                    &is_ordinary);
+      if (is_ordinary
+         && st_shndx == shndx
+         && static_cast<off_t>(sym.get_st_value()) <= offset
+         && (static_cast<off_t>(sym.get_st_value() + sym.get_st_size())
+             > offset))
         {
           if (sym.get_st_name() > names_size)
            info->enclosing_symbol_name = "(invalid)";
index 9e64277d486ff1c37938cac7dc6cb0584ba68ea1..aaaa48dc8b95169e3737dae15016856bd1964eb4 100644 (file)
@@ -39,6 +39,7 @@ class Task;
 class Layout;
 class Output_section;
 class Output_file;
+class Output_symtab_xindex;
 class Dynobj;
 class Object_merge_map;
 class Relocatable_relocs;
@@ -127,6 +128,55 @@ struct Read_relocs_data
   File_view* local_symbols;
 };
 
+// The Xindex class manages section indexes for objects with more than
+// 0xff00 sections.
+
+class Xindex
+{
+ public:
+  Xindex(int large_shndx_offset)
+    : large_shndx_offset_(large_shndx_offset), symtab_xindex_()
+  { }
+
+  // Initialize the symtab_xindex_ array, given the object and the
+  // section index of the symbol table to use.
+  template<int size, bool big_endian>
+  void
+  initialize_symtab_xindex(Object*, unsigned int symtab_shndx);
+
+  // Read in the symtab_xindex_ array, given its section index.
+  // PSHDRS may optionally point to the section headers.
+  template<int size, bool big_endian>
+  void
+  read_symtab_xindex(Object*, unsigned int xindex_shndx,
+                    const unsigned char* pshdrs);
+
+  // Symbol SYMNDX in OBJECT has a section of SHN_XINDEX; return the
+  // real section index.
+  unsigned int
+  sym_xindex_to_shndx(Object* object, unsigned int symndx);
+
+ private:
+  // The type of the array giving the real section index for symbols
+  // whose st_shndx field holds SHN_XINDEX.
+  typedef std::vector<unsigned int> Symtab_xindex;
+
+  // Adjust a section index if necessary.  This should only be called
+  // for ordinary section indexes.
+  unsigned int
+  adjust_shndx(unsigned int shndx)
+  {
+    if (shndx >= elfcpp::SHN_LORESERVE)
+      shndx += this->large_shndx_offset_;
+    return shndx;
+  }
+
+  // Adjust to apply to large section indexes.
+  int large_shndx_offset_;
+  // The data from the SHT_SYMTAB_SHNDX section.
+  Symtab_xindex symtab_xindex_;
+};
+
 // Object is an abstract base class which represents either a 32-bit
 // or a 64-bit input object.  This can be a regular object file
 // (ET_REL) or a shared object (ET_DYN).
@@ -141,7 +191,7 @@ class Object
   Object(const std::string& name, Input_file* input_file, bool is_dynamic,
         off_t offset = 0)
     : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
-      is_dynamic_(is_dynamic), target_(NULL)
+      is_dynamic_(is_dynamic), target_(NULL), xindex_(NULL)
   { input_file->file().add_object(); }
 
   virtual ~Object()
@@ -214,6 +264,29 @@ class Object
   const unsigned char*
   section_contents(unsigned int shndx, section_size_type* plen, bool cache);
 
+  // Adjust a symbol's section index as needed.  SYMNDX is the index
+  // of the symbol and SHNDX is the symbol's section from
+  // get_st_shndx.  This returns the section index.  It sets
+  // *IS_ORDINARY to indicate whether this is a normal section index,
+  // rather than a special code between SHN_LORESERVE and
+  // SHN_HIRESERVE.
+  unsigned int
+  adjust_sym_shndx(unsigned int symndx, unsigned int shndx, bool* is_ordinary)
+  {
+    if (shndx < elfcpp::SHN_LORESERVE)
+      *is_ordinary = true;
+    else if (shndx == elfcpp::SHN_XINDEX)
+      {
+       if (this->xindex_ == NULL)
+         this->xindex_ = this->do_initialize_xindex();
+       shndx = this->xindex_->sym_xindex_to_shndx(this, symndx);
+       *is_ordinary = true;
+      }
+    else
+      *is_ordinary = false;
+    return shndx;
+  }
+
   // Return the size of a section given a section index.
   uint64_t
   section_size(unsigned int shndx)
@@ -399,6 +472,10 @@ class Object
   virtual uint64_t
   do_section_addralign(unsigned int shndx) = 0;
 
+  // Return the Xindex structure to use.
+  virtual Xindex*
+  do_initialize_xindex() = 0;
+
   // Get the file.  We pass on const-ness.
   Input_file*
   input_file()
@@ -426,6 +503,14 @@ class Object
   read_section_data(elfcpp::Elf_file<size, big_endian, Object>*,
                    Read_symbols_data*);
 
+  // Let the child class initialize the xindex object directly.
+  void
+  set_xindex(Xindex* xindex)
+  {
+    gold_assert(this->xindex_ == NULL);
+    this->xindex_ = xindex;
+  }
+
   // If NAME is the name of a special .gnu.warning section, arrange
   // for the warning to be issued.  SHNDX is the section index.
   // Return whether it is a warning section.
@@ -451,6 +536,8 @@ class Object
   bool is_dynamic_;
   // Target functions--may be NULL if the target is not known.
   Target* target_;
+  // Many sections for objects with more than SHN_LORESERVE sections.
+  Xindex* xindex_;
 };
 
 // Implement sized_target inline for efficiency.  This approach breaks
@@ -774,8 +861,8 @@ class Symbol_value
 
   Symbol_value()
     : output_symtab_index_(0), output_dynsym_index_(-1U), input_shndx_(0),
-      is_section_symbol_(false), is_tls_symbol_(false),
-      has_output_value_(true)
+      is_ordinary_shndx_(false), is_section_symbol_(false),
+      is_tls_symbol_(false), has_output_value_(true)
   { this->u_.value = 0; }
 
   // Get the value of this symbol.  OBJECT is the object in which this
@@ -787,8 +874,11 @@ class Symbol_value
     if (this->has_output_value_)
       return this->u_.value + addend;
     else
-      return this->u_.merged_symbol_value->value(object, this->input_shndx_,
-                                                addend);
+      {
+       gold_assert(this->is_ordinary_shndx_);
+       return this->u_.merged_symbol_value->value(object, this->input_shndx_,
+                                                  addend);
+      }
   }
 
   // Set the value of this symbol in the output symbol table.
@@ -814,7 +904,7 @@ class Symbol_value
   {
     if (!this->has_output_value_)
       {
-       gold_assert(this->is_section_symbol_);
+       gold_assert(this->is_section_symbol_ && this->is_ordinary_shndx_);
        Merged_symbol_value<size>* msv = this->u_.merged_symbol_value;
        msv->initialize_input_to_output_map(object, this->input_shndx_);
       }
@@ -908,18 +998,22 @@ class Symbol_value
 
   // Set the index of the input section in the input file.
   void
-  set_input_shndx(unsigned int i)
+  set_input_shndx(unsigned int i, bool is_ordinary)
   {
     this->input_shndx_ = i;
     // input_shndx_ field is a bitfield, so make sure that the value
     // fits.
     gold_assert(this->input_shndx_ == i);
+    this->is_ordinary_shndx_ = is_ordinary;
   }
 
   // Return the index of the input section in the input file.
   unsigned int
-  input_shndx() const
-  { return this->input_shndx_; }
+  input_shndx(bool* is_ordinary) const
+  {
+    *is_ordinary = this->is_ordinary_shndx_;
+    return this->input_shndx_;
+  }
 
   // Whether this is a section symbol.
   bool
@@ -953,7 +1047,10 @@ class Symbol_value
   unsigned int output_dynsym_index_;
   // The section index in the input file in which this symbol is
   // defined.
-  unsigned int input_shndx_ : 29;
+  unsigned int input_shndx_ : 28;
+  // Whether the section index is an ordinary index, not a special
+  // value.
+  bool is_ordinary_shndx_ : 1;
   // Whether this is a STT_SECTION symbol.
   bool is_section_symbol_ : 1;
   // Whether this is a STT_TLS symbol.
@@ -1087,12 +1184,13 @@ class Sized_relobj : public Relobj
   }
 
   // Return the section index of symbol SYM.  Set *VALUE to its value
-  // in the object file.  Note that for a symbol which is not defined
-  // in this object file, this will set *VALUE to 0 and return
-  // SHN_UNDEF; it will not return the final value of the symbol in
-  // the link.
+  // in the object file.  Set *IS_ORDINARY if this is an ordinary
+  // section index, not a special code between SHN_LORESERVE and
+  // SHN_HIRESERVE.  Note that for a symbol which is not defined in
+  // this object file, this will set *VALUE to 0 and return SHN_UNDEF;
+  // it will not return the final value of the symbol in the link.
   unsigned int
-  symbol_section_and_value(unsigned int sym, Address* value);
+  symbol_section_and_value(unsigned int sym, Address* value, bool* is_ordinary);
 
   // Return a pointer to the Symbol_value structure which holds the
   // value of a local symbol.
@@ -1123,10 +1221,10 @@ class Sized_relobj : public Relobj
 
   // Return the input section index of local symbol SYM.
   unsigned int
-  local_symbol_input_shndx(unsigned int sym) const
+  local_symbol_input_shndx(unsigned int sym, bool* is_ordinary) const
   {
     gold_assert(sym < this->local_values_.size());
-    return this->local_values_[sym].input_shndx();
+    return this->local_values_[sym].input_shndx(is_ordinary);
   }
 
   // Return the appropriate Sized_target structure.
@@ -1284,6 +1382,10 @@ class Sized_relobj : public Relobj
   do_section_addralign(unsigned int shndx)
   { return this->elf_file_.section_addralign(shndx); }
 
+  // Return the Xindex structure to use.
+  Xindex*
+  do_initialize_xindex();
+
  private:
   // For convenience.
   typedef Sized_relobj<size, big_endian> This;
@@ -1292,6 +1394,15 @@ class Sized_relobj : public Relobj
   static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
   typedef elfcpp::Shdr<size, big_endian> Shdr;
 
+  // Adjust a section index if necessary.
+  unsigned int
+  adjust_shndx(unsigned int shndx)
+  {
+    if (shndx >= elfcpp::SHN_LORESERVE)
+      shndx += this->elf_file_.large_shndx_offset();
+    return shndx;
+  }
+
   // Find the SHT_SYMTAB section, given the section headers.
   void
   find_symtab(const unsigned char* pshdrs);
@@ -1391,7 +1502,9 @@ class Sized_relobj : public Relobj
   void
   write_local_symbols(Output_file*,
                      const Stringpool_template<char>*,
-                     const Stringpool_template<char>*);
+                     const Stringpool_template<char>*,
+                     Output_symtab_xindex*,
+                     Output_symtab_xindex*);
 
   // Clear the local symbol information.
   void
index 09b7312de34205bbe23925c2d5614b13c3aa470f..ded6d42bb9d8bc349d1094c502e3119abd041f4f 100644 (file)
@@ -87,12 +87,14 @@ Output_section_headers::Output_section_headers(
     const Layout::Segment_list* segment_list,
     const Layout::Section_list* section_list,
     const Layout::Section_list* unattached_section_list,
-    const Stringpool* secnamepool)
+    const Stringpool* secnamepool,
+    const Output_section* shstrtab_section)
   : layout_(layout),
     segment_list_(segment_list),
     section_list_(section_list),
     unattached_section_list_(unattached_section_list),
-    secnamepool_(secnamepool)
+    secnamepool_(secnamepool),
+    shstrtab_section_(shstrtab_section)
 {
   // Count all the sections.  Start with 1 for the null section.
   off_t count = 1;
@@ -175,8 +177,20 @@ Output_section_headers::do_sized_write(Output_file* of)
     oshdr.put_sh_flags(0);
     oshdr.put_sh_addr(0);
     oshdr.put_sh_offset(0);
-    oshdr.put_sh_size(0);
-    oshdr.put_sh_link(0);
+
+    size_t section_count = (this->data_size()
+                           / elfcpp::Elf_sizes<size>::shdr_size);
+    if (section_count < elfcpp::SHN_LORESERVE)
+      oshdr.put_sh_size(0);
+    else
+      oshdr.put_sh_size(section_count);
+
+    unsigned int shstrndx = this->shstrtab_section_->out_shndx();
+    if (shstrndx < elfcpp::SHN_LORESERVE)
+      oshdr.put_sh_link(0);
+    else
+      oshdr.put_sh_link(shstrndx);
+
     oshdr.put_sh_info(0);
     oshdr.put_sh_addralign(0);
     oshdr.put_sh_entsize(0);
@@ -447,9 +461,20 @@ Output_file_header::do_sized_write(Output_file* of)
     }
 
   oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
-  oehdr.put_e_shnum(this->section_header_->data_size()
-                    / elfcpp::Elf_sizes<size>::shdr_size);
-  oehdr.put_e_shstrndx(this->shstrtab_->out_shndx());
+  size_t section_count = (this->section_header_->data_size()
+                         / elfcpp::Elf_sizes<size>::shdr_size);
+
+  if (section_count < elfcpp::SHN_LORESERVE)
+    oehdr.put_e_shnum(this->section_header_->data_size()
+                     / elfcpp::Elf_sizes<size>::shdr_size);
+  else
+    oehdr.put_e_shnum(0);
+
+  unsigned int shstrndx = this->shstrtab_->out_shndx();
+  if (shstrndx < elfcpp::SHN_LORESERVE)
+    oehdr.put_e_shstrndx(this->shstrtab_->out_shndx());
+  else
+    oehdr.put_e_shstrndx(elfcpp::SHN_XINDEX);
 
   of->write_output_view(0, ehdr_size, view);
 }
@@ -1478,6 +1503,38 @@ Output_data_dynamic::sized_write(Output_file* of)
   this->entries_.clear();
 }
 
+// Class Output_symtab_xindex.
+
+void
+Output_symtab_xindex::do_write(Output_file* of)
+{
+  const off_t offset = this->offset();
+  const off_t oview_size = this->data_size();
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+  memset(oview, 0, oview_size);
+
+  if (parameters->target().is_big_endian())
+    this->endian_do_write<true>(oview);
+  else
+    this->endian_do_write<false>(oview);
+
+  of->write_output_view(offset, oview_size, oview);
+
+  // We no longer need the data.
+  this->entries_.clear();
+}
+
+template<bool big_endian>
+void
+Output_symtab_xindex::endian_do_write(unsigned char* const oview)
+{
+  for (Xindex_entries::const_iterator p = this->entries_.begin();
+       p != this->entries_.end();
+       ++p)
+    elfcpp::Swap<32, big_endian>::writeval(oview + p->first * 4, p->second);
+}
+
 // Output_section::Input_section methods.
 
 // Return the data size.  For an input section we store the size here.
index 4772cb4aaf9ab3a4c9988f3acbb3ba3150c2b105..b6527a34f72f57566425c54c8fab5c93abb2824d 100644 (file)
@@ -384,7 +384,8 @@ class Output_section_headers : public Output_data
                         const Layout::Segment_list*,
                         const Layout::Section_list*,
                         const Layout::Section_list*,
-                        const Stringpool*);
+                        const Stringpool*,
+                        const Output_section*);
 
  protected:
   // Write the data to the file.
@@ -407,6 +408,7 @@ class Output_section_headers : public Output_data
   const Layout::Section_list* section_list_;
   const Layout::Section_list* unattached_section_list_;
   const Stringpool* secnamepool_;
+  const Output_section* shstrtab_section_;
 };
 
 // Output the segment headers.
@@ -1682,6 +1684,41 @@ class Output_data_dynamic : public Output_section_data
   Stringpool* pool_;
 };
 
+// Output_symtab_xindex is used to handle SHT_SYMTAB_SHNDX sections,
+// which may be required if the object file has more than
+// SHN_LORESERVE sections.
+
+class Output_symtab_xindex : public Output_section_data
+{
+ public:
+  Output_symtab_xindex(size_t symcount)
+    : Output_section_data(symcount * 4, 4),
+      entries_()
+  { }
+
+  // Add an entry: symbol number SYMNDX has section SHNDX.
+  void
+  add(unsigned int symndx, unsigned int shndx)
+  { this->entries_.push_back(std::make_pair(symndx, shndx)); }
+
+ protected:
+  void
+  do_write(Output_file*);
+
+ private:
+  template<bool big_endian>
+  void
+  endian_do_write(unsigned char*);
+
+  // It is likely that most symbols will not require entries.  Rather
+  // than keep a vector for all symbols, we keep pairs of symbol index
+  // and section index.
+  typedef std::vector<std::pair<unsigned int, unsigned int> > Xindex_entries;
+
+  // The entries we need.
+  Xindex_entries entries_;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -1861,6 +1898,11 @@ class Output_section : public Output_data
   set_addralign(uint64_t v)
   { this->addralign_ = v; }
 
+  // Whether the output section index has been set.
+  bool
+  has_out_shndx() const
+  { return this->out_shndx_ != -1U; }
+
   // Indicate that we need a symtab index.
   void
   set_needs_symtab_index()
index 99a736bdc95a1933b9a4f5eaef3cae5e4869f5b2..b44dd721b1d1b4f3a3d2a15606e498b53121f842 100644 (file)
@@ -208,7 +208,7 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
       if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
        continue;
 
-      unsigned int shndx = shdr.get_sh_info();
+      unsigned int shndx = this->adjust_shndx(shdr.get_sh_info());
       if (shndx >= shnum)
        {
          this->error(_("relocation section %u has bad info %u"),
@@ -233,11 +233,11 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
          && !parameters->options().emit_relocs())
        continue;
 
-      if (shdr.get_sh_link() != this->symtab_shndx_)
+      if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx_)
        {
          this->error(_("relocation section %u uses unexpected "
                        "symbol table %u"),
-                     i, shdr.get_sh_link());
+                     i, this->adjust_shndx(shdr.get_sh_link()));
          continue;
        }
 
@@ -507,7 +507,8 @@ Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
     }
 
   // Write out the local symbols.
-  this->write_local_symbols(of, layout->sympool(), layout->dynpool());
+  this->write_local_symbols(of, layout->sympool(), layout->dynpool(),
+                           layout->symtab_xindex(), layout->dynsym_xindex());
 
   // We should no longer need the local symbol values.
   this->clear_local_symbols();
@@ -714,7 +715,7 @@ Sized_relobj<size, big_endian>::relocate_sections(
       if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
        continue;
 
-      unsigned int index = shdr.get_sh_info();
+      unsigned int index = this->adjust_shndx(shdr.get_sh_info());
       if (index >= this->shnum())
        {
          this->error(_("relocation section %u has bad info %u"),
@@ -735,11 +736,11 @@ Sized_relobj<size, big_endian>::relocate_sections(
       if (parameters->options().relocatable())
        gold_assert((*pviews)[i].view != NULL);
 
-      if (shdr.get_sh_link() != this->symtab_shndx_)
+      if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx_)
        {
          gold_error(_("relocation section %u uses unexpected "
                       "symbol table %u"),
-                    i, shdr.get_sh_link());
+                    i, this->adjust_shndx(shdr.get_sh_link()));
          continue;
        }
 
index 00e92780324aded33e2010e93fa551a077dda646..21a7fc634f29927161694fccd9fe37fbe3890289 100644 (file)
@@ -37,6 +37,7 @@ namespace gold
 template<int size, bool big_endian>
 void
 Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
+                     unsigned int st_shndx, bool is_ordinary,
                      Object* object, const char* version)
 {
   gold_assert(this->source_ == FROM_OBJECT);
@@ -46,8 +47,8 @@ Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
       gold_assert(this->version() == NULL);
       this->version_ = version;
     }
-  // FIXME: Handle SHN_XINDEX.
-  this->u_.from_object.shndx = sym.get_st_shndx();
+  this->u_.from_object.shndx = st_shndx;
+  this->is_ordinary_shndx_ = is_ordinary;
   this->type_ = sym.get_st_type();
   this->binding_ = sym.get_st_bind();
   this->visibility_ = sym.get_st_visibility();
@@ -64,9 +65,10 @@ template<int size>
 template<bool big_endian>
 void
 Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
+                            unsigned st_shndx, bool is_ordinary,
                             Object* object, const char* version)
 {
-  this->override_base(sym, object, version);
+  this->override_base(sym, st_shndx, is_ordinary, object, version);
   this->value_ = sym.get_st_value();
   this->symsize_ = sym.get_st_size();
 }
@@ -78,9 +80,10 @@ template<int size, bool big_endian>
 void
 Symbol_table::override(Sized_symbol<size>* tosym,
                       const elfcpp::Sym<size, big_endian>& fromsym,
+                      unsigned int st_shndx, bool is_ordinary,
                       Object* object, const char* version)
 {
-  tosym->override(fromsym, object, version);
+  tosym->override(fromsym, st_shndx, is_ordinary, object, version);
   if (tosym->has_alias())
     {
       Symbol* sym = this->weak_aliases_[tosym];
@@ -88,7 +91,7 @@ Symbol_table::override(Sized_symbol<size>* tosym,
       Sized_symbol<size>* ssym = this->get_sized_symbol<size>(sym);
       do
        {
-         ssym->override(fromsym, object, version);
+         ssym->override(fromsym, st_shndx, is_ordinary, object, version);
          sym = this->weak_aliases_[ssym];
          gold_assert(sym != NULL);
          ssym = this->get_sized_symbol<size>(sym);
@@ -121,7 +124,7 @@ static const unsigned int common_flag = 2 << def_undef_or_common_shift;
 
 static unsigned int
 symbol_to_bits(elfcpp::STB binding, bool is_dynamic,
-              unsigned int shndx, elfcpp::STT type)
+              unsigned int shndx, bool is_ordinary, elfcpp::STT type)
 {
   unsigned int bits;
 
@@ -160,7 +163,8 @@ symbol_to_bits(elfcpp::STB binding, bool is_dynamic,
       break;
 
     case elfcpp::SHN_COMMON:
-      bits |= common_flag;
+      if (!is_ordinary)
+       bits |= common_flag;
       break;
 
     default:
@@ -175,17 +179,20 @@ symbol_to_bits(elfcpp::STB binding, bool is_dynamic,
 }
 
 // Resolve a symbol.  This is called the second and subsequent times
-// we see a symbol.  TO is the pre-existing symbol.  ORIG_SYM is the
-// new symbol, seen in OBJECT.  SYM is almost always identical to
-// ORIG_SYM, but may be munged (for instance, if we determine the
-// symbol is in a to-be-discarded section, we'll set sym's shndx to
-// UNDEFINED).  VERSION of the version of SYM.
+// we see a symbol.  TO is the pre-existing symbol.  ST_SHNDX is the
+// section index for SYM, possibly adjusted for many sections.
+// IS_ORDINARY is whether ST_SHNDX is a normal section index rather
+// than a special code.  ORIG_ST_SHNDX is the original section index,
+// before any munging because of discarded sections, except that all
+// non-ordinary section indexes are mapped to SHN_UNDEF.  VERSION of
+// the version of SYM.
 
 template<int size, bool big_endian>
 void
 Symbol_table::resolve(Sized_symbol<size>* to,
                      const elfcpp::Sym<size, big_endian>& sym,
-                     const elfcpp::Sym<size, big_endian>& orig_sym,
+                     unsigned int st_shndx, bool is_ordinary,
+                     unsigned int orig_st_shndx,
                      Object* object, const char* version)
 {
   if (object->target()->has_resolve())
@@ -209,7 +216,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
 
   unsigned int frombits = symbol_to_bits(sym.get_st_bind(),
                                          object->is_dynamic(),
-                                         sym.get_st_shndx(),
+                                        st_shndx, is_ordinary,
                                          sym.get_st_type());
 
   bool adjust_common_sizes;
@@ -218,7 +225,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     {
       typename Sized_symbol<size>::Size_type tosize = to->symsize();
 
-      this->override(to, sym, object, version);
+      this->override(to, sym, st_shndx, is_ordinary, object, version);
 
       if (adjust_common_sizes && tosize > to->symsize())
         to->set_symsize(tosize);
@@ -236,24 +243,25 @@ Symbol_table::resolve(Sized_symbol<size>* to,
   // actually refer to the same lines of code.  (Note: not all ODR
   // violations can be found this way, and not everything this finds
   // is an ODR violation.  But it's helpful to warn about.)
-  // We use orig_sym here because we want the symbol exactly as it
-  // appears in the object file, not munged via our future processing.
+  bool to_is_ordinary;
   if (parameters->options().detect_odr_violations()
-      && orig_sym.get_st_bind() == elfcpp::STB_WEAK
+      && sym.get_st_bind() == elfcpp::STB_WEAK
       && to->binding() == elfcpp::STB_WEAK
-      && orig_sym.get_st_shndx() != elfcpp::SHN_UNDEF
-      && to->shndx() != elfcpp::SHN_UNDEF
-      && orig_sym.get_st_size() != 0    // Ignore weird 0-sized symbols.
+      && orig_st_shndx != elfcpp::SHN_UNDEF
+      && to->shndx(&to_is_ordinary) != elfcpp::SHN_UNDEF
+      && to_is_ordinary
+      && sym.get_st_size() != 0    // Ignore weird 0-sized symbols.
       && to->symsize() != 0
-      && (orig_sym.get_st_type() != to->type()
-          || orig_sym.get_st_size() != to->symsize())
+      && (sym.get_st_type() != to->type()
+          || sym.get_st_size() != to->symsize())
       // C does not have a concept of ODR, so we only need to do this
       // on C++ symbols.  These have (mangled) names starting with _Z.
       && to->name()[0] == '_' && to->name()[1] == 'Z')
     {
       Symbol_location fromloc
-          = { object, orig_sym.get_st_shndx(), orig_sym.get_st_value() };
-      Symbol_location toloc = { to->object(), to->shndx(), to->value() };
+          = { object, orig_st_shndx, sym.get_st_value() };
+      Symbol_location toloc = { to->object(), to->shndx(&to_is_ordinary),
+                               to->value() };
       this->candidate_odr_violations_[to->name()].insert(fromloc);
       this->candidate_odr_violations_[to->name()].insert(toloc);
     }
@@ -273,14 +281,19 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits,
   *adjust_common_sizes = false;
 
   unsigned int tobits;
-  if (to->source() == Symbol::FROM_OBJECT)
-    tobits = symbol_to_bits(to->binding(),
-                           to->object()->is_dynamic(),
-                           to->shndx(),
+  if (to->source() != Symbol::FROM_OBJECT)
+    tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_ABS, false,
                            to->type());
   else
-    tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_ABS,
-                           to->type());
+    {
+      bool is_ordinary;
+      unsigned int shndx = to->shndx(&is_ordinary);
+      tobits = symbol_to_bits(to->binding(),
+                             to->object()->is_dynamic(),
+                             shndx,
+                             is_ordinary,
+                             to->type());
+    }
 
   // FIXME: Warn if either but not both of TO and SYM are STT_TLS.
 
@@ -733,7 +746,9 @@ void
 Symbol_table::resolve<32, false>(
     Sized_symbol<32>* to,
     const elfcpp::Sym<32, false>& sym,
-    const elfcpp::Sym<32, false>& orig_sym,
+    unsigned int st_shndx,
+    bool is_ordinary,
+    unsigned int orig_st_shndx,
     Object* object,
     const char* version);
 #endif
@@ -744,7 +759,9 @@ void
 Symbol_table::resolve<32, true>(
     Sized_symbol<32>* to,
     const elfcpp::Sym<32, true>& sym,
-    const elfcpp::Sym<32, true>& orig_sym,
+    unsigned int st_shndx,
+    bool is_ordinary,
+    unsigned int orig_st_shndx,
     Object* object,
     const char* version);
 #endif
@@ -755,7 +772,9 @@ void
 Symbol_table::resolve<64, false>(
     Sized_symbol<64>* to,
     const elfcpp::Sym<64, false>& sym,
-    const elfcpp::Sym<64, false>& orig_sym,
+    unsigned int st_shndx,
+    bool is_ordinary,
+    unsigned int orig_st_shndx,
     Object* object,
     const char* version);
 #endif
@@ -766,7 +785,9 @@ void
 Symbol_table::resolve<64, true>(
     Sized_symbol<64>* to,
     const elfcpp::Sym<64, true>& sym,
-    const elfcpp::Sym<64, true>& orig_sym,
+    unsigned int st_shndx,
+    bool is_ordinary,
+    unsigned int orig_st_shndx,
     Object* object,
     const char* version);
 #endif
index 1ae48c3377879ccc0a0e3a94824a51a56ef03e70..60e85241d71cc83c997c35bc676b40f2d188a64a 100644 (file)
@@ -1737,13 +1737,21 @@ Target_sparc<size, big_endian>::Scan::local(
                 Output_data_got<size, big_endian>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
-                got->add_local_pair_with_rela(object, r_sym, 
-                                             lsym.get_st_shndx(),
-                                             GOT_TYPE_TLS_PAIR,
-                                             target->rela_dyn_section(layout),
-                                             (size == 64 ?
-                                              elfcpp::R_SPARC_TLS_DTPMOD64 :
-                                              elfcpp::R_SPARC_TLS_DTPMOD32), 0);
+               unsigned int shndx = lsym.get_st_shndx();
+               bool is_ordinary;
+               shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+               if (!is_ordinary)
+                 object->error(_("local symbol %u has bad shndx %u"),
+                               r_sym, shndx);
+               else
+                 got->add_local_pair_with_rela(object, r_sym, 
+                                               lsym.get_st_shndx(),
+                                               GOT_TYPE_TLS_PAIR,
+                                               target->rela_dyn_section(layout),
+                                               (size == 64
+                                                ? elfcpp::R_SPARC_TLS_DTPMOD64
+                                                : elfcpp::R_SPARC_TLS_DTPMOD32),
+                                                0);
                if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
                  generate_tls_call(symtab, layout, target);
              }
index 517d011c11299a8df2dc0c0f625f9e6a1056cdc2..eeb32fdd5722a223926c600679c2053caa3b8908 100644 (file)
@@ -72,6 +72,7 @@ Symbol::init_fields(const char* name, const char* version,
   this->has_warning_ = false;
   this->is_copied_from_dynobj_ = false;
   this->is_forced_local_ = false;
+  this->is_ordinary_shndx_ = false;
 }
 
 // Return the demangled version of the symbol's name, but only
@@ -105,13 +106,14 @@ Symbol::demangled_name() const
 template<int size, bool big_endian>
 void
 Symbol::init_base(const char* name, const char* version, Object* object,
-                 const elfcpp::Sym<size, big_endian>& sym)
+                 const elfcpp::Sym<size, big_endian>& sym,
+                 unsigned int st_shndx, bool is_ordinary)
 {
   this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
                    sym.get_st_visibility(), sym.get_st_nonvis());
   this->u_.from_object.object = object;
-  // FIXME: Handle SHN_XINDEX.
-  this->u_.from_object.shndx = sym.get_st_shndx();
+  this->u_.from_object.shndx = st_shndx;
+  this->is_ordinary_shndx_ = is_ordinary;
   this->source_ = FROM_OBJECT;
   this->in_reg_ = !object->is_dynamic();
   this->in_dyn_ = object->is_dynamic();
@@ -177,9 +179,10 @@ template<int size>
 template<bool big_endian>
 void
 Sized_symbol<size>::init(const char* name, const char* version, Object* object,
-                        const elfcpp::Sym<size, big_endian>& sym)
+                        const elfcpp::Sym<size, big_endian>& sym,
+                        unsigned int st_shndx, bool is_ordinary)
 {
-  this->init_base(name, version, object, sym);
+  this->init_base(name, version, object, sym, st_shndx, is_ordinary);
   this->value_ = sym.get_st_value();
   this->symsize_ = sym.get_st_size();
 }
@@ -309,7 +312,7 @@ Symbol::output_section() const
     case FROM_OBJECT:
       {
        unsigned int shndx = this->u_.from_object.shndx;
-       if (shndx != elfcpp::SHN_UNDEF && shndx < elfcpp::SHN_LORESERVE)
+       if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
          {
            gold_assert(!this->u_.from_object.object->is_dynamic());
            Relobj* relobj = static_cast<Relobj*>(this->u_.from_object.object);
@@ -449,13 +452,15 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
 {
   unsigned char buf[elfcpp::Elf_sizes<size>::sym_size];
   elfcpp::Sym_write<size, big_endian> esym(buf);
-  // We don't bother to set the st_name field.
+  // We don't bother to set the st_name or the st_shndx field.
   esym.put_st_value(from->value());
   esym.put_st_size(from->symsize());
   esym.put_st_info(from->binding(), from->type());
   esym.put_st_other(from->visibility(), from->nonvis());
-  esym.put_st_shndx(from->shndx());
-  this->resolve(to, esym.sym(), esym.sym(), from->object(), version);
+  bool is_ordinary;
+  unsigned int shndx = from->shndx(&is_ordinary);
+  this->resolve(to, esym.sym(), shndx, is_ordinary, shndx, from->object(),
+               version);
   if (from->in_reg())
     to->set_in_reg();
   if (from->in_dyn())
@@ -528,7 +533,9 @@ Symbol_table::wrap_symbol(Object* object, const char* name,
 
 // Add one symbol from OBJECT to the symbol table.  NAME is symbol
 // name and VERSION is the version; both are canonicalized.  DEF is
-// whether this is the default version.
+// whether this is the default version.  ST_SHNDX is the symbol's
+// section index; IS_ORDINARY is whether this is a normal section
+// rather than a special code.
 
 // If DEF is true, then this is the definition of a default version of
 // a symbol.  That means that any lookup of NAME/NULL and any lookup
@@ -549,10 +556,10 @@ Symbol_table::wrap_symbol(Object* object, const char* name,
 // Note that entries in the hash table will never be marked as
 // forwarders.
 //
-// SYM and ORIG_SYM are almost always the same.  ORIG_SYM is the
-// symbol exactly as it existed in the input file.  SYM is usually
-// that as well, but can be modified, for instance if we determine
-// it's in a to-be-discarded section.
+// ORIG_ST_SHNDX and ST_SHNDX are almost always the same.
+// ORIG_ST_SHNDX is the section index in the input file, or SHN_UNDEF
+// for a special section code.  ST_SHNDX may be modified if the symbol
+// is defined in a section being discarded.
 
 template<int size, bool big_endian>
 Sized_symbol<size>*
@@ -563,12 +570,14 @@ Symbol_table::add_from_object(Object* object,
                              Stringpool::Key version_key,
                              bool def,
                              const elfcpp::Sym<size, big_endian>& sym,
-                             const elfcpp::Sym<size, big_endian>& orig_sym)
+                             unsigned int st_shndx,
+                             bool is_ordinary,
+                             unsigned int orig_st_shndx)
 {
   // Print a message if this symbol is being traced.
   if (parameters->options().is_trace_symbol(name))
     {
-      if (orig_sym.get_st_shndx() == elfcpp::SHN_UNDEF)
+      if (orig_st_shndx == elfcpp::SHN_UNDEF)
         gold_info(_("%s: reference to %s"), object->name().c_str(), name);
       else
         gold_info(_("%s: definition of %s"), object->name().c_str(), name);
@@ -576,7 +585,7 @@ Symbol_table::add_from_object(Object* object,
 
   // For an undefined symbol, we may need to adjust the name using
   // --wrap.
-  if (orig_sym.get_st_shndx() == elfcpp::SHN_UNDEF
+  if (orig_st_shndx == elfcpp::SHN_UNDEF
       && parameters->options().any_wrap())
     {
       const char* wrap_name = this->wrap_symbol(object, name, &name_key);
@@ -625,7 +634,8 @@ Symbol_table::add_from_object(Object* object,
       was_undefined = ret->is_undefined();
       was_common = ret->is_common();
 
-      this->resolve(ret, sym, orig_sym, object, version);
+      this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
+                   version);
 
       if (def)
        {
@@ -671,7 +681,8 @@ Symbol_table::add_from_object(Object* object,
          was_undefined = ret->is_undefined();
          was_common = ret->is_common();
 
-         this->resolve(ret, sym, orig_sym, object, version);
+         this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
+                       version);
          ins.first->second = ret;
        }
       else
@@ -703,7 +714,7 @@ Symbol_table::add_from_object(Object* object,
                }
            }
 
-         ret->init(name, version, object, sym);
+         ret->init(name, version, object, sym, st_shndx, is_ordinary);
 
          ins.first->second = ret;
          if (def)
@@ -744,6 +755,7 @@ Symbol_table::add_from_relobj(
     Sized_relobj<size, big_endian>* relobj,
     const unsigned char* syms,
     size_t count,
+    size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
     typename Sized_relobj<size, big_endian>::Symbols* sympointers)
@@ -759,9 +771,8 @@ Symbol_table::add_from_relobj(
   for (size_t i = 0; i < count; ++i, p += sym_size)
     {
       elfcpp::Sym<size, big_endian> sym(p);
-      elfcpp::Sym<size, big_endian>* psym = &sym;
 
-      unsigned int st_name = psym->get_st_name();
+      unsigned int st_name = sym.get_st_name();
       if (st_name >= sym_name_size)
        {
          relobj->error(_("bad global symbol name offset %u at %zu"),
@@ -771,20 +782,20 @@ Symbol_table::add_from_relobj(
 
       const char* name = sym_names + st_name;
 
+      bool is_ordinary;
+      unsigned int st_shndx = relobj->adjust_sym_shndx(i + symndx_offset,
+                                                      sym.get_st_shndx(),
+                                                      &is_ordinary);
+      unsigned int orig_st_shndx = st_shndx;
+      if (!is_ordinary)
+       orig_st_shndx = elfcpp::SHN_UNDEF;
+
       // A symbol defined in a section which we are not including must
       // be treated as an undefined symbol.
-      unsigned char symbuf[sym_size];
-      elfcpp::Sym<size, big_endian> sym2(symbuf);
-      unsigned int st_shndx = psym->get_st_shndx();
       if (st_shndx != elfcpp::SHN_UNDEF
-         && st_shndx < elfcpp::SHN_LORESERVE
+         && is_ordinary
          && !relobj->is_section_included(st_shndx))
-       {
-         memcpy(symbuf, p, sym_size);
-         elfcpp::Sym_write<size, big_endian> sw(symbuf);
-         sw.put_st_shndx(elfcpp::SHN_UNDEF);
-         psym = &sym2;
-       }
+       st_shndx = elfcpp::SHN_UNDEF;
 
       // In an object file, an '@' in the name separates the symbol
       // name from the version name.  If there are two '@' characters,
@@ -810,7 +821,7 @@ Symbol_table::add_from_relobj(
       // even if it is listed in the version script.  FIXME: What
       // about a common symbol?
       else if (!version_script_.empty()
-              && psym->get_st_shndx() != elfcpp::SHN_UNDEF)
+              && st_shndx != elfcpp::SHN_UNDEF)
         {
           // The symbol name did not have a version, but
           // the version script may assign a version anyway.
@@ -826,14 +837,14 @@ Symbol_table::add_from_relobj(
             local = true;
         }
 
+      elfcpp::Sym<size, big_endian>* psym = &sym;
+      unsigned char symbuf[sym_size];
+      elfcpp::Sym<size, big_endian> sym2(symbuf);
       if (just_symbols)
        {
-         if (psym != &sym2)
-           memcpy(symbuf, p, sym_size);
+         memcpy(symbuf, p, sym_size);
          elfcpp::Sym_write<size, big_endian> sw(symbuf);
-         sw.put_st_shndx(elfcpp::SHN_ABS);
-         if (st_shndx != elfcpp::SHN_UNDEF
-             && st_shndx < elfcpp::SHN_LORESERVE)
+         if (orig_st_shndx != elfcpp::SHN_UNDEF && is_ordinary)
            {
              // Symbol values in object files are section relative.
              // This is normally what we want, but since here we are
@@ -841,9 +852,11 @@ Symbol_table::add_from_relobj(
              // section address.  The section address in an object
              // file is normally zero, but people can use a linker
              // script to change it.
-             sw.put_st_value(sym2.get_st_value()
-                             + relobj->section_address(st_shndx));
+             sw.put_st_value(sym.get_st_value()
+                             + relobj->section_address(orig_st_shndx));
            }
+         st_shndx = elfcpp::SHN_ABS;
+         is_ordinary = false;
          psym = &sym2;
        }
 
@@ -853,7 +866,8 @@ Symbol_table::add_from_relobj(
          Stringpool::Key name_key;
          name = this->namepool_.add(name, true, &name_key);
          res = this->add_from_object(relobj, name, name_key, NULL, 0,
-                                     false, *psym, sym);
+                                     false, *psym, st_shndx, is_ordinary,
+                                     orig_st_shndx);
           if (local)
            this->force_local(res);
        }
@@ -866,7 +880,8 @@ Symbol_table::add_from_relobj(
          ver = this->namepool_.add(ver, true, &ver_key);
 
          res = this->add_from_object(relobj, name, name_key, ver, ver_key,
-                                     def, *psym, sym);
+                                     def, *psym, st_shndx, is_ordinary,
+                                     orig_st_shndx);
        }
 
       (*sympointers)[i] = res;
@@ -937,6 +952,10 @@ Symbol_table::add_from_dynobj(
 
       const char* name = sym_names + st_name;
 
+      bool is_ordinary;
+      unsigned int st_shndx = dynobj->adjust_sym_shndx(i, sym.get_st_shndx(),
+                                                      &is_ordinary);
+
       Sized_symbol<size>* res;
 
       if (versym == NULL)
@@ -944,7 +963,8 @@ Symbol_table::add_from_dynobj(
          Stringpool::Key name_key;
          name = this->namepool_.add(name, true, &name_key);
          res = this->add_from_object(dynobj, name, name_key, NULL, 0,
-                                     false, sym, sym);
+                                     false, sym, st_shndx, is_ordinary,
+                                     st_shndx);
        }
       else
        {
@@ -963,7 +983,7 @@ Symbol_table::add_from_dynobj(
          // linker will generate.
 
          if (v == static_cast<unsigned int>(elfcpp::VER_NDX_LOCAL)
-             && sym.get_st_shndx() != elfcpp::SHN_UNDEF)
+             && st_shndx != elfcpp::SHN_UNDEF)
            {
              // This symbol should not be visible outside the object.
              continue;
@@ -978,7 +998,8 @@ Symbol_table::add_from_dynobj(
            {
              // This symbol does not have a version.
              res = this->add_from_object(dynobj, name, name_key, NULL, 0,
-                                         false, sym, sym);
+                                         false, sym, st_shndx, is_ordinary,
+                                         st_shndx);
            }
          else
            {
@@ -1005,24 +1026,27 @@ Symbol_table::add_from_dynobj(
              // version definition symbol.  These symbols exist to
              // support using -u to pull in particular versions.  We
              // do not want to record a version for them.
-             if (sym.get_st_shndx() == elfcpp::SHN_ABS
+             if (st_shndx == elfcpp::SHN_ABS
+                 && !is_ordinary
                  && name_key == version_key)
                res = this->add_from_object(dynobj, name, name_key, NULL, 0,
-                                           false, sym, sym);
+                                           false, sym, st_shndx, is_ordinary,
+                                           st_shndx);
              else
                {
                  const bool def = (!hidden
-                                   && (sym.get_st_shndx()
-                                       != elfcpp::SHN_UNDEF));
+                                   && st_shndx != elfcpp::SHN_UNDEF);
                  res = this->add_from_object(dynobj, name, name_key, version,
-                                             version_key, def, sym, sym);
+                                             version_key, def, sym, st_shndx,
+                                             is_ordinary, st_shndx);
                }
            }
        }
 
       // Note that it is possible that RES was overridden by an
       // earlier object, in which case it can't be aliased here.
-      if (sym.get_st_shndx() != elfcpp::SHN_UNDEF
+      if (st_shndx != elfcpp::SHN_UNDEF
+         && is_ordinary
          && sym.get_st_type() == elfcpp::STT_OBJECT
          && res->source() == Symbol::FROM_OBJECT
          && res->object() == dynobj)
@@ -1047,8 +1071,14 @@ bool
 Weak_alias_sorter<size>::operator()(const Sized_symbol<size>* s1,
                                    const Sized_symbol<size>* s2) const
 {
-  if (s1->shndx() != s2->shndx())
-    return s1->shndx() < s2->shndx();
+  bool is_ordinary;
+  unsigned int s1_shndx = s1->shndx(&is_ordinary);
+  gold_assert(is_ordinary);
+  unsigned int s2_shndx = s2->shndx(&is_ordinary);
+  gold_assert(is_ordinary);
+  if (s1_shndx != s2_shndx)
+    return s1_shndx < s2_shndx;
+
   if (s1->value() != s2->value())
     return s1->value() < s2->value();
   if (s1->binding() != s2->binding())
@@ -1091,7 +1121,8 @@ Symbol_table::record_weak_aliases(std::vector<Sized_symbol<size>*>* symbols)
       typename std::vector<Sized_symbol<size>*>::const_iterator q;
       for (q = p + 1; q != symbols->end(); ++q)
        {
-         if ((*q)->shndx() != from_sym->shndx()
+         bool dummy;
+         if ((*q)->shndx(&dummy) != from_sym->shndx(&dummy)
              || (*q)->value() != from_sym->value())
            break;
 
@@ -1798,10 +1829,11 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
     {
     case Symbol::FROM_OBJECT:
       {
-       unsigned int shndx = sym->shndx();
+       bool is_ordinary;
+       unsigned int shndx = sym->shndx(&is_ordinary);
 
        // FIXME: We need some target specific support here.
-       if (shndx >= elfcpp::SHN_LORESERVE
+       if (!is_ordinary
            && shndx != elfcpp::SHN_ABS
            && shndx != elfcpp::SHN_COMMON)
          {
@@ -1818,7 +1850,8 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
          }
        else if (shndx == elfcpp::SHN_UNDEF)
          value = 0;
-       else if (shndx == elfcpp::SHN_ABS || shndx == elfcpp::SHN_COMMON)
+       else if (!is_ordinary
+                && (shndx == elfcpp::SHN_ABS || shndx == elfcpp::SHN_COMMON))
          value = sym->value();
        else
          {
@@ -1904,32 +1937,39 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
 void
 Symbol_table::write_globals(const Input_objects* input_objects,
                            const Stringpool* sympool,
-                           const Stringpool* dynpool, Output_file* of) const
+                           const Stringpool* dynpool,
+                           Output_symtab_xindex* symtab_xindex,
+                           Output_symtab_xindex* dynsym_xindex,
+                           Output_file* of) const
 {
   switch (parameters->size_and_endianness())
     {
 #ifdef HAVE_TARGET_32_LITTLE
     case Parameters::TARGET_32_LITTLE:
       this->sized_write_globals<32, false>(input_objects, sympool,
-                                           dynpool, of);
+                                           dynpool, symtab_xindex,
+                                          dynsym_xindex, of);
       break;
 #endif
 #ifdef HAVE_TARGET_32_BIG
     case Parameters::TARGET_32_BIG:
       this->sized_write_globals<32, true>(input_objects, sympool,
-                                          dynpool, of);
+                                          dynpool, symtab_xindex,
+                                         dynsym_xindex, of);
       break;
 #endif
 #ifdef HAVE_TARGET_64_LITTLE
     case Parameters::TARGET_64_LITTLE:
       this->sized_write_globals<64, false>(input_objects, sympool,
-                                           dynpool, of);
+                                           dynpool, symtab_xindex,
+                                          dynsym_xindex, of);
       break;
 #endif
 #ifdef HAVE_TARGET_64_BIG
     case Parameters::TARGET_64_BIG:
       this->sized_write_globals<64, true>(input_objects, sympool,
-                                          dynpool, of);
+                                          dynpool, symtab_xindex,
+                                         dynsym_xindex, of);
       break;
 #endif
     default:
@@ -1944,6 +1984,8 @@ void
 Symbol_table::sized_write_globals(const Input_objects* input_objects,
                                  const Stringpool* sympool,
                                  const Stringpool* dynpool,
+                                 Output_symtab_xindex* symtab_xindex,
+                                 Output_symtab_xindex* dynsym_xindex,
                                  Output_file* of) const
 {
   const Target& target = parameters->target();
@@ -1998,10 +2040,11 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects,
        {
        case Symbol::FROM_OBJECT:
          {
-           unsigned int in_shndx = sym->shndx();
+           bool is_ordinary;
+           unsigned int in_shndx = sym->shndx(&is_ordinary);
 
            // FIXME: We need some target specific support here.
-           if (in_shndx >= elfcpp::SHN_LORESERVE
+           if (!is_ordinary
                && in_shndx != elfcpp::SHN_ABS
                && in_shndx != elfcpp::SHN_COMMON)
              {
@@ -2019,8 +2062,9 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects,
                    shndx = elfcpp::SHN_UNDEF;
                  }
                else if (in_shndx == elfcpp::SHN_UNDEF
-                        || in_shndx == elfcpp::SHN_ABS
-                        || in_shndx == elfcpp::SHN_COMMON)
+                        || (!is_ordinary
+                            && (in_shndx == elfcpp::SHN_ABS
+                                || in_shndx == elfcpp::SHN_COMMON)))
                  shndx = in_shndx;
                else
                  {
@@ -2031,6 +2075,15 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects,
                    gold_assert(os != NULL);
                    shndx = os->out_shndx();
 
+                   if (shndx >= elfcpp::SHN_LORESERVE)
+                     {
+                       if (sym_index != -1U)
+                         symtab_xindex->add(sym_index, shndx);
+                       if (dynsym_index != -1U)
+                         dynsym_xindex->add(dynsym_index, shndx);
+                       shndx = elfcpp::SHN_XINDEX;
+                     }
+
                    // In object files symbol values are section
                    // relative.
                    if (parameters->options().relocatable())
@@ -2042,6 +2095,14 @@ Symbol_table::sized_write_globals(const Input_objects* input_objects,
 
        case Symbol::IN_OUTPUT_DATA:
          shndx = sym->output_data()->out_shndx();
+         if (shndx >= elfcpp::SHN_LORESERVE)
+           {
+             if (sym_index != -1U)
+               symtab_xindex->add(sym_index, shndx);
+             if (dynsym_index != -1U)
+               dynsym_xindex->add(dynsym_index, shndx);
+             shndx = elfcpp::SHN_XINDEX;
+           }
          break;
 
        case Symbol::IN_OUTPUT_SEGMENT:
@@ -2125,9 +2186,10 @@ Symbol_table::warn_about_undefined_dynobj_symbol(
     const Input_objects* input_objects,
     Symbol* sym) const
 {
+  bool dummy;
   if (sym->source() == Symbol::FROM_OBJECT
       && sym->object()->is_dynamic()
-      && sym->shndx() == elfcpp::SHN_UNDEF
+      && sym->shndx(&dummy) == elfcpp::SHN_UNDEF
       && sym->binding() != elfcpp::STB_WEAK
       && !parameters->options().allow_shlib_undefined()
       && !parameters->target().is_defined_by_abi(sym)
@@ -2146,6 +2208,7 @@ Symbol_table::warn_about_undefined_dynobj_symbol(
 
 void
 Symbol_table::write_section_symbol(const Output_section *os,
+                                  Output_symtab_xindex* symtab_xindex,
                                   Output_file* of,
                                   off_t offset) const
 {
@@ -2153,22 +2216,26 @@ Symbol_table::write_section_symbol(const Output_section *os,
     {
 #ifdef HAVE_TARGET_32_LITTLE
     case Parameters::TARGET_32_LITTLE:
-      this->sized_write_section_symbol<32, false>(os, of, offset);
+      this->sized_write_section_symbol<32, false>(os, symtab_xindex, of,
+                                                 offset);
       break;
 #endif
 #ifdef HAVE_TARGET_32_BIG
     case Parameters::TARGET_32_BIG:
-      this->sized_write_section_symbol<32, true>(os, of, offset);
+      this->sized_write_section_symbol<32, true>(os, symtab_xindex, of,
+                                                offset);
       break;
 #endif
 #ifdef HAVE_TARGET_64_LITTLE
     case Parameters::TARGET_64_LITTLE:
-      this->sized_write_section_symbol<64, false>(os, of, offset);
+      this->sized_write_section_symbol<64, false>(os, symtab_xindex, of,
+                                                 offset);
       break;
 #endif
 #ifdef HAVE_TARGET_64_BIG
     case Parameters::TARGET_64_BIG:
-      this->sized_write_section_symbol<64, true>(os, of, offset);
+      this->sized_write_section_symbol<64, true>(os, symtab_xindex, of,
+                                                offset);
       break;
 #endif
     default:
@@ -2181,6 +2248,7 @@ Symbol_table::write_section_symbol(const Output_section *os,
 template<int size, bool big_endian>
 void
 Symbol_table::sized_write_section_symbol(const Output_section* os,
+                                        Output_symtab_xindex* symtab_xindex,
                                         Output_file* of,
                                         off_t offset) const
 {
@@ -2195,7 +2263,14 @@ Symbol_table::sized_write_section_symbol(const Output_section* os,
   osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL,
                                       elfcpp::STT_SECTION));
   osym.put_st_other(elfcpp::elf_st_other(elfcpp::STV_DEFAULT, 0));
-  osym.put_st_shndx(os->out_shndx());
+
+  unsigned int shndx = os->out_shndx();
+  if (shndx >= elfcpp::SHN_LORESERVE)
+    {
+      symtab_xindex->add(os->symtab_index(), shndx);
+      shndx = elfcpp::SHN_XINDEX;
+    }
+  osym.put_st_shndx(shndx);
 
   of->write_output_view(offset, sym_size, pov);
 }
@@ -2359,6 +2434,7 @@ Symbol_table::add_from_relobj<32, false>(
     Sized_relobj<32, false>* relobj,
     const unsigned char* syms,
     size_t count,
+    size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
     Sized_relobj<32, true>::Symbols* sympointers);
@@ -2371,6 +2447,7 @@ Symbol_table::add_from_relobj<32, true>(
     Sized_relobj<32, true>* relobj,
     const unsigned char* syms,
     size_t count,
+    size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
     Sized_relobj<32, false>::Symbols* sympointers);
@@ -2383,6 +2460,7 @@ Symbol_table::add_from_relobj<64, false>(
     Sized_relobj<64, false>* relobj,
     const unsigned char* syms,
     size_t count,
+    size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
     Sized_relobj<64, true>::Symbols* sympointers);
@@ -2395,6 +2473,7 @@ Symbol_table::add_from_relobj<64, true>(
     Sized_relobj<64, true>* relobj,
     const unsigned char* syms,
     size_t count,
+    size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
     Sized_relobj<64, false>::Symbols* sympointers);
index a4c1e78b0a5ceb2b0d7fc4489f324d9d9e1ad783..1ee3131d8f662ca50f5f7a90c1bc317154b37afb 100644 (file)
@@ -52,6 +52,7 @@ class Output_data;
 class Output_section;
 class Output_segment;
 class Output_file;
+class Output_symtab_xindex;
 
 // The base class of an entry in the symbol table.  The symbol table
 // can have a lot of entries, so we don't want this class to big.
@@ -142,9 +143,10 @@ class Symbol
   // Return the index of the section in the input relocatable or
   // dynamic object file.
   unsigned int
-  shndx() const
+  shndx(bool* is_ordinary) const
   {
     gold_assert(this->source_ == FROM_OBJECT);
+    *is_ordinary = this->is_ordinary_shndx_;
     return this->u_.from_object.shndx;
   }
 
@@ -386,9 +388,13 @@ class Symbol
   bool
   is_defined() const
   {
-    return (this->source_ != FROM_OBJECT
-           || (this->shndx() != elfcpp::SHN_UNDEF
-               && this->shndx() != elfcpp::SHN_COMMON));
+    bool is_ordinary;
+    if (this->source_ != FROM_OBJECT)
+      return true;
+    unsigned int shndx = this->shndx(&is_ordinary);
+    return (is_ordinary
+           ? shndx != elfcpp::SHN_UNDEF
+           : shndx != elfcpp::SHN_COMMON);
   }
 
   // Return true if this symbol is from a dynamic object.
@@ -402,31 +408,41 @@ class Symbol
   bool
   is_undefined() const
   {
-    return this->source_ == FROM_OBJECT && this->shndx() == elfcpp::SHN_UNDEF;
+    bool is_ordinary;
+    return (this->source_ == FROM_OBJECT
+           && this->shndx(&is_ordinary) == elfcpp::SHN_UNDEF
+           && is_ordinary);
   }
 
   // Return whether this is a weak undefined symbol.
   bool
   is_weak_undefined() const
   {
+    bool is_ordinary;
     return (this->source_ == FROM_OBJECT
             && this->binding() == elfcpp::STB_WEAK
-            && this->shndx() == elfcpp::SHN_UNDEF);
+            && this->shndx(&is_ordinary) == elfcpp::SHN_UNDEF
+           && is_ordinary);
   }
 
   // Return whether this is an absolute symbol.
   bool
   is_absolute() const
   {
-    return this->source_ == FROM_OBJECT && this->shndx() == elfcpp::SHN_ABS;
+    bool is_ordinary;
+    return (this->source_ == FROM_OBJECT
+           && this->shndx(&is_ordinary) == elfcpp::SHN_ABS
+           && !is_ordinary);
   }
 
   // Return whether this is a common symbol.
   bool
   is_common() const
   {
+    bool is_ordinary;
     return (this->source_ == FROM_OBJECT
-           && (this->shndx() == elfcpp::SHN_COMMON
+           && ((this->shndx(&is_ordinary) == elfcpp::SHN_COMMON
+                && !is_ordinary)
                || this->type_ == elfcpp::STT_COMMON));
   }
 
@@ -619,11 +635,14 @@ class Symbol
              elfcpp::STT type, elfcpp::STB binding,
              elfcpp::STV visibility, unsigned char nonvis);
 
-  // Initialize fields from an ELF symbol in OBJECT.
+  // Initialize fields from an ELF symbol in OBJECT.  ST_SHNDX is the
+  // section index, IS_ORDINARY is whether it is a normal section
+  // index rather than a special code.
   template<int size, bool big_endian>
   void
   init_base(const char *name, const char* version, Object* object,
-           const elfcpp::Sym<size, big_endian>&);
+           const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+           bool is_ordinary);
 
   // Initialize fields for an Output_data.
   void
@@ -644,8 +663,8 @@ class Symbol
   // Override existing symbol.
   template<int size, bool big_endian>
   void
-  override_base(const elfcpp::Sym<size, big_endian>&, Object* object,
-               const char* version);
+  override_base(const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+               bool is_ordinary, Object* object, const char* version);
 
   // Override existing symbol with a special symbol.
   void
@@ -725,20 +744,20 @@ class Symbol
   // section.
   unsigned int plt_offset_;
 
-  // Symbol type.
+  // Symbol type (bits 0 to 3).
   elfcpp::STT type_ : 4;
-  // Symbol binding.
+  // Symbol binding (bits 4 to 7).
   elfcpp::STB binding_ : 4;
-  // Symbol visibility.
+  // Symbol visibility (bits 8 to 9).
   elfcpp::STV visibility_ : 2;
-  // Rest of symbol st_other field.
+  // Rest of symbol st_other field (bits 10 to 15).
   unsigned int nonvis_ : 6;
-  // The type of symbol.
+  // The type of symbol (bits 16 to 18).
   Source source_ : 3;
   // True if this symbol always requires special target-specific
-  // handling.
+  // handling (bit 19).
   bool is_target_special_ : 1;
-  // True if this is the default version of the symbol.
+  // True if this is the default version of the symbol (bit 20).
   bool is_def_ : 1;
   // True if this symbol really forwards to another symbol.  This is
   // used when we discover after the fact that two different entries
@@ -746,30 +765,35 @@ class Symbol
   // never be set for a symbol found in the hash table, but may be set
   // for a symbol found in the list of symbols attached to an Object.
   // It forwards to the symbol found in the forwarders_ map of
-  // Symbol_table.
+  // Symbol_table (bit 21).
   bool is_forwarder_ : 1;
   // True if the symbol has an alias in the weak_aliases table in
-  // Symbol_table.
+  // Symbol_table (bit 22).
   bool has_alias_ : 1;
-  // True if this symbol needs to be in the dynamic symbol table.
+  // True if this symbol needs to be in the dynamic symbol table (bit
+  // 23).
   bool needs_dynsym_entry_ : 1;
-  // True if we've seen this symbol in a regular object.
+  // True if we've seen this symbol in a regular object (bit 24).
   bool in_reg_ : 1;
-  // True if we've seen this symbol in a dynamic object.
+  // True if we've seen this symbol in a dynamic object (bit 25).
   bool in_dyn_ : 1;
-  // True if the symbol has an entry in the PLT section.
+  // True if the symbol has an entry in the PLT section (bit 26).
   bool has_plt_offset_ : 1;
   // True if this is a dynamic symbol which needs a special value in
-  // the dynamic symbol table.
+  // the dynamic symbol table (bit 27).
   bool needs_dynsym_value_ : 1;
-  // True if there is a warning for this symbol.
+  // True if there is a warning for this symbol (bit 28).
   bool has_warning_ : 1;
   // True if we are using a COPY reloc for this symbol, so that the
-  // real definition lives in a dynamic object.
+  // real definition lives in a dynamic object (bit 29).
   bool is_copied_from_dynobj_ : 1;
   // True if this symbol was forced to local visibility by a version
-  // script.
+  // script (bit 30).
   bool is_forced_local_ : 1;
+  // True if the field u_.from_object.shndx is an ordinary section
+  // index, not one of the special codes from SHN_LORESERVE to
+  // SHN_HIRESERVE.
+  bool is_ordinary_shndx_ : 1;
 };
 
 // The parts of a symbol which are size specific.  Using a template
@@ -785,11 +809,14 @@ class Sized_symbol : public Symbol
   Sized_symbol()
   { }
 
-  // Initialize fields from an ELF symbol in OBJECT.
+  // Initialize fields from an ELF symbol in OBJECT.  ST_SHNDX is the
+  // section index, IS_ORDINARY is whether it is a normal section
+  // index rather than a special code.
   template<bool big_endian>
   void
   init(const char *name, const char* version, Object* object,
-       const elfcpp::Sym<size, big_endian>&);
+       const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+       bool is_ordinary);
 
   // Initialize fields for an Output_data.
   void
@@ -811,8 +838,8 @@ class Sized_symbol : public Symbol
   // Override existing symbol.
   template<bool big_endian>
   void
-  override(const elfcpp::Sym<size, big_endian>&, Object* object,
-          const char* version);
+  override(const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
+          bool is_ordinary, Object* object, const char* version);
 
   // Override existing symbol with a special symbol.
   void
@@ -1011,14 +1038,16 @@ class Symbol_table
   ~Symbol_table();
 
   // Add COUNT external symbols from the relocatable object RELOBJ to
-  // the symbol table.  SYMS is the symbols, SYM_NAMES is their names,
-  // SYM_NAME_SIZE is the size of SYM_NAMES.  This sets SYMPOINTERS to
-  // point to the symbols in the symbol table.
+  // the symbol table.  SYMS is the symbols, SYMNDX_OFFSET is the
+  // offset in the symbol table of the first symbol, SYM_NAMES is
+  // their names, SYM_NAME_SIZE is the size of SYM_NAMES.  This sets
+  // SYMPOINTERS to point to the symbols in the symbol table.
   template<int size, bool big_endian>
   void
   add_from_relobj(Sized_relobj<size, big_endian>* relobj,
                  const unsigned char* syms, size_t count,
-                 const char* sym_names, size_t sym_name_size,
+                 size_t symndx_offset, const char* sym_names,
+                 size_t sym_name_size,
                  typename Sized_relobj<size, big_endian>::Symbols*);
 
   // Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
@@ -1161,11 +1190,13 @@ class Symbol_table
   // Write out the global symbols.
   void
   write_globals(const Input_objects*, const Stringpool*, const Stringpool*,
+               Output_symtab_xindex*, Output_symtab_xindex*,
                Output_file*) const;
 
   // Write out a section symbol.  Return the updated offset.
   void
-  write_section_symbol(const Output_section*, Output_file*, off_t) const;
+  write_section_symbol(const Output_section*, Output_symtab_xindex*,
+                      Output_file*, off_t) const;
 
   // Dump statistical information to stderr.
   void
@@ -1193,14 +1224,16 @@ class Symbol_table
   add_from_object(Object*, const char *name, Stringpool::Key name_key,
                  const char *version, Stringpool::Key version_key,
                  bool def, const elfcpp::Sym<size, big_endian>& sym,
-                  const elfcpp::Sym<size, big_endian>& orig_sym);
+                 unsigned int st_shndx, bool is_ordinary,
+                 unsigned int orig_st_shndx);
 
   // Resolve symbols.
   template<int size, bool big_endian>
   void
   resolve(Sized_symbol<size>* to,
          const elfcpp::Sym<size, big_endian>& sym,
-         const elfcpp::Sym<size, big_endian>& orig_sym,
+         unsigned int st_shndx, bool is_ordinary,
+         unsigned int orig_st_shndx,
          Object*, const char* version);
 
   template<int size, bool big_endian>
@@ -1226,6 +1259,7 @@ class Symbol_table
   void
   override(Sized_symbol<size>* tosym,
           const elfcpp::Sym<size, big_endian>& fromsym,
+          unsigned int st_shndx, bool is_ordinary,
           Object* object, const char* version);
 
   // Whether we should override a symbol with a special symbol which
@@ -1317,7 +1351,8 @@ class Symbol_table
   template<int size, bool big_endian>
   void
   sized_write_globals(const Input_objects*, const Stringpool*,
-                     const Stringpool*, Output_file*) const;
+                     const Stringpool*, Output_symtab_xindex*,
+                     Output_symtab_xindex*, Output_file*) const;
 
   // Write out a symbol to P.
   template<int size, bool big_endian>
@@ -1334,7 +1369,8 @@ class Symbol_table
   // Write out a section symbol, specialized for size and endianness.
   template<int size, bool big_endian>
   void
-  sized_write_section_symbol(const Output_section*, Output_file*, off_t) const;
+  sized_write_section_symbol(const Output_section*, Output_symtab_xindex*,
+                            Output_file*, off_t) const;
 
   // The type of the symbol hash table.
 
index eab3c37eb4a0605339f24cb6698e0a8544012131..b0d71f5cb6fe119247369a67706739ab0246b062 100644 (file)
@@ -78,10 +78,12 @@ scan_relocs(
          gold_assert(plocal_syms != NULL);
          typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
                                                      + r_sym * sym_size);
-         const unsigned int shndx = lsym.get_st_shndx();
-         if (shndx < elfcpp::SHN_LORESERVE
+         unsigned int shndx = lsym.get_st_shndx();
+         bool is_ordinary;
+         shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+         if (is_ordinary
              && shndx != elfcpp::SHN_UNDEF
-             && !object->is_section_included(lsym.get_st_shndx()))
+             && !object->is_section_included(shndx))
            {
              // RELOC is a relocation against a local symbol in a
              // section we are discarding.  We can ignore this
@@ -333,10 +335,12 @@ scan_relocatable_relocs(
              gold_assert(plocal_syms != NULL);
              typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
                                                          + r_sym * sym_size);
-             const unsigned int shndx = lsym.get_st_shndx();
-             if (shndx < elfcpp::SHN_LORESERVE
+             unsigned int shndx = lsym.get_st_shndx();
+             bool is_ordinary;
+             shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+             if (is_ordinary
                  && shndx != elfcpp::SHN_UNDEF
-                 && !object->is_section_included(lsym.get_st_shndx()))
+                 && !object->is_section_included(shndx))
                {
                  // RELOC is a relocation against a local symbol
                  // defined in a section we are discarding.  Discard
@@ -428,7 +432,10 @@ relocate_for_relocatable(
                // the output section corresponding to input section
                // in which this symbol is defined.
                gold_assert(r_sym < local_count);
-               unsigned int shndx = object->local_symbol_input_shndx(r_sym);
+               bool is_ordinary;
+               unsigned int shndx =
+                 object->local_symbol_input_shndx(r_sym, &is_ordinary);
+               gold_assert(is_ordinary);
                section_offset_type dummy;
                Output_section* os = object->output_section(shndx, &dummy);
                gold_assert(os != NULL);
index fc4e78b5aba1d78873352d3e2f6471a8013631ff..c538aca0239ccfd760f5b272d12620377388e0d4 100644 (file)
@@ -43,6 +43,8 @@ MOSTLYCLEANFILES = *.so
 check_SCRIPTS =
 check_DATA =
 check_PROGRAMS =
+BUILT_SOURCES =
+
 TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
 
 # ---------------------------------------------------------------------
@@ -548,6 +550,32 @@ endif FN_PTRS_IN_SO_WITHOUT_PIC
 
 endif TLS
 
+check_PROGRAMS += many_sections_test
+many_sections_test_SOURCES = many_sections_test.cc
+many_sections_test_DEPENDENCIES = gcctestdir/ld
+many_sections_test_LDFLAGS = -Bgcctestdir/ -rdynamic
+
+BUILT_SOURCES += many_sections_define.h
+many_sections_define.h:
+       (for i in `seq 1 70000`; do \
+          echo "int var_$$i __attribute__((section(\"section_$$i\"))) = $$i;"; \
+        done) > $@.tmp
+       mv -f $@.tmp $@
+
+BUILT_SOURCES += many_sections_check.h
+many_sections_check.h:
+       (for i in `seq 1 70000`; do \
+          echo "assert(var_$$i == $$i);"; \
+        done) > $@.tmp
+       mv -f $@.tmp $@
+
+check_PROGRAMS += many_sections_r_test
+many_sections_r_test_SOURCES =
+many_sections_r_test_DEPENDENCIES = gcctestdir/ld many_sections_r_test.o
+many_sections_r_test_LDFLAGS = -Bgcctestdir/
+many_sections_r_test_LDADD = many_sections_r_test.o
+many_sections_r_test.o: many_sections_test.o gcctestdir/ld
+       gcctestdir/ld -r -o $@ many_sections_test.o
 
 if CONSTRUCTOR_PRIORITY
 
index 8896a3f6ae9803a59b45ee5dc885ceeb23c7bdb1..c47de28edc13be77841b78e127c2b6ab52413ad6 100644 (file)
@@ -47,7 +47,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
        $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
        $(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_13) $(am__EXEEXT_14) $(am__EXEEXT_15)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = basic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \
@@ -155,7 +155,18 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_9 = tls_static_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@      tls_static_pic_test
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_10 = tls_shared_nonpic_test
-@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_11 = initpri1
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_11 = many_sections_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_r_test
+@GCC_FALSE@many_sections_test_DEPENDENCIES = libgoldtest.a \
+@GCC_FALSE@    ../libgold.a ../../libiberty/libiberty.a \
+@GCC_FALSE@    $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@NATIVE_LINKER_FALSE@many_sections_test_DEPENDENCIES = libgoldtest.a \
+@NATIVE_LINKER_FALSE@  ../libgold.a ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_12 = many_sections_define.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h
+@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_13 = initpri1
 @CONSTRUCTOR_PRIORITY_FALSE@initpri1_DEPENDENCIES = libgoldtest.a \
 @CONSTRUCTOR_PRIORITY_FALSE@   ../libgold.a \
 @CONSTRUCTOR_PRIORITY_FALSE@   ../../libiberty/libiberty.a \
@@ -172,7 +183,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 # Test --detect-odr-violations
 
 # Similar to --detect-odr-violations: check for undefined symbols in .so's
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_12 = debug_msg.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_14 = debug_msg.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.sh ver_test_2.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_4.sh ver_test_5.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.sh \
@@ -186,7 +197,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 
 # We also want to make sure we do something reasonable when there's no
 # debug info available.  For the best test, we use .so's.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_13 = debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = debug_msg.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err ver_test_2.syms \
@@ -195,7 +206,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_14 = debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = debug_msg.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err \
@@ -204,17 +215,17 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout
 
 # Test -o when emitting to a special file (such as something in /dev).
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = flagstest_o_specialfile
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = flagstest_o_specialfile
 
 # Test --compress-debug-sections.  FIXME: check we actually compress.
 
 # The specialfile output has a tricky case when we also compress debug
 # sections, because it requires output-file resizing.
-@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = flagstest_compress_debug_sections \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_18 = flagstest_compress_debug_sections \
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections
 
 # Test symbol versioning.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = ver_test ver_test_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_19 = ver_test ver_test_2 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6 script_test_1 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2 justsyms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test script_test_3
@@ -318,11 +329,14 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__EXEEXT_9 = tls_static_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@      tls_static_pic_test$(EXEEXT)
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__EXEEXT_10 = tls_shared_nonpic_test$(EXEEXT)
-@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_11 = initpri1$(EXEEXT)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_12 = flagstest_o_specialfile$(EXEEXT)
-@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_13 = flagstest_compress_debug_sections$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_11 =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_r_test$(EXEEXT)
+@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_12 = initpri1$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_13 = flagstest_o_specialfile$(EXEEXT)
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_14 = flagstest_compress_debug_sections$(EXEEXT) \
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_14 = ver_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_15 = ver_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_2$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1$(EXEEXT) \
@@ -464,6 +478,13 @@ am__justsyms_SOURCES_DIST = justsyms_1.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms_1.$(OBJEXT)
 justsyms_OBJECTS = $(am_justsyms_OBJECTS)
 justsyms_LDADD = $(LDADD)
+am_many_sections_r_test_OBJECTS =
+many_sections_r_test_OBJECTS = $(am_many_sections_r_test_OBJECTS)
+am__many_sections_test_SOURCES_DIST = many_sections_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_many_sections_test_OBJECTS =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_test.$(OBJEXT)
+many_sections_test_OBJECTS = $(am_many_sections_test_OBJECTS)
+many_sections_test_LDADD = $(LDADD)
 am_object_unittest_OBJECTS = object_unittest.$(OBJEXT)
 object_unittest_OBJECTS = $(am_object_unittest_OBJECTS)
 object_unittest_LDADD = $(LDADD)
@@ -710,6 +731,7 @@ 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 \
        $(initpri1_SOURCES) $(justsyms_SOURCES) \
+       $(many_sections_r_test_SOURCES) $(many_sections_test_SOURCES) \
        $(object_unittest_SOURCES) $(script_test_1_SOURCES) \
        $(script_test_2_SOURCES) script_test_3.c \
        $(tls_pic_test_SOURCES) $(tls_shared_gd_to_ie_test_SOURCES) \
@@ -755,6 +777,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) \
+       $(many_sections_r_test_SOURCES) \
+       $(am__many_sections_test_SOURCES_DIST) \
        $(object_unittest_SOURCES) $(am__script_test_1_SOURCES_DIST) \
        $(am__script_test_2_SOURCES_DIST) script_test_3.c \
        $(am__tls_pic_test_SOURCES_DIST) \
@@ -956,13 +980,14 @@ TEST_STRIP = $(top_builddir)/../binutils/strip-new
 # .o's), but not all of them (such as .so's and .err files).  We
 # improve on that here.  automake-1.9 info docs say "mostlyclean" is
 # the right choice for files 'make' builds that people rebuild.
-MOSTLYCLEANFILES = *.so $(am__append_14)
+MOSTLYCLEANFILES = *.so $(am__append_16)
 
 # We will add to these later, for each individual test.  Note
 # that we add each test under check_SCRIPTS or check_PROGRAMS;
 # the TESTS variable is automatically populated from these.
-check_SCRIPTS = $(am__append_12)
-check_DATA = $(am__append_13)
+check_SCRIPTS = $(am__append_14)
+check_DATA = $(am__append_15)
+BUILT_SOURCES = $(am__append_12)
 TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
 
 # ---------------------------------------------------------------------
@@ -1216,6 +1241,13 @@ binary_unittest_SOURCES = binary_unittest.cc
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_nonpic_test_DEPENDENCIES = gcctestdir/ld tls_test_shared_nonpic.so
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_nonpic_test_LDADD = tls_test_shared_nonpic.so -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_test_SOURCES = many_sections_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_test_DEPENDENCIES = gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_test_LDFLAGS = -Bgcctestdir/ -rdynamic
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_r_test_SOURCES = 
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_r_test_DEPENDENCIES = gcctestdir/ld many_sections_r_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_r_test_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_r_test_LDADD = many_sections_r_test.o
 @CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri1_SOURCES = initpri1.c
 @CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri1_DEPENDENCIES = gcctestdir/ld
 @CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@initpri1_LDFLAGS = -Bgcctestdir/
@@ -1243,7 +1275,8 @@ binary_unittest_SOURCES = binary_unittest.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_SOURCES = binary_test.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_DEPENDENCIES = gcctestdir/ld binary.txt
 @GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_LDFLAGS = -Bgcctestdir/ -Wl,--format,binary,binary.txt,--format,elf
-all: all-am
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-am
 
 .SUFFIXES:
 .SUFFIXES: .c .cc .o .obj
@@ -1376,6 +1409,12 @@ initpri1$(EXEEXT): $(initpri1_OBJECTS) $(initpri1_DEPENDENCIES)
 justsyms$(EXEEXT): $(justsyms_OBJECTS) $(justsyms_DEPENDENCIES) 
        @rm -f justsyms$(EXEEXT)
        $(CXXLINK) $(justsyms_LDFLAGS) $(justsyms_OBJECTS) $(justsyms_LDADD) $(LIBS)
+many_sections_r_test$(EXEEXT): $(many_sections_r_test_OBJECTS) $(many_sections_r_test_DEPENDENCIES) 
+       @rm -f many_sections_r_test$(EXEEXT)
+       $(LINK) $(many_sections_r_test_LDFLAGS) $(many_sections_r_test_OBJECTS) $(many_sections_r_test_LDADD) $(LIBS)
+many_sections_test$(EXEEXT): $(many_sections_test_OBJECTS) $(many_sections_test_DEPENDENCIES) 
+       @rm -f many_sections_test$(EXEEXT)
+       $(CXXLINK) $(many_sections_test_LDFLAGS) $(many_sections_test_OBJECTS) $(many_sections_test_LDADD) $(LIBS)
 object_unittest$(EXEEXT): $(object_unittest_OBJECTS) $(object_unittest_DEPENDENCIES) 
        @rm -f object_unittest$(EXEEXT)
        $(CXXLINK) $(object_unittest_LDFLAGS) $(object_unittest_OBJECTS) $(object_unittest_LDADD) $(LIBS)
@@ -1528,6 +1567,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)/many_sections_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2.Po@am__quote@
@@ -1733,10 +1773,12 @@ check-am: all-am
        $(MAKE) $(AM_MAKEFLAGS) $(check_LIBRARIES) $(check_PROGRAMS) \
          $(check_SCRIPTS) $(check_DATA)
        $(MAKE) $(AM_MAKEFLAGS) check-TESTS
-check: check-am
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
 all-am: Makefile
 installdirs:
-install: install-am
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
 install-exec: install-exec-am
 install-data: install-data-am
 uninstall: uninstall-am
@@ -1761,6 +1803,7 @@ distclean-generic:
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-am
 
 clean-am: clean-checkLIBRARIES clean-checkPROGRAMS clean-generic \
@@ -1965,6 +2008,18 @@ uninstall-am: uninstall-info-am
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@  $(CXXLINK) -Bgcctestdir/ -shared tls_test_gnu2.o tls_test_file2_gnu2.o tls_test_c_gnu2.o
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o tls_test_c.o gcctestdir/ld
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o tls_test_c.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_define.h:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ (for i in `seq 1 70000`; do \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@    echo "int var_$$i __attribute__((section(\"section_$$i\"))) = $$i;"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@  done) > $@.tmp
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ mv -f $@.tmp $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_check.h:
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ (for i in `seq 1 70000`; do \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@    echo "assert(var_$$i == $$i);"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@  done) > $@.tmp
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ mv -f $@.tmp $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@many_sections_r_test.o: many_sections_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ many_sections_test.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.o: debug_msg.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation1.o: odr_violation1.cc
index 229be7e0738744145fd53d2b8aca5650a96a49f5..44db01ecb78f413209933d024c14acdfb8ddb225 100644 (file)
@@ -94,13 +94,19 @@ Sized_binary_test(Target* target)
   Sized_relobj<size, big_endian>* relobj =
     static_cast<Sized_relobj<size, big_endian>*>(object);
   typename Sized_relobj<size, big_endian>::Address value;
-  CHECK(relobj->symbol_section_and_value(0, &value) == 0);
+  bool is_ordinary;
+  CHECK(relobj->symbol_section_and_value(0, &value, &is_ordinary) == 0);
+  CHECK(is_ordinary);
   CHECK(value == 0);
-  CHECK(relobj->symbol_section_and_value(1, &value) == 1);
+  CHECK(relobj->symbol_section_and_value(1, &value, &is_ordinary) == 1);
+  CHECK(is_ordinary);
   CHECK(value == 0);
-  CHECK(relobj->symbol_section_and_value(2, &value) == 1);
+  CHECK(relobj->symbol_section_and_value(2, &value, &is_ordinary) == 1);
+  CHECK(is_ordinary);
   CHECK(static_cast<off_t>(value) == st.st_size);
-  CHECK(relobj->symbol_section_and_value(3, &value) == elfcpp::SHN_ABS);
+  CHECK(relobj->symbol_section_and_value(3, &value, &is_ordinary)
+       == elfcpp::SHN_ABS);
+  CHECK(!is_ordinary);
   CHECK(static_cast<off_t>(value) == st.st_size);
 
   object->unlock(task);
diff --git a/gold/testsuite/many_sections_test.cc b/gold/testsuite/many_sections_test.cc
new file mode 100644 (file)
index 0000000..dcb1cd2
--- /dev/null
@@ -0,0 +1,37 @@
+// many_sections_test.cc -- test lots of sections for gold
+
+// Copyright 2008 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.
+
+// This program tests having many sections.  It uses a generated .h
+// files to define 70,000 variables, each in a different section.  It
+// uses another generated .h file to verify that they all have the
+// right value.
+
+#include <cassert>
+
+#include "many_sections_define.h"
+
+int
+main(int, char**)
+{
+#include "many_sections_check.h"
+  return 0;
+}
index 247f9d0322cf43bea7e54df7d4f511d3e36f756e..927ed39be0f6eb7d16304f3b3cc0449e5a4d1e8f 100644 (file)
@@ -998,20 +998,26 @@ Target_x86_64::Scan::local(const General_options&,
           this->check_non_pic(object, r_type);
 
           Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+         unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
           if (lsym.get_st_type() != elfcpp::STT_SECTION)
-            {
-              unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
-              rela_dyn->add_local(object, r_sym, r_type, output_section,
-                                  data_shndx, reloc.get_r_offset(),
-                                  reloc.get_r_addend());
-            }
+           rela_dyn->add_local(object, r_sym, r_type, output_section,
+                               data_shndx, reloc.get_r_offset(),
+                               reloc.get_r_addend());
           else
             {
               gold_assert(lsym.get_st_value() == 0);
-              rela_dyn->add_local_section(object, lsym.get_st_shndx(),
-                                          r_type, output_section,
-                                          data_shndx, reloc.get_r_offset(),
-                                          reloc.get_r_addend());
+             unsigned int shndx = lsym.get_st_shndx();
+             bool is_ordinary;
+             shndx = object->adjust_sym_shndx(r_sym, shndx,
+                                              &is_ordinary);
+             if (!is_ordinary)
+               object->error(_("section symbol %u has bad shndx %u"),
+                             r_sym, shndx);
+             else
+               rela_dyn->add_local_section(object, shndx,
+                                           r_type, output_section,
+                                           data_shndx, reloc.get_r_offset(),
+                                           reloc.get_r_addend());
             }
         }
       break;
@@ -1109,11 +1115,18 @@ Target_x86_64::Scan::local(const General_options&,
                 Output_data_got<64, false>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
-                got->add_local_pair_with_rela(object, r_sym,
-                                              lsym.get_st_shndx(),
-                                              GOT_TYPE_TLS_PAIR,
-                                              target->rela_dyn_section(layout),
-                                              elfcpp::R_X86_64_DTPMOD64, 0);
+               unsigned int shndx = lsym.get_st_shndx();
+               bool is_ordinary;
+               shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+               if (!is_ordinary)
+                 object->error(_("local symbol %u has bad shndx %u"),
+                             r_sym, shndx);
+                else
+                 got->add_local_pair_with_rela(object, r_sym,
+                                               shndx,
+                                               GOT_TYPE_TLS_PAIR,
+                                               target->rela_dyn_section(layout),
+                                               elfcpp::R_X86_64_DTPMOD64, 0);
               }
             else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
@@ -1130,11 +1143,18 @@ Target_x86_64::Scan::local(const General_options&,
                 Output_data_got<64, false>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
-                got->add_local_pair_with_rela(object, r_sym,
-                                              lsym.get_st_shndx(),
-                                              GOT_TYPE_TLS_DESC,
-                                              target->rela_dyn_section(layout),
-                                              elfcpp::R_X86_64_TLSDESC, 0);
+               unsigned int shndx = lsym.get_st_shndx();
+               bool is_ordinary;
+               shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+               if (!is_ordinary)
+                 object->error(_("local symbol %u has bad shndx %u"),
+                             r_sym, shndx);
+                else
+                 got->add_local_pair_with_rela(object, r_sym,
+                                               shndx,
+                                               GOT_TYPE_TLS_DESC,
+                                               target->rela_dyn_section(layout),
+                                               elfcpp::R_X86_64_TLSDESC, 0);
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);