This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH COMMITTED: Add large section support to gold


I committed this patch to add support for object files with large
numbers of sections to gold.  The general approach is to couple a
boolean field, is_ordinary, with every section index.  When
is_ordinary is true, a section index between SHN_LORESERVE and
SHN_HIRESERVE is simply an index into the section table, not a special
code.

gold can handle files with large numbers of sections generated by the
GNU binutils before the PR 5900 fix, adjusting the section indexes as
needed.  (Files generated after the fix are of course handled also.)

I extended the ELF specification to permit the dynamic symbol table to
include symbols defined in sections with indexes larger than
SHN_LORESERVE in the obvious way: I create an allocated dynsym_shndx
section with type SHT_SYMTAB_SHNDX, linked to the SHT_DYNSYM section.
I actually did this before I realized that the ELF specification says
that SHT_SYMTAB_SHNDX sections only link to SHT_SYMTAB sections.  The
extension is safe in the sense that it is unambiguous, and will be
recognized by gold on input (the section of a dynamic symbol only
matters in a couple of unusual cases).  Unfortunately it will not be
recognized by readelf or the other GNU binutils.

Ian


gold/ChangeLog:
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.

elfcpp/ChangeLog:
2008-04-19  Ian Lance Taylor  <iant@google.com>

	* elfcpp_file.h (class Elf_file): Add large_shndx_offset_ field.
	(Elf_file::large_shndx_offset): New function.
	(Elf_file::construct): Initialize large_shndx_offset_.
	(Elf_File::initialize_shnum): If necessary, adjust shstrndx_ and
	set large_shndx_offset_.


Index: copy-relocs.cc
===================================================================
RCS file: /cvs/src/src/gold/copy-relocs.cc,v
retrieving revision 1.1
diff -u -p -r1.1 copy-relocs.cc
--- copy-relocs.cc	16 Apr 2008 22:54:29 -0000	1.1
+++ copy-relocs.cc	19 Apr 2008 18:29:27 -0000
@@ -118,8 +118,11 @@ Copy_relocs<sh_type, size, big_endian>::
   // 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: dwarf_reader.cc
===================================================================
RCS file: /cvs/src/src/gold/dwarf_reader.cc,v
retrieving revision 1.19
diff -u -p -r1.19 dwarf_reader.cc
--- dwarf_reader.cc	3 Apr 2008 04:18:53 -0000	1.19
+++ dwarf_reader.cc	19 Apr 2008 18:29:28 -0000
@@ -175,7 +175,7 @@ Sized_dwarf_line_info<size, big_endian>:
   // 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>:
 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>:
   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>:
 
 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: dwarf_reader.h
===================================================================
RCS file: /cvs/src/src/gold/dwarf_reader.h,v
retrieving revision 1.12
diff -u -p -r1.12 dwarf_reader.h
--- dwarf_reader.h	13 Mar 2008 21:04:21 -0000	1.12
+++ dwarf_reader.h	19 Apr 2008 18:29:28 -0000
@@ -101,17 +101,18 @@ class Sized_dwarf_line_info : public Dwa
   // 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: dynobj.cc
===================================================================
RCS file: /cvs/src/src/gold/dynobj.cc,v
retrieving revision 1.37
diff -u -p -r1.37 dynobj.cc
--- dynobj.cc	2 Apr 2008 20:58:21 -0000	1.37
+++ dynobj.cc	19 Apr 2008 18:29:28 -0000
@@ -72,7 +72,8 @@ Sized_dynobj<size, big_endian>::Sized_dy
     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_dyn
       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_dyn
 	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_dyn
 
   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_dyn
   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_
 
   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_
   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_
 	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_
 
       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_
 		       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: dynobj.h
===================================================================
RCS file: /cvs/src/src/gold/dynobj.h,v
retrieving revision 1.25
diff -u -p -r1.25 dynobj.h
--- dynobj.h	13 Mar 2008 21:04:21 -0000	1.25
+++ dynobj.h	19 Apr 2008 18:29:28 -0000
@@ -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: ehframe.cc
===================================================================
RCS file: /cvs/src/src/gold/ehframe.cc,v
retrieving revision 1.12
diff -u -p -r1.12 ehframe.cc
--- ehframe.cc	13 Mar 2008 21:04:21 -0000	1.12
+++ ehframe.cc	19 Apr 2008 18:29:28 -0000
@@ -971,9 +971,12 @@ Eh_frame::read_fde(Sized_relobj<size, bi
   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: gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.53
diff -u -p -r1.53 gold.cc
--- gold.cc	17 Apr 2008 07:12:00 -0000	1.53
+++ gold.cc	19 Apr 2008 18:29:28 -0000
@@ -310,7 +310,8 @@ queue_final_tasks(const General_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: i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.71
diff -u -p -r1.71 i386.cc
--- i386.cc	17 Apr 2008 02:00:54 -0000	1.71
+++ i386.cc	19 Apr 2008 18:29:28 -0000
@@ -881,18 +881,24 @@ Target_i386::Scan::local(const General_o
       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_o
                 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_o
                 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: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.99
diff -u -p -r1.99 layout.cc
--- layout.cc	16 Apr 2008 23:21:01 -0000	1.99
+++ layout.cc	19 Apr 2008 18:29:29 -0000
@@ -76,15 +76,33 @@ Layout_task_runner::run(Workqueue* workq
 // 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* in
   // 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* in
   // 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, L
 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* 
 
 // 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 Inp
 							     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 Inpu
   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 Inpu
   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* s
 	      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* s
 	  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: layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.54
diff -u -p -r1.54 layout.h
--- layout.h	15 Apr 2008 04:06:41 -0000	1.54
+++ layout.h	19 Apr 2008 18:29:29 -0000
@@ -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: object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.68
diff -u -p -r1.68 object.cc
--- object.cc	17 Apr 2008 22:45:47 -0000	1.68
+++ object.cc	19 Apr 2008 18:29:29 -0000
@@ -40,6 +40,93 @@
 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_sym
       // 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_sym
 	  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_
   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_
 }
 
 // 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_s
 
   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_
 
   // 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_
   // 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_
   // 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_layou
       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_layou
       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_s
     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
 					      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
 
       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
 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_final
     {
       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_lo
 					      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_lo
     {
       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_lo
         }
 
       // 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_symb
 							&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_symb
 	    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: object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.57
diff -u -p -r1.57 object.h
--- object.h	2 Apr 2008 20:58:21 -0000	1.57
+++ object.h	19 Apr 2008 18:29:29 -0000
@@ -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: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.72
diff -u -p -r1.72 output.cc
--- output.cc	15 Apr 2008 04:06:41 -0000	1.72
+++ output.cc	19 Apr 2008 18:29:30 -0000
@@ -87,12 +87,14 @@ Output_section_headers::Output_section_h
     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(O
     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(Outpu
     }
 
   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_
   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: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.64
diff -u -p -r1.64 output.h
--- output.h	16 Apr 2008 22:54:29 -0000	1.64
+++ output.h	19 Apr 2008 18:29:30 -0000
@@ -384,7 +384,8 @@ class Output_section_headers : public Ou
 			 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 Ou
   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 Outpu
   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_dat
   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: reloc.cc
===================================================================
RCS file: /cvs/src/src/gold/reloc.cc,v
retrieving revision 1.35
diff -u -p -r1.35 reloc.cc
--- reloc.cc	16 Apr 2008 22:54:29 -0000	1.35
+++ reloc.cc	19 Apr 2008 18:29:30 -0000
@@ -208,7 +208,7 @@ Sized_relobj<size, big_endian>::do_read_
       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_
 	  && !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_reloc
     }
 
   // 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
       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
       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: resolve.cc
===================================================================
RCS file: /cvs/src/src/gold/resolve.cc,v
retrieving revision 1.33
diff -u -p -r1.33 resolve.cc
--- resolve.cc	25 Mar 2008 18:37:16 -0000	1.33
+++ resolve.cc	19 Apr 2008 18:29:30 -0000
@@ -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<
       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
       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 = 
 
 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
       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
 }
 
 // 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>
 
   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>
     {
       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>
   // 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 Symb
   *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: sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.4
diff -u -p -r1.4 sparc.cc
--- sparc.cc	17 Apr 2008 07:07:37 -0000	1.4
+++ sparc.cc	19 Apr 2008 18:29:31 -0000
@@ -1737,13 +1737,21 @@ Target_sparc<size, big_endian>::Scan::lo
                 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: symtab.cc
===================================================================
RCS file: /cvs/src/src/gold/symtab.cc,v
retrieving revision 1.93
diff -u -p -r1.93 symtab.cc
--- symtab.cc	17 Apr 2008 22:45:47 -0000	1.93
+++ symtab.cc	19 Apr 2008 18:29:31 -0000
@@ -72,6 +72,7 @@ Symbol::init_fields(const char* name, co
   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>
 {
   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
 
 // 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
 // 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* ob
 			      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* ob
 
   // 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* ob
       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* ob
 	  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* ob
 		}
 	    }
 
-	  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::v
       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(Symb
     {
     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(Symb
 	  }
 	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(Symb
 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 
 	{
 	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 
 		    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 
 		    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 
 
 	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_dynob
     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_dynob
 
 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
     {
 #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
 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
   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: symtab.h
===================================================================
RCS file: /cvs/src/src/gold/symtab.h,v
retrieving revision 1.74
diff -u -p -r1.74 symtab.h
--- symtab.h	17 Apr 2008 07:12:00 -0000	1.74
+++ symtab.h	19 Apr 2008 18:29:31 -0000
@@ -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: target-reloc.h
===================================================================
RCS file: /cvs/src/src/gold/target-reloc.h,v
retrieving revision 1.22
diff -u -p -r1.22 target-reloc.h
--- target-reloc.h	20 Mar 2008 05:22:37 -0000	1.22
+++ target-reloc.h	19 Apr 2008 18:29:31 -0000
@@ -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: x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.64
diff -u -p -r1.64 x86_64.cc
--- x86_64.cc	17 Apr 2008 02:00:54 -0000	1.64
+++ x86_64.cc	19 Apr 2008 18:29:31 -0000
@@ -998,20 +998,26 @@ Target_x86_64::Scan::local(const General
           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
                 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
                 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);
Index: testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.64
diff -u -p -r1.64 Makefile.am
--- testsuite/Makefile.am	17 Apr 2008 07:12:00 -0000	1.64
+++ testsuite/Makefile.am	19 Apr 2008 18:29:32 -0000
@@ -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: testsuite/binary_unittest.cc
===================================================================
RCS file: /cvs/src/src/gold/testsuite/binary_unittest.cc,v
retrieving revision 1.4
diff -u -p -r1.4 binary_unittest.cc
--- testsuite/binary_unittest.cc	28 Feb 2008 00:18:24 -0000	1.4
+++ testsuite/binary_unittest.cc	19 Apr 2008 18:29:32 -0000
@@ -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);
Index: testsuite/many_sections_test.cc
===================================================================
RCS file: testsuite/many_sections_test.cc
diff -N testsuite/many_sections_test.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/many_sections_test.cc	19 Apr 2008 18:29:32 -0000
@@ -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: elfcpp_file.h
===================================================================
RCS file: /cvs/src/src/elfcpp/elfcpp_file.h,v
retrieving revision 1.8
diff -u -p -r1.8 elfcpp_file.h
--- elfcpp_file.h	7 Feb 2008 01:51:25 -0000	1.8
+++ elfcpp_file.h	19 Apr 2008 18:31:19 -0000
@@ -115,6 +115,15 @@ class Elf_file
     return this->shstrndx_;
   }
 
+  // Return the value to subtract from section indexes >=
+  // SHN_LORESERVE.  See the comment in initialize_shnum.
+  int
+  large_shndx_offset()
+  {
+    this->initialize_shnum();
+    return this->large_shndx_offset_;
+  }
+
   // Return the location of the header of section SHNDX.
   typename File::Location
   section_header(unsigned int shndx)
@@ -180,6 +189,8 @@ class Elf_file
   unsigned int shnum_;
   // The section index of the section name string table.
   unsigned int shstrndx_;
+  // Offset to add to sections larger than SHN_LORESERVE.
+  int large_shndx_offset_;
 };
 
 // Template function definitions.
@@ -194,6 +205,7 @@ Elf_file<size, big_endian, File>::constr
   this->shoff_ = ehdr.get_e_shoff();
   this->shnum_ = ehdr.get_e_shnum();
   this->shstrndx_ = ehdr.get_e_shstrndx();
+  this->large_shndx_offset_ = 0;
   if (ehdr.get_e_ehsize() != This::ehdr_size)
     file->error(_("bad e_ehsize (%d != %d)"),
 		ehdr.get_e_ehsize(), This::ehdr_size);
@@ -223,10 +235,37 @@ Elf_file<size, big_endian, File>::initia
     {
       typename File::View v(this->file_->view(this->shoff_, This::shdr_size));
       Ef_shdr shdr(v.data());
+
       if (this->shnum_ == 0)
 	this->shnum_ = shdr.get_sh_size();
+
       if (this->shstrndx_ == SHN_XINDEX)
-	this->shstrndx_ = shdr.get_sh_link();
+	{
+	  this->shstrndx_ = shdr.get_sh_link();
+
+	  // Versions of the GNU binutils between 2.12 and 2.18 did
+	  // not handle objects with more than SHN_LORESERVE sections
+	  // correctly.  All large section indexes were offset by
+	  // 0x100.  Some information can be found here:
+	  // http://sourceware.org/bugzilla/show_bug.cgi?id=5900 .
+	  // Fortunately these object files are easy to detect, as the
+	  // GNU binutils always put the section header string table
+	  // near the end of the list of sections.  Thus if the
+	  // section header string table index is larger than the
+	  // number of sections, then we know we have to subtract
+	  // 0x100 to get the real section index.
+	  if (this->shstrndx_ >= this->shnum_)
+	    {
+	      if (this->shstrndx_ >= elfcpp::SHN_LORESERVE + 0x100)
+		{
+		  this->large_shndx_offset_ = - 0x100;
+		  this->shstrndx_ -= 0x100;
+		}
+	      if (this->shstrndx_ >= this->shnum_)
+		this->file_->error(_("bad shstrndx: %u >= %u"),
+				   this->shstrndx_, this->shnum_);
+	    }
+	}
     }
 }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]