]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Merge elfcpp and gold from trunk.
authorIan Lance Taylor <ian@airs.com>
Fri, 16 Oct 2009 05:51:18 +0000 (05:51 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 16 Oct 2009 05:51:18 +0000 (05:51 +0000)
60 files changed:
elfcpp/ChangeLog
elfcpp/elfcpp.h
elfcpp/elfcpp_file.h
gold/ChangeLog
gold/README
gold/archive.cc
gold/arm.cc
gold/config.in
gold/configure
gold/configure.ac
gold/copy-relocs.cc
gold/debug.h
gold/descriptors.cc
gold/dwarf_reader.cc
gold/dwarf_reader.h
gold/dynobj.cc
gold/dynobj.h
gold/fileread.cc
gold/fileread.h
gold/gc.h
gold/gold.cc
gold/i386.cc
gold/icf.cc
gold/incremental.cc
gold/incremental.h
gold/layout.cc
gold/layout.h
gold/main.cc
gold/merge.h
gold/object.cc
gold/object.h
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h
gold/parameters.cc
gold/parameters.h
gold/plugin.cc
gold/plugin.h
gold/powerpc.cc
gold/pread.c
gold/readsyms.cc
gold/reloc.cc
gold/resolve.cc
gold/script-sections.cc
gold/script-sections.h
gold/script.cc
gold/sparc.cc
gold/symtab.cc
gold/symtab.h
gold/target-reloc.h
gold/target.cc
gold/target.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/binary_unittest.cc
gold/testsuite/initpri1.c
gold/testsuite/object_unittest.cc
gold/testsuite/testfile.cc
gold/x86_64.cc

index 2a668a674442e39ad9c4450ac622a1f3955ef0ec..ec8143614c720ef22c96357721775f98c0411f46 100644 (file)
@@ -1,3 +1,18 @@
+2009-10-09  Andrew Pinski  <andrew_pinski@playstation.sony.com>
+
+       * elfcpp/elfcpp_file.h (Elf_file::section_name): Change shstr_size
+       to Elf_WXword.
+
+2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
+
+       * elf_file.h: (class Elf_strtab): New class.
+
+2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
+
+       * elfcpp_file.h: Fix header guard.  Include <cstdio>.
+       (class Elf_recognizer): New class, code from gold/object.cc.
+       (Elf_file::find_section_by_type): New method.
+
 2009-07-23  Ulrich Drepper  <drepper@redhat.com>
 
        * elfcpp.h (enum STB): Add STB_GNU_UNIQUE.
index 683cd9dceb03cd5ba6bbfe6262aac19e41355a1e..11b072683e763cded4b78fda20955ebf555094ae 100644 (file)
@@ -17,7 +17,7 @@
 // combinations without any restriction coming from the use of this
 // file.  (The Library Public License restrictions do apply in other
 // respects; for example, they cover modification of the file, and
-/// distribution when not linked into a combined executable.)
+// distribution when not linked into a combined executable.)
 
 // This program is distributed in the hope that it will be useful, but
 // WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -657,7 +657,7 @@ enum DT
   DT_RUNPATH = 29,
   DT_FLAGS = 30,
   DT_ENCODING = 32,
-  DT_PREINIT_ARRAY = 33,
+  DT_PREINIT_ARRAY = 32,
   DT_PREINIT_ARRAYSZ = 33,
   DT_LOOS = 0x6000000d,
   DT_HIOS = 0x6ffff000,
index f1f4423a14e88f790b025f732105a3f4d7cfa171..cc61622692acec3ad93f636dacfe80f5232c44af 100644 (file)
 // This permits writing
 //    elfcpp::Shdr shdr(file, ef.section_header(n));
 
-#ifndef ELFPCP_FILE_H
+#ifndef ELFCPP_FILE_H
 #define ELFCPP_FILE_H
 
 #include <string>
+#include <cstdio>
 #include <cstring>
 
 namespace elfcpp
 {
 
+// A simple helper class to recognize if a file has an ELF header.
+
+class Elf_recognizer
+{
+ public:
+  // Maximum header size.  The user should try to read this much of
+  // the file when using this class.
+
+  static const int max_header_size = Elf_sizes<64>::ehdr_size;
+
+  // Checks if the file contains the ELF magic.  Other header fields
+  // are not checked.
+
+  static bool
+  is_elf_file(const unsigned char* ehdr_buf, int size);
+
+  // Check if EHDR_BUF/BUFSIZE is a valid header of a 32-bit or
+  // 64-bit, little-endian or big-endian ELF file.  Assumes
+  // is_elf_file() has been checked to be true.  If the header is not
+  // valid, *ERROR contains a human-readable error message.  If is is,
+  // *SIZE is set to either 32 or 64, *BIG_ENDIAN is set to indicate
+  // whether the file is big-endian.
+
+  static bool
+  is_valid_header(const unsigned char* ehdr_buf, off_t bufsize,
+                  int* size, bool* big_endian,
+                  std::string* error);
+};
+
 // This object is used to read an ELF file.
 //   SIZE: The size of file, 32 or 64.
 //   BIG_ENDIAN: Whether the file is in big-endian format.
@@ -99,6 +129,11 @@ class Elf_file
   shoff() const
   { return this->shoff_; }
 
+  // Find the first section with an sh_type field equal to TYPE and
+  // return its index.  Returns SHN_UNDEF if there is no such section.
+  unsigned int
+  find_section_by_type(unsigned int type);
+
   // Return the number of sections.
   unsigned int
   shnum()
@@ -193,6 +228,142 @@ class Elf_file
   int large_shndx_offset_;
 };
 
+// A small wrapper around SHT_STRTAB data mapped to memory. It checks that the
+// index is not out of bounds and the string is NULL-terminated.
+
+class Elf_strtab
+{
+ public:
+  // Construct an Elf_strtab for a section with contents *P and size SIZE.
+  Elf_strtab(const unsigned char* p, size_t size);
+
+  // Return the file offset to the section headers.
+  bool
+  get_c_string(size_t offset, const char** cstring) const
+  {
+    if (offset >= this->usable_size_)
+      return false;
+    *cstring = this->base_ + offset;
+    return true;
+  }
+
+ private:
+  // Contents of the section mapped to memory.
+  const char* base_;
+  // One larger that the position of the last NULL character in the section.
+  // For valid SHT_STRTAB sections, this is the size of the section.
+  size_t usable_size_;
+};
+
+// Inline function definitions.
+
+// Check for presence of the ELF magic number.
+
+inline bool
+Elf_recognizer::is_elf_file(const unsigned char* ehdr_buf, int size)
+{
+  if (size < 4)
+    return false;
+
+  static unsigned char elfmagic[4] =
+    {
+      elfcpp::ELFMAG0, elfcpp::ELFMAG1,
+      elfcpp::ELFMAG2, elfcpp::ELFMAG3
+    };
+  return memcmp(ehdr_buf, elfmagic, 4) == 0;
+}
+
+namespace
+{
+
+// Print a number to a string.
+
+inline std::string
+internal_printf_int(const char* format, int arg)
+{
+  char buf[256];
+  snprintf(buf, sizeof(buf), format, arg);
+  return std::string(buf);
+}
+
+}  // End anonymous namespace.
+
+// Check the validity of the ELF header.
+
+inline bool
+Elf_recognizer::is_valid_header(
+    const unsigned char* ehdr_buf,
+    off_t bufsize,
+    int* size,
+    bool* big_endian,
+    std::string* error)
+{
+  if (bufsize < elfcpp::EI_NIDENT)
+    {
+      *error = _("ELF file too short");
+      return false;
+    }
+
+  int v = ehdr_buf[elfcpp::EI_VERSION];
+  if (v != elfcpp::EV_CURRENT)
+    {
+      if (v == elfcpp::EV_NONE)
+        *error = _("invalid ELF version 0");
+      else
+        *error = internal_printf_int(_("unsupported ELF version %d"), v);
+      return false;
+    }
+
+  int c = ehdr_buf[elfcpp::EI_CLASS];
+  if (c == elfcpp::ELFCLASSNONE)
+    {
+      *error = _("invalid ELF class 0");
+      return false;
+    }
+  else if (c != elfcpp::ELFCLASS32
+           && c != elfcpp::ELFCLASS64)
+    {
+      *error = internal_printf_int(_("unsupported ELF class %d"), c);
+      return false;
+    }
+
+  int d = ehdr_buf[elfcpp::EI_DATA];
+  if (d == elfcpp::ELFDATANONE)
+    {
+      *error = _("invalid ELF data encoding");
+      return false;
+    }
+  else if (d != elfcpp::ELFDATA2LSB
+           && d != elfcpp::ELFDATA2MSB)
+    {
+      *error = internal_printf_int(_("unsupported ELF data encoding %d"), d);
+      return false;
+    }
+
+  *big_endian = (d == elfcpp::ELFDATA2MSB);
+
+  if (c == elfcpp::ELFCLASS32)
+    {
+      if (bufsize < elfcpp::Elf_sizes<32>::ehdr_size)
+        {
+          *error = _("ELF file too short");
+          return false;
+        }
+      *size = 32;
+    }
+  else
+    {
+      if (bufsize < elfcpp::Elf_sizes<64>::ehdr_size)
+        {
+          *error = _("ELF file too short");
+          return false;
+        }
+      *size = 64;
+    }
+
+  return true;
+}
+
 // Template function definitions.
 
 // Construct an Elf_file given an ELF file header.
@@ -269,6 +440,25 @@ Elf_file<size, big_endian, File>::initialize_shnum()
     }
 }
 
+// Find section with sh_type equal to TYPE and return its index.
+// Returns SHN_UNDEF if not found.
+
+template<int size, bool big_endian, typename File>
+unsigned int
+Elf_file<size, big_endian, File>::find_section_by_type(unsigned int type)
+{
+  unsigned int shnum = this->shnum();
+  typename File::View v(this->file_->view(this->shoff_,
+                                         This::shdr_size * shnum));
+  for (unsigned int i = 0; i < shnum; i++)
+    {
+      Ef_shdr shdr(v.data() + This::shdr_size * i);
+      if (shdr.get_sh_type() == type)
+        return i;
+    }
+  return SHN_UNDEF;
+}
+
 // Return the file offset of the section header of section SHNDX.
 
 template<int size, bool big_endian, typename File>
@@ -300,7 +490,7 @@ Elf_file<size, big_endian, File>::section_name(unsigned int shndx)
 
   // Get the file offset for the section name string table data.
   off_t shstr_off;
-  off_t shstr_size;
+  typename Elf_types<size>::Elf_WXword shstr_size;
   {
     const unsigned int shstrndx = this->shstrndx_;
     typename File::View v(file->view(this->section_header_offset(shstrndx),
@@ -479,6 +669,18 @@ Elf_file<size, big_endian, File>::section_addralign(unsigned int shndx)
   return shdr.get_sh_addralign();
 }
 
+inline
+Elf_strtab::Elf_strtab(const unsigned char* p, size_t size)
+{
+  // Check if the section is NUL-terminated. If it isn't, we ignore
+  // the last part to make sure we don't return non-NUL-terminated
+  // strings.
+  while (size > 0 && p[size - 1] != 0)
+    size--;
+  this->base_ = reinterpret_cast<const char*>(p);
+  this->usable_size_ = size;
+}
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFCPP_FILE_H)
index 5f625b95365b4bdc8374929fada03b5129ccbaeb..cb3254933cd4dd2c776861af0c192dc9a3f2699f 100644 (file)
+2009-10-15  Ian Lance Taylor  <iant@google.com>
+
+       * script.cc (Script_options::add_symbol_assignment): Always add a
+       dot assginment to script_sections_.
+       * script-sections.cc (Script_sections::add_dot_assignment):
+       Initialize if necessary.
+
+       * layout.cc (Layout::relaxation_loop_body): Don't crash if we see
+       program headers with no load segment if there is a linker script.
+
+       * layout.cc (Layout::set_segment_offsets): Align the file offset
+       to the segment aligment for -N or -n with no load segment.
+       * output.cc (Output_segment::add_output_section): Don't crash if
+       the first section is a TLS section.
+       (Output_segment::set_section_list_addresses): Print an error
+       message if the address moves backward in a linker script.
+       * script-sections.cc
+       (Output_section_element_input::set_section_addresses): Don't
+       increase *dot_value for a SHF_TLS/SHT_NOBITS section.
+       (Orphan_output_section::set_section_addresses): Likewise.
+
+2009-10-15  Doug Kwan  <dougkwan@google.com>
+
+       * layout.cc (Layout::finish_dynamic_section): Generate tags
+       DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_INIT_ARRAY, DT_INIT_ARRAYSZ,
+       DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ as needed. If -Bsymbolic is
+       used, add DT_SYMBOLIC and set DF_SYMBOLIC in DT_FLAGS.
+
+2009-10-14  Ian Lance Taylor  <iant@google.com>
+
+       * object.h (class Relocate_info): Add reloc_shdr and data_shdr
+       fields.
+       * object.cc (Sized_relobj::relocate_sections): Set reloc_shdr and
+       data_shdr fields of relinfo.
+       * i386.cc (class Target_i386::Relocate): Remove ldo_addrs_ field.
+       (Target_i386::Relocate::relocate_tls): Don't call fix_up_ldo.  For
+       R_386_TLS_LDO_32, adjust based on section flags.
+       (Target_i386::Relocate::fix_up_ldo): Remove.
+
+2009-10-13  Ian Lance Taylor  <iant@google.com>
+
+       Add support for -pie.
+       * options.h (class General_options): Add -pie and
+       --pic-executable.
+       (General_options::output_is_position_independent): Test -pie.
+       (General_options::output_is_executable): Return true if not shared
+       and not relocatable.
+       (General_options::output_is_pie): Remove.
+       * options.cc (General_options::finalize): Reject incompatible uses
+       of -pie.
+       * gold.cc (queue_middle_tasks): A -pie link is not static.
+       * symtab.h (Symbol::needs_plt_entry): Return false if -pie.
+       * symtab.cc (Symbol::final_value_is_known): Return false if
+       output_is_position_independent.
+       * layout.cc (Layout::set_segment_offsets): Start at address 0 if
+       output_is_position_independent.
+       * output.cc (Output_file_header::do_sized_write): Use ET_DYN if
+       output_is_position_independent.
+       * i386.cc (Output_data_plt_i386::do_write): Use the PIC PLT if
+       output_is_position_independent.
+       * testsuite/Makefile.am (check_PROGRAMS): Add basic_pie_test and
+       two_file_pie_test.
+       (basic_pie_test.o, basic_pie_test): New targets.
+       (two_file_test_1_pie.o, two_file_test_1b_pie.o): New targets.
+       (two_file_test_2_pie.o, two_file_test_main_pie.o): New targets.
+       (two_file_pie_test): New target.
+       * testsuite/Makefile.in: Rebuild.
+       * README: Remove note saying that -pie is not supported.
+
+2009-10-13  Bernhard Reutner-Fischer  <aldot@gcc.gnu.org>
+
+       * options.h (class General_options): Add -init and -fini.
+       * layout.cc (Layout::finish_dynamic_section): Emit
+       given init and fini functions.
+
+2009-10-13  Sriraman Tallam  <tmsriram@google.com>
+
+       * gc.h (gc_process_relocs): Check if icf is enabled using new
+       function.
+       * gold.cc (queue_initial_tasks): Likewise.
+       (queue_middle_tasks): Likewise.
+       * object.cc (do_layout): Likewise.
+       * symtab.cc (is_section_folded): Likewise.
+       * main.cc (main): Likewise.
+       * reloc.cc (Read_relocs::run): Likewise.
+       (Sized_relobj::do_scan_relocs): Likewise.
+       * icf.cc (is_function_ctor_or_dtor): New function.
+       (Icf::find_identical_sections): Check if function is ctor or dtor when
+       safe icf is chosen.
+       * options.h (General_options::icf): Change option to be an enum.
+       (Icf_status): New enum.
+       (icf_enabled): New method.
+       (icf_safe_folding): New method.
+       (set_icf_status): New method.
+       (icf_status_): New variable.
+       * (options.cc) (General_options::finalize): Set icf_status_.
+       * testsuite/Makefile.am: Add commands to build icf_safe_test. Modify
+       icf_test and icf_keep_unique_test to use the --icf enum flag.
+       * testsuite/icf_safe_test.sh: New file.
+       * testsuite/icf_safe_test.cc: New file. 
+
+2009-10-12  Sriraman Tallam  <tmsriram@google.com>
+
+       * symtab.h: Check for GOLD_SYMTAB_H before header includes. Remove
+       includes to gc.h and icf.h.
+       * arm.cc: Include gc.h.
+       * gold.cc: Likewise.
+       * i386.cc: Likewise.
+       * powerpc.cc: Likewise.
+       * sparc.cc: Likewise.
+       * x86_64.cc: Likewise.
+       * gc.h: Include icf.h.
+
+2009-10-11  Ian Lance Taylor  <iant@google.com>
+
+       * plugin.cc: Include "gold.h" before other header files.
+
+2009-10-10  Chris Demetriou  <cgd@google.com>
+
+       * options.h (Input_file_argument::Input_file_type): New enum.
+       (Input_file_argument::is_lib_): Replace with...
+       (Input_file_argument::type_): New member.
+       (Input_file_argument::Input_file_argument): Take Input_file_type
+       'type' rather than boolean 'is_lib' as second argument.
+       (Input_file_argument::is_lib): Use type_.
+       (Input_file_argument::is_searched_file): New function.
+       (Input_file_argument::may_need_search): Handle is_searched_file.
+       * options.cc (General_options::parse_library): Support -l:filename.
+       (General_options::parse_just_symbols): Update for Input_file_argument
+       changes.
+       (Command_line::process): Likewise.
+       * archive.cc (Archive::get_file_and_offset): Likewise.
+       * plugin.cc (Plugin_manager::release_input_file): Likewise.
+       * script.cc (read_script_file, script_add_file): Likewise.
+       * fileread.cc (Input_file::Input_file): Likewise.
+       (Input_file::will_search_for): Handle is_searched_file.
+       (Input_file::open): Likewise.
+       * readsyms.cc (Read_symbols::get_name): Likewise.
+       * testsuite/Makefile.am (searched_file_test): New test.
+       * testsuite/Makefile.in: Regenerate.
+       * testsuite/searched_file_test.cc: New file.
+       * testsuite/searched_file_test_lib.cc: New file.
+
+2009-10-09  Andrew Pinski  <andrew_pinski@playstation.sony.com>
+           Ian Lance Taylor  <iant@google.com>
+
+       * descriptor.cc: Include <cstdio> and "binary-io.h".
+       (Descriptors::open): Open the files in binary mode always.
+       * script.cc (Lex::get_token): Treat \r as whitespace.
+
+2009-10-09  Ian Lance Taylor  <iant@google.com>
+
+       * testsuite/retain_symbols_file_test.sh: Don't test for __tcf_0.
+
+2009-10-09  Andrew Pinski  <andrew_pinski@playstation.sony.com>
+           Ian Lance Taylor  <iant@google.com>
+
+       * configure.ac: Check for readv function also.
+       * fileread.cc (readv): Define if not HAVE_READV.
+       * fileread.h (File_read:: max_readv_entries): Set to 1 if readv
+       does not exist.
+       * config.in: Regenerate.
+       * configure: Regenerate.
+
+2009-10-09  Doug Kwan  <dougkwan@google.com>
+
+       * layout.cc (Layout::make_output_section): Call target hook to make
+       ordinary output section.
+       (Layout::finalize): Adjust parameter list of call the
+       Target::may_relax().
+       * layout.h (class Layout::section_list): New method.
+       * merge.h (Output_merge_base::entsize): Change visibility to public.
+       (Output_merge_base::is_string, Output_merge_base::do_is_string):
+       New methods.
+       (Output_merge_string::do_is_string): New method.
+       * object.cc (Sized_relobj::do_setup): renamed from
+       Sized_relobj::set_up.
+       * object.h (Sized_relobj::adjust_shndx,
+       Sized_relobj::initializ_input_to_output_maps,
+       Sized_relobj::free_input_to_output_maps): Change visibilities to
+       protected.
+       (Sized_relobj::setup): Virtualize.
+       (Sized_relobj::do_setup): New method declaration.
+       (Sized_relobj::invalidate_section_offset,
+       Sized_relobj::do_invalidate_section_offset): New method decfinitions.
+       (Sized_relobj::elf_file, Sized_relobj::local_values): New methods.
+       * options.cc (parse_int): New function.
+       * options.h (parse_int): New declaration.
+       (DEFINE_int): New macro.
+       (stub_group_size): New option.
+       * output.cc (Output_section::Output_section): Initialize memebers
+       merge_section_map_, merge_section_by_properties_map_,
+       relaxed_input_section_map_, is_relaxed_input_section_map_valid_.
+       (Output_section::add_input_section): Handled deferred code-fill
+       generation and remove an old comment.
+       (Output_section::add_relaxed_input_section): New method definition.
+       (Output_section::add_merge_input_section): Use merge section by
+       properties map to speed to search.  Update merge section maps
+       as appropriate.
+       (Output_section::build_relaxation_map): New method definition.
+       (Output_section::convert_input_sections_in_list_to_relaxed_sections):
+       Same.
+       (Output_section::relax_input_section): Renamed to
+       Output_section::convert_input_sections_to_relaxed_sections and change
+       interface to take a vector of pointers to relaxed sections.
+       (Output_section::find_merge_section,
+       Output_section::find_relaxed_input_section): New method definitions.
+       (Output_section::is_input_address_mapped,
+       Output_section::output_offset, Output_section::output_address):
+       Use output section data maps to speed up searching.
+       (Output_section::find_starting_output_address): Add comments.
+       (Output_section::do_write,
+       Output_section::write_to_postprocessing_buffer): Do code-fill
+       generation as appropriate.
+       (Output_section::get_input_sections): Invalidate relaxed input section
+       map.
+       (Output_section::restore_states): Adjust type of checkpoint .
+       Invalidate relaxed input section map.
+       * output.h (Output_merge_base): New class declaration.
+       (Input_section_specifier): New class defintion.
+       (class Output_relaxed_input_section) Change base class to
+       Output_section_data_build.
+       (Output_relaxed_input_section::Output_relaxed_input_section): Adjust
+       base class initializer.
+       (Output_section::add_relaxed_input_section): New method declaration.
+       (Output_section::Input_section): Change visibility to protected.
+       (Output_section::Input_section::relobj,
+       Output_section::Input_section::shndx): Handle relaxed input sections.
+       Output_section::input_sections) Change visibility to protected.  Also
+       define overload to return a non-const pointer.
+       (Output_section::Merge_section_properties): New class defintion.
+       (Output_section::Merge_section_by_properties_map,
+       Output_section::Output_section_data_by_input_section_map,
+       Output_section::Relaxation_map): New types.
+       (Output_section::relax_input_section): Rename method to
+       Output_section::convert_input_sections_to_relaxed_sections and change
+       interface to take a vector of relaxed section pointers.
+       (Output_section::find_merge_section,
+       Output_section::find_relaxed_input_section,
+       Output_section::build_relaxation_map,
+       Output_section::convert_input_sections_in_list_to_relaxed_sections):
+       New method declarations.
+       (Output_section::merge_section_map_
+       Output_section::merge_section_by_properties_map_,
+       Output_section::relaxed_input_section_map_,
+       Output_section::is_relaxed_input_section_map_valid_,
+       Output_section::generate_code_fills_at_write_): New data members.
+       * script-sections.cc
+       (Output_section_element_input::set_section_addresses): Call
+       current_data_size and addralign methods of relaxed input sections.
+       (Orphan_output_section::set_section_addresses): Call current_data_size
+       and addralign methods of relaxed input sections.
+       * symtab.cc (Symbol_table::compute_final_value): Extract template
+       from the body of Symbol_table::sized_finalize_symbol.
+       (Symbol_table::sized_finalized_symbol): Call
+       Symbol_table::compute_final_value.
+       * symtab.h (Symbol_table::Compute_final_value_status): New enum type.
+       (Symbol_table::compute_final_value): New templated method declaration.
+       * target.cc (Target::do_make_output_section): New method defintion.
+       * target.h (Target::make_output_section): New method declaration.
+       (Target::relax): Add more parameters for input objects, symbol table
+       and layout.  Adjust call to do_relax.
+       (Target::do_make_output_section): New method declaration.
+       (Target::do_relax): Add parameters for input objects, symbol table
+       and layout.
+
+2009-10-09  Andrew Pinski  <andrew_pinski@playstation.sony.com>
+
+       * pread.c: Include stdio.h.
+
+2009-10-09  Andrew Pinski  <andrew_pinski@playstation.sony.com>
+
+       * plugin.cc: Don't include dlfcn.h when ENABLE_PLUGINS is not
+       defined.
+
+2009-10-09  Andrew Pinski  <andrew_pinski@playstation.sony.com>
+
+       * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info):
+       Change read_shndx type to unsigned int.
+       (Sized_dwarf_line_info::read_lines): Change shndx type to unsigned
+       int.
+       (Sized_dwarf_line_info::read_line_mappings): Likewise.
+       * dwarf_reader.h (Sized_dwarf_line_info::Sized_dwarf_line_info):
+       Change read_shndx type to unsigned int.
+       (Sized_dwarf_line_info::read_lines): Change shndx type to unsigned
+       int.
+       (Sized_dwarf_line_info::read_line_mappings): Likewise.
+       * layout.cc (Layout::create_symtab_sections): Cast the result of
+       local_symcount * symsize to off_t in the gold_assert.
+
+2009-10-09  Viktor Kutuzov  <vkutuzov@accesssoftek.com>
+
+       * arm.cc (Target_arm::relocate::reloc_is_non_pic): Return true for
+       R_ARM_THM_ABS5, R_ARM_ABS8, R_ARM_ABS12, R_ARM_ABS16,
+       R_ARM_BASE_ABS.
+       (Arm_relocate_functions::abs8): Remove has_thumb_bit parameter.
+       (Arm_relocate_functions::thm_abs5): New function.
+       (Arm_relocate_functions::abs12): New function.
+       (Arm_relocate_functions::abs16): New function.
+       (Arm_relocate_functions::base_abs): New function.
+       (Scan::check_non_pic): Handle R_ARM_ABS32_NOI.
+       (Scan::local): Remove special handling of R_ARM_ABS8.  Handle
+       R_ARM_ABS32_NOI, R_ARM_THM_ABS5, R_ARM_ABS12, R_ARM_ABS16, and
+       R_ARM_BASE_ABS.
+       (Scan::global): Likewise.
+       (Relocate::relocate): Handle R_ARM_ABS12, R_ARM_ABS16,
+       R_ARM_ABS32_NOI, R_ARM_THM_ABS5, and R_ARM_BASE_ABS.
+       (Relocatable_size_for_reloc::get_size_for_reloc): Handle
+       R_ARM_ABS16, R_ARM_THM_ABS5, R_ARM_ABS32_NOI, R_ARM_ABS12, and
+       R_ARM_BASE_ABS.
+
+2009-10-09  Viktor Kutuzov  <vkutuzov@accesssoftek.com>
+
+       * arm.cc (Arm_relocate_functions::movw_prel_nc): New function.
+       (Arm_relocate_functions::movt_prel): New function.
+       (Arm_relocate_functions::thm_movw_prel_nc): New function.
+       (Arm_relocate_functions::thm_movt_prel): New function.
+       (Scan::local): Handle R_ARM_MOVW_PREL_NC, R_ARM_MOVT_PREL,
+       R_ARM_THM_MOVW_PREL_NC, and R_ARM_THM_MOVT_PREL.
+       (Scan::global, Relocate::relocate): Likewise.
+       (Relocatable_size_for_reloc::get_size_for_reloc): Likewise.
+
+2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
+
+       * gold.cc: (queue_initial_tasks): Pass incremental_inputs to
+       Incremental_checker.
+       * incremental.cc: (INCREMENTAL_LINK_VERSION): Change type to
+       unsigned int.
+       (class Incremental_inputs_header): New class.
+       (Incremental_inputs_header_writer): Edit comment.
+       (Incremental_inputs_entry): New class.
+       (Incremental_inputs_entry_writer): Edit comment.
+       (Sized_incremental_binary::do_find_incremental_inputs_section):
+       Add *strtab_shndx parameter, fill it.
+       (Sized_incremental_binary::do_check_inputs): New method.
+       (Incremental_checker::can_incrementally_link_output_file): Use
+       Sized_incremental_binary::check_inputs.
+       (Incremental_inputs::report_command_line): Save command line in
+       command_line_.
+       * incremental.h:
+       (Incremental_binary::find_incremental_inputs_section): New
+       method.
+       (Incremental_binary::do_find_incremental_inputs_section): Add
+       strtab_shndx parameter.
+       (Incremental_binary::do_check_inputs): New pure virtual method.
+       (Sized_incremental_binary::do_check_inputs): Declare.
+       (Incremental_checker::Incremental_checker): Add incremental_inputs
+       parameter, use it to initialize incremental_inputs_.
+       (Incremental_checker::incremental_inputs_): New field.
+       (Incremental_checker::command_line): New method.
+       (Incremental_checker::inputs): New method.
+       (Incremental_checker::command_line_): New field.
+
+2009-10-09  Mikolaj Zalewski  <mikolajz@google.com>
+
+       * incremental.cc: Include <cstdarg> and "target-select.h".
+       (vexplain_no_incremental): New function.
+       (explain_no_incremental): New function.
+       (Incremental_binary::error): New method.
+       (Sized_incremental_binary::do_find_incremental_inputs_section): New
+       method.
+       (make_sized_incremental_binary): New function.
+       (open_incremental_binary): New function.
+       (can_incrementally_link_file): Add checks if output is ELF and has
+       inputs section.
+       * incremental.h: Include "elfcpp_file.h" and "output.h".
+       (Incremental_binary): New class.
+       (Sized_incremental_binary): New class.
+       (open_incremental_binary): Declare.
+       * object.cc (is_elf_object): Use
+       elfcpp::Elf_recognizer::is_elf_file.
+       (make_elf_object): Use elfcpp::Elf_recognizer::is_valid_header.
+       * output.h (Output_file::filesize): New method.
+
+2009-10-07  Viktor Kutuzov  <vkutuzov@accesssoftek.com>
+
+       * arm.cc (Arm_relocate_functions::extract_arm_movw_movt_addend):
+       New function.
+       (Arm_relocate_functions::insert_val_arm_movw_movt): New function.
+       (Arm_relocate_functions::extract_thumb_movw_movt_addend): New
+       function.
+       (Arm_relocate_functions::insert_val_thumb_movw_movt): New
+       function.
+       (Arm_relocate_functions::movw_abs_nc): New function.
+       (Arm_relocate_functions::movt_abs): New function.
+       (Arm_relocate_functions::thm_movw_abs_nc): New function.
+       (Arm_relocate_functions::thm_movt_abs): New function.
+       (Scan::local): Handle R_ARM_MOVW_ABS_NC, R_ARM_MOVT_ABS,
+       R_ARM_THM_MOVW_ABS_NC, R_ARM_THM_MOVT_ABS.
+       (Scan::global): Likewise.
+       (Relocate::relocate): Likewise.
+       (Relocatable_size_for_reloc::get_size_for_reloc): Likewise.
+
+2009-10-07  Viktor Kutuzov  <vkutuzov@accesssoftek.com>
+
+       * arm.cc (Arm_relocate_functions::got_prel) New function.
+       (Scan::local, Scan::global): Handle R_ARM_GOT_PREL.
+       (Relocate::relocate): Likewise.
+       (Relocatable_size_for_reloc::get_size_for_reloc): Likewise.
+
+2009-10-06  Ian Lance Taylor  <iant@google.com>
+
+       * options.h (class General_options): Define
+       split_stack_adjust_size parameter.
+       * object.h (class Object): Add uses_split_stack_ and
+       has_no_split_stack_ fields.  Add uses_split_stack and
+       has_no_split_stack accessor functions.  Declare
+       handle_split_stack_section.
+       (class Reloc_symbol_changes): Define.
+       (class Sized_relobj): Define Function_offsets.  Declare
+       split_stack_adjust, split_stack_adjust_reltype, and
+       find_functions.
+       * object.cc (Object::handle_split_stack_section): New function.
+       (Sized_relobj::do_layout): Call handle_split_stack_section.
+       * dynobj.cc (Sized_dynobj::do_layout): Call
+       handle_split_stack_section.
+       * reloc.cc (Sized_relobj::relocate_sections): Call
+       split_stack_adjust for executable sections in split_stack
+       objects.  Pass reloc_map to relocate_section.
+       (Sized_relobj::split_stack_adjust): New function.
+       (Sized_relobj::split_stack_adjust_reltype): New function.
+       (Sized_relobj::find_functions): New function.
+       * target-reloc.h: Include "object.h".
+       (relocate_section): Add reloc_symbol_changes parameter.  Change
+       all callers.
+       * target.h (class Target): Add calls_non_split method.  Declare
+       do_calls_non_split virtual method.  Declare match_view and
+       set_view_to_nop.
+       * target.cc: Include "elfcpp.h".
+       (Target::do_calls_non_split): New function.
+       (Target::match_view): New function.
+       (Target::set_view_to_nop): New function.
+       * gold.cc (queue_middle_tasks): Give an error if mixing
+       split-stack and non-split-stack objects with -r.
+       * i386.cc (Target_i386::relocate_section): Add
+       reloc_symbol_changes parameter.
+       (Target_i386::do_calls_non_split): New function.
+       * x86_64.cc (Target_x86_64::relocate_section): Add
+       reloc_symbol_changes parameter.
+       (Target_x86_64::do_calls_non_split): New function.
+       * arm.cc (Target_arm::relocate_section): Add reloc_symbol_changes
+       parameter.
+       * powerpc.cc (Target_powerpc::relocate_section): Add
+       reloc_symbol_changes parameter.
+       * sparc.cc (Target_sparc::relocate_section): Add
+       reloc_symbol_changes parameter.
+       * configure.ac: Call AM_CONDITIONAL for the default target.
+       * configure: Rebuild.
+       * testsuite/Makefile.am (TEST_AS): New variable.
+       (check_SCRIPTS): Add split_i386.sh and split_x86_64.sh.
+       (check_DATA): Add split_i386 and split_x86_64 files.
+       (SPLIT_DEFSYMS): Define.
+       (split_i386_[1234n].o): New targets.
+       (split_i386_[124]): New targets.
+       (split_i386_[1234r].stdout): New targets.
+       (split_x86_64_[1234n].o): New targets.
+       (split_x86_64_[124]): New targets.
+       (split_x86_64_[1234r].stdout): New targets.
+       (MOSTLYCLEANFILES): Add new executables.
+       * testsuite/split_i386.sh: New file.
+       * testsuite/split_x86_64.sh: New file.
+       * testsuite/split_i386_1.s: New file.
+       * testsuite/split_i386_2.s: New file.
+       * testsuite/split_i386_3.s: New file.
+       * testsuite/split_i386_4.s: New file.
+       * testsuite/split_i386_n.s: New file.
+       * testsuite/split_x86_64_1.s: New file.
+       * testsuite/split_x86_64_2.s: New file.
+       * testsuite/split_x86_64_3.s: New file.
+       * testsuite/split_x86_64_4.s: New file.
+       * testsuite/split_x86_64_n.s: New file.
+       * testsuite/testfile.cc (Target_test): Update relocation_section
+       function.
+       * testsuite/Makefile.in: Rebuild.
+
+2009-10-06  Ian Lance Taylor  <iant@google.com>
+
+       * i386.cc (class Target_i386::Relocate): Add ldo_addrs_ field.
+       (Target_i386::Relocate::relocate_tls): Call fix_up_ldo before
+       changing local_dynamic_type_ from LOCAL_DYNAMIC_NONE.  When
+       handling R_386_TLS_LDO_32, if local_dynamic_type_ is NONE, push
+       the address on ldo_addrs_.
+       (Target_i386::Relocate::fix_up_ldo): New function.
+
+2009-10-06   Rafael Espindola  <espindola@google.com>
+
+       * plugin.cc (add_input_library): New.
+       (Plugin::load): Add add_input_library to tv.
+       (Plugin_manager::add_input_file): Add the is_lib argument.
+       (add_input_file): Update call to Plugin_manager::add_input_file.
+       (add_input_library): New.
+       * plugin.h (Plugin_manager::add_input_file): Add the is_lib argument.
+
+2009-09-30  Doug Kwan  <dougkwan@google.com>
+
+       * arm.cc (Target_arm::may_need_copy_reloc): Check for THUMB function
+       symbol and call Symbol::may_need_copy_reloc to determine if
+       a copy reloc is needed.
+       * copy-relocs.cc (Copy_relocs::need_copy_reloc): Return false if -z
+       nocopyreloc is given in command line.
+       (Copy_relocs::emit_copy_reloc): Assert that -z nocopyreloc is not
+       given in command line.
+       * i386.cc (Target_i386::may_need_copy_reloc): Remove.
+       (Target_i386::Scan::global): Use Symbol::may_need_copy_reloc instead
+       of the removed Target_i386::may_need_copy_reloc.
+       * options.h (copyreloc): New option with default value false.
+       * powerpc.cc (Target_powerpc::may_need_copy_reloc): Remove.
+       (Target_powerpc::Scan::global): Use Symbol::may_need_copy_reloc
+       instead of the removed Target_powerpc::may_need_copy_reloc.
+       * sparc.cc (Target_powerpc::may_need_copy_reloc): Remove.
+       (Target_sparc::Scan::global): Use Symbol::may_need_copy_reloc
+       instead of the removed Target_sparc::may_need_copy_reloc.
+       * symtab.h (Symbol::may_need_copy_reloc): New method definition.
+       * x86_64.cc (Target_powerpc::may_need_copy_reloc): Remove.
+       (Target_x86_64::Scan::global): Use Symbol::may_need_copy_reloc
+       instead of the removed Target_x86_64::may_need_copy_reloc.
+
+2009-09-30  Ian Lance Taylor  <iant@google.com>
+
+       * object.h (class Object): Remove target_ field, and target,
+       sized_target, and set_target methods.
+       (Object::sized_target): Remove.
+       (class Sized_relobj): Update declarations.  Remove sized_target.
+       * object.cc (Sized_relobj::setup): Remove target parameter.
+       Change all callers.
+       (Input_objects::add_object): Don't do anything with the target.
+       (make_elf_sized_object): Add punconfigured parameter.  Change all
+       callers.  Set or test parameter target.
+       * dynobj.cc (Sized_dynobj::target): Remove target parameter.
+       Change all callers.
+       * parameters.cc (Parameters::set_target): Change parameter type to
+       be non-const.
+       (Parameters::default_target): Remove.
+       (set_parameters_target): Change parameter type to be non-const.
+       (parameters_force_valid_target): New function.
+       (parameters_clear_target): New function.
+       * parameters.h (class Parameters): Update declarations.  Remove
+       default_target method.  Add sized_target and clear_target
+       methods.  Change target_ to be non-const.
+       (set_parameters_target): Update declaration.
+       (parameters_force_valid_target): Declare.
+       (parameters_clear_target): Declare.
+       * readsyms.cc (Read_symbols::do_read_symbols): Pass punconfigured
+       as NULL if we aren't searching.
+       (Add_symbols::run): Don't check for compatible target.
+       * fileread.cc (Input_file::open_binary): Call
+       parameters_force_valid_target.
+       * gold.cc (queue_middle_tasks): Likewise.
+       * plugin.cc (make_sized_plugin_object): Likewise.  Don't call
+       set_target on object.
+       * dynobj.h (class Sized_dynobj): Update declarations.
+       * archive.cc (Archive::get_elf_object_for_member): Return NULL if
+       make_elf_object returns NULL.
+       (Archive::include_member): Don't check whether object target is
+       compatible.
+       * output.cc (Output_section::add_input_section): Get target from
+       parameters.
+       (Output_section::relax_input_section): Likewise.
+       * reloc.cc (Sized_relobj::do_gc_process_relocs): Get target from
+       parameters.
+       (Sized_relobj::do_scan_relocs): Likewise.
+       (Sized_relobj::relocate_sections): Likewise.
+       * resolve.cc (Symbol_table::resolve): Likewise.
+       * symtab.cc (Symbol_table::wrap_symbol): Likewise.  Remove object
+       parameter.  Change all callers.
+       (Symbol_table::add_from_object): Get target from parameters.
+       (Symbol_table::add_from_relobj): Don't check object target.
+       (Symbol_table::add_from_dynobj): Likewise.
+       (Symbol_table::define_special_symbol): Get target from
+       parameters.
+       * symtab.h (class Symbol_table): Update declaration.
+       * testsuite/binary_unittest.cc (gold_testsuite): Remove target
+       parameter.  Change all callers.  Clear parameter target.
+       (Binary_test): Test target here.
+       * testsuite/object_unittest.cc (gold_testsuite): Remove
+       target_test_pointer parameter.  Change all callers.
+       (Object_test): Test target here.
+
+2009-09-26  Ian Lance Taylor  <iant@google.com>
+
+       * testsuite/initpri1.c: Don't try to use constructor priorities if
+       compiling with gcc before 4.3.
+
+2009-09-22  Mikolaj Zalewski  <mikolajz@google.com>
+
+       * testsuite/retain_symbols_file_test.sh (check_present): Change
+       output file name to retain_symbols_file_test.stdout.
+       (check_absent): Likewise.
+
+2009-09-18  Craig Silverstein  <csilvers@google.com>
+
+       * object.cc (Sized_relobj::do_count): Test should_retain_symbol map.
+       * options.cc: Include <cerrno> and <fstream>.
+       (General_options::finalize): Parse -retain-symbols-file tag.
+       * options.h: New flag.
+       (General_options): New method should_retain_symbol, new
+       variable symbols_to_retain.
+       * symtab.cc (Symbol_table::sized_finalize_symbol): Test
+       should_retain_symbol map.
+       * testsuite/Makefile.am (retain_symbols_file_test): New test.
+       * testsuite/Makefile.in: Regenerate.
+       * testsuite/retain_symbols_file_test.sh: New file.
+
 2009-09-18  Nick Clifton  <nickc@redhat.com>
 
        * po/es.po: Updated Spanish translation.
 
+2009-09-17  Doug Kwan  <dougkwan@google.com>
+
+       * debug.h (DEBUG_RELAXATION): New constant.
+       (DEBUG_ALL): Add DEBUG_RELAXATION.
+       (debug_string_to_enum): Add relaxation debug option.
+       * layout.cc
+       (Layout::Relaxation_debug_check::check_output_data_for_reset_values,
+       Layout::Relaxation_debug_check::read_sections,
+       Layout::Relaxation_debug_check::read_sections): New method definitions.
+       (Layout::Layout): Initialize data members
+       record_output_section_data_from_scrips_,
+       script_output_section_data_list_ and relaxation_debug_check_.
+       (Layout::save_segments, Layout::restore_segments,
+       Layout::clean_up_after_relaxation, Layout::prepare_for_relaxation,
+       Layout::relaxation_loop_body): New method definitions.
+       (Layout::finalize): Support relaxation.  Move section layout code to
+       Layout::relaxation_loop_body.
+       (Layout::set_asection_address_from_script): Move code for orphan
+       section placement out.
+       (Layout::place_orphan_sections_in_script): New method definition.
+       * layout.h (Output_segment_headers, Output_file_header):
+       New forward class declarations.
+       (Layout::~Layout): Define.
+       (Layout::new_output_section_data_from_script): New method definition.
+       (Layout::place_orphan_sections_in_script): New method declaration.
+       (Layout::Segment_states): New type declaration.
+       (Layout::save_segments, Layout::restore_segments,
+       Layout::clean_up_after_relaxation, Layout::prepare_for_relaxation,
+       Layout::relaxation_loop_body): New method declarations.
+       (Layout::Output_section_data_list): New type declaration.
+       (Layout::Relaxation_debug_check): New class definition.
+       (Layout::record_output_section_data_from_script_,
+       Layout::script_output_section_data_list_, Layout::segment_states_,
+       Layout::relaxation_debug_check_): New data members.
+       * output.cc: (Output_section_headers::do_size): New method definition.
+       (Output_section_headers::Output_section_headers): Move size
+       computation to Output_section_headers::do_size.
+       (Output_segment_headers::do_size): New method definition.
+       (Output_file_header::Output_file_header): Move size computation to 
+       Output_file_header::do_size and call it.
+       (Output_file_header::do_size): New method definition.
+       (Output_data_group::Output_data_group): Adjust call to
+       Output_section_data.
+       (Output_data_dynamic::set_final_data_size): Add DT_NULL tag only once.
+       (Output_symtab_xindex::do_write): Add array bound check.
+       (Output_section::Input_section::print_to_mapfile): Handle
+       RELAXED_INPUT_SECTION_CODE.
+       (Output_section::Output_section): Initialize data member checkpoint_.
+       (Output_section::~Output_section): Delete checkpoint object pointed
+       by checkpoint_.
+       (Output_section::add_input_section): Always add an Input_section if
+       relaxing.
+       (Output_section::add_merge_input_section): Add assert.
+       (Output_section::relax_input_section): New method definition.
+       (Output_section::set_final_data_size): Set load address to zero for
+       an unallocated section.
+       (Output_section::do_address_and_file_offset_have_reset_values):
+       New method definition.
+       (Output_section::Input_section_sort_enty::Input_section_sort_enty):
+       Handle relaxed input section.
+       (Output_section::sort_attached_input_sections): Checkpoint input
+       section list lazily.
+       (Output_section::get_input_sections): Change type of input_sections to
+       list of Simple_input_section pointers.  Checkpoint input section list
+       lazily.  Also handle relaxed input sections.
+       (Output_section::add_input_section_for_script): Take a reference to
+       a Simple_input_section object instead of Relobj pointer and section
+       index as parameter.  Handle relaxed input sections.
+       (Output_section::save_states, Output_section::restore_states): New
+       method definitions.
+       * output.h (Output_data::Output_data): Initialize is_data_size_fixed_.
+       (Output_data::is_data_size_fixed): New method definition.
+       (Output_data::reset_addresss_and_file_offset): Do not reset data size
+       if it is fixed.
+       (Output_data::address_and_file_offset_have_reset_values): New method
+       definition.
+       (Output_data::do_address_and_file_offset_have_reset_values): New method
+       definition.
+       (Output_data::set_data_size): Check that data size is not fixed.
+       (Output_data::fix_data_size): New method definition.
+       (Output_data::is_data_size_fixed_): New data member.
+       (Output_section_headers::set_final_data_size): New method definition.
+       (Output_section_headers::do_size): New method declaration.
+       (Output_segment_headers::set_final_data_size): New method definition.
+       (Output_segment_headers::do_size): New method declaration.
+       (Output_file_header::set_final_data_size)::New method definition.
+       (Output_file_header::do_size)::New method declaration.
+       (Output_section_data::Output_section_data): Add new parameter
+       is_data_size_fixed and use it to fix data size.
+       (Output_data_const::Output_data_const): Adjust call to base class
+       constructor and fix data size.
+       (Output_data_const_buffer::Output_data_const_buffer): Adjust call to
+       base class constructor and fix data size.
+       (Output_data_fixed_space::Output_data_fixed_space): Adjust call to
+       base class constructor and fix data size.
+       (Output_data_zero_fill::Output_data_zero_fill): Adjust call to base
+       class constructor and fix data size.
+       (Output_data_group::set_final_data_size): New method definition.
+       (Output_data_dynamic::Dynamic_entry::tag): New method definition.
+       (Output_symtab_xindex::Output_symtab_xindex): Adjust call to base
+       class constructor and fix data size.
+       (Output_relaxed_input_section): New class definition.
+       (Output_section::Simple_input_section): New class definition.
+       (Output_section::get_input_sections): Adjust parameter list.
+       (Output_section::add_input_section_for_script): Same.
+       (Output_section::save_states, Output_section::restore_states,
+       Output_section::do_address_and_file_offset_have_reset_values,
+       (Output_section::Input_section::Input_section): Handle
+       RELAXED_INPUT_SECTION_CODE.  Add new overload for
+       Output_relaxed_input_section.
+       (Output_section::Input_section::is_input_section,
+       Output_section::Input_section::set_output_section): Handle relaxed
+       input section.
+       (Output_section::Input_section::is_relaxed_input_section,
+       Output_section::Input_section::output_section_data,
+       Output_section::Input_section::relaxed_input_section): New method
+       definitions.
+       (Output_section::Input_section::RELAXED_INPUT_SECTION_CODE): New enum
+       value.
+       (Output_section::Input_section::u1_): Update comments.
+       (Output_section::Input_section::u2_): Add new union member poris.
+       (Output_section::Checkpoint_output_section): New classs definition.
+       (Output_section::relax_input_section): New method declaration.
+       (Output_section::checkpoint_): New data member.
+       (Output_segment): Update comments.
+       (Output_segment::Output_segment): Un-privatize copy constructor.
+       (Output_segment::operator=): Un-privatize.
+       * script-sections.cc (Output_section_element::Input_section_list):
+       Change element type to Output_section::Simple_input_section.
+       (Output_section_element_dot_assignment::set_section_addresses):
+       Register output section data for relaxation clean up.
+       (Output_data_exression::Output_data_expression): Adjust call to base
+       constructor to fix data size.
+       (Output_section_element_data::set_section_addresses): Register
+       Output_data_expression object for relaxation clean up.
+       (struct Input_section_info): Replace Relobj pointer and section index
+       pair with Output_section::Simple_input_section and Convert struct to a
+       class.
+       (Input_section_sorter::operator()): Adjust access to
+       Input_section_info data member to use accessors. 
+       (Output_section_element_input::set_section_addresses): Use layout
+       parameter.  Adjust code to use Output_section::Simple_input_section
+       and Input_secction_info classes.  Register filler for relaxation
+       clean up.
+       (Orphan_output_section::set_section_addresses): Replace Relobj pointer
+       and section index pair with Output_section::Simple_input_section
+       class.  Adjust code accordingly.
+       (Phdrs_element::release_segment): New method definition.
+       (Script_sections::attach_sections_using_phdrs_clause): Do not modify
+       segment list.
+       (Script_sections::release_segments): New method definition.
+       * gold/script-sections.h (Script_sections::release_segments): New
+       method declaration.
+       * gold/target.h (Target::may_relax, Target::relax,
+       Target::do_may_relax, Target::do_relax): New method definitions.
+
+2009-09-17  Viktor Kutuzov  <vkutuzov@accesssoftek.com>
+
+       * arm.cc (has_signed_unsigned_overflow): New function.
+       (Arm_relocate_functions::abs8): New function.
+       (Target_arm::Scan::local): Handle R_ARM_ABS8.
+       (Target_arm::Scan::global): Likewise.
+       (Target_arm::relocate::relocate): Likewise.
+       (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc):
+       Likewise.
+
+2009-09-16  Cary Coutant  <ccoutant@google.com>
+
+       * testsuite/Makefile.am (MOSTLYCLEANFILES): Add more generated files.
+       * testsuite/Makefile.in: Regenerate.
+
 2009-09-11  Nick Clifton  <nickc@redhat.com>
 
        * po/gold.pot: Updated by the Translation project.
 
+2009-09-08  Cary Coutant  <ccoutant@google.com>
+
+       * output.cc (Output_file::open): Add execute permission to empty file.
+       * testsuite/Makefile.am (permission_test): New test.
+       * testsuite/Makefile.in: Regenerate.
+
 2009-09-02  Ian Lance Taylor  <iant@google.com>
 
        * output.cc (Output_file::resize): Call map_no_anonymous rather
index 8891d624d65bbedb26e6c084c3c996504d66b650..80da4558aa7a68d0813e4c2a882fa51a1a2ae5d9 100644 (file)
@@ -18,7 +18,6 @@ gold--are:
   * MEMORY regions in linker scripts
   * MRI compatible linker scripts
   * cross-reference reports (--cref)
-  * position independent executables (-pie)
   * various other minor options
 
 
index 8e809e25d1cce99fcfeba6422fdb48bd622062a4..569a491ae1a1b6628b189abd74c9ef2aec683dc3 100644 (file)
@@ -489,8 +489,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff,
       else
         {
           Input_file_argument* input_file_arg =
-            new Input_file_argument(member_name->c_str(), false, "", false,
-                                    parameters->options());
+            new Input_file_argument(member_name->c_str(),
+                                    Input_file_argument::INPUT_FILE_TYPE_FILE,
+                                    "", false, parameters->options());
           *input_file = new Input_file(input_file_arg);
          int dummy = 0;
           if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
@@ -509,8 +510,9 @@ Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff,
   // This is an external member of a thin archive.  Open the
   // file as a regular relocatable object file.
   Input_file_argument* input_file_arg =
-      new Input_file_argument(member_name->c_str(), false, "", false,
-                              this->input_file_->options());
+      new Input_file_argument(member_name->c_str(),
+                              Input_file_argument::INPUT_FILE_TYPE_FILE,
+                              "", false, this->input_file_->options());
   *input_file = new Input_file(input_file_arg);
   int dummy = 0;
   if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy))
@@ -564,6 +566,8 @@ Archive::get_elf_object_for_member(off_t off, bool* punconfigured)
                                 + "(" + member_name + ")"),
                                input_file, memoff, ehdr, read_size,
                                punconfigured);
+  if (obj == NULL)
+    return NULL;
   obj->set_no_export(this->no_export());
   return obj;
 }
@@ -807,11 +811,6 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
     {
       Object *obj = p->second.obj_;
 
-      if (!this->included_member_
-         && this->searched_for()
-         && !parameters->is_compatible_target(obj->target()))
-       return false;
-
       Read_symbols_data *sd = p->second.sd_;
       if (mapfile != NULL)
         mapfile->report_include_archive_member(obj->name(), sym, why);
@@ -830,9 +829,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
 
   if (!this->included_member_
       && this->searched_for()
-      && (obj == NULL
-         ? unconfigured
-         : !parameters->is_compatible_target(obj->target())))
+      && obj == NULL
+      && unconfigured)
     {
       if (obj != NULL)
        delete obj;
index 0e4a3ebecdf6213ec76598b3ab920aea14c6a45c..dd5f67dca23cb624a353916e689938e434446d5e 100644 (file)
@@ -42,6 +42,7 @@
 #include "target-select.h"
 #include "tls.h"
 #include "defstd.h"
+#include "gc.h"
 
 namespace
 {
@@ -59,6 +60,12 @@ class Output_data_plt_arm;
 //
 // R_ARM_NONE
 // R_ARM_ABS32
+// R_ARM_ABS32_NOI
+// R_ARM_ABS16
+// R_ARM_ABS12
+// R_ARM_ABS8
+// R_ARM_THM_ABS5
+// R_ARM_BASE_ABS
 // R_ARM_REL32
 // R_ARM_THM_CALL
 // R_ARM_COPY
@@ -68,11 +75,21 @@ class Output_data_plt_arm;
 // R_ARM_RELATIVE
 // R_ARM_GOTOFF32
 // R_ARM_GOT_BREL
+// R_ARM_GOT_PREL
 // R_ARM_PLT32
 // R_ARM_CALL
 // R_ARM_JUMP24
 // R_ARM_TARGET1
 // R_ARM_PREL31
+// R_ARM_ABS8
+// R_ARM_MOVW_ABS_NC
+// R_ARM_MOVT_ABS
+// R_ARM_THM_MOVW_ABS_NC
+// R_ARM_THM_MOVT_ABS
+// R_ARM_MOVW_PREL_NC
+// R_ARM_MOVT_PREL
+// R_ARM_THM_MOVW_PREL_NC
+// R_ARM_THM_MOVT_PREL
 // 
 // TODOs:
 // - Generate various branch stubs.
@@ -117,6 +134,23 @@ namespace utils
     return as_signed > max || as_signed < min;
   }
 
+  // Detects overflow of an NO_BITS integer stored in a uint32_t when it
+  // fits in the given number of bits as either a signed or unsigned value.
+  // For example, has_signed_unsigned_overflow<8> would check
+  // -128 <= bits <= 255
+  template<int no_bits>
+  static inline bool
+  has_signed_unsigned_overflow(uint32_t bits)
+  {
+    gold_assert(no_bits >= 2 && no_bits <= 32);
+    if (no_bits == 32)
+      return false;
+    int32_t max = static_cast<int32_t>((1U << no_bits) - 1);
+    int32_t min = -(1 << (no_bits - 1));
+    int32_t as_signed = static_cast<int32_t>(bits);
+    return as_signed > max || as_signed < min;
+  }
+
   // Select bits from A and B using bits in MASK.  For each n in [0..31],
   // the n-th bit in the result is chosen from the n-th bits of A and B.
   // A zero selects A and a one selects B.
@@ -188,7 +222,8 @@ class Target_arm : public Sized_target<32, big_endian>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   elfcpp::Elf_types<32>::Elf_Addr view_address,
-                  section_size_type view_size);
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -338,6 +373,11 @@ class Target_arm : public Sized_target<32, big_endian>
        case elfcpp::R_ARM_CALL:
        case elfcpp::R_ARM_JUMP24:
        case elfcpp::R_ARM_PREL31:
+       case elfcpp::R_ARM_THM_ABS5:
+       case elfcpp::R_ARM_ABS8:
+       case elfcpp::R_ARM_ABS12:
+       case elfcpp::R_ARM_ABS16:
+       case elfcpp::R_ARM_BASE_ABS:
          return true;
        default:
          return false;
@@ -388,10 +428,8 @@ class Target_arm : public Sized_target<32, big_endian>
   bool
   may_need_copy_reloc(Symbol* gsym)
   {
-    return (!parameters->options().shared()
-           && gsym->is_from_dynobj()
-           && gsym->type() != elfcpp::STT_FUNC
-           && gsym->type() != elfcpp::STT_ARM_TFUNC);
+    return (gsym->type() != elfcpp::STT_ARM_TFUNC
+           && gsym->may_need_copy_reloc());
   }
 
   // Add a potential copy relocation.
@@ -491,6 +529,79 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
       return psymval->value(object, addend);
   }
 
+  // Encoding of imm16 argument for movt and movw ARM instructions
+  // from ARM ARM:
+  //     
+  //     imm16 := imm4 | imm12
+  //
+  //  f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0 
+  // +-------+---------------+-------+-------+-----------------------+
+  // |       |               |imm4   |       |imm12                  |
+  // +-------+---------------+-------+-------+-----------------------+
+
+  // Extract the relocation addend from VAL based on the ARM
+  // instruction encoding described above.
+  static inline typename elfcpp::Swap<32, big_endian>::Valtype
+  extract_arm_movw_movt_addend(
+      typename elfcpp::Swap<32, big_endian>::Valtype val)
+  {
+    // According to the Elf ABI for ARM Architecture the immediate
+    // field is sign-extended to form the addend.
+    return utils::sign_extend<16>(((val >> 4) & 0xf000) | (val & 0xfff));
+  }
+
+  // Insert X into VAL based on the ARM instruction encoding described
+  // above.
+  static inline typename elfcpp::Swap<32, big_endian>::Valtype
+  insert_val_arm_movw_movt(
+      typename elfcpp::Swap<32, big_endian>::Valtype val,
+      typename elfcpp::Swap<32, big_endian>::Valtype x)
+  {
+    val &= 0xfff0f000;
+    val |= x & 0x0fff;
+    val |= (x & 0xf000) << 4;
+    return val;
+  }
+
+  // Encoding of imm16 argument for movt and movw Thumb2 instructions
+  // from ARM ARM:
+  //     
+  //     imm16 := imm4 | i | imm3 | imm8
+  //
+  //  f e d c b a 9 8 7 6 5 4 3 2 1 0  f e d c b a 9 8 7 6 5 4 3 2 1 0 
+  // +---------+-+-----------+-------++-+-----+-------+---------------+
+  // |         |i|           |imm4   || |imm3 |       |imm8           |
+  // +---------+-+-----------+-------++-+-----+-------+---------------+
+
+  // Extract the relocation addend from VAL based on the Thumb2
+  // instruction encoding described above.
+  static inline typename elfcpp::Swap<32, big_endian>::Valtype
+  extract_thumb_movw_movt_addend(
+      typename elfcpp::Swap<32, big_endian>::Valtype val)
+  {
+    // According to the Elf ABI for ARM Architecture the immediate
+    // field is sign-extended to form the addend.
+    return utils::sign_extend<16>(((val >> 4) & 0xf000)
+                                 | ((val >> 15) & 0x0800)
+                                 | ((val >> 4) & 0x0700)
+                                 | (val & 0x00ff));
+  }
+
+  // Insert X into VAL based on the Thumb2 instruction encoding
+  // described above.
+  static inline typename elfcpp::Swap<32, big_endian>::Valtype
+  insert_val_thumb_movw_movt(
+      typename elfcpp::Swap<32, big_endian>::Valtype val,
+      typename elfcpp::Swap<32, big_endian>::Valtype x)
+  {
+    val &= 0xfbf08f00;
+    val |= (x & 0xf000) << 4;
+    val |= (x & 0x0800) << 15;
+    val |= (x & 0x0700) << 4;
+    val |= (x & 0x00ff);
+    return val;
+  }
+
   // FIXME: This probably only works for Android on ARM v5te. We should
   // following GNU ld for the general case.
   template<unsigned r_type>
@@ -555,6 +666,83 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
   }
 
  public:
+
+  // R_ARM_ABS8: S + A
+  static inline typename This::Status
+  abs8(unsigned char *view,
+       const Sized_relobj<32, big_endian>* object,
+       const Symbol_value<32>* psymval)
+  {
+    typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<8, big_endian>::readval(wv);
+    Reltype addend = utils::sign_extend<8>(val);
+    Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+    val = utils::bit_select(val, x, 0xffU);
+    elfcpp::Swap<8, big_endian>::writeval(wv, val);
+    return (utils::has_signed_unsigned_overflow<8>(x)
+           ? This::STATUS_OVERFLOW
+           : This::STATUS_OKAY);
+  }
+
+  // R_ARM_THM_ABS5: S + A
+  static inline typename This::Status
+  thm_abs5(unsigned char *view,
+       const Sized_relobj<32, big_endian>* object,
+       const Symbol_value<32>* psymval)
+  {
+    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
+    Reltype addend = (val & 0x7e0U) >> 6;
+    Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+    val = utils::bit_select(val, x << 6, 0x7e0U);
+    elfcpp::Swap<16, big_endian>::writeval(wv, val);
+    return (utils::has_overflow<5>(x)
+           ? This::STATUS_OVERFLOW
+           : This::STATUS_OKAY);
+  }
+
+  // R_ARM_ABS12: S + A
+  static inline typename This::Status
+  abs12(unsigned char *view,
+       const Sized_relobj<32, big_endian>* object,
+       const Symbol_value<32>* psymval)
+  {
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+    Reltype addend = val & 0x0fffU;
+    Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+    val = utils::bit_select(val, x, 0x0fffU);
+    elfcpp::Swap<32, big_endian>::writeval(wv, val);
+    return (utils::has_overflow<12>(x)
+           ? This::STATUS_OVERFLOW
+           : This::STATUS_OKAY);
+  }
+
+  // R_ARM_ABS16: S + A
+  static inline typename This::Status
+  abs16(unsigned char *view,
+       const Sized_relobj<32, big_endian>* object,
+       const Symbol_value<32>* psymval)
+  {
+    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
+    Reltype addend = utils::sign_extend<16>(val);
+    Reltype x = This::arm_symbol_value(object, psymval, addend, false);
+    val = utils::bit_select(val, x, 0xffffU);
+    elfcpp::Swap<16, big_endian>::writeval(wv, val);
+    return (utils::has_signed_unsigned_overflow<16>(x)
+           ? This::STATUS_OVERFLOW
+           : This::STATUS_OKAY);
+  }
+
   // R_ARM_ABS32: (S + A) | T
   static inline typename This::Status
   abs32(unsigned char *view,
@@ -634,6 +822,15 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
     return STATUS_OKAY;
   }
 
+  // R_ARM_BASE_ABS: B(S) + A
+  static inline typename This::Status
+  base_abs(unsigned char* view,
+           elfcpp::Elf_types<32>::Elf_Addr origin)
+  {
+    Base::rel32(view, origin);
+    return STATUS_OKAY;
+  }
+
   // R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
   static inline typename This::Status
   got_brel(unsigned char* view,
@@ -643,6 +840,16 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
     return This::STATUS_OKAY;
   }
 
+  // R_ARM_GOT_PREL: GOT(S) + A â€“ P
+  static inline typename This::Status
+  got_prel(unsigned char* view,
+          typename elfcpp::Swap<32, big_endian>::Valtype got_offset,
+          elfcpp::Elf_types<32>::Elf_Addr address)
+  {
+    Base::rel32(view, got_offset - address);
+    return This::STATUS_OKAY;
+  }
+
   // R_ARM_PLT32: (S + A) | T - P
   static inline typename This::Status
   plt32(unsigned char *view,
@@ -698,6 +905,158 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
     return (utils::has_overflow<31>(x) ?
            This::STATUS_OVERFLOW : This::STATUS_OKAY);
   }
+
+  // R_ARM_MOVW_ABS_NC: (S + A) | T
+  static inline typename This::Status 
+  movw_abs_nc(unsigned char *view,
+             const Sized_relobj<32, big_endian>* object,
+             const Symbol_value<32>* psymval,
+             bool has_thumb_bit)
+  {
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+    Valtype addend =  This::extract_arm_movw_movt_addend(val);
+    Valtype x = This::arm_symbol_value(object, psymval, addend, has_thumb_bit);
+    val = This::insert_val_arm_movw_movt(val, x);
+    elfcpp::Swap<32, big_endian>::writeval(wv, val);
+    return This::STATUS_OKAY;
+  }
+
+  // R_ARM_MOVT_ABS: S + A
+  static inline typename This::Status
+  movt_abs(unsigned char *view,
+          const Sized_relobj<32, big_endian>* object,
+           const Symbol_value<32>* psymval)
+  {
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+    Valtype addend = This::extract_arm_movw_movt_addend(val);
+    Valtype x = This::arm_symbol_value(object, psymval, addend, 0) >> 16;
+    val = This::insert_val_arm_movw_movt(val, x);
+    elfcpp::Swap<32, big_endian>::writeval(wv, val);
+    return This::STATUS_OKAY;
+  }
+
+  //  R_ARM_THM_MOVW_ABS_NC: S + A | T
+  static inline typename This::Status 
+  thm_movw_abs_nc(unsigned char *view,
+                 const Sized_relobj<32, big_endian>* object,
+                 const Symbol_value<32>* psymval,
+                 bool has_thumb_bit)
+  {
+    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Reltype val = ((elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+                  | elfcpp::Swap<16, big_endian>::readval(wv + 1));
+    Reltype addend = extract_thumb_movw_movt_addend(val);
+    Reltype x = This::arm_symbol_value(object, psymval, addend, has_thumb_bit);
+    val = This::insert_val_thumb_movw_movt(val, x);
+    elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+    elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+    return This::STATUS_OKAY;
+  }
+
+  //  R_ARM_THM_MOVT_ABS: S + A
+  static inline typename This::Status 
+  thm_movt_abs(unsigned char *view,
+              const Sized_relobj<32, big_endian>* object,
+              const Symbol_value<32>* psymval)
+  {
+    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Reltype val = ((elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+                  | elfcpp::Swap<16, big_endian>::readval(wv + 1));
+    Reltype addend = This::extract_thumb_movw_movt_addend(val);
+    Reltype x = This::arm_symbol_value(object, psymval, addend, 0) >> 16;
+    val = This::insert_val_thumb_movw_movt(val, x);
+    elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+    elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+    return This::STATUS_OKAY;
+  }
+
+  // R_ARM_MOVW_PREL_NC: (S + A) | T - P
+  static inline typename This::Status
+  movw_prel_nc(unsigned char *view,
+              const Sized_relobj<32, big_endian>* object,
+              const Symbol_value<32>* psymval,
+              elfcpp::Elf_types<32>::Elf_Addr address,
+              bool has_thumb_bit)
+  {
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+    Valtype addend = This::extract_arm_movw_movt_addend(val);
+    Valtype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
+                 - address);
+    val = This::insert_val_arm_movw_movt(val, x);
+    elfcpp::Swap<32, big_endian>::writeval(wv, val);
+    return This::STATUS_OKAY;
+  }
+
+  // R_ARM_MOVT_PREL: S + A - P
+  static inline typename This::Status
+  movt_prel(unsigned char *view,
+           const Sized_relobj<32, big_endian>* object,
+           const Symbol_value<32>* psymval,
+            elfcpp::Elf_types<32>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
+    Valtype addend = This::extract_arm_movw_movt_addend(val);
+    Valtype x = (This::arm_symbol_value(object, psymval, addend, 0)
+                 - address) >> 16;
+    val = This::insert_val_arm_movw_movt(val, x);
+    elfcpp::Swap<32, big_endian>::writeval(wv, val);
+    return This::STATUS_OKAY;
+  }
+
+  // R_ARM_THM_MOVW_PREL_NC: (S + A) | T - P
+  static inline typename This::Status
+  thm_movw_prel_nc(unsigned char *view,
+                  const Sized_relobj<32, big_endian>* object,
+                  const Symbol_value<32>* psymval,
+                  elfcpp::Elf_types<32>::Elf_Addr address,
+                  bool has_thumb_bit)
+  {
+    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Reltype val = (elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+                 | elfcpp::Swap<16, big_endian>::readval(wv + 1);
+    Reltype addend = This::extract_thumb_movw_movt_addend(val);
+    Reltype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
+                 - address);
+    val = This::insert_val_thumb_movw_movt(val, x);
+    elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+    elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+    return This::STATUS_OKAY;
+  }
+
+  // R_ARM_THM_MOVT_PREL: S + A - P
+  static inline typename This::Status
+  thm_movt_prel(unsigned char *view,
+               const Sized_relobj<32, big_endian>* object,
+               const Symbol_value<32>* psymval,
+               elfcpp::Elf_types<32>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Reltype val = (elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+                 | elfcpp::Swap<16, big_endian>::readval(wv + 1);
+    Reltype addend = This::extract_thumb_movw_movt_addend(val);
+    Reltype x = (This::arm_symbol_value(object, psymval, addend, 0)
+                 - address) >> 16;
+    val = This::insert_val_thumb_movw_movt(val, x);
+    elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+    elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+    return This::STATUS_OKAY;
+  }
 };
 
 // Get the GOT section, creating it if necessary.
@@ -1027,6 +1386,7 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object,
     case elfcpp::R_ARM_GLOB_DAT:
     case elfcpp::R_ARM_JUMP_SLOT:
     case elfcpp::R_ARM_ABS32:
+    case elfcpp::R_ARM_ABS32_NOI:
     case elfcpp::R_ARM_PC24:
     // FIXME: The following 3 types are not supported by Android's dynamic
     // linker.
@@ -1075,6 +1435,7 @@ Target_arm<big_endian>::Scan::local(const General_options&,
       break;
 
     case elfcpp::R_ARM_ABS32:
+    case elfcpp::R_ARM_ABS32_NOI:
       // If building a shared library (or a position-independent
       // executable), we need to create a dynamic relocation for
       // this location. The relocation applied at link time will
@@ -1099,6 +1460,19 @@ Target_arm<big_endian>::Scan::local(const General_options&,
     case elfcpp::R_ARM_PREL31:
     case elfcpp::R_ARM_JUMP24:
     case elfcpp::R_ARM_PLT32:
+    case elfcpp::R_ARM_THM_ABS5:
+    case elfcpp::R_ARM_ABS8:
+    case elfcpp::R_ARM_ABS12:
+    case elfcpp::R_ARM_ABS16:
+    case elfcpp::R_ARM_BASE_ABS:
+    case elfcpp::R_ARM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_MOVT_ABS:
+    case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_THM_MOVT_ABS:
+    case elfcpp::R_ARM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_MOVT_PREL:
+    case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_THM_MOVT_PREL:
       break;
 
     case elfcpp::R_ARM_GOTOFF32:
@@ -1111,6 +1485,7 @@ Target_arm<big_endian>::Scan::local(const General_options&,
       break;
 
     case elfcpp::R_ARM_GOT_BREL:
+    case elfcpp::R_ARM_GOT_PREL:
       {
        // The symbol requires a GOT entry.
        Output_data_got<32, big_endian>* got =
@@ -1188,6 +1563,7 @@ Target_arm<big_endian>::Scan::global(const General_options&,
       break;
 
     case elfcpp::R_ARM_ABS32:
+    case elfcpp::R_ARM_ABS32_NOI:
       {
        // Make a dynamic relocation if necessary.
        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
@@ -1218,6 +1594,33 @@ Target_arm<big_endian>::Scan::global(const General_options&,
       }
       break;
 
+    case elfcpp::R_ARM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_MOVT_ABS:
+    case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_THM_MOVT_ABS:
+    case elfcpp::R_ARM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_MOVT_PREL:
+    case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_THM_MOVT_PREL:
+      break;
+
+    case elfcpp::R_ARM_THM_ABS5:
+    case elfcpp::R_ARM_ABS8:
+    case elfcpp::R_ARM_ABS12:
+    case elfcpp::R_ARM_ABS16:
+    case elfcpp::R_ARM_BASE_ABS:
+      {
+       // No dynamic relocs of this kinds.
+       // Report the error in case of PIC.
+       int flags = Symbol::NON_PIC_REF;
+       if (gsym->type() == elfcpp::STT_FUNC
+           || gsym->type() == elfcpp::STT_ARM_TFUNC)
+         flags |= Symbol::FUNCTION_CALL;
+       if (gsym->needs_dynamic_reloc(flags))
+         check_non_pic(object, r_type);
+      }
+      break;
+
     case elfcpp::R_ARM_REL32:
     case elfcpp::R_ARM_PREL31:
       {
@@ -1296,6 +1699,7 @@ Target_arm<big_endian>::Scan::global(const General_options&,
       break;
       
     case elfcpp::R_ARM_GOT_BREL:
+    case elfcpp::R_ARM_GOT_PREL:
       {
        // The symbol requires a GOT entry.
        Output_data_got<32, big_endian>* got =
@@ -1568,6 +1972,7 @@ Target_arm<big_endian>::Relocate::relocate(
   switch (r_type)
     {
     case elfcpp::R_ARM_GOT_BREL:
+    case elfcpp::R_ARM_GOT_PREL:
       if (gsym != NULL)
        {
          gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
@@ -1595,6 +2000,24 @@ Target_arm<big_endian>::Relocate::relocate(
     case elfcpp::R_ARM_NONE:
       break;
 
+    case elfcpp::R_ARM_ABS8:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::abs8(view, object, psymval);
+      break;
+
+    case elfcpp::R_ARM_ABS12:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::abs12(view, object, psymval);
+      break;
+
+    case elfcpp::R_ARM_ABS16:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::abs16(view, object, psymval);
+      break;
+
     case elfcpp::R_ARM_ABS32:
       if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
                                    output_section))
@@ -1602,11 +2025,88 @@ Target_arm<big_endian>::Relocate::relocate(
                                                     has_thumb_bit);
       break;
 
+    case elfcpp::R_ARM_ABS32_NOI:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+                                   output_section))
+       // No thumb bit for this relocation: (S + A)
+       reloc_status = Arm_relocate_functions::abs32(view, object, psymval,
+                                                    false);
+      break;
+
+    case elfcpp::R_ARM_MOVW_ABS_NC:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::movw_abs_nc(view, object,
+                                                          psymval,
+                                                                  has_thumb_bit);
+      else
+       gold_error(_("relocation R_ARM_MOVW_ABS_NC cannot be used when making"
+                    "a shared object; recompile with -fPIC"));
+      break;
+
+    case elfcpp::R_ARM_MOVT_ABS:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::movt_abs(view, object, psymval);
+      else
+       gold_error(_("relocation R_ARM_MOVT_ABS cannot be used when making"
+                    "a shared object; recompile with -fPIC"));
+      break;
+
+    case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::thm_movw_abs_nc(view, object,
+                                                              psymval,
+                                                                      has_thumb_bit);
+      else
+       gold_error(_("relocation R_ARM_THM_MOVW_ABS_NC cannot be used when"
+                    "making a shared object; recompile with -fPIC"));
+      break;
+
+    case elfcpp::R_ARM_THM_MOVT_ABS:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::thm_movt_abs(view, object,
+                                                           psymval);
+      else
+       gold_error(_("relocation R_ARM_THM_MOVT_ABS cannot be used when"
+                    "making a shared object; recompile with -fPIC"));
+      break;
+
+    case elfcpp::R_ARM_MOVW_PREL_NC:
+      reloc_status = Arm_relocate_functions::movw_prel_nc(view, object,
+                                                         psymval, address,
+                                                         has_thumb_bit);
+      break;
+
+    case elfcpp::R_ARM_MOVT_PREL:
+      reloc_status = Arm_relocate_functions::movt_prel(view, object,
+                                                       psymval, address);
+      break;
+
+    case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+      reloc_status = Arm_relocate_functions::thm_movw_prel_nc(view, object,
+                                                             psymval, address,
+                                                             has_thumb_bit);
+      break;
+
+    case elfcpp::R_ARM_THM_MOVT_PREL:
+      reloc_status = Arm_relocate_functions::thm_movt_prel(view, object,
+                                                          psymval, address);
+      break;
+       
     case elfcpp::R_ARM_REL32:
       reloc_status = Arm_relocate_functions::rel32(view, object, psymval,
                                                   address, has_thumb_bit);
       break;
 
+    case elfcpp::R_ARM_THM_ABS5:
+      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
+                                   output_section))
+       reloc_status = Arm_relocate_functions::thm_abs5(view, object, psymval);
+      break;
+
     case elfcpp::R_ARM_THM_CALL:
       reloc_status = Arm_relocate_functions::thm_call(view, object, psymval,
                                                      address, has_thumb_bit);
@@ -1641,11 +2141,52 @@ Target_arm<big_endian>::Relocate::relocate(
       }
       break;
 
+    case elfcpp::R_ARM_BASE_ABS:
+      {
+       if (!should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+                                     output_section))
+         break;
+
+       uint32_t origin;
+       // Get the addressing origin of the output segment defining
+       // the symbol gsym (AAELF 4.6.1.2 Relocation types).
+       if (gsym == NULL)
+         // R_ARM_BASE_ABS with the NULL symbol will give the
+         // absolute address of the GOT origin (GOT_ORG) (see ARM IHI
+         // 0044C (AAELF): 4.6.1.8 Proxy generating relocations).
+         origin = target->got_plt_section()->address();
+       else if (gsym->source() == Symbol::IN_OUTPUT_SEGMENT)
+         origin = gsym->output_segment()->vaddr();
+       else if (gsym->source () == Symbol::IN_OUTPUT_DATA)
+         origin = gsym->output_data()->address();
+       else
+         {
+            gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
+                                  _("cannot find origin of R_ARM_BASE_ABS"));
+           return true;
+         }
+
+       reloc_status = Arm_relocate_functions::base_abs(view, origin);
+      }
+      break;
+
     case elfcpp::R_ARM_GOT_BREL:
       gold_assert(have_got_offset);
       reloc_status = Arm_relocate_functions::got_brel(view, got_offset);
       break;
 
+    case elfcpp::R_ARM_GOT_PREL:
+      gold_assert(have_got_offset);
+      // Get the address origin for GOT PLT, which is allocated right
+      // after the GOT section, to calculate an absolute address of
+      // the symbol GOT entry (got_origin + got_offset).
+      elfcpp::Elf_types<32>::Elf_Addr got_origin;
+      got_origin = target->got_plt_section()->address();
+      reloc_status = Arm_relocate_functions::got_prel(view,
+                                                     got_origin + got_offset,
+                                                     address);
+      break;
+
     case elfcpp::R_ARM_PLT32:
       gold_assert(gsym == NULL
                  || gsym->has_plt_offset()
@@ -1731,7 +2272,8 @@ Target_arm<big_endian>::relocate_section(
     bool needs_special_offset_handling,
     unsigned char* view,
     elfcpp::Elf_types<32>::Elf_Addr address,
-    section_size_type view_size)
+    section_size_type view_size,
+    const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef typename Target_arm<big_endian>::Relocate Arm_relocate;
   gold_assert(sh_type == elfcpp::SHT_REL);
@@ -1746,7 +2288,8 @@ Target_arm<big_endian>::relocate_section(
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
@@ -1764,16 +2307,35 @@ Target_arm<big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
     case elfcpp::R_ARM_NONE:
       return 0;
 
+    case elfcpp::R_ARM_ABS8:
+      return 1;
+
+    case elfcpp::R_ARM_ABS16:
+    case elfcpp::R_ARM_THM_ABS5:
+      return 2;
+
     case elfcpp::R_ARM_ABS32:
+    case elfcpp::R_ARM_ABS32_NOI:
+    case elfcpp::R_ARM_ABS12:
+    case elfcpp::R_ARM_BASE_ABS:
     case elfcpp::R_ARM_REL32:
     case elfcpp::R_ARM_THM_CALL:
     case elfcpp::R_ARM_GOTOFF32:
     case elfcpp::R_ARM_BASE_PREL:
     case elfcpp::R_ARM_GOT_BREL:
+    case elfcpp::R_ARM_GOT_PREL:
     case elfcpp::R_ARM_PLT32:
     case elfcpp::R_ARM_CALL:
     case elfcpp::R_ARM_JUMP24:
     case elfcpp::R_ARM_PREL31:
+    case elfcpp::R_ARM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_MOVT_ABS:
+    case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_THM_MOVT_ABS:
+    case elfcpp::R_ARM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_MOVT_PREL:
+    case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_THM_MOVT_PREL:
       return 4;
 
     case elfcpp::R_ARM_TARGET1:
index 5fccefb5750c190f64e34fee97152738eaf89b9f..93d7517caa72fd6de9036ed2309b3dc24b982efe 100644 (file)
@@ -99,6 +99,9 @@
 /* Define to 1 if you have the `pread' function. */
 #undef HAVE_PREAD
 
+/* Define to 1 if you have the `readv' function. */
+#undef HAVE_READV
+
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
index 59f52a54a5a366052f2692e2de1cf06bbf8b92d6..e4eb9fb82a9dd4ea412a2d72d571eb1ac37ce293 100755 (executable)
@@ -668,6 +668,16 @@ LDFLAGS
 CFLAGS
 CC
 TARGETOBJS
+DEFAULT_TARGET_X86_64_FALSE
+DEFAULT_TARGET_X86_64_TRUE
+DEFAULT_TARGET_SPARC_FALSE
+DEFAULT_TARGET_SPARC_TRUE
+DEFAULT_TARGET_POWERPC_FALSE
+DEFAULT_TARGET_POWERPC_TRUE
+DEFAULT_TARGET_I386_FALSE
+DEFAULT_TARGET_I386_TRUE
+DEFAULT_TARGET_ARM_FALSE
+DEFAULT_TARGET_ARM_TRUE
 PLUGINS_FALSE
 PLUGINS_TRUE
 THREADS_FALSE
@@ -3354,6 +3364,47 @@ for targ in $target $canon_targets; do
        default_size=$targ_size
        default_big_endian=$targ_big_endian
        default_osabi=$targ_osabi
+
+        if test "$targ_obj" = "arm"; then
+  DEFAULT_TARGET_ARM_TRUE=
+  DEFAULT_TARGET_ARM_FALSE='#'
+else
+  DEFAULT_TARGET_ARM_TRUE='#'
+  DEFAULT_TARGET_ARM_FALSE=
+fi
+
+        if test "$targ_obj" = "i386"; then
+  DEFAULT_TARGET_I386_TRUE=
+  DEFAULT_TARGET_I386_FALSE='#'
+else
+  DEFAULT_TARGET_I386_TRUE='#'
+  DEFAULT_TARGET_I386_FALSE=
+fi
+
+        if test "$targ_obj" = "powerpc"; then
+  DEFAULT_TARGET_POWERPC_TRUE=
+  DEFAULT_TARGET_POWERPC_FALSE='#'
+else
+  DEFAULT_TARGET_POWERPC_TRUE='#'
+  DEFAULT_TARGET_POWERPC_FALSE=
+fi
+
+        if test "$targ_obj" = "sparc"; then
+  DEFAULT_TARGET_SPARC_TRUE=
+  DEFAULT_TARGET_SPARC_FALSE='#'
+else
+  DEFAULT_TARGET_SPARC_TRUE='#'
+  DEFAULT_TARGET_SPARC_FALSE=
+fi
+
+        if test "$targ_obj" = "x86_64"; then
+  DEFAULT_TARGET_X86_64_TRUE=
+  DEFAULT_TARGET_X86_64_FALSE='#'
+else
+  DEFAULT_TARGET_X86_64_TRUE='#'
+  DEFAULT_TARGET_X86_64_FALSE=
+fi
+
       fi
     fi
   fi
@@ -6650,7 +6701,7 @@ fi
 
 done
 
-for ac_func in mallinfo posix_fallocate
+for ac_func in mallinfo posix_fallocate readv
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -6970,6 +7021,26 @@ if test -z "${PLUGINS_TRUE}" && test -z "${PLUGINS_FALSE}"; then
   as_fn_error "conditional \"PLUGINS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${DEFAULT_TARGET_ARM_TRUE}" && test -z "${DEFAULT_TARGET_ARM_FALSE}"; then
+  as_fn_error "conditional \"DEFAULT_TARGET_ARM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_I386_TRUE}" && test -z "${DEFAULT_TARGET_I386_FALSE}"; then
+  as_fn_error "conditional \"DEFAULT_TARGET_I386\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_POWERPC_TRUE}" && test -z "${DEFAULT_TARGET_POWERPC_FALSE}"; then
+  as_fn_error "conditional \"DEFAULT_TARGET_POWERPC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_SPARC_TRUE}" && test -z "${DEFAULT_TARGET_SPARC_FALSE}"; then
+  as_fn_error "conditional \"DEFAULT_TARGET_SPARC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DEFAULT_TARGET_X86_64_TRUE}" && test -z "${DEFAULT_TARGET_X86_64_FALSE}"; then
+  as_fn_error "conditional \"DEFAULT_TARGET_X86_64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
   as_fn_error "conditional \"AMDEP\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
index 0a535987d914fda02ec71eb001f8db8a037330bf..85e23f9ce456c92fc78ceeae3dc3c34ab089aa27 100644 (file)
@@ -151,6 +151,12 @@ for targ in $target $canon_targets; do
        default_size=$targ_size
        default_big_endian=$targ_big_endian
        default_osabi=$targ_osabi
+
+       AM_CONDITIONAL(DEFAULT_TARGET_ARM, test "$targ_obj" = "arm")
+       AM_CONDITIONAL(DEFAULT_TARGET_I386, test "$targ_obj" = "i386")
+       AM_CONDITIONAL(DEFAULT_TARGET_POWERPC, test "$targ_obj" = "powerpc")
+       AM_CONDITIONAL(DEFAULT_TARGET_SPARC, test "$targ_obj" = "sparc")
+       AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$targ_obj" = "x86_64")
       fi
     fi
   fi
@@ -332,7 +338,7 @@ AC_LANG_PUSH(C++)
 AC_CHECK_HEADERS(tr1/unordered_set tr1/unordered_map)
 AC_CHECK_HEADERS(ext/hash_map ext/hash_set)
 AC_CHECK_HEADERS(byteswap.h)
-AC_CHECK_FUNCS(mallinfo posix_fallocate)
+AC_CHECK_FUNCS(mallinfo posix_fallocate readv)
 AC_CHECK_DECLS([basename, ffs, asprintf, vasprintf, snprintf, vsnprintf, strverscmp, strndup, memmem])
 
 # Use of ::std::tr1::unordered_map::rehash causes undefined symbols
index 80b50df8838ca8a4bc3863f42a06a063bd9401a4..6ef72d3ed38677ca903142989e4ba28c5cd6ee4b 100644 (file)
@@ -84,7 +84,8 @@ Copy_relocs<sh_type, size, big_endian>::need_copy_reloc(
     Sized_relobj<size, big_endian>* object,
     unsigned int shndx) const
 {
-  // FIXME: Handle -z nocopyrelocs.
+  if (!parameters->options().copyreloc())
+    return false;
 
   if (sym->symsize() == 0)
     return false;
@@ -109,6 +110,9 @@ Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc(
     Sized_symbol<size>* sym,
     Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
 {
+  // We should not be here if -z nocopyreloc is given.
+  gold_assert(parameters->options().copyreloc());
+
   typename elfcpp::Elf_types<size>::Elf_WXword symsize = sym->symsize();
 
   // There is no defined way to determine the required alignment of
index 8428dc81f0700cd4537da94ed2cf067650fa2bba..4b9ef19fe4dd95624a50c5205c82d7e75d3267ed 100644 (file)
@@ -36,8 +36,10 @@ namespace gold
 const int DEBUG_TASK = 0x1;
 const int DEBUG_SCRIPT = 0x2;
 const int DEBUG_FILES = 0x4;
+const int DEBUG_RELAXATION = 0x8;
 
-const int DEBUG_ALL = DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES;
+const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES
+                      | DEBUG_RELAXATION);
 
 // Convert a debug string to the appropriate enum.
 inline int
@@ -49,6 +51,7 @@ debug_string_to_enum(const char* arg)
     { "task", DEBUG_TASK },
     { "script", DEBUG_SCRIPT },
     { "files", DEBUG_FILES },
+    { "relaxation", DEBUG_RELAXATION },
     { "all", DEBUG_ALL }
   };
 
index 3d059e2c222ed79a02157d282d9a2d70d4ddce55..f4a02d03296caaf2cc1b6eeaf12204785b31ac12 100644 (file)
@@ -23,6 +23,7 @@
 #include "gold.h"
 
 #include <cerrno>
+#include <cstdio>
 #include <cstring>
 #include <fcntl.h>
 #include <unistd.h>
@@ -31,6 +32,7 @@
 #include "options.h"
 #include "gold-threads.h"
 #include "descriptors.h"
+#include "binary-io.h"
 
 // Very old systems may not define FD_CLOEXEC.
 #ifndef FD_CLOEXEC
@@ -98,6 +100,9 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode)
       // require callers to pass it.
       flags |= O_CLOEXEC;
 
+      // Always open the file as a binary file.
+      flags |= O_BINARY;
+
       int new_descriptor = ::open(name, flags, mode);
       if (new_descriptor < 0
          && errno != ENFILE
index 3d0f65a4b5a1cfb4ad6469b3ba3116e63fba431c..d142586a60754bddad182118f2580ebf96e7dfda 100644 (file)
@@ -1,6 +1,6 @@
 // dwarf_reader.cc -- parse dwarf2/3 debug information
 
-// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -129,7 +129,7 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt)
 
 template<int size, bool big_endian>
 Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info(Object* object,
-                                                               off_t read_shndx)
+                                                               unsigned int read_shndx)
   : data_valid_(false), buffer_(NULL), symtab_buffer_(NULL),
     directories_(), files_(), current_header_index_(-1)
 {
@@ -508,7 +508,7 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
 template<int size, bool big_endian>
 unsigned const char*
 Sized_dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr,
-                                                    off_t shndx)
+                                                    unsigned int shndx)
 {
   struct LineStateMachine lsm;
 
@@ -595,7 +595,7 @@ Sized_dwarf_line_info<size, big_endian>::read_relocs(Object* object)
 template<int size, bool big_endian>
 void
 Sized_dwarf_line_info<size, big_endian>::read_line_mappings(Object* object,
-                                                           off_t shndx)
+                                                           unsigned int shndx)
 {
   gold_assert(this->data_valid_ == true);
 
index c9d760ce53ff04c74917ef1aee868aa663e9022b..c18ed8951b0312139710cb2288089921bc24a1f0 100644 (file)
@@ -1,6 +1,6 @@
 // dwarf_reader.h -- parse dwarf2/3 debug information for gold  -*- C++ -*-
 
-// Copyright 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -105,7 +105,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info
   // Initializes a .debug_line reader for a given object file.
   // If SHNDX is specified and non-negative, only read the debug
   // information that pertains to the specified section.
-  Sized_dwarf_line_info(Object* object, off_t read_shndx = -1U);
+  Sized_dwarf_line_info(Object* object, unsigned int read_shndx = -1U);
 
  private:
   std::string
@@ -115,7 +115,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info
   // If SHNDX is non-negative, only store debug information that
   // pertains to the specified section.
   void
-  read_line_mappings(Object*, off_t shndx);
+  read_line_mappings(Object*, unsigned int shndx);
 
   // Reads the relocation section associated with .debug_line and
   // stores relocation information in reloc_map_.
@@ -140,7 +140,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info
   // discard all line information that doesn't pertain to the given
   // section.
   const unsigned char*
-  read_lines(const unsigned char* lineptr, off_t shndx);
+  read_lines(const unsigned char* lineptr, unsigned int shndx);
 
   // Process a single line info opcode at START using the state
   // machine at LSM.  Return true if we should define a line using the
index df2afeb319701794092d9f7bd5ae13b179045dbe..b14d06db12dd8f360067ab47afd1b8fad8f6eb72 100644 (file)
@@ -83,9 +83,8 @@ Sized_dynobj<size, big_endian>::Sized_dynobj(
 
 template<int size, bool big_endian>
 void
-Sized_dynobj<size, big_endian>::setup(Target *target)
+Sized_dynobj<size, big_endian>::setup()
 {
-  this->set_target(target);
   const unsigned int shnum = this->elf_file_.shnum();
   this->set_shnum(shnum);
 }
@@ -409,7 +408,7 @@ Sized_dynobj<size, big_endian>::do_initialize_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.
+// here is check for .gnu.warning and .note.GNU-split-stack sections.
 
 template<int size, bool big_endian>
 void
@@ -444,6 +443,7 @@ Sized_dynobj<size, big_endian>::do_layout(Symbol_table* symtab,
       const char* name = pnames + shdr.get_sh_name();
 
       this->handle_gnu_warning_section(name, i, symtab);
+      this->handle_split_stack_section(name);
     }
 
   delete sd->section_headers;
index f6c6538ad123a8a043c5ef1deb8817d22eb55036..2768c837986bc0213ea863bf5786deac45f51162 100644 (file)
@@ -163,7 +163,7 @@ class Sized_dynobj : public Dynobj
 
   // Set up the object file based on TARGET.
   void
-  setup(Target *target);
+  setup();
 
   // Read the symbols.
   void
index bb10aa9cc447e24faab86dd6055bb29184857607..7067b0b8ac1fce04a4709e4c113531f9287a7aa7 100644 (file)
 #include "descriptors.h"
 #include "fileread.h"
 
+#ifndef HAVE_READV
+struct iovec { void* iov_base; size_t iov_len };
+ssize_t
+readv(int, const iovec*, int)
+{
+  gold_unreachable();
+}
+#endif
+
 namespace gold
 {
 
@@ -717,8 +726,8 @@ Input_file::Input_file(const Task* task, const char* name,
   : file_()
 {
   this->input_argument_ =
-    new Input_file_argument(name, false, "", false,
-                           Position_dependent_options());
+    new Input_file_argument(name, Input_file_argument::INPUT_FILE_TYPE_FILE,
+                            "", false, Position_dependent_options());
   bool ok = this->file_.open(task, name, contents, size);
   gold_assert(ok);
 }
@@ -765,6 +774,7 @@ Input_file::will_search_for() const
 {
   return (!IS_ABSOLUTE_PATH(this->input_argument_->name())
          && (this->input_argument_->is_lib()
+             || this->input_argument_->is_searched_file()
              || this->input_argument_->extra_search_path() != NULL));
 }
 
@@ -789,9 +799,10 @@ File_read::get_mtime()
 
 // If the filename is not absolute, we assume it is in the current
 // directory *except* when:
-//    A) input_argument_->is_lib() is true; or
-//    B) input_argument_->extra_search_path() is not empty.
-// In both cases, we look in extra_search_path + library_path to find
+//    A) input_argument_->is_lib() is true;
+//    B) input_argument_->is_searched_file() is true; or
+//    C) input_argument_->extra_search_path() is not empty.
+// In each, we look in extra_search_path + library_path to find
 // the file location, rather than the current directory.
 
 bool
@@ -800,35 +811,43 @@ Input_file::open(const Dirsearch& dirpath, const Task* task, int *pindex)
   std::string name;
 
   // Case 1: name is an absolute file, just try to open it
-  // Case 2: name is relative but is_lib is false and extra_search_path
-  //         is empty
+  // Case 2: name is relative but is_lib is false, is_searched_file is false,
+  //         and extra_search_path is empty
   if (IS_ABSOLUTE_PATH(this->input_argument_->name())
       || (!this->input_argument_->is_lib()
+         && !this->input_argument_->is_searched_file()
          && this->input_argument_->extra_search_path() == NULL))
     {
       name = this->input_argument_->name();
       this->found_name_ = name;
     }
-  // Case 3: is_lib is true
-  else if (this->input_argument_->is_lib())
+  // Case 3: is_lib is true or is_searched_file is true
+  else if (this->input_argument_->is_lib()
+          || this->input_argument_->is_searched_file())
     {
       // We don't yet support extra_search_path with -l.
       gold_assert(this->input_argument_->extra_search_path() == NULL);
-      std::string n1("lib");
-      n1 += this->input_argument_->name();
-      std::string n2;
-      if (parameters->options().is_static()
-         || !this->input_argument_->options().Bdynamic())
-       n1 += ".a";
-      else
+      std::string n1, n2;
+      if (this->input_argument_->is_lib())
        {
-         n2 = n1 + ".a";
-         n1 += ".so";
+         n1 = "lib";
+         n1 += this->input_argument_->name();
+         if (parameters->options().is_static()
+             || !this->input_argument_->options().Bdynamic())
+           n1 += ".a";
+         else
+           {
+             n2 = n1 + ".a";
+             n1 += ".so";
+           }
        }
+      else
+       n1 = this->input_argument_->name();
       name = dirpath.find(n1, n2, &this->is_in_sysroot_, pindex);
       if (name.empty())
        {
-         gold_error(_("cannot find -l%s"),
+         gold_error(_("cannot find %s%s"),
+                    this->input_argument_->is_lib() ? "-l" : "",
                     this->input_argument_->name());
          return false;
        }
@@ -898,15 +917,12 @@ Input_file::open_binary(const Task* task, const std::string& name)
   // In order to open a binary file, we need machine code, size, and
   // endianness.  We may not have a valid target at this point, in
   // which case we use the default target.
-  const Target* target;
-  if (parameters->target_valid())
-    target = &parameters->target();
-  else
-    target = &parameters->default_target();
+  parameters_force_valid_target();
+  const Target& target(parameters->target());
 
-  Binary_to_elf binary_to_elf(target->machine_code(),
-                             target->get_size(),
-                             target->is_big_endian(),
+  Binary_to_elf binary_to_elf(target.machine_code(),
+                             target.get_size(),
+                             target.is_big_endian(),
                              name);
   if (!binary_to_elf.convert(task))
     return false;
index 920a4da7b518149b11e4ffc946caa806aa1763f1..bdffdd15fec7a74d1e33877b0795f2ff03bb36cc 100644 (file)
@@ -370,7 +370,13 @@ class File_read
   { return (file_size + (page_size - 1)) & ~ (page_size - 1); }
 
   // The maximum number of entries we will pass to ::readv.
+#ifdef HAVE_READV
   static const size_t max_readv_entries = 128;
+#else
+  // On targets that don't have readv set the max to 1 so readv is not
+  // used.
+  static const size_t max_readv_entries = 1;
+#endif
 
   // Use readv to read data.
   void
index ffb721c7fb868c8c1f29eb4fef96a4ce3d8bbb8e..757a33dc309d590a53cd0d2f26f60e1a3d87f062 100644 (file)
--- a/gold/gc.h
+++ b/gold/gc.h
@@ -28,6 +28,7 @@
 
 #include "elfcpp.h"
 #include "symtab.h"
+#include "icf.h"
 
 namespace gold
 {
@@ -162,7 +163,7 @@ gc_process_relocs(
   std::vector<std::pair<long long, long long> >* addendvec = NULL;
   bool is_icf_tracked = false;
 
-  if (parameters->options().icf()
+  if (parameters->options().icf_enabled()
       && is_prefix_of(".text.", (src_obj)->section_name(src_indx).c_str()))
     {
       is_icf_tracked = true;
index cb29e7d9a1be52f672f596b75e45b7957d60135e..4ac1e3dca0388a22efc84801db073f0267f757b5 100644 (file)
@@ -41,6 +41,7 @@
 #include "reloc.h"
 #include "defstd.h"
 #include "plugin.h"
+#include "gc.h"
 #include "icf.h"
 #include "incremental.h"
 
@@ -180,7 +181,8 @@ queue_initial_tasks(const General_options& options,
   if (cmdline.options().incremental())
     {
       Incremental_checker incremental_checker(
-          parameters->options().output_file_name());
+          parameters->options().output_file_name(),
+          layout->incremental_inputs());
       if (incremental_checker.can_incrementally_link_output_file())
         {
           // TODO: remove when incremental linking implemented.
@@ -219,10 +221,12 @@ queue_initial_tasks(const General_options& options,
     }
 
   if (parameters->options().relocatable()
-      && (parameters->options().gc_sections() || parameters->options().icf()))
+      && (parameters->options().gc_sections()
+         || parameters->options().icf_enabled()))
     gold_error(_("cannot mix -r with --gc-sections or --icf"));
 
-  if (parameters->options().gc_sections() || parameters->options().icf())
+  if (parameters->options().gc_sections()
+      || parameters->options().icf_enabled())
     {
       workqueue->queue(new Task_function(new Gc_runner(options,
                                                        input_objects,
@@ -330,7 +334,7 @@ queue_middle_tasks(const General_options& options,
   // If identical code folding (--icf) is chosen it makes sense to do it 
   // only after garbage collection (--gc-sections) as we do not want to 
   // be folding sections that will be garbage.
-  if (parameters->options().icf())
+  if (parameters->options().icf_enabled())
     {
       symtab->icf()->find_identical_sections(input_objects, symtab);
     }
@@ -340,7 +344,8 @@ queue_middle_tasks(const General_options& options,
   // --gc-sections or --icf is turned on, Object::layout is 
   // called twice.  It is called the first time when the 
   // symbols are added.
-  if (parameters->options().gc_sections() || parameters->options().icf())
+  if (parameters->options().gc_sections()
+      || parameters->options().icf_enabled())
     {
       for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
            p != input_objects->relobj_end();
@@ -358,7 +363,8 @@ queue_middle_tasks(const General_options& options,
       plugins->layout_deferred_objects();
     }     
 
-  if (parameters->options().gc_sections() || parameters->options().icf())
+  if (parameters->options().gc_sections()
+      || parameters->options().icf_enabled())
     {
       for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
            p != input_objects->relobj_end();
@@ -382,7 +388,7 @@ queue_middle_tasks(const General_options& options,
   // pass an empty archive to the linker and get an empty object file
   // out.  In order to do this we need to use a default target.
   if (input_objects->number_of_input_objects() == 0)
-    set_parameters_target(&parameters->default_target());
+    parameters_force_valid_target();
 
   int thread_count = options.thread_count_middle();
   if (thread_count == 0)
@@ -390,8 +396,9 @@ queue_middle_tasks(const General_options& options,
   workqueue->set_thread_count(thread_count);
 
   // Now we have seen all the input files.
-  const bool doing_static_link = (!input_objects->any_dynamic()
-                                 && !parameters->options().shared());
+  const bool doing_static_link =
+    (!input_objects->any_dynamic()
+     && !parameters->options().output_is_position_independent());
   set_parameters_doing_static_link(doing_static_link);
   if (!doing_static_link && options.is_static())
     {
@@ -408,6 +415,23 @@ queue_middle_tasks(const General_options& options,
     gold_fatal(_("cannot use non-ELF output format with dynamic object %s"),
               (*input_objects->dynobj_begin())->name().c_str());
 
+  if (parameters->options().relocatable())
+    {
+      Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+      if (p != input_objects->relobj_end())
+       {
+         bool uses_split_stack = (*p)->uses_split_stack();
+         for (++p; p != input_objects->relobj_end(); ++p)
+           {
+             if ((*p)->uses_split_stack() != uses_split_stack)
+               gold_fatal(_("cannot mix split-stack '%s' and "
+                            "non-split-stack '%s' when using -r"),
+                          (*input_objects->relobj_begin())->name().c_str(),
+                          (*p)->name().c_str());
+           }
+       }
+    }
+
   if (is_debugging_enabled(DEBUG_SCRIPT))
     layout->script_options()->print(stderr);
 
@@ -453,7 +477,8 @@ queue_middle_tasks(const General_options& options,
 
   // If doing garbage collection, the relocations have already been read.
   // Otherwise, read and scan the relocations.
-  if (parameters->options().gc_sections() || parameters->options().icf())
+  if (parameters->options().gc_sections()
+      || parameters->options().icf_enabled())
     {
       for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
            p != input_objects->relobj_end();
index 0b68613d4dca1027b758a551b01b8f957869220d..445a7ac4bdbae6916aeca99fef587c7f4fe1a2c1 100644 (file)
@@ -38,6 +38,7 @@
 #include "target-select.h"
 #include "tls.h"
 #include "freebsd.h"
+#include "gc.h"
 
 namespace
 {
@@ -113,7 +114,8 @@ class Target_i386 : public Target_freebsd<32, false>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   elfcpp::Elf_types<32>::Elf_Addr view_address,
-                  section_size_type view_size);
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -168,6 +170,13 @@ class Target_i386 : public Target_freebsd<32, false>
     return Target::do_is_local_label_name(name);
   }
 
+  // Adjust -fstack-split code which calls non-stack-split code.
+  void
+  do_calls_non_split(Relobj* object, unsigned int shndx,
+                    section_offset_type fnoffset, section_size_type fnsize,
+                    unsigned char* view, section_size_type view_size,
+                    std::string* from, std::string* to) const;
+
   // Return the size of the GOT section.
   section_size_type
   got_size()
@@ -375,17 +384,6 @@ class Target_i386 : public Target_freebsd<32, false>
   Reloc_section*
   rel_dyn_section(Layout*);
 
-  // Return true if the symbol may need a COPY relocation.
-  // References from an executable object to non-function symbols
-  // defined in a dynamic object may need a COPY relocation.
-  bool
-  may_need_copy_reloc(Symbol* gsym)
-  {
-    return (!parameters->options().shared()
-            && gsym->is_from_dynobj()
-            && gsym->type() != elfcpp::STT_FUNC);
-  }
-
   // Add a potential copy relocation.
   void
   copy_reloc(Symbol_table* symtab, Layout* layout,
@@ -688,7 +686,7 @@ Output_data_plt_i386::do_write(Output_file* of)
   elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
   elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
 
-  if (parameters->options().shared())
+  if (parameters->options().output_is_position_independent())
     memcpy(pov, dyn_first_plt_entry, plt_entry_size);
   else
     {
@@ -720,7 +718,7 @@ Output_data_plt_i386::do_write(Output_file* of)
     {
       // Set and adjust the PLT entry itself.
 
-      if (parameters->options().shared())
+      if (parameters->options().output_is_position_independent())
        {
          memcpy(pov, dyn_plt_entry, plt_entry_size);
          elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
@@ -1213,7 +1211,7 @@ Target_i386::Scan::global(const General_options&,
         // Make a dynamic relocation if necessary.
         if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -1259,7 +1257,7 @@ Target_i386::Scan::global(const General_options&,
           flags |= Symbol::FUNCTION_CALL;
         if (gsym->needs_dynamic_reloc(flags))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -2015,14 +2013,19 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       break;
 
     case elfcpp::R_386_TLS_LDO_32:       // Alternate local-dynamic
-      // This reloc can appear in debugging sections, in which case we
-      // won't see the TLS_LDM reloc.  The local_dynamic_type field
-      // tells us this.
-      if (optimized_type == tls::TLSOPT_TO_LE
-          && this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
+      if (optimized_type == tls::TLSOPT_TO_LE)
        {
-          gold_assert(tls_segment != NULL);
-          value -= tls_segment->memsz();
+         // This reloc can appear in debugging sections, in which
+         // case we must not convert to local-exec.  We decide what
+         // to do based on whether the section is marked as
+         // containing executable code.  That is what the GNU linker
+         // does as well.
+         elfcpp::Shdr<32, false> shdr(relinfo->data_shdr);
+         if ((shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+           {
+             gold_assert(tls_segment != NULL);
+             value -= tls_segment->memsz();
+           }
        }
       Relocate_functions<32, false>::rel32(view, value);
       break;
@@ -2441,7 +2444,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
                              bool needs_special_offset_handling,
                              unsigned char* view,
                              elfcpp::Elf_types<32>::Elf_Addr address,
-                             section_size_type view_size)
+                             section_size_type view_size,
+                             const Reloc_symbol_changes* reloc_symbol_changes)
 {
   gold_assert(sh_type == elfcpp::SHT_REL);
 
@@ -2455,7 +2459,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
@@ -2675,6 +2680,63 @@ Target_i386::do_code_fill(section_size_type length) const
   return std::string(nops[length], length);
 }
 
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fstack-split.  The function calls non-stack-split
+// code.  We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+void
+Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx,
+                               section_offset_type fnoffset,
+                               section_size_type fnsize,
+                               unsigned char* view,
+                               section_size_type view_size,
+                               std::string* from,
+                               std::string* to) const
+{
+  // The function starts with a comparison of the stack pointer and a
+  // field in the TCB.  This is followed by a jump.
+
+  // cmp %gs:NN,%esp
+  if (this->match_view(view, view_size, fnoffset, "\x65\x3b\x25", 3)
+      && fnsize > 7)
+    {
+      // We will call __morestack if the carry flag is set after this
+      // comparison.  We turn the comparison into an stc instruction
+      // and some nops.
+      view[fnoffset] = '\xf9';
+      this->set_view_to_nop(view, view_size, fnoffset + 1, 6);
+    }
+  // lea NN(%esp),%ecx
+  else if (this->match_view(view, view_size, fnoffset, "\x8d\x8c\x24", 3)
+          && fnsize > 7)
+    {
+      // This is loading an offset from the stack pointer for a
+      // comparison.  The offset is negative, so we decrease the
+      // offset by the amount of space we need for the stack.  This
+      // means we will avoid calling __morestack if there happens to
+      // be plenty of space on the stack already.
+      unsigned char* pval = view + fnoffset + 3;
+      uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
+      val -= parameters->options().split_stack_adjust_size();
+      elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
+    }
+  else
+    {
+      if (!object->has_no_split_stack())
+       object->error(_("failed to match split-stack sequence at "
+                       "section %u offset %0zx"),
+                     shndx, fnoffset);
+      return;
+    }
+
+  // We have to change the function so that it calls
+  // __morestack_non_split instead of __morestack.  The former will
+  // allocate additional stack space.
+  *from = "__morestack";
+  *to = "__morestack_non_split";
+}
+
 // The selector for i386 object files.
 
 class Target_selector_i386 : public Target_selector_freebsd
index 411cf2e2344cea761c2c581420089f2e55727bb4..03b927adc40de763a486d85395cab9ffddd7fdc9 100644 (file)
 #include "icf.h"
 #include "symtab.h"
 #include "libiberty.h"
+#include "demangle.h"
 
 namespace gold
 {
@@ -530,6 +531,22 @@ match_sections(unsigned int iteration_num,
   return converged;
 }
 
+// During safe icf (--icf=safe), only fold functions that are ctors or dtors.
+// This function returns true if the mangled function name is a ctor or a
+// dtor.
+
+static bool
+is_function_ctor_or_dtor(const char* mangled_func_name)
+{
+  if ((is_prefix_of("_ZN", mangled_func_name)
+       || is_prefix_of("_ZZ", mangled_func_name))
+      && (is_gnu_v3_mangled_ctor(mangled_func_name)
+          || is_gnu_v3_mangled_dtor(mangled_func_name)))
+    {
+      return true;
+    }
+  return false;
+}
 
 // This is the main ICF function called in gold.cc.  This does the
 // initialization and calls match_sections repeatedly (twice by default)
@@ -552,14 +569,19 @@ Icf::find_identical_sections(const Input_objects* input_objects,
     {
       for (unsigned int i = 0;i < (*p)->shnum(); ++i)
         {
+         const char* section_name = (*p)->section_name(i).c_str();
           // Only looking to fold functions, so just look at .text sections.
-          if (!is_prefix_of(".text.", (*p)->section_name(i).c_str()))
+          if (!is_prefix_of(".text.", section_name))
             continue;
           if (!(*p)->is_section_included(i))
             continue;
           if (parameters->options().gc_sections()
               && symtab->gc()->is_section_garbage(*p, i))
               continue;
+         // With --icf=safe, check if mangled name is a ctor or a dtor.
+         if (parameters->options().icf_safe_folding()
+             && !is_function_ctor_or_dtor(section_name + 6))
+           continue;
           this->id_section_.push_back(Section_id(*p, i));
           this->section_id_[Section_id(*p, i)] = section_num;
           this->kept_section_id_.push_back(section_num);
index 4a3ecb1a69168b60884784ba5cc8186865bb0119..519f35fe150c798e04e5f4e2825508eee646c41d 100644 (file)
 // MA 02110-1301, USA.
 
 #include "gold.h"
+
+#include <cstdarg>
+
 #include "elfcpp.h"
 #include "output.h"
 #include "incremental.h"
 #include "archive.h"
 #include "output.h"
+#include "target-select.h"
 
 using elfcpp::Convert;
 
@@ -33,7 +37,7 @@ namespace gold {
 
 // Version information. Will change frequently during the development, later
 // we could think about backward (and forward?) compatibility.
-const int INCREMENTAL_LINK_VERSION = 1;
+const unsigned int INCREMENTAL_LINK_VERSION = 1;
 
 namespace internal {
 
@@ -80,7 +84,42 @@ struct Incremental_inputs_entry_data
 
 // Accessors.
 
-// See internal::Incremental_input_header for fields descriptions.
+// Reader class for .gnu_incremental_inputs header. See
+// internal::Incremental_input_header for fields descriptions.
+
+template<int size, bool big_endian>
+class Incremental_inputs_header
+{
+ public:
+  Incremental_inputs_header(const unsigned char *p)
+    : p_(reinterpret_cast<const internal::Incremental_inputs_header_data*>(p))
+  { }
+
+  static const int data_size = sizeof(internal::Incremental_inputs_header_data);
+
+  elfcpp::Elf_Word
+  get_version() const
+  { return Convert<32, big_endian>::convert_host(this->p_->version); }
+
+  elfcpp::Elf_Word
+  get_input_file_count() const
+  { return Convert<32, big_endian>::convert_host(this->p_->input_file_count); }
+
+  elfcpp::Elf_Word
+  get_command_line_offset() const
+  { return Convert<32, big_endian>::convert_host(this->p_->command_line_offset); }
+
+  elfcpp::Elf_Word
+  get_reserved() const
+  { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
+
+ private:
+  const internal::Incremental_inputs_header_data* p_;
+};
+
+// Writer class for .gnu_incremental_inputs header. See
+// internal::Incremental_input_header for fields descriptions.
+
 template<int size, bool big_endian>
 class Incremental_inputs_header_write
 {
@@ -111,7 +150,48 @@ class Incremental_inputs_header_write
   internal::Incremental_inputs_header_data* p_;
 };
 
-// See internal::Incremental_input_entry for fields descriptions.
+// Reader class for an .gnu_incremental_inputs entry. See
+// internal::Incremental_input_entry for fields descriptions.
+template<int size, bool big_endian>
+class Incremental_inputs_entry
+{
+ public:
+  Incremental_inputs_entry(const unsigned char *p)
+    : p_(reinterpret_cast<const internal::Incremental_inputs_entry_data*>(p))
+  { }
+
+  static const int data_size = sizeof(internal::Incremental_inputs_entry_data);
+
+  elfcpp::Elf_Word
+  get_filename_offset(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->filename_offset); }
+
+  elfcpp::Elf_Word
+  get_data_offset(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->data_offset); }
+
+  elfcpp::Elf_Xword
+  get_timestamp_sec(elfcpp::Elf_Xword v)
+  { return Convert<64, big_endian>::convert_host(this->p_->timestamp_sec); }
+
+  elfcpp::Elf_Word
+  get_timestamp_nsec(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->timestamp_nsec); }
+
+  elfcpp::Elf_Word
+  get_input_type(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->input_type); }
+
+  elfcpp::Elf_Word
+  get_reserved(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
+
+ private:
+  const internal::Incremental_inputs_entry_data* p_;
+};
+
+// Writer class for an .gnu_incremental_inputs entry. See
+// internal::Incremental_input_entry for fields descriptions.
 template<int size, bool big_endian>
 class Incremental_inputs_entry_write
 {
@@ -150,6 +230,223 @@ class Incremental_inputs_entry_write
   internal::Incremental_inputs_entry_data* p_;
 };
 
+// Inform the user why we don't do an incremental link.  Not called in
+// the obvious case of missing output file.  TODO: Is this helpful?
+
+void
+vexplain_no_incremental(const char* format, va_list args)
+{
+  char* buf = NULL;
+  if (vasprintf(&buf, format, args) < 0)
+    gold_nomem();
+  gold_info(_("the link might take longer: "
+              "cannot perform incremental link: %s"), buf);
+  free(buf);
+}
+
+void
+explain_no_incremental(const char* format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  vexplain_no_incremental(format, args);
+  va_end(args);
+}
+
+// Report an error.
+
+void
+Incremental_binary::error(const char* format, ...) const
+{
+  va_list args;
+  va_start(args, format);
+  // Current code only checks if the file can be used for incremental linking,
+  // so errors shouldn't fail the build, but only result in a fallback to a
+  // full build.
+  // TODO: when we implement incremental editing of the file, we may need a
+  // flag that will cause errors to be treated seriously.
+  vexplain_no_incremental(format, args);
+  va_end(args);
+}
+
+template<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section(
+    Location* location,
+    unsigned int* strtab_shndx)
+{
+  unsigned int shndx = this->elf_file_.find_section_by_type(
+      elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
+  if (shndx == elfcpp::SHN_UNDEF)  // Not found.
+    return false;
+  *strtab_shndx = this->elf_file_.section_link(shndx);
+  *location = this->elf_file_.section_contents(shndx);
+  return true;
+}
+
+template<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::do_check_inputs(
+    Incremental_inputs* incremental_inputs)
+{
+  const int entry_size =
+      Incremental_inputs_entry_write<size, big_endian>::data_size;
+  const int header_size =
+      Incremental_inputs_header_write<size, big_endian>::data_size;
+
+  unsigned int strtab_shndx;
+  Location location;
+
+  if (!do_find_incremental_inputs_section(&location, &strtab_shndx))
+    {
+      explain_no_incremental(_("no incremental data from previous build"));
+      return false;
+    }
+  if (location.data_size < header_size
+      || strtab_shndx >= this->elf_file_.shnum()
+      || this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
+    {
+      explain_no_incremental(_("invalid incremental build data"));
+      return false;
+    }
+
+  Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
+  View data_view(view(location));
+  View strtab_view(view(strtab_location));
+  elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
+  Incremental_inputs_header<size, big_endian> header(data_view.data());
+
+  if (header.get_version() != INCREMENTAL_LINK_VERSION)
+    {
+      explain_no_incremental(_("different version of incremental build data"));
+      return false;
+    }
+
+  const char* command_line;
+  // We divide instead of multiplying to make sure there is no integer
+  // overflow.
+  size_t max_input_entries = (location.data_size - header_size) / entry_size;
+  if (header.get_input_file_count() > max_input_entries
+      || !strtab.get_c_string(header.get_command_line_offset(), &command_line))
+    {
+      explain_no_incremental(_("invalid incremental build data"));
+      return false;
+    }
+
+  if (incremental_inputs->command_line() != command_line)
+    {
+      explain_no_incremental(_("command line changed"));
+      return false;
+    }
+
+  // TODO: compare incremental_inputs->inputs() with entries in data_view.
+  return true;
+}
+
+namespace
+{
+
+// Create a Sized_incremental_binary object of the specified size and
+// endianness. Fails if the target architecture is not supported.
+
+template<int size, bool big_endian>
+Incremental_binary*
+make_sized_incremental_binary(Output_file* file,
+                              const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+  Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
+                                 ehdr.get_e_ident()[elfcpp::EI_OSABI],
+                                 ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
+  if (target == NULL)
+    {
+      explain_no_incremental(_("unsupported ELF machine number %d"),
+               ehdr.get_e_machine());
+      return NULL;
+    }
+
+  return new Sized_incremental_binary<size, big_endian>(file, ehdr, target);
+}
+
+}  // End of anonymous namespace.
+
+// Create an Incremental_binary object for FILE. Returns NULL is this is not
+// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE
+// should be opened.
+
+Incremental_binary*
+open_incremental_binary(Output_file* file)
+{
+  off_t filesize = file->filesize();
+  int want = elfcpp::Elf_recognizer::max_header_size;
+  if (filesize < want)
+    want = filesize;
+
+  const unsigned char* p = file->get_input_view(0, want);
+  if (!elfcpp::Elf_recognizer::is_elf_file(p, want))
+    {
+      explain_no_incremental(_("output is not an ELF file."));
+      return NULL;
+    }
+
+  int size;
+  bool big_endian;
+  std::string error;
+  if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian,
+                                               &error))
+    {
+      explain_no_incremental(error.c_str());
+      return NULL;
+    }
+
+  Incremental_binary* result = NULL;
+  if (size == 32)
+    {
+      if (big_endian)
+        {
+#ifdef HAVE_TARGET_32_BIG
+          result = make_sized_incremental_binary<32, true>(
+              file, elfcpp::Ehdr<32, true>(p));
+#else
+          explain_no_incremental(_("unsupported file: 32-bit, big-endian"));
+#endif
+        }
+      else
+        {
+#ifdef HAVE_TARGET_32_LITTLE
+          result = make_sized_incremental_binary<32, false>(
+              file, elfcpp::Ehdr<32, false>(p));
+#else
+          explain_no_incremental(_("unsupported file: 32-bit, little-endian"));
+#endif
+        }
+    }
+  else if (size == 64)
+    {
+      if (big_endian)
+        {
+#ifdef HAVE_TARGET_64_BIG
+          result = make_sized_incremental_binary<64, true>(
+              file, elfcpp::Ehdr<64, true>(p));
+#else
+          explain_no_incremental(_("unsupported file: 64-bit, big-endian"));
+#endif
+        }
+      else
+        {
+#ifdef HAVE_TARGET_64_LITTLE
+          result = make_sized_incremental_binary<64, false>(
+              file, elfcpp::Ehdr<64, false>(p));
+#else
+          explain_no_incremental(_("unsupported file: 64-bit, little-endian"));
+#endif
+        }
+    }
+  else
+    gold_unreachable();
+
+  return result;
+}
+
 // Analyzes the output file to check if incremental linking is possible and
 // (to be done) what files need to be relinked.
 
@@ -159,7 +456,10 @@ Incremental_checker::can_incrementally_link_output_file()
   Output_file output(this->output_name_);
   if (!output.open_for_modification())
     return false;
-  return true;
+  Incremental_binary* binary = open_incremental_binary(&output);
+  if (binary == NULL)
+    return false;
+  return binary->check_inputs(this->incremental_inputs_);
 }
 
 // Add the command line to the string table, setting
@@ -196,7 +496,10 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
         }
       args.append("'");
     }
-  this->strtab_->add(args.c_str(), true, &this->command_line_key_);
+
+  this->command_line_ = args;
+  this->strtab_->add(this->command_line_.c_str(), false,
+                     &this->command_line_key_);
 }
 
 // Record that the input argument INPUT is an achive ARCHIVE.  This is
@@ -392,4 +695,26 @@ Incremental_inputs::sized_create_inputs_section_data()
                                      "** incremental link inputs list");
 }
 
+// Instantiate the templates we need.
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Sized_incremental_binary<32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Sized_incremental_binary<32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Sized_incremental_binary<64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Sized_incremental_binary<64, true>;
+#endif
+
 } // End namespace gold.
index 9650993303259ed1f1a1dec01113517f95152114..b53f6c1cc3c0243b86002b929848c8db346d2056 100644 (file)
 #include <map>
 #include <vector>
 
+#include "elfcpp_file.h"
 #include "stringpool.h"
 #include "workqueue.h"
 #include "fileread.h"
+#include "output.h"
 
 namespace gold
 {
@@ -50,13 +52,150 @@ enum Incremental_input_type
   INCREMENTAL_INPUT_SCRIPT = 4
 };
 
+// An object representing the ELF file we edit during an incremental build.
+// Similar to Object or Dynobj, but operates on Output_file and contains
+// method specific to file edition (TBD). This is the abstract parent class
+// implemented in Sized_incremental_binary<size, big_endian> for a specific
+// endianness and size.
+
+class Incremental_binary
+{
+ public:
+  Incremental_binary(Output_file* output, Target* target)
+    : output_(output), target_(target)
+  { }
+
+  virtual
+  ~Incremental_binary()
+  { }
+
+  // Functions and types for the elfcpp::Elf_file interface.  This
+  // permit us to use Incremental_binary as the File template parameter for
+  // elfcpp::Elf_file.
+
+  // The View class is returned by view.  It must support a single
+  // method, data().  This is trivial, because Output_file::get_output_view
+  // does what we need.
+  class View
+  {
+   public:
+    View(const unsigned char* p)
+      : p_(p)
+    { }
+
+    const unsigned char*
+    data() const
+    { return this->p_; }
+
+   private:
+    const unsigned char* p_;
+  };
+
+  // Return a View.
+  View
+  view(off_t file_offset, section_size_type data_size)
+  { return View(this->output_->get_input_view(file_offset, data_size)); }
+
+  // A location in the file.
+  struct Location
+  {
+    off_t file_offset;
+    off_t data_size;
+
+    Location(off_t fo, section_size_type ds)
+      : file_offset(fo), data_size(ds)
+    { }
+
+    Location()
+      : file_offset(0), data_size(0)
+    { }
+  };
+
+  // Get a View given a Location.
+  View view(Location loc)
+  { return View(this->view(loc.file_offset, loc.data_size)); }
+
+  // Report an error.
+  void
+  error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
+
+  // Find the .gnu_incremental_inputs section.  It selects the first section
+  // of type SHT_GNU_INCREMENTAL_INPUTS.  Returns false if such a section
+  // is not found.
+  bool
+  find_incremental_inputs_section(Location* location,
+                                  unsigned int* strtab_shndx)
+  { return do_find_incremental_inputs_section(location, strtab_shndx); }
+
+  // Check the .gnu_incremental_inputs section to see whether an incremental
+  // build is possible.
+  // TODO: on success, should report what files needs to be rebuilt.
+  // INCREMENTAL_INPUTS is used to read the canonical form of the command line
+  // and read the input arguments.  TODO: for items that don't need to be
+  // rebuilt, we should also copy the incremental input information.
+  virtual bool
+  check_inputs(Incremental_inputs* incremental_inputs)
+  { return do_check_inputs(incremental_inputs); }
+
+ protected:
+  // Find incremental inputs section.
+  virtual bool
+  do_find_incremental_inputs_section(Location* location,
+                                     unsigned int* strtab_shndx) = 0;
+
+  // Check the .gnu_incremental_inputs section to see whether an incremental
+  // build is possible.
+  virtual bool
+  do_check_inputs(Incremental_inputs* incremental_inputs) = 0;
+
+ private:
+  // Edited output file object.
+  Output_file* output_;
+  // Target of the output file.
+  Target* target_;
+};
+
+template<int size, bool big_endian>
+class Sized_incremental_binary : public Incremental_binary
+{
+ public:
+  Sized_incremental_binary(Output_file* output,
+                           const elfcpp::Ehdr<size, big_endian>& ehdr,
+                           Target* target)
+    : Incremental_binary(output, target), elf_file_(this, ehdr)
+  { }
+
+ protected:
+  virtual bool
+  do_find_incremental_inputs_section(Location* location,
+                                     unsigned int* strtab_shndx);
+
+  virtual bool
+  do_check_inputs(Incremental_inputs* incremental_inputs);
+
+ private:
+  // Output as an ELF file.
+  elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file_;
+};
+
+// Create an Incremental_binary object for FILE. Returns NULL is this is not
+// possible, e.g. FILE is not an ELF file or has an unsupported target.
+Incremental_binary*
+open_incremental_binary(Output_file* file);
+
 // Code invoked early during an incremental link that checks what files need
 // to be relinked.
 class Incremental_checker
 {
  public:
-  Incremental_checker(const char* output_name)
-    : output_name_(output_name)
+  // Check if the file named OUTPUT_NAME can be linked incrementally.
+  // INCREMENTAL_INPUTS must have the canonical form of the command line
+  // and input arguments filled - at this point of linking other fields are
+  // probably not filled yet.  TODO: for inputs that don't need to be
+  // rebuilt, this function should fill the incremental input information.
+  Incremental_checker(const char* output_name,
+                      Incremental_inputs* incremental_inputs)
+    : output_name_(output_name), incremental_inputs_(incremental_inputs)
   { }
 
   // Analyzes the output file to check if incremental linking is possible and
@@ -65,7 +204,12 @@ class Incremental_checker
   can_incrementally_link_output_file();
 
  private:
+  // Name of the output file to analyze.
   const char* output_name_;
+
+  // The Incremental_inputs object. At this stage of link, only the command
+  // line and inputs are filled.
+  Incremental_inputs* incremental_inputs_;
 };
 
 // This class contains the information needed during an incremental
@@ -114,6 +258,17 @@ class Incremental_inputs
   get_stringpool()
   { return this->strtab_; }
 
+  // Return the canonical form of the command line, as will be stored in
+  // .gnu_incremental_strtab.
+  const std::string&
+  command_line()
+  { return this->command_line_; }
+
+  // Return the input files found in the command line.
+  const Input_arguments*
+  inputs()
+  { return this->inputs_; }
+
  private:
   // Code for each of the four possible variants of create_inputs_section_data.
   template<int size, bool big_endian>
@@ -176,8 +331,13 @@ class Incremental_inputs
   // A map containing additional information about the input elements.
   Inputs_info_map inputs_map_;
 
+  // Canonical form of the command line, as will be stored in
+  // .gnu_incremental_strtab.
+  std::string command_line_;
+
   // The key of the command line string in the string pool.
   Stringpool::Key command_line_key_;
+
   // The .gnu_incremental_strtab string pool associated with the
   // .gnu_incremental_inputs.
   Stringpool* strtab_;
index 6907295dc0a2af8943c0bd6fb253d8269f919a59..028703ae1cec80a774f157a39c79ea88d4bda1be 100644 (file)
 namespace gold
 {
 
+// Layout::Relaxation_debug_check methods.
+
+// Check that sections and special data are in reset states.
+// We do not save states for Output_sections and special Output_data.
+// So we check that they have not assigned any addresses or offsets.
+// clean_up_after_relaxation simply resets their addresses and offsets.
+void
+Layout::Relaxation_debug_check::check_output_data_for_reset_values(
+    const Layout::Section_list& sections,
+    const Layout::Data_list& special_outputs)
+{
+  for(Layout::Section_list::const_iterator p = sections.begin();
+      p != sections.end();
+      ++p)
+    gold_assert((*p)->address_and_file_offset_have_reset_values());
+
+  for(Layout::Data_list::const_iterator p = special_outputs.begin();
+      p != special_outputs.end();
+      ++p)
+    gold_assert((*p)->address_and_file_offset_have_reset_values());
+}
+  
+// Save information of SECTIONS for checking later.
+
+void
+Layout::Relaxation_debug_check::read_sections(
+    const Layout::Section_list& sections)
+{
+  for(Layout::Section_list::const_iterator p = sections.begin();
+      p != sections.end();
+      ++p)
+    {
+      Output_section* os = *p;
+      Section_info info;
+      info.output_section = os;
+      info.address = os->is_address_valid() ? os->address() : 0;
+      info.data_size = os->is_data_size_valid() ? os->data_size() : -1;
+      info.offset = os->is_offset_valid()? os->offset() : -1 ;
+      this->section_infos_.push_back(info);
+    }
+}
+
+// Verify SECTIONS using previously recorded information.
+
+void
+Layout::Relaxation_debug_check::verify_sections(
+    const Layout::Section_list& sections)
+{
+  size_t i = 0;
+  for(Layout::Section_list::const_iterator p = sections.begin();
+      p != sections.end();
+      ++p, ++i)
+    {
+      Output_section* os = *p;
+      uint64_t address = os->is_address_valid() ? os->address() : 0;
+      off_t data_size = os->is_data_size_valid() ? os->data_size() : -1;
+      off_t offset = os->is_offset_valid()? os->offset() : -1 ;
+
+      if (i >= this->section_infos_.size())
+       {
+         gold_fatal("Section_info of %s missing.\n", os->name());
+       }
+      const Section_info& info = this->section_infos_[i];
+      if (os != info.output_section)
+       gold_fatal("Section order changed.  Expecting %s but see %s\n",
+                  info.output_section->name(), os->name());
+      if (address != info.address
+         || data_size != info.data_size
+         || offset != info.offset)
+       gold_fatal("Section %s changed.\n", os->name());
+    }
+}
+
 // Layout_task_runner methods.
 
 // Lay out the sections.  This is called after all the input objects
@@ -125,7 +198,11 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
     any_postprocessing_sections_(false),
     resized_signatures_(false),
     have_stabstr_section_(false),
-    incremental_inputs_(NULL)
+    incremental_inputs_(NULL),
+    record_output_section_data_from_script_(false),
+    script_output_section_data_list_(),
+    segment_states_(NULL),
+    relaxation_debug_check_(NULL)
 {
   // Make space for more than enough segments for a typical file.
   // This is just for efficiency--it's OK if we wind up needing more.
@@ -793,7 +870,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
         this->debug_info_->set_abbreviations(this->debug_abbrev_);
     }
  else
-    os = new Output_section(name, type, flags);
+    {
+      // FIXME: const_cast is ugly.
+      Target* target = const_cast<Target*>(&parameters->target());
+      os = target->make_output_section(name, type, flags);
+    }
 
   parameters->target().new_output_section(os);
 
@@ -1170,6 +1251,228 @@ Layout::find_first_load_seg()
   return load_seg;
 }
 
+// Save states of all current output segments.  Store saved states
+// in SEGMENT_STATES.
+
+void
+Layout::save_segments(Segment_states* segment_states)
+{
+  for (Segment_list::const_iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    {
+      Output_segment* segment = *p;
+      // Shallow copy.
+      Output_segment* copy = new Output_segment(*segment);
+      (*segment_states)[segment] = copy;
+    }
+}
+
+// Restore states of output segments and delete any segment not found in
+// SEGMENT_STATES.
+
+void
+Layout::restore_segments(const Segment_states* segment_states)
+{
+  // Go through the segment list and remove any segment added in the
+  // relaxation loop.
+  this->tls_segment_ = NULL;
+  this->relro_segment_ = NULL;
+  Segment_list::iterator list_iter = this->segment_list_.begin();
+  while (list_iter != this->segment_list_.end())
+    {
+      Output_segment* segment = *list_iter;
+      Segment_states::const_iterator states_iter =
+         segment_states->find(segment);
+      if (states_iter != segment_states->end())
+       {
+         const Output_segment* copy = states_iter->second;
+         // Shallow copy to restore states.
+         *segment = *copy;
+
+         // Also fix up TLS and RELRO segment pointers as appropriate.
+         if (segment->type() == elfcpp::PT_TLS)
+           this->tls_segment_ = segment;
+         else if (segment->type() == elfcpp::PT_GNU_RELRO)
+           this->relro_segment_ = segment;
+
+         ++list_iter;
+       } 
+      else
+       {
+         list_iter = this->segment_list_.erase(list_iter); 
+         // This is a segment created during section layout.  It should be
+         // safe to remove it since we should have removed all pointers to it.
+         delete segment;
+       }
+    }
+}
+
+// Clean up after relaxation so that sections can be laid out again.
+
+void
+Layout::clean_up_after_relaxation()
+{
+  // Restore the segments to point state just prior to the relaxation loop.
+  Script_sections* script_section = this->script_options_->script_sections();
+  script_section->release_segments();
+  this->restore_segments(this->segment_states_);
+
+  // Reset section addresses and file offsets
+  for (Section_list::iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      (*p)->reset_address_and_file_offset();
+      (*p)->restore_states();
+    }
+  
+  // Reset special output object address and file offsets.
+  for (Data_list::iterator p = this->special_output_list_.begin();
+       p != this->special_output_list_.end();
+       ++p)
+    (*p)->reset_address_and_file_offset();
+
+  // A linker script may have created some output section data objects.
+  // They are useless now.
+  for (Output_section_data_list::const_iterator p =
+        this->script_output_section_data_list_.begin();
+       p != this->script_output_section_data_list_.end();
+       ++p)
+    delete *p;
+  this->script_output_section_data_list_.clear(); 
+}
+
+// Prepare for relaxation.
+
+void
+Layout::prepare_for_relaxation()
+{
+  // Create an relaxation debug check if in debugging mode.
+  if (is_debugging_enabled(DEBUG_RELAXATION))
+    this->relaxation_debug_check_ = new Relaxation_debug_check();
+
+  // Save segment states.
+  this->segment_states_ = new Segment_states();
+  this->save_segments(this->segment_states_);
+
+  for(Section_list::const_iterator p = this->section_list_.begin();
+      p != this->section_list_.end();
+      ++p)
+    (*p)->save_states();
+
+  if (is_debugging_enabled(DEBUG_RELAXATION))
+    this->relaxation_debug_check_->check_output_data_for_reset_values(
+        this->section_list_, this->special_output_list_);
+
+  // Also enable recording of output section data from scripts.
+  this->record_output_section_data_from_script_ = true;
+}
+
+// Relaxation loop body:  If target has no relaxation, this runs only once
+// Otherwise, the target relaxation hook is called at the end of
+// each iteration.  If the hook returns true, it means re-layout of
+// section is required.  
+//
+// The number of segments created by a linking script without a PHDRS
+// clause may be affected by section sizes and alignments.  There is
+// a remote chance that relaxation causes different number of PT_LOAD
+// segments are created and sections are attached to different segments.
+// Therefore, we always throw away all segments created during section
+// layout.  In order to be able to restart the section layout, we keep
+// a copy of the segment list right before the relaxation loop and use
+// that to restore the segments.
+// 
+// PASS is the current relaxation pass number. 
+// SYMTAB is a symbol table.
+// PLOAD_SEG is the address of a pointer for the load segment.
+// PHDR_SEG is a pointer to the PHDR segment.
+// SEGMENT_HEADERS points to the output segment header.
+// FILE_HEADER points to the output file header.
+// PSHNDX is the address to store the output section index.
+
+off_t inline
+Layout::relaxation_loop_body(
+    int pass,
+    Target* target,
+    Symbol_table* symtab,
+    Output_segment** pload_seg,
+    Output_segment* phdr_seg,
+    Output_segment_headers* segment_headers,
+    Output_file_header* file_header,
+    unsigned int* pshndx)
+{
+  // If this is not the first iteration, we need to clean up after
+  // relaxation so that we can lay out the sections again.
+  if (pass != 0)
+    this->clean_up_after_relaxation();
+
+  // If there is a SECTIONS clause, put all the input sections into
+  // the required order.
+  Output_segment* load_seg;
+  if (this->script_options_->saw_sections_clause())
+    load_seg = this->set_section_addresses_from_script(symtab);
+  else if (parameters->options().relocatable())
+    load_seg = NULL;
+  else
+    load_seg = this->find_first_load_seg();
+
+  if (parameters->options().oformat_enum()
+      != General_options::OBJECT_FORMAT_ELF)
+    load_seg = NULL;
+
+  gold_assert(phdr_seg == NULL
+             || load_seg != NULL
+             || this->script_options_->saw_sections_clause());
+
+  // Lay out the segment headers.
+  if (!parameters->options().relocatable())
+    {
+      gold_assert(segment_headers != NULL);
+      if (load_seg != NULL)
+        load_seg->add_initial_output_data(segment_headers);
+      if (phdr_seg != NULL)
+        phdr_seg->add_initial_output_data(segment_headers);
+    }
+
+  // Lay out the file header.
+  if (load_seg != NULL)
+    load_seg->add_initial_output_data(file_header);
+
+  if (this->script_options_->saw_phdrs_clause()
+      && !parameters->options().relocatable())
+    {
+      // Support use of FILEHDRS and PHDRS attachments in a PHDRS
+      // clause in a linker script.
+      Script_sections* ss = this->script_options_->script_sections();
+      ss->put_headers_in_phdrs(file_header, segment_headers);
+    }
+
+  // We set the output section indexes in set_segment_offsets and
+  // set_section_indexes.
+  *pshndx = 1;
+
+  // Set the file offsets of all the segments, and all the sections
+  // they contain.
+  off_t off;
+  if (!parameters->options().relocatable())
+    off = this->set_segment_offsets(target, load_seg, pshndx);
+  else
+    off = this->set_relocatable_section_offsets(file_header, pshndx);
+
+   // Verify that the dummy relaxation does not change anything.
+  if (is_debugging_enabled(DEBUG_RELAXATION))
+    {
+      if (pass == 0)
+       this->relaxation_debug_check_->read_sections(this->section_list_);
+      else
+       this->relaxation_debug_check_->verify_sections(this->section_list_);
+    }
+
+  *pload_seg = load_seg;
+  return off;
+}
+
 // Finalize the layout.  When this is called, we have created all the
 // output sections and all the output segments which are based on
 // input sections.  We have several things to do, and we have to do
@@ -1258,66 +1561,45 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
       this->create_incremental_info_sections();
     }
 
-  // If there is a SECTIONS clause, put all the input sections into
-  // the required order.
-  Output_segment* load_seg;
-  if (this->script_options_->saw_sections_clause())
-    load_seg = this->set_section_addresses_from_script(symtab);
-  else if (parameters->options().relocatable())
-    load_seg = NULL;
-  else
-    load_seg = this->find_first_load_seg();
-
-  if (parameters->options().oformat_enum()
-      != General_options::OBJECT_FORMAT_ELF)
-    load_seg = NULL;
-
-  gold_assert(phdr_seg == NULL || load_seg != NULL);
-
-  // Lay out the segment headers.
-  Output_segment_headers* segment_headers;
-  if (parameters->options().relocatable())
-    segment_headers = NULL;
-  else
-    {
-      segment_headers = new Output_segment_headers(this->segment_list_);
-      if (load_seg != NULL)
-       load_seg->add_initial_output_data(segment_headers);
-      if (phdr_seg != NULL)
-       phdr_seg->add_initial_output_data(segment_headers);
-    }
+  // Create segment headers.
+  Output_segment_headers* segment_headers =
+    (parameters->options().relocatable()
+     ? NULL
+     : new Output_segment_headers(this->segment_list_));
 
   // Lay out the file header.
-  Output_file_header* file_header;
-  file_header = new Output_file_header(target, symtab, segment_headers,
-                                      parameters->options().entry());
-  if (load_seg != NULL)
-    load_seg->add_initial_output_data(file_header);
+  Output_file_header* file_header
+    = new Output_file_header(target, symtab, segment_headers,
+                            parameters->options().entry());
 
   this->special_output_list_.push_back(file_header);
   if (segment_headers != NULL)
     this->special_output_list_.push_back(segment_headers);
 
-  if (this->script_options_->saw_phdrs_clause()
-      && !parameters->options().relocatable())
+  // Find approriate places for orphan output sections if we are using
+  // a linker script.
+  if (this->script_options_->saw_sections_clause())
+    this->place_orphan_sections_in_script();
+  
+  Output_segment* load_seg;
+  off_t off;
+  unsigned int shndx;
+  int pass = 0;
+
+  // Take a snapshot of the section layout as needed.
+  if (target->may_relax())
+    this->prepare_for_relaxation();
+  
+  // Run the relaxation loop to lay out sections.
+  do
     {
-      // Support use of FILEHDRS and PHDRS attachments in a PHDRS
-      // clause in a linker script.
-      Script_sections* ss = this->script_options_->script_sections();
-      ss->put_headers_in_phdrs(file_header, segment_headers);
+      off = this->relaxation_loop_body(pass, target, symtab, &load_seg,
+                                      phdr_seg, segment_headers, file_header,
+                                      &shndx);
+      pass++;
     }
-
-  // We set the output section indexes in set_segment_offsets and
-  // set_section_indexes.
-  unsigned int shndx = 1;
-
-  // Set the file offsets of all the segments, and all the sections
-  // they contain.
-  off_t off;
-  if (!parameters->options().relocatable())
-    off = this->set_segment_offsets(target, load_seg, &shndx);
-  else
-    off = this->set_relocatable_section_offsets(file_header, &shndx);
+  while (target->may_relax()
+        && target->relax(pass, input_objects, symtab, this));
 
   // Set the file offsets of all the non-data sections we've seen so
   // far which don't have to wait for the input sections.  We need
@@ -1864,7 +2146,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
   uint64_t addr;
   if (parameters->options().user_set_Ttext())
     addr = parameters->options().Ttext();
-  else if (parameters->options().shared())
+  else if (parameters->options().output_is_position_independent())
     addr = 0;
   else
     addr = target->default_text_segment_address();
@@ -1957,6 +2239,19 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
          if (!parameters->options().nmagic()
              && !parameters->options().omagic())
            off = align_file_offset(off, addr, abi_pagesize);
+         else if (load_seg == NULL)
+           {
+             // This is -N or -n with a section script which prevents
+             // us from using a load segment.  We need to ensure that
+             // the file offset is aligned to the alignment of the
+             // segment.  This is because the linker script
+             // implicitly assumed a zero offset.  If we don't align
+             // here, then the alignment of the sections in the
+             // linker script may not match the alignment of the
+             // sections in the set_section_addresses call below,
+             // causing an error about dot moving backward.
+             off = align_address(off, (*p)->maximum_alignment());
+           }
 
          unsigned int shndx_hold = *pshndx;
          uint64_t new_addr = (*p)->set_section_addresses(this, false, addr,
@@ -2148,6 +2443,16 @@ Layout::set_section_indexes(unsigned int shndx)
 
 Output_segment*
 Layout::set_section_addresses_from_script(Symbol_table* symtab)
+{
+  Script_sections* ss = this->script_options_->script_sections();
+  gold_assert(ss->saw_sections_clause());
+  return this->script_options_->set_section_addresses(symtab, this);
+}
+
+// Place the orphan sections in the linker script.
+
+void
+Layout::place_orphan_sections_in_script()
 {
   Script_sections* ss = this->script_options_->script_sections();
   gold_assert(ss->saw_sections_clause());
@@ -2160,8 +2465,6 @@ Layout::set_section_addresses_from_script(Symbol_table* symtab)
       if (!(*p)->found_in_sections_clause())
        ss->place_orphan(*p);
     }
-
-  return this->script_options_->set_section_addresses(symtab, this);
 }
 
 // Count the local symbols in the regular symbol table and the dynamic
@@ -2259,7 +2562,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
     }
 
   unsigned int local_symcount = local_symbol_index;
-  gold_assert(local_symcount * symsize == off - startoff);
+  gold_assert(static_cast<off_t>(local_symcount * symsize) == off - startoff);
 
   off_t dynoff;
   size_t dyn_global_index;
@@ -2808,17 +3111,37 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
        odyn->add_string(elfcpp::DT_SONAME, soname);
     }
 
-  // FIXME: Support --init and --fini.
-  Symbol* sym = symtab->lookup("_init");
+  Symbol* sym = symtab->lookup(parameters->options().init());
   if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
     odyn->add_symbol(elfcpp::DT_INIT, sym);
 
-  sym = symtab->lookup("_fini");
+  sym = symtab->lookup(parameters->options().fini());
   if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj())
     odyn->add_symbol(elfcpp::DT_FINI, sym);
 
-  // FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
-
+  // Look for .init_array, .preinit_array and .fini_array by checking
+  // section types.
+  for(Layout::Section_list::const_iterator p = this->section_list_.begin();
+      p != this->section_list_.end();
+      ++p)
+    switch((*p)->type())
+      {
+      case elfcpp::SHT_FINI_ARRAY:
+       odyn->add_section_address(elfcpp::DT_FINI_ARRAY, *p);
+       odyn->add_section_size(elfcpp::DT_FINI_ARRAYSZ, *p); 
+       break;
+      case elfcpp::SHT_INIT_ARRAY:
+       odyn->add_section_address(elfcpp::DT_INIT_ARRAY, *p);
+       odyn->add_section_size(elfcpp::DT_INIT_ARRAYSZ, *p); 
+       break;
+      case elfcpp::SHT_PREINIT_ARRAY:
+       odyn->add_section_address(elfcpp::DT_PREINIT_ARRAY, *p);
+       odyn->add_section_size(elfcpp::DT_PREINIT_ARRAYSZ, *p); 
+       break;
+      default:
+       break;
+      }
+  
   // Add a DT_RPATH entry if needed.
   const General_options::Dir_list& rpath(parameters->options().rpath());
   if (!rpath.empty())
@@ -2899,6 +3222,12 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
     flags |= elfcpp::DF_STATIC_TLS;
   if (parameters->options().origin())
     flags |= elfcpp::DF_ORIGIN;
+  if (parameters->options().Bsymbolic())
+    {
+      flags |= elfcpp::DF_SYMBOLIC;
+      // Add DT_SYMBOLIC for compatibility with older loaders.
+      odyn->add_constant(elfcpp::DT_SYMBOLIC, 0);
+    }
   if (parameters->options().now())
     flags |= elfcpp::DF_BIND_NOW;
   odyn->add_constant(elfcpp::DT_FLAGS, flags);
index 0affa81caa25cc51448f17637b208802110c3215..675c65813b8bd0b4aa9b91ddaf9f2ba3acc7c2b6 100644 (file)
@@ -47,6 +47,8 @@ class Symbol_table;
 class Output_section_data;
 class Output_section;
 class Output_section_headers;
+class Output_segment_headers;
+class Output_file_header;
 class Output_segment;
 class Output_data;
 class Output_data_dynamic;
@@ -286,6 +288,12 @@ class Layout
  public:
   Layout(int number_of_input_files, Script_options*);
 
+  ~Layout()
+  {
+    delete this->relaxation_debug_check_;
+    delete this->segment_states_;
+  }
+
   // Given an input section SHNDX, named NAME, with data in SHDR, from
   // the object file OBJECT, return the output section where this
   // input section should go.  RELOC_SHNDX is the index of a
@@ -585,6 +593,20 @@ class Layout
   void
   attach_sections_to_segments();
 
+  // For relaxation clean up, we need to know output section data created
+  // from a linker script.
+  void
+  new_output_section_data_from_script(Output_section_data* posd)
+  {
+    if (this->record_output_section_data_from_script_)
+      this->script_output_section_data_list_.push_back(posd);
+  }
+
+  // Return section list.
+  const Section_list&
+  section_list() const
+  { return this->section_list_; }
+
  private:
   Layout(const Layout&);
   Layout& operator=(const Layout&);
@@ -777,10 +799,42 @@ class Layout
   Output_segment*
   set_section_addresses_from_script(Symbol_table*);
 
+  // Find appropriate places or orphan sections in a script.
+  void
+  place_orphan_sections_in_script();
+
   // Return whether SEG1 comes before SEG2 in the output file.
   static bool
   segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
 
+  // Use to save and restore segments during relaxation. 
+  typedef Unordered_map<const Output_segment*, const Output_segment*>
+    Segment_states;
+
+  // Save states of current output segments.
+  void
+  save_segments(Segment_states*);
+
+  // Restore output segment states.
+  void
+  restore_segments(const Segment_states*);
+
+  // Clean up after relaxation so that it is possible to lay out the
+  // sections and segments again.
+  void
+  clean_up_after_relaxation();
+
+  // Doing preparation work for relaxation.  This is factored out to make
+  // Layout::finalized a bit smaller and easier to read.
+  void
+  prepare_for_relaxation();
+
+  // Main body of the relaxation loop, which lays out the section.
+  off_t
+  relaxation_loop_body(int, Target*, Symbol_table*, Output_segment**,
+                      Output_segment*, Output_segment_headers*,
+                      Output_file_header*, unsigned int*);
+
   // A mapping used for kept comdats/.gnu.linkonce group signatures.
   typedef Unordered_map<std::string, Kept_section> Signatures;
 
@@ -807,6 +861,47 @@ class Layout
     { return Layout::segment_precedes(seg1, seg2); }
   };
 
+  typedef std::vector<Output_section_data*> Output_section_data_list;
+
+  // Debug checker class.
+  class Relaxation_debug_check
+  {
+   public:
+    Relaxation_debug_check()
+      : section_infos_()
+    { }
+    // Check that sections and special data are in reset states.
+    void
+    check_output_data_for_reset_values(const Layout::Section_list&,
+                                      const Layout::Data_list&);
+  
+    // Record information of a section list.
+    void
+    read_sections(const Layout::Section_list&);
+
+    // Verify a section list with recorded information.
+    void
+    verify_sections(const Layout::Section_list&);
+   private:
+    // Information we care about a section.
+    struct Section_info
+    {
+      // Output section described by this.
+      Output_section* output_section;
+      // Load address.
+      uint64_t address;
+      // Data size.
+      off_t data_size;
+      // File offset.
+      off_t offset;
+    };
+
+    // Section information.
+    std::vector<Section_info> section_infos_;
+  };
+
   // The number of input files, for sizing tables.
   int number_of_input_files_;
   // Information set by scripts or by command line options.
@@ -889,6 +984,14 @@ class Layout
   // In incremental build, holds information check the inputs and build the
   // .gnu_incremental_inputs section.
   Incremental_inputs* incremental_inputs_;
+  // Whether we record output section data created in script
+  bool record_output_section_data_from_script_;
+  // List of output data that needs to be removed at relexation clean up.
+  Output_section_data_list script_output_section_data_list_;
+  // Structure to save segment states before entering the relaxation loop.
+  Segment_states* segment_states_;
+  // A relaxation debug checker.  We only create one when in debugging mode.
+  Relaxation_debug_check* relaxation_debug_check_;
 };
 
 // This task handles writing out data in output sections which is not
index d8ef582ec0856c9fa884a628e79001e041faf4e2..66e8b244318fee8cf0ff4a1964bc88b4d4a3a454 100644 (file)
@@ -220,7 +220,7 @@ main(int argc, char** argv)
   if (parameters->options().gc_sections())
     symtab.set_gc(&gc);
 
-  if (parameters->options().icf())
+  if (parameters->options().icf_enabled())
     symtab.set_icf(&icf);
 
   // The layout object.
index fb6721d2925da70c63a5f5e2f1c785af8fec1cb6..345b1154ebe17e6b95e847867222675b6ee46e0f 100644 (file)
@@ -219,6 +219,17 @@ class Output_merge_base : public Output_section_data
     : Output_section_data(addralign), merge_map_(), entsize_(entsize)
   { }
 
+  // Return the entry size.
+  uint64_t
+  entsize() const
+  { return this->entsize_; }
+
+  // Whether this is a merge string section.  This is only true of
+  // Output_merge_string.
+  bool
+  is_string()
+  { return this->do_is_string(); }
+
  protected:
   // Return the output offset for an input offset.
   bool
@@ -230,11 +241,6 @@ class Output_merge_base : public Output_section_data
   bool
   do_is_merge_section_for(const Relobj*, unsigned int shndx) const;
 
-  // Return the entry size.
-  uint64_t
-  entsize() const
-  { return this->entsize_; }
-
   // Add a mapping from an OFFSET in input section SHNDX in object
   // OBJECT to an OUTPUT_OFFSET in the output section.  OUTPUT_OFFSET
   // is the offset from the start of the merged data in the output
@@ -246,6 +252,11 @@ class Output_merge_base : public Output_section_data
     this->merge_map_.add_mapping(object, shndx, offset, length, output_offset);
   }
 
+  // This may be overriden by the child class.
+  virtual bool
+  do_is_string()
+  { return false; }
+
  private:
   // A mapping from input object/section/offset to offset in output
   // section.
@@ -424,6 +435,11 @@ class Output_merge_string : public Output_merge_base
   clear_stringpool()
   { this->stringpool_.clear(); }
 
+  // Whether this is a merge string section.
+  virtual bool
+  do_is_string()
+  { return true; }
+
  private:
   // The name of the string type, for stats.
   const char*
index be6294c31fd579a07c21d6cb5c40da8c45fe63ac..e9826b08a206a60ea335435bf3724b1e06f88e7a 100644 (file)
@@ -231,6 +231,25 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
   return false;
 }
 
+// If NAME is the name of the special section which indicates that
+// this object was compiled with -fstack-split, mark it accordingly.
+
+bool
+Object::handle_split_stack_section(const char* name)
+{
+  if (strcmp(name, ".note.GNU-split-stack") == 0)
+    {
+      this->uses_split_stack_ = true;
+      return true;
+    }
+  if (strcmp(name, ".note.GNU-no-split-stack") == 0)
+    {
+      this->has_no_split_stack_ = true;
+      return true;
+    }
+  return false;
+}
+
 // Class Relobj
 
 // To copy the symbols data read from the file to a local data structure.
@@ -336,14 +355,12 @@ Sized_relobj<size, big_endian>::~Sized_relobj()
 }
 
 // Set up an object file based on the file header.  This sets up the
-// target and reads the section information.
+// section information.
 
 template<int size, bool big_endian>
 void
-Sized_relobj<size, big_endian>::setup(Target *target)
+Sized_relobj<size, big_endian>::do_setup()
 {
-  this->set_target(target);
-
   const unsigned int shnum = this->elf_file_.shnum();
   this->set_shnum(shnum);
 }
@@ -917,16 +934,16 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
   const unsigned int shnum = this->shnum();
   bool is_gc_pass_one = ((parameters->options().gc_sections() 
                           && !symtab->gc()->is_worklist_ready())
-                         || (parameters->options().icf()
+                         || (parameters->options().icf_enabled()
                              && !symtab->icf()->is_icf_ready()));
  
   bool is_gc_pass_two = ((parameters->options().gc_sections() 
                           && symtab->gc()->is_worklist_ready())
-                         || (parameters->options().icf()
+                         || (parameters->options().icf_enabled()
                              && symtab->icf()->is_icf_ready()));
 
   bool is_gc_or_icf = (parameters->options().gc_sections()
-                       || parameters->options().icf()); 
+                       || parameters->options().icf_enabled()); 
 
   // Both is_gc_pass_one and is_gc_pass_two should not be true.
   gold_assert(!(is_gc_pass_one  && is_gc_pass_two));
@@ -1111,6 +1128,16 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
              omit[i] = true;
             }
 
+         // The .note.GNU-split-stack section is also special.  It
+         // indicates that the object was compiled with
+         // -fsplit-stack.
+         if (this->handle_split_stack_section(name))
+           {
+             if (!parameters->options().relocatable()
+                 && !parameters->options().shared())
+               omit[i] = true;
+           }
+
           bool discard = omit[i];
           if (!discard)
             {
@@ -1211,7 +1238,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
               }
         }
 
-      if (is_gc_pass_two && parameters->options().icf())
+      if (is_gc_pass_two && parameters->options().icf_enabled())
         {
           if (out_sections[i] == NULL)
             {
@@ -1562,6 +1589,14 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
          continue;
        }
 
+      // Discard the local symbol if -retain_symbols_file is specified
+      // and the local symbol is not in that file.
+      if (!parameters->options().should_retain_symbol(name))
+        {
+          lv.set_no_output_symtab_entry();
+          continue;
+        }
+
       // Add the symbol to the symbol table string pool.
       pool->add(name, true, NULL);
       ++count;
@@ -2059,16 +2094,6 @@ Sized_relobj<size, big_endian>::do_get_global_symbol_counts(
 bool
 Input_objects::add_object(Object* obj)
 {
-  // Set the global target from the first object file we recognize.
-  Target* target = obj->target();
-  if (!parameters->target_valid())
-    set_parameters_target(target);
-  else if (target != &parameters->target())
-    {
-      obj->error(_("incompatible target"));
-      return false;
-    }
-
   // Print the filename if the -t/--trace option is selected.
   if (parameters->options().trace())
     gold_info("%s", obj->name().c_str());
@@ -2219,7 +2244,8 @@ using namespace gold;
 template<int size, bool big_endian>
 Object*
 make_elf_sized_object(const std::string& name, Input_file* input_file,
-                     off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
+                     off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr,
+                     bool* punconfigured)
 {
   Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
                                 ehdr.get_e_ident()[elfcpp::EI_OSABI],
@@ -2227,6 +2253,18 @@ make_elf_sized_object(const std::string& name, Input_file* input_file,
   if (target == NULL)
     gold_fatal(_("%s: unsupported ELF machine number %d"),
               name.c_str(), ehdr.get_e_machine());
+
+  if (!parameters->target_valid())
+    set_parameters_target(target);
+  else if (target != &parameters->target())
+    {
+      if (punconfigured != NULL)
+       *punconfigured = true;
+      else
+       gold_error(_("%s: incompatible target"), name.c_str());
+      return NULL;
+    }
+
   return target->make_elf_object<size, big_endian>(name, input_file, offset,
                                                   ehdr);
 }
@@ -2243,7 +2281,7 @@ is_elf_object(Input_file* input_file, off_t offset,
              const unsigned char** start, int *read_size)
 {
   off_t filesize = input_file->file().filesize();
-  int want = elfcpp::Elf_sizes<64>::ehdr_size;
+  int want = elfcpp::Elf_recognizer::max_header_size;
   if (filesize - offset < want)
     want = filesize - offset;
 
@@ -2252,15 +2290,7 @@ is_elf_object(Input_file* input_file, off_t offset,
   *start = p;
   *read_size = want;
 
-  if (want < 4)
-    return false;
-
-  static unsigned char elfmagic[4] =
-    {
-      elfcpp::ELFMAG0, elfcpp::ELFMAG1,
-      elfcpp::ELFMAG2, elfcpp::ELFMAG3
-    };
-  return memcmp(p, elfmagic, 4) == 0;
+  return elfcpp::Elf_recognizer::is_elf_file(p, want);
 }
 
 // Read an ELF file and return the appropriate instance of Object.
@@ -2273,63 +2303,24 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
   if (punconfigured != NULL)
     *punconfigured = false;
 
-  if (bytes < elfcpp::EI_NIDENT)
-    {
-      gold_error(_("%s: ELF file too short"), name.c_str());
-      return NULL;
-    }
-
-  int v = p[elfcpp::EI_VERSION];
-  if (v != elfcpp::EV_CURRENT)
-    {
-      if (v == elfcpp::EV_NONE)
-       gold_error(_("%s: invalid ELF version 0"), name.c_str());
-      else
-       gold_error(_("%s: unsupported ELF version %d"), name.c_str(), v);
-      return NULL;
-    }
-
-  int c = p[elfcpp::EI_CLASS];
-  if (c == elfcpp::ELFCLASSNONE)
-    {
-      gold_error(_("%s: invalid ELF class 0"), name.c_str());
-      return NULL;
-    }
-  else if (c != elfcpp::ELFCLASS32
-          && c != elfcpp::ELFCLASS64)
+  std::string error;
+  bool big_endian;
+  int size;
+  if (!elfcpp::Elf_recognizer::is_valid_header(p, bytes, &size,
+                                               &big_endian, &error))
     {
-      gold_error(_("%s: unsupported ELF class %d"), name.c_str(), c);
+      gold_error(_("%s: %s"), name.c_str(), error.c_str());
       return NULL;
     }
 
-  int d = p[elfcpp::EI_DATA];
-  if (d == elfcpp::ELFDATANONE)
+  if (size == 32)
     {
-      gold_error(_("%s: invalid ELF data encoding"), name.c_str());
-      return NULL;
-    }
-  else if (d != elfcpp::ELFDATA2LSB
-          && d != elfcpp::ELFDATA2MSB)
-    {
-      gold_error(_("%s: unsupported ELF data encoding %d"), name.c_str(), d);
-      return NULL;
-    }
-
-  bool big_endian = d == elfcpp::ELFDATA2MSB;
-
-  if (c == elfcpp::ELFCLASS32)
-    {
-      if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
-       {
-         gold_error(_("%s: ELF file too short"), name.c_str());
-         return NULL;
-       }
       if (big_endian)
        {
 #ifdef HAVE_TARGET_32_BIG
          elfcpp::Ehdr<32, true> ehdr(p);
          return make_elf_sized_object<32, true>(name, input_file,
-                                                offset, ehdr);
+                                                offset, ehdr, punconfigured);
 #else
          if (punconfigured != NULL)
            *punconfigured = true;
@@ -2345,7 +2336,7 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
 #ifdef HAVE_TARGET_32_LITTLE
          elfcpp::Ehdr<32, false> ehdr(p);
          return make_elf_sized_object<32, false>(name, input_file,
-                                                 offset, ehdr);
+                                                 offset, ehdr, punconfigured);
 #else
          if (punconfigured != NULL)
            *punconfigured = true;
@@ -2357,19 +2348,14 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
 #endif
        }
     }
-  else
+  else if (size == 64)
     {
-      if (bytes < elfcpp::Elf_sizes<64>::ehdr_size)
-       {
-         gold_error(_("%s: ELF file too short"), name.c_str());
-         return NULL;
-       }
       if (big_endian)
        {
 #ifdef HAVE_TARGET_64_BIG
          elfcpp::Ehdr<64, true> ehdr(p);
          return make_elf_sized_object<64, true>(name, input_file,
-                                                offset, ehdr);
+                                                offset, ehdr, punconfigured);
 #else
          if (punconfigured != NULL)
            *punconfigured = true;
@@ -2385,7 +2371,7 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
 #ifdef HAVE_TARGET_64_LITTLE
          elfcpp::Ehdr<64, false> ehdr(p);
          return make_elf_sized_object<64, false>(name, input_file,
-                                                 offset, ehdr);
+                                                 offset, ehdr, punconfigured);
 #else
          if (punconfigured != NULL)
            *punconfigured = true;
@@ -2397,6 +2383,8 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
 #endif
        }
     }
+  else
+    gold_unreachable();
 }
 
 // Instantiate the templates we need.
index 439431819469b7bc54d7a235be52e407039ee3ed..ff9668291f714c2367203fffaeacd8d317f7f530 100644 (file)
@@ -195,7 +195,8 @@ 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), xindex_(NULL), no_export_(false)
+      is_dynamic_(is_dynamic), uses_split_stack_(false),
+      has_no_split_stack_(false), xindex_(NULL), no_export_(false)
   { input_file->file().add_object(); }
 
   virtual ~Object()
@@ -216,17 +217,23 @@ class Object
   is_dynamic() const
   { return this->is_dynamic_; }
 
+  // Return whether this object was compiled with -fsplit-stack.
+  bool
+  uses_split_stack() const
+  { return this->uses_split_stack_; }
+
+  // Return whether this object contains any functions compiled with
+  // the no_split_stack attribute.
+  bool
+  has_no_split_stack() const
+  { return this->has_no_split_stack_; }
+
   // Returns NULL for Objects that are not plugin objects.  This method
   // is overridden in the Pluginobj class.
   Pluginobj*
   pluginobj()
   { return this->do_pluginobj(); }
 
-  // Return the target structure associated with this object.
-  Target*
-  target() const
-  { return this->target_; }
-
   // Get the file.  We pass on const-ness.
   Input_file*
   input_file()
@@ -266,13 +273,6 @@ class Object
   just_symbols() const
   { return this->input_file()->just_symbols(); }
 
-  // Return the sized target structure associated with this object.
-  // This is like the target method but it returns a pointer of
-  // appropriate checked type.
-  template<int size, bool big_endian>
-  Sized_target<size, big_endian>*
-  sized_target() const;
-
   // Get the number of sections.
   unsigned int
   shnum() const
@@ -453,11 +453,6 @@ class Object
                           size_t* used) const
   { this->do_get_global_symbol_counts(symtab, defined, used); }
 
-  // Set the target.
-  void
-  set_target(Target* target)
-  { this->target_ = target; }
-
   // Return whether this object was found in a system directory.
   bool
   is_in_system_directory() const
@@ -573,6 +568,12 @@ class Object
   handle_gnu_warning_section(const char* name, unsigned int shndx,
                             Symbol_table*);
 
+  // If NAME is the name of the special section which indicates that
+  // this object was compiled with -fstack-split, mark it accordingly,
+  // and return true.  Otherwise return false.
+  bool
+  handle_split_stack_section(const char* name);
+
  private:
   // This class may not be copied.
   Object(const Object&);
@@ -589,8 +590,11 @@ class Object
   unsigned int shnum_;
   // Whether this is a dynamic object.
   bool is_dynamic_;
-  // Target functions--may be NULL if the target is not known.
-  Target* target_;
+  // Whether this object was compiled with -fsplit-stack.
+  bool uses_split_stack_;
+  // Whether this object contains any functions compiled with the
+  // no_split_stack attribute.
+  bool has_no_split_stack_;
   // Many sections for objects with more than SHN_LORESERVE sections.
   Xindex* xindex_;
   // True if exclude this object from automatic symbol export.
@@ -598,18 +602,6 @@ class Object
   bool no_export_;
 };
 
-// Implement sized_target inline for efficiency.  This approach breaks
-// static type checking, but is made safe using asserts.
-
-template<int size, bool big_endian>
-inline Sized_target<size, big_endian>*
-Object::sized_target() const
-{
-  gold_assert(this->target_->get_size() == size);
-  gold_assert(this->target_->is_big_endian() ? big_endian : !big_endian);
-  return static_cast<Sized_target<size, big_endian>*>(this->target_);
-}
-
 // A regular object (ET_REL).  This is an abstract base class itself.
 // The implementation is the template class Sized_relobj.
 
@@ -1283,6 +1275,30 @@ class Got_offset_list
   Got_offset_list* got_next_;
 };
 
+// This type is used to modify relocations for -fsplit-stack.  It is
+// indexed by relocation index, and means that the relocation at that
+// index should use the symbol from the vector, rather than the one
+// indicated by the relocation.
+
+class Reloc_symbol_changes
+{
+ public:
+  Reloc_symbol_changes(size_t count)
+    : vec_(count, NULL)
+  { }
+
+  void
+  set(size_t i, Symbol* sym)
+  { this->vec_[i] = sym; }
+
+  const Symbol*
+  operator[](size_t i) const
+  { return this->vec_[i]; }
+
+ private:
+  std::vector<Symbol*> vec_;
+};
+
 // A regular object file.  This is size and endian specific.
 
 template<int size, bool big_endian>
@@ -1308,7 +1324,8 @@ class Sized_relobj : public Relobj
 
   // Set up the object file based on TARGET.
   void
-  setup(Target *target);
+  setup()
+  { this->do_setup(); }
 
   // Return the number of symbols.  This is only valid after
   // Object::add_symbols has been called.
@@ -1373,11 +1390,6 @@ class Sized_relobj : public Relobj
     return this->local_values_[sym].input_shndx(is_ordinary);
   }
 
-  // Return the appropriate Sized_target structure.
-  Sized_target<size, big_endian>*
-  sized_target()
-  { return this->Object::sized_target<size, big_endian>(); }
-
   // Record that local symbol SYM needs a dynamic symbol entry.
   void
   set_needs_output_dynsym_entry(unsigned int sym)
@@ -1451,7 +1463,16 @@ class Sized_relobj : public Relobj
   Address
   map_to_kept_section(unsigned int shndx, bool* found) const;
 
+  // Make section offset invalid.  This is needed for relaxation.
+  void
+  invalidate_section_offset(unsigned int shndx)
+  { this->do_invalidate_section_offset(shndx); }
+
  protected:
+  // Set up.
+  virtual void
+  do_setup();
+
   // Read the symbols.
   void
   do_read_symbols(Read_symbols_data*);
@@ -1585,6 +1606,48 @@ class Sized_relobj : public Relobj
     this->section_offsets_[shndx] = convert_types<Address, uint64_t>(off);
   }
 
+  // Set the offset of a section to invalid_address.
+  virtual void
+  do_invalidate_section_offset(unsigned int shndx)
+  {
+    gold_assert(shndx < this->section_offsets_.size());
+    this->section_offsets_[shndx] = invalid_address;
+  }
+
+  // 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;
+  }
+
+  // Initialize input to output maps for section symbols in merged
+  // sections.
+  void
+  initialize_input_to_output_maps();
+
+  // Free the input to output maps for section symbols in merged
+  // sections.
+  void
+  free_input_to_output_maps();
+
+  // Return symbol table section index.
+  unsigned int
+  symtab_shndx() const
+  { return this->symtab_shndx_; }
+
+  // Allow a child class to access the ELF file.
+  elfcpp::Elf_file<size, big_endian, Object>*
+  elf_file()
+  { return &this->elf_file_; }
+  
+  // Allow a child class to access the local values.
+  Local_values*
+  local_values()
+  { return &this->local_values_; }
+
  private:
   // For convenience.
   typedef Sized_relobj<size, big_endian> This;
@@ -1607,15 +1670,6 @@ class Sized_relobj : public Relobj
   typedef std::map<unsigned int, Kept_comdat_section>
       Kept_comdat_section_table;
 
-  // 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);
@@ -1707,15 +1761,29 @@ class Sized_relobj : public Relobj
                      unsigned char* reloc_view,
                      section_size_type reloc_view_size);
 
-  // Initialize input to output maps for section symbols in merged
-  // sections.
+  // A type shared by split_stack_adjust_reltype and find_functions.
+  typedef std::map<section_offset_type, section_size_type> Function_offsets;
+
+  // Check for -fsplit-stack routines calling non-split-stack routines.
   void
-  initialize_input_to_output_maps();
+  split_stack_adjust(const Symbol_table*, const unsigned char* pshdrs,
+                    unsigned int sh_type, unsigned int shndx,
+                    const unsigned char* prelocs, size_t reloc_count,
+                    unsigned char* view, section_size_type view_size,
+                    Reloc_symbol_changes** reloc_map);
 
-  // Free the input to output maps for section symbols in merged
-  // sections.
+  template<int sh_type>
   void
-  free_input_to_output_maps();
+  split_stack_adjust_reltype(const Symbol_table*, const unsigned char* pshdrs,
+                            unsigned int shndx, const unsigned char* prelocs,
+                            size_t reloc_count, unsigned char* view,
+                            section_size_type view_size,
+                            Reloc_symbol_changes** reloc_map);
+
+  // Find all functions in a section.
+  void
+  find_functions(const unsigned char* pshdrs, unsigned int shndx,
+                Function_offsets*);
 
   // Write out the local symbols.
   void
@@ -1939,8 +2007,12 @@ struct Relocate_info
   Sized_relobj<size, big_endian>* object;
   // Section index of relocation section.
   unsigned int reloc_shndx;
+  // Section header of relocation section.
+  const unsigned char* reloc_shdr;
   // Section index of section being relocated.
   unsigned int data_shndx;
+  // Section header of data section.
+  const unsigned char* data_shdr;
 
   // Return a string showing the location of a relocation.  This is
   // only used for error messages.
index bf420c679fdef01dec75f757659984ed5316ffb7..299a748048b03ea7cfd4481f0e38209ea9d56c5c 100644 (file)
 
 #include "gold.h"
 
+#include <cerrno>
 #include <cstdlib>
 #include <cstring>
+#include <fstream>
 #include <vector>
 #include <iostream>
 #include <sys/stat.h>
@@ -192,6 +194,16 @@ parse_uint(const char* option_name, const char* arg, int* retval)
                option_name, arg);
 }
 
+void
+parse_int(const char* option_name, const char* arg, int* retval)
+{
+  char* endptr;
+  *retval = strtol(arg, &endptr, 0);
+  if (*endptr != '\0')
+    gold_fatal(_("%s: invalid option value (expected an integer): %s"),
+               option_name, arg);
+}
+
 void
 parse_uint64(const char* option_name, const char* arg, uint64_t *retval)
 {
@@ -329,7 +341,19 @@ void
 General_options::parse_library(const char*, const char* arg,
                                Command_line* cmdline)
 {
-  Input_file_argument file(arg, true, "", false, *this);
+  Input_file_argument::Input_file_type type;
+  const char *name;
+  if (arg[0] == ':')
+    {
+      type = Input_file_argument::INPUT_FILE_TYPE_SEARCHED_FILE;
+      name = arg + 1;
+    }
+  else
+    {
+      type = Input_file_argument::INPUT_FILE_TYPE_LIBRARY;
+      name = arg;
+    }
+  Input_file_argument file(name, type, "", false, *this);
   cmdline->inputs().add_file(file);
 }
 
@@ -366,7 +390,8 @@ void
 General_options::parse_just_symbols(const char*, const char* arg,
                                     Command_line* cmdline)
 {
-  Input_file_argument file(arg, false, "", true, *this);
+  Input_file_argument file(arg, Input_file_argument::INPUT_FILE_TYPE_FILE,
+                          "", true, *this);
   cmdline->inputs().add_file(file);
 }
 
@@ -849,6 +874,15 @@ General_options::finalize()
   else if (this->noexecstack())
     this->set_execstack_status(EXECSTACK_NO);
 
+  // icf_status_ is a three-state variable; update it based on the
+  // value of this->icf().
+  if (strcmp(this->icf(), "none") == 0)
+    this->set_icf_status(ICF_NONE);
+  else if (strcmp(this->icf(), "safe") == 0)
+    this->set_icf_status(ICF_SAFE);
+  else
+    this->set_icf_status(ICF_ALL);
+
   // Handle the optional argument for --demangle.
   if (this->user_set_demangle())
     {
@@ -938,6 +972,25 @@ General_options::finalize()
       this->add_to_library_path_with_sysroot("/usr/lib");
     }
 
+  // Parse the contents of -retain-symbols-file into a set.
+  if (this->retain_symbols_file())
+    {
+      std::ifstream in;
+      in.open(this->retain_symbols_file());
+      if (!in)
+        gold_fatal(_("unable to open -retain-symbols-file file %s: %s"),
+                   this->retain_symbols_file(), strerror(errno));
+      std::string line;
+      std::getline(in, line);   // this chops off the trailing \n, if any
+      while (in)
+        {
+          if (!line.empty() && line[line.length() - 1] == '\r')   // Windows
+            line.resize(line.length() - 1);
+          this->symbols_to_retain_.insert(line);
+          std::getline(in, line);
+        }
+    }
+
   if (this->shared() && !this->user_set_allow_shlib_undefined())
     this->set_allow_shlib_undefined(true);
 
@@ -948,13 +1001,24 @@ General_options::finalize()
   // Now that we've normalized the options, check for contradictory ones.
   if (this->shared() && this->is_static())
     gold_fatal(_("-shared and -static are incompatible"));
+  if (this->shared() && this->pie())
+    gold_fatal(_("-shared and -pie are incompatible"));
 
   if (this->shared() && this->relocatable())
     gold_fatal(_("-shared and -r are incompatible"));
+  if (this->pie() && this->relocatable())
+    gold_fatal(_("-pie and -r are incompatible"));
+
+  // TODO: implement support for -retain-symbols-file with -r, if needed.
+  if (this->relocatable() && this->retain_symbols_file())
+    gold_fatal(_("-retain-symbols-file does not yet work with -r"));
 
   if (this->oformat_enum() != General_options::OBJECT_FORMAT_ELF
-      && (this->shared() || this->relocatable()))
-    gold_fatal(_("binary output format not compatible with -shared or -r"));
+      && (this->shared()
+         || this->pie()
+         || this->relocatable()))
+    gold_fatal(_("binary output format not compatible "
+                "with -shared or -pie or -r"));
 
   if (this->user_set_hash_bucket_empty_fraction()
       && (this->hash_bucket_empty_fraction() < 0.0
@@ -1122,8 +1186,9 @@ Command_line::process(int argc, const char** argv)
       this->position_options_.copy_from_options(this->options());
       if (no_more_options || argv[i][0] != '-')
         {
-          Input_file_argument file(argv[i], false, "", false,
-                                   this->position_options_);
+         Input_file_argument file(argv[i],
+                                  Input_file_argument::INPUT_FILE_TYPE_FILE,
+                                  "", false, this->position_options_);
           this->inputs_.add_file(file);
           ++i;
         }
index 3f145293df2f9bbd05e112f25957dfe33a98eee3..cbb45b52179abd68f583fe59d2fef4d87b2d84f3 100644 (file)
@@ -82,6 +82,9 @@ typedef Unordered_set<std::string> String_set;
 extern void
 parse_bool(const char* option_name, const char* arg, bool* retval);
 
+extern void
+parse_int(const char* option_name, const char* arg, int* retval);
+
 extern void
 parse_uint(const char* option_name, const char* arg, int* retval);
 
@@ -333,6 +336,12 @@ struct Struct_special : public Struct_var
   };                                                                     \
   Struct_disable_##varname__ disable_##varname__##_initializer_
 
+#define DEFINE_int(varname__, dashes__, shortname__, default_value__,   \
+                   helpstring__, helparg__)                             \
+  DEFINE_var(varname__, dashes__, shortname__, default_value__,         \
+             #default_value__, helpstring__, helparg__, false,         \
+             int, int, options::parse_int)
+
 #define DEFINE_uint(varname__, dashes__, shortname__, default_value__,  \
                    helpstring__, helparg__)                             \
   DEFINE_var(varname__, dashes__, shortname__, default_value__,         \
@@ -678,6 +687,9 @@ class General_options
              N_("Treat warnings as errors"),
              N_("Do not treat warnings as errors"));
 
+  DEFINE_string(fini, options::ONE_DASH, '\0', "_fini",
+                N_("Call SYMBOL at unload-time"), N_("SYMBOL"));
+
   DEFINE_string(soname, options::ONE_DASH, 'h', NULL,
                 N_("Set shared library name"), N_("FILENAME"));
 
@@ -705,6 +717,9 @@ class General_options
   DEFINE_special(incremental_unknown, options::TWO_DASHES, '\0',
                  N_("Use timestamps to check files (default)"), NULL);
 
+  DEFINE_string(init, options::ONE_DASH, '\0', "_init",
+                N_("Call SYMBOL at load-time"), N_("SYMBOL"));
+
   DEFINE_special(just_symbols, options::TWO_DASHES, '\0',
                  N_("Read only symbol values from FILE"), N_("FILE"));
 
@@ -748,6 +763,12 @@ class General_options
   DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf",
                N_("Set output format"), N_("[binary]"));
 
+  DEFINE_bool(pie, options::ONE_DASH, '\0', false,
+             N_("Create a position independent executable"), NULL);
+  DEFINE_bool_alias(pic_executable, pie, options::TWO_DASHES, '\0',
+                   N_("Create a position independent executable"), NULL,
+                   false);
+
 #ifdef ENABLE_PLUGINS
   DEFINE_special(plugin, options::TWO_DASHES, '\0',
                  N_("Load a plugin library"), N_("PLUGIN"));
@@ -774,6 +795,9 @@ class General_options
   DEFINE_bool(relax, options::TWO_DASHES, '\0', false,
              N_("Relax branches on certain targets"), NULL);
 
+  DEFINE_string(retain_symbols_file, options::EXACTLY_ONE_DASH, '\0', NULL,
+                N_("keep only symbols listed in this file"), N_("[file]"));
+
   // -R really means -rpath, but can mean --just-symbols for
   // compatibility with GNU ld.  -rpath is always -rpath, so we list
   // it separately.
@@ -799,6 +823,12 @@ class General_options
   DEFINE_bool(strip_lto_sections, options::TWO_DASHES, '\0', true,
               N_("Strip LTO intermediate code sections"), NULL);
 
+  DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
+             N_("(ARM only) The maximum distance from instructions in a group "
+               "of sections to their stubs.  Negative values mean stubs "
+               "are always after the group. 1 means using default size.\n"),
+            N_("SIZE"));
+
   DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false,
               N_("Use less memory and more disk I/O "
                  "(included only for compatibility with GNU ld)"), NULL);
@@ -809,14 +839,20 @@ class General_options
   DEFINE_bool(Bshareable, options::ONE_DASH, '\0', false,
               N_("Generate shared library"), NULL);
 
+  DEFINE_uint(split_stack_adjust_size, options::TWO_DASHES, '\0', 0x4000,
+             N_("Stack size when -fsplit-stack function calls non-split"),
+             N_("SIZE"));
+
   // This is not actually special in any way, but I need to give it
   // a non-standard accessor-function name because 'static' is a keyword.
   DEFINE_special(static, options::ONE_DASH, '\0',
                  N_("Do not link against shared libraries"), NULL);
 
-  DEFINE_bool(icf, options::TWO_DASHES, '\0', false,
-              N_("Identical Code Folding (Fold identical functions)"),
-              N_("Don't fold identical functions (default)"));
+  DEFINE_enum(icf, options::TWO_DASHES, '\0', "none",
+              N_("Identical Code Folding. "
+                 "\'--icf=safe\' folds only ctors and dtors."),
+             ("[none,all,safe]"),      
+              {"none", "all", "safe"});
 
   DEFINE_uint(icf_iterations, options::TWO_DASHES , '\0', 0,
               N_("Number of iterations of ICF (default 2)"), N_("COUNT"));
@@ -925,6 +961,9 @@ class General_options
              NULL);
   DEFINE_uint64(max_page_size, options::DASH_Z, '\0', 0,
                 N_("Set maximum page size to SIZE"), N_("SIZE"));
+  DEFINE_bool(copyreloc, options::DASH_Z, '\0', true,
+             NULL,
+             N_("Do not create copy relocs"));
   DEFINE_bool(nodefaultlib, options::DASH_Z, '\0', false,
              N_("Mark object not to use default search paths"),
              NULL);
@@ -976,7 +1015,7 @@ class General_options
   // the output is position-independent or not.
   bool
   output_is_position_independent() const
-  { return this->shared(); }
+  { return this->shared() || this->pie(); }
 
   // Return true if the output is something that can be exec()ed, such
   // as a static executable, or a position-dependent or
@@ -984,13 +1023,7 @@ class General_options
   // object file.
   bool
   output_is_executable() const
-  { return !this->shared() || this->output_is_pie(); }
-
-  // Return true if the output is a position-independent executable.
-  // This is currently not supported.
-  bool
-  output_is_pie() const
-  { return false; }
+  { return !this->shared() && !this->relocatable(); }
 
   // This would normally be static(), and defined automatically, but
   // since static is a keyword, we need to come up with our own name.
@@ -1021,6 +1054,15 @@ class General_options
   bool
   is_in_system_directory(const std::string& name) const;
 
+  // RETURN whether SYMBOL_NAME should be kept, according to symbols_to_retain_.
+  bool
+  should_retain_symbol(const char* symbol_name) const
+    {
+      if (symbols_to_retain_.empty())    // means flag wasn't specified
+        return true;
+      return symbols_to_retain_.find(symbol_name) != symbols_to_retain_.end();
+    }
+
   // These are the best way to get access to the execstack state,
   // not execstack() and noexecstack() which are hard to use properly.
   bool
@@ -1031,6 +1073,14 @@ class General_options
   is_stack_executable() const
   { return this->execstack_status_ == EXECSTACK_YES; }
 
+  bool
+  icf_enabled() const
+  { return this->icf_status_ != ICF_NONE; }
+
+  bool
+  icf_safe_folding() const
+  { return this->icf_status_ == ICF_SAFE; }
+
   // The --demangle option takes an optional string, and there is also
   // a --no-demangle option.  This is the best way to decide whether
   // to demangle or not.
@@ -1081,6 +1131,20 @@ class General_options
     EXECSTACK_NO
   };
 
+  enum Icf_status
+  {
+    // Do not fold any functions (Default or --icf=none).
+    ICF_NONE,
+    // All functions are candidates for folding. (--icf=all).
+    ICF_ALL,   
+    // Only ctors and dtors are candidates for folding. (--icf=safe).
+    ICF_SAFE
+  };
+
+  void
+  set_icf_status(Icf_status value)
+  { this->icf_status_ = value; }
+
   void
   set_execstack_status(Execstack value)
   { this->execstack_status_ = value; }
@@ -1114,6 +1178,8 @@ class General_options
   bool printed_version_;
   // Whether to mark the stack as executable.
   Execstack execstack_status_;
+  // Whether to do code folding.
+  Icf_status icf_status_;
   // Whether to do a static link.
   bool static_;
   // Whether to do demangling.
@@ -1132,8 +1198,10 @@ class General_options
   // build (--incremental-changed, --incremental-unchanged or
   // --incremental-unknown)
   bool implicit_incremental_;
-  // Libraries excluded from automatic export via --exclude-libs
+  // Libraries excluded from automatic export, via --exclude-libs.
   Unordered_set<std::string> excluded_libs_;
+  // List of symbol-names to keep, via -retain-symbol-info.
+  Unordered_set<std::string> symbols_to_retain_;
 };
 
 // The position-dependent options.  We use this to store the state of
@@ -1192,9 +1260,20 @@ class Position_dependent_options
 class Input_file_argument
 {
  public:
+  enum Input_file_type
+  {
+    // A regular file, name used as-is, not searched.
+    INPUT_FILE_TYPE_FILE,
+    // A library name.  When used, "lib" will be prepended and ".so" or
+    // ".a" appended to make a filename, and that filename will be searched
+    // for using the -L paths.
+    INPUT_FILE_TYPE_LIBRARY,
+    // A regular file, name used as-is, but searched using the -L paths.
+    INPUT_FILE_TYPE_SEARCHED_FILE
+  };
+
   // name: file name or library name
-  // is_lib: true if name is a library name: that is, emits the leading
-  //         "lib" and trailing ".so"/".a" from the name
+  // type: the type of this input file.
   // extra_search_path: an extra directory to look for the file, prior
   //         to checking the normal library search path.  If this is "",
   //         then no extra directory is added.
@@ -1202,15 +1281,15 @@ class Input_file_argument
   // options: The position dependent options at this point in the
   //         command line, such as --whole-archive.
   Input_file_argument()
-    : name_(), is_lib_(false), extra_search_path_(""), just_symbols_(false),
-      options_()
+    : name_(), type_(INPUT_FILE_TYPE_FILE), extra_search_path_(""),
+      just_symbols_(false), options_()
   { }
 
-  Input_file_argument(const char* name, bool is_lib,
+  Input_file_argument(const char* name, Input_file_type type,
                       const char* extra_search_path,
                       bool just_symbols,
                       const Position_dependent_options& options)
-    : name_(name), is_lib_(is_lib), extra_search_path_(extra_search_path),
+    : name_(name), type_(type), extra_search_path_(extra_search_path),
       just_symbols_(just_symbols), options_(options)
   { }
 
@@ -1218,11 +1297,11 @@ class Input_file_argument
   // Position_dependent_options.  In that case, we extract the
   // position-independent vars from the General_options and only store
   // those.
-  Input_file_argument(const char* name, bool is_lib,
+  Input_file_argument(const char* name, Input_file_type type,
                       const char* extra_search_path,
                       bool just_symbols,
                       const General_options& options)
-    : name_(name), is_lib_(is_lib), extra_search_path_(extra_search_path),
+    : name_(name), type_(type), extra_search_path_(extra_search_path),
       just_symbols_(just_symbols), options_(options)
   { }
 
@@ -1236,7 +1315,11 @@ class Input_file_argument
 
   bool
   is_lib() const
-  { return this->is_lib_; }
+  { return type_ == INPUT_FILE_TYPE_LIBRARY; }
+
+  bool
+  is_searched_file() const
+  { return type_ == INPUT_FILE_TYPE_SEARCHED_FILE; }
 
   const char*
   extra_search_path() const
@@ -1255,14 +1338,18 @@ class Input_file_argument
   // options.
   bool
   may_need_search() const
-  { return this->is_lib_ || !this->extra_search_path_.empty(); }
+  {
+    return (this->is_lib()
+           || this->is_searched_file()
+           || !this->extra_search_path_.empty());
+  }
 
  private:
   // We use std::string, not const char*, here for convenience when
   // using script files, so that we do not have to preserve the string
   // in that case.
   std::string name_;
-  bool is_lib_;
+  Input_file_type type_;
   std::string extra_search_path_;
   bool just_symbols_;
   Position_dependent_options options_;
index fd47407052c34fb0f4100019cb52bdf5ea918e40..e2d758520c28e29e07dd48d48a22f7860f20da27 100644 (file)
@@ -30,7 +30,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <algorithm>
-#include "libiberty.h"   // for unlink_if_ordinary()
+#include "libiberty.h"
 
 #include "parameters.h"
 #include "object.h"
@@ -108,26 +108,35 @@ Output_section_headers::Output_section_headers(
     unattached_section_list_(unattached_section_list),
     secnamepool_(secnamepool),
     shstrtab_section_(shstrtab_section)
+{
+}
+
+// Compute the current data size.
+
+off_t
+Output_section_headers::do_size() const
 {
   // Count all the sections.  Start with 1 for the null section.
   off_t count = 1;
   if (!parameters->options().relocatable())
     {
-      for (Layout::Segment_list::const_iterator p = segment_list->begin();
-          p != segment_list->end();
+      for (Layout::Segment_list::const_iterator p =
+            this->segment_list_->begin();
+          p != this->segment_list_->end();
           ++p)
        if ((*p)->type() == elfcpp::PT_LOAD)
          count += (*p)->output_section_count();
     }
   else
     {
-      for (Layout::Section_list::const_iterator p = section_list->begin();
-          p != section_list->end();
+      for (Layout::Section_list::const_iterator p =
+            this->section_list_->begin();
+          p != this->section_list_->end();
           ++p)
        if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
          ++count;
     }
-  count += unattached_section_list->size();
+  count += this->unattached_section_list_->size();
 
   const int size = parameters->target().get_size();
   int shdr_size;
@@ -138,7 +147,7 @@ Output_section_headers::Output_section_headers(
   else
     gold_unreachable();
 
-  this->set_data_size(count * shdr_size);
+  return count * shdr_size;
 }
 
 // Write out the section headers.
@@ -269,16 +278,6 @@ Output_segment_headers::Output_segment_headers(
     const Layout::Segment_list& segment_list)
   : segment_list_(segment_list)
 {
-  const int size = parameters->target().get_size();
-  int phdr_size;
-  if (size == 32)
-    phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
-  else if (size == 64)
-    phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
-  else
-    gold_unreachable();
-
-  this->set_data_size(segment_list.size() * phdr_size);
 }
 
 void
@@ -335,6 +334,21 @@ Output_segment_headers::do_sized_write(Output_file* of)
   of->write_output_view(this->offset(), all_phdrs_size, view);
 }
 
+off_t
+Output_segment_headers::do_size() const
+{
+  const int size = parameters->target().get_size();
+  int phdr_size;
+  if (size == 32)
+    phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
+  else if (size == 64)
+    phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
+  else
+    gold_unreachable();
+
+  return this->segment_list_.size() * phdr_size;
+}
+
 // Output_file_header methods.
 
 Output_file_header::Output_file_header(const Target* target,
@@ -348,16 +362,7 @@ Output_file_header::Output_file_header(const Target* target,
     shstrtab_(NULL),
     entry_(entry)
 {
-  const int size = parameters->target().get_size();
-  int ehdr_size;
-  if (size == 32)
-    ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
-  else if (size == 64)
-    ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
-  else
-    gold_unreachable();
-
-  this->set_data_size(ehdr_size);
+  this->set_data_size(this->do_size());
 }
 
 // Set the section table information for a file header.
@@ -437,7 +442,7 @@ Output_file_header::do_sized_write(Output_file* of)
   elfcpp::ET e_type;
   if (parameters->options().relocatable())
     e_type = elfcpp::ET_REL;
-  else if (parameters->options().shared())
+  else if (parameters->options().output_is_position_independent())
     e_type = elfcpp::ET_DYN;
   else
     e_type = elfcpp::ET_EXEC;
@@ -539,6 +544,20 @@ Output_file_header::entry()
   return v;
 }
 
+// Compute the current data size.
+
+off_t
+Output_file_header::do_size() const
+{
+  const int size = parameters->target().get_size();
+  if (size == 32)
+    return elfcpp::Elf_sizes<32>::ehdr_size;
+  else if (size == 64)
+    return elfcpp::Elf_sizes<64>::ehdr_size;
+  else
+    gold_unreachable();
+}
+
 // Output_data_const methods.
 
 void
@@ -1075,7 +1094,7 @@ Output_data_group<size, big_endian>::Output_data_group(
     section_size_type entry_count,
     elfcpp::Elf_Word flags,
     std::vector<unsigned int>* input_shndxes)
-  : Output_section_data(entry_count * 4, 4),
+  : Output_section_data(entry_count * 4, 4, false),
     relobj_(relobj),
     flags_(flags)
 {
@@ -1501,8 +1520,11 @@ Output_data_dynamic::do_adjust_output_section(Output_section* os)
 void
 Output_data_dynamic::set_final_data_size()
 {
-  // Add the terminating entry.
-  this->add_constant(elfcpp::DT_NULL, 0);
+  // Add the terminating entry if it hasn't been added.
+  // Because of relaxation, we can run this multiple times.
+  if (this->entries_.empty()
+      || this->entries_.rbegin()->tag() != elfcpp::DT_NULL)
+    this->add_constant(elfcpp::DT_NULL, 0);
 
   int dyn_size;
   if (parameters->target().get_size() == 32)
@@ -1602,7 +1624,11 @@ 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);
+    {
+      unsigned int symndx = p->first;
+      gold_assert(symndx * 4 < this->data_size());
+      elfcpp::Swap<32, big_endian>::writeval(oview + symndx * 4, p->second);
+    }
 }
 
 // Output_section::Input_section methods.
@@ -1720,6 +1746,14 @@ Output_section::Input_section::print_to_mapfile(Mapfile* mapfile) const
       this->u2_.posd->print_to_mapfile(mapfile);
       break;
 
+    case RELAXED_INPUT_SECTION_CODE:
+      {
+        Output_relaxed_input_section* relaxed_section =
+         this->relaxed_input_section();
+        mapfile->print_input_section(relaxed_section->relobj(),
+                                    relaxed_section->shndx());
+      }
+      break;
     default:
       mapfile->print_input_section(this->u2_.object, this->shndx_);
       break;
@@ -1766,7 +1800,13 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     is_relro_local_(false),
     is_small_section_(false),
     is_large_section_(false),
-    tls_offset_(0)
+    tls_offset_(0),
+    checkpoint_(NULL),
+    merge_section_map_(),
+    merge_section_by_properties_map_(),
+    relaxed_input_section_map_(),
+    is_relaxed_input_section_map_valid_(true),
+    generate_code_fills_at_write_(false)
 {
   // An unallocated section has no address.  Forcing this means that
   // we don't need special treatment for symbols defined in debug
@@ -1777,6 +1817,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
 
 Output_section::~Output_section()
 {
+  delete this->checkpoint_;
 }
 
 // Set the entry size.
@@ -1856,10 +1897,24 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
   off_t aligned_offset_in_section = align_address(offset_in_section,
                                                   addralign);
 
+  // Determine if we want to delay code-fill generation until the output
+  // section is written.  When the target is relaxing, we want to delay fill
+  // generating to avoid adjusting them during relaxation.
+  if (!this->generate_code_fills_at_write_
+      && !have_sections_script
+      && (sh_flags & elfcpp::SHF_EXECINSTR) != 0
+      && parameters->target().has_code_fill()
+      && parameters->target().may_relax())
+    {
+      gold_assert(this->fills_.empty());
+      this->generate_code_fills_at_write_ = true;
+    }
+
   if (aligned_offset_in_section > offset_in_section
+      && !this->generate_code_fills_at_write_
       && !have_sections_script
       && (sh_flags & elfcpp::SHF_EXECINSTR) != 0
-      && object->target()->has_code_fill())
+      && parameters->target().has_code_fill())
     {
       // We need to add some fill data.  Using fill_list_ when
       // possible is an optimization, since we will often have fill
@@ -1869,9 +1924,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
         this->fills_.push_back(Fill(offset_in_section, fill_len));
       else
         {
-          // FIXME: When relaxing, the size needs to adjust to
-          // maintain a constant alignment.
-          std::string fill_data(object->target()->code_fill(fill_len));
+          std::string fill_data(parameters->target().code_fill(fill_len));
           Output_data_const* odc = new Output_data_const(fill_data, 1);
           this->input_sections_.push_back(Input_section(odc));
         }
@@ -1883,13 +1936,13 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
   // We need to keep track of this section if we are already keeping
   // track of sections, or if we are relaxing.  Also, if this is a
   // section which requires sorting, or which may require sorting in
-  // the future, we keep track of the sections.  FIXME: Add test for
-  // relaxing.
+  // the future, we keep track of the sections.
   if (have_sections_script
       || !this->input_sections_.empty()
       || this->may_sort_attached_input_sections()
       || this->must_sort_attached_input_sections()
-      || parameters->options().user_set_Map())
+      || parameters->options().user_set_Map()
+      || parameters->target().may_relax())
     this->input_sections_.push_back(Input_section(object, shndx,
                                                  shdr.get_sh_size(),
                                                  addralign));
@@ -1915,6 +1968,31 @@ Output_section::add_output_section_data(Output_section_data* posd)
     }
 }
 
+// Add a relaxed input section.
+
+void
+Output_section::add_relaxed_input_section(Output_relaxed_input_section* poris)
+{
+  Input_section inp(poris);
+  this->add_output_section_data(&inp);
+  if (this->is_relaxed_input_section_map_valid_)
+    {
+      Input_section_specifier iss(poris->relobj(), poris->shndx());
+      this->relaxed_input_section_map_[iss] = poris;
+    }
+
+  // For a relaxed section, we use the current data size.  Linker scripts
+  // get all the input sections, including relaxed one from an output
+  // section and add them back to them same output section to compute the
+  // output section size.  If we do not account for sizes of relaxed input
+  // sections,  an output section would be incorrectly sized.
+  off_t offset_in_section = this->current_data_size_for_child();
+  off_t aligned_offset_in_section = align_address(offset_in_section,
+                                                 poris->addralign());
+  this->set_current_data_size_for_child(aligned_offset_in_section
+                                       + poris->current_data_size());
+}
+
 // Add arbitrary data to an output section by Input_section.
 
 void
@@ -1956,45 +2034,156 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
   if (is_string && addralign > entsize)
     return false;
 
-  Input_section_list::iterator p;
-  for (p = this->input_sections_.begin();
-       p != this->input_sections_.end();
-       ++p)
-    if (p->is_merge_section(is_string, entsize, addralign))
-      {
-        p->add_input_section(object, shndx);
-        return true;
-      }
+  // We cannot restore merged input section states.
+  gold_assert(this->checkpoint_ == NULL);
+
+  // Look up merge sections by required properties.
+  Merge_section_properties msp(is_string, entsize, addralign);
+  Merge_section_by_properties_map::const_iterator p =
+    this->merge_section_by_properties_map_.find(msp);
+  if (p != this->merge_section_by_properties_map_.end())
+    {
+      Output_merge_base* merge_section = p->second;
+      merge_section->add_input_section(object, shndx);
+      gold_assert(merge_section->is_string() == is_string
+                 && merge_section->entsize() == entsize
+                 && merge_section->addralign() == addralign);
+
+      // Link input section to found merge section.
+      Input_section_specifier iss(object, shndx);
+      this->merge_section_map_[iss] = merge_section;
+      return true;
+    }
 
   // We handle the actual constant merging in Output_merge_data or
   // Output_merge_string_data.
-  Output_section_data* posd;
+  Output_merge_base* pomb;
   if (!is_string)
-    posd = new Output_merge_data(entsize, addralign);
+    pomb = new Output_merge_data(entsize, addralign);
   else
     {
       switch (entsize)
        {
         case 1:
-         posd = new Output_merge_string<char>(addralign);
+         pomb = new Output_merge_string<char>(addralign);
          break;
         case 2:
-         posd = new Output_merge_string<uint16_t>(addralign);
+         pomb = new Output_merge_string<uint16_t>(addralign);
          break;
         case 4:
-         posd = new Output_merge_string<uint32_t>(addralign);
+         pomb = new Output_merge_string<uint32_t>(addralign);
          break;
         default:
          return false;
        }
     }
 
-  this->add_output_merge_section(posd, is_string, entsize);
-  posd->add_input_section(object, shndx);
+  // Add new merge section to this output section and link merge section
+  // properties to new merge section in map.
+  this->add_output_merge_section(pomb, is_string, entsize);
+  this->merge_section_by_properties_map_[msp] = pomb;
+
+  // Add input section to new merge section and link input section to new
+  // merge section in map.
+  pomb->add_input_section(object, shndx);
+  Input_section_specifier iss(object, shndx);
+  this->merge_section_map_[iss] = pomb;
 
   return true;
 }
 
+// Build a relaxation map to speed up relaxation of existing input sections.
+// Look up to the first LIMIT elements in INPUT_SECTIONS.
+
+void
+Output_section::build_relaxation_map(
+  const Input_section_list& input_sections,
+  size_t limit,
+  Relaxation_map* relaxation_map) const
+{
+  for (size_t i = 0; i < limit; ++i)
+    {
+      const Input_section& is(input_sections[i]);
+      if (is.is_input_section() || is.is_relaxed_input_section())
+       {
+         Input_section_specifier iss(is.relobj(), is.shndx());
+         (*relaxation_map)[iss] = i;
+       }
+    }
+}
+
+// Convert regular input sections in INPUT_SECTIONS into relaxed input
+// sections in RELAXED_SECTIONS.  MAP is a prebuilt map from input section
+// specifier to indices of INPUT_SECTIONS.
+
+void
+Output_section::convert_input_sections_in_list_to_relaxed_sections(
+  const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+  const Relaxation_map& map,
+  Input_section_list* input_sections)
+{
+  for (size_t i = 0; i < relaxed_sections.size(); ++i)
+    {
+      Output_relaxed_input_section* poris = relaxed_sections[i];
+      Input_section_specifier iss(poris->relobj(), poris->shndx());
+      Relaxation_map::const_iterator p = map.find(iss);
+      gold_assert(p != map.end());
+      gold_assert((*input_sections)[p->second].is_input_section());
+      (*input_sections)[p->second] = Input_section(poris);
+    }
+}
+  
+// Convert regular input sections into relaxed input sections. RELAXED_SECTIONS
+// is a vector of pointers to Output_relaxed_input_section or its derived
+// classes.  The relaxed sections must correspond to existing input sections.
+
+void
+Output_section::convert_input_sections_to_relaxed_sections(
+  const std::vector<Output_relaxed_input_section*>& relaxed_sections)
+{
+  gold_assert(parameters->target().may_relax());
+
+  // We want to make sure that restore_states does not undo the effect of
+  // this.  If there is no checkpoint active, just search the current
+  // input section list and replace the sections there.  If there is
+  // a checkpoint, also replace the sections there.
+  
+  // By default, we look at the whole list.
+  size_t limit = this->input_sections_.size();
+
+  if (this->checkpoint_ != NULL)
+    {
+      // Replace input sections with relaxed input section in the saved
+      // copy of the input section list.
+      if (this->checkpoint_->input_sections_saved())
+       {
+         Relaxation_map map;
+         this->build_relaxation_map(
+                   *(this->checkpoint_->input_sections()),
+                   this->checkpoint_->input_sections()->size(),
+                   &map);
+         this->convert_input_sections_in_list_to_relaxed_sections(
+                   relaxed_sections,
+                   map,
+                   this->checkpoint_->input_sections());
+       }
+      else
+       {
+         // We have not copied the input section list yet.  Instead, just
+         // look at the portion that would be saved.
+         limit = this->checkpoint_->input_sections_size();
+       }
+    }
+
+  // Convert input sections in input_section_list.
+  Relaxation_map map;
+  this->build_relaxation_map(this->input_sections_, limit, &map);
+  this->convert_input_sections_in_list_to_relaxed_sections(
+           relaxed_sections,
+           map,
+           &this->input_sections_);
+}
+
 // Update the output section flags based on input section flags.
 
 void
@@ -2013,6 +2202,60 @@ Output_section::update_flags_for_input_section(elfcpp::Elf_Xword flags)
                      | elfcpp::SHF_EXECINSTR));
 }
 
+// Find the merge section into which an input section with index SHNDX in
+// OBJECT has been added.  Return NULL if none found.
+
+Output_section_data*
+Output_section::find_merge_section(const Relobj* object,
+                                  unsigned int shndx) const
+{
+  Input_section_specifier iss(object, shndx);
+  Output_section_data_by_input_section_map::const_iterator p =
+    this->merge_section_map_.find(iss);
+  if (p != this->merge_section_map_.end())
+    {
+      Output_section_data* posd = p->second;
+      gold_assert(posd->is_merge_section_for(object, shndx));
+      return posd;
+    }
+  else
+    return NULL;
+}
+
+// Find an relaxed input section corresponding to an input section
+// in OBJECT with index SHNDX.
+
+const Output_section_data*
+Output_section::find_relaxed_input_section(const Relobj* object,
+                                          unsigned int shndx) const
+{
+  // Be careful that the map may not be valid due to input section export
+  // to scripts or a check-point restore.
+  if (!this->is_relaxed_input_section_map_valid_)
+    {
+      // Rebuild the map as needed.
+      this->relaxed_input_section_map_.clear();
+      for (Input_section_list::const_iterator p = this->input_sections_.begin();
+          p != this->input_sections_.end();
+          ++p)
+       if (p->is_relaxed_input_section())
+         {
+           Input_section_specifier iss(p->relobj(), p->shndx());
+           this->relaxed_input_section_map_[iss] =
+             p->relaxed_input_section();
+         }
+      this->is_relaxed_input_section_map_valid_ = true;
+    }
+
+  Input_section_specifier iss(object, shndx);
+  Output_section_data_by_input_section_map::const_iterator p =
+    this->relaxed_input_section_map_.find(iss);
+  if (p != this->relaxed_input_section_map_.end())
+    return p->second;
+  else
+    return NULL;
+}
+
 // Given an address OFFSET relative to the start of input section
 // SHNDX in OBJECT, return whether this address is being included in
 // the final link.  This should only be called if SHNDX in OBJECT has
@@ -2023,6 +2266,20 @@ Output_section::is_input_address_mapped(const Relobj* object,
                                        unsigned int shndx,
                                        off_t offset) const
 {
+  // Look at the Output_section_data_maps first.
+  const Output_section_data* posd = this->find_merge_section(object, shndx);
+  if (posd == NULL)
+    posd = this->find_relaxed_input_section(object, shndx);
+
+  if (posd != NULL)
+    {
+      section_offset_type output_offset;
+      bool found = posd->output_offset(object, shndx, offset, &output_offset);
+      gold_assert(found);   
+      return output_offset != -1;
+    }
+
+  // Fall back to the slow look-up.
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
@@ -2047,9 +2304,23 @@ section_offset_type
 Output_section::output_offset(const Relobj* object, unsigned int shndx,
                              section_offset_type offset) const
 {
-  // This can only be called meaningfully when layout is complete.
-  gold_assert(Output_data::is_layout_complete());
+  // This can only be called meaningfully when we know the data size
+  // of this.
+  gold_assert(this->is_data_size_valid());
 
+  // Look at the Output_section_data_maps first.
+  const Output_section_data* posd = this->find_merge_section(object, shndx);
+  if (posd == NULL) 
+    posd = this->find_relaxed_input_section(object, shndx);
+  if (posd != NULL)
+    {
+      section_offset_type output_offset;
+      bool found = posd->output_offset(object, shndx, offset, &output_offset);
+      gold_assert(found);   
+      return output_offset;
+    }
+
+  // Fall back to the slow look-up.
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
@@ -2069,6 +2340,20 @@ Output_section::output_address(const Relobj* object, unsigned int shndx,
                               off_t offset) const
 {
   uint64_t addr = this->address() + this->first_input_offset_;
+
+  // Look at the Output_section_data_maps first.
+  const Output_section_data* posd = this->find_merge_section(object, shndx);
+  if (posd == NULL) 
+    posd = this->find_relaxed_input_section(object, shndx);
+  if (posd != NULL && posd->is_address_valid())
+    {
+      section_offset_type output_offset;
+      bool found = posd->output_offset(object, shndx, offset, &output_offset);
+      gold_assert(found);
+      return posd->address() + output_offset;
+    }
+
+  // Fall back to the slow look-up.
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
@@ -2100,6 +2385,9 @@ Output_section::find_starting_output_address(const Relobj* object,
                                             unsigned int shndx,
                                             uint64_t* paddr) const
 {
+  // FIXME: This becomes a bottle-neck if we have many relaxed sections.
+  // Looking up the merge section map does not always work as we sometimes
+  // find a merge section without its address set.
   uint64_t addr = this->address() + this->first_input_offset_;
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
@@ -2160,11 +2448,32 @@ Output_section::set_final_data_size()
 void
 Output_section::do_reset_address_and_file_offset()
 {
+  // An unallocated section has no address.  Forcing this means that
+  // we don't need special treatment for symbols defined in debug
+  // sections.  We do the same in the constructor.
+  if ((this->flags_ & elfcpp::SHF_ALLOC) == 0)
+     this->set_address(0);
+
   for (Input_section_list::iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
     p->reset_address_and_file_offset();
 }
+  
+// Return true if address and file offset have the values after reset.
+
+bool
+Output_section::do_address_and_file_offset_have_reset_values() const
+{
+  if (this->is_offset_valid())
+    return false;
+
+  // An unallocated section has address 0 after its construction or a reset.
+  if ((this->flags_ & elfcpp::SHF_ALLOC) == 0)
+    return this->is_address_valid() && this->address() == 0;
+  else
+    return !this->is_address_valid();
+}
 
 // Set the TLS offset.  Called only for SHT_TLS sections.
 
@@ -2193,7 +2502,8 @@ class Output_section::Input_section_sort_entry
   Input_section_sort_entry(const Input_section& input_section,
                           unsigned int index)
     : input_section_(input_section), index_(index),
-      section_has_name_(input_section.is_input_section())
+      section_has_name_(input_section.is_input_section()
+                       || input_section.is_relaxed_input_section())
   {
     if (this->section_has_name_)
       {
@@ -2201,7 +2511,9 @@ class Output_section::Input_section_sort_entry
        // so it is OK to lock.  Unfortunately we have no way to pass
        // in a Task token.
        const Task* dummy_task = reinterpret_cast<const Task*>(-1);
-       Object* obj = input_section.relobj();
+       Object* obj = (input_section.is_input_section()
+                      ? input_section.relobj()
+                      : input_section.relaxed_input_section()->relobj());
        Task_lock_obj<Object> tl(dummy_task, obj);
 
        // This is a slow operation, which should be cached in
@@ -2350,6 +2662,10 @@ Output_section::sort_attached_input_sections()
   if (this->attached_input_sections_are_sorted_)
     return;
 
+  if (this->checkpoint_ != NULL
+      && !this->checkpoint_->input_sections_saved())
+    this->checkpoint_->save_input_sections();
+
   // The only thing we know about an input section is the object and
   // the section index.  We need the section name.  Recomputing this
   // is slow but this is an unusual case.  If this becomes a speed
@@ -2435,6 +2751,9 @@ Output_section::do_write(Output_file* of)
 {
   gold_assert(!this->requires_postprocessing());
 
+  // If the target performs relaxation, we delay filler generation until now.
+  gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
   off_t output_section_file_offset = this->offset();
   for (Fill_list::iterator p = this->fills_.begin();
        p != this->fills_.end();
@@ -2445,10 +2764,22 @@ Output_section::do_write(Output_file* of)
                fill_data.data(), fill_data.size());
     }
 
+  off_t off = this->offset() + this->first_input_offset_;
   for (Input_section_list::iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
-    p->write(of);
+    {
+      off_t aligned_off = align_address(off, p->addralign());
+      if (this->generate_code_fills_at_write_ && (off != aligned_off))
+       {
+         size_t fill_len = aligned_off - off;
+         std::string fill_data(parameters->target().code_fill(fill_len));
+         of->write(off, fill_data.data(), fill_data.size());
+       }
+
+      p->write(of);
+      off = aligned_off + p->data_size();
+    }
 }
 
 // If a section requires postprocessing, create the buffer to use.
@@ -2489,6 +2820,9 @@ Output_section::write_to_postprocessing_buffer()
 {
   gold_assert(this->requires_postprocessing());
 
+  // If the target performs relaxation, we delay filler generation until now.
+  gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
   unsigned char* buffer = this->postprocessing_buffer();
   for (Fill_list::iterator p = this->fills_.begin();
        p != this->fills_.end();
@@ -2504,9 +2838,16 @@ Output_section::write_to_postprocessing_buffer()
        p != this->input_sections_.end();
        ++p)
     {
-      off = align_address(off, p->addralign());
-      p->write_to_buffer(buffer + off);
-      off += p->data_size();
+      off_t aligned_off = align_address(off, p->addralign());
+      if (this->generate_code_fills_at_write_ && (off != aligned_off))
+       {
+         size_t fill_len = aligned_off - off;
+         std::string fill_data(parameters->target().code_fill(fill_len));
+         memcpy(buffer + off, fill_data.data(), fill_data.size());
+       }
+
+      p->write_to_buffer(buffer + aligned_off);
+      off = aligned_off + p->data_size();
     }
 }
 
@@ -2524,8 +2865,15 @@ uint64_t
 Output_section::get_input_sections(
     uint64_t address,
     const std::string& fill,
-    std::list<std::pair<Relobj*, unsigned int> >* input_sections)
+    std::list<Simple_input_section>* input_sections)
 {
+  if (this->checkpoint_ != NULL
+      && !this->checkpoint_->input_sections_saved())
+    this->checkpoint_->save_input_sections();
+
+  // Invalidate the relaxed input section map.
+  this->is_relaxed_input_section_map_valid_ = false;
+
   uint64_t orig_address = address;
 
   address = align_address(address, this->addralign());
@@ -2536,7 +2884,11 @@ Output_section::get_input_sections(
        ++p)
     {
       if (p->is_input_section())
-       input_sections->push_back(std::make_pair(p->relobj(), p->shndx()));
+       input_sections->push_back(Simple_input_section(p->relobj(),
+                                                      p->shndx()));
+      else if (p->is_relaxed_input_section())
+       input_sections->push_back(
+           Simple_input_section(p->relaxed_input_section()));
       else
        {
          uint64_t aligned_address = align_address(address, p->addralign());
@@ -2574,8 +2926,7 @@ Output_section::get_input_sections(
 // Add an input section from a script.
 
 void
-Output_section::add_input_section_for_script(Relobj* object,
-                                            unsigned int shndx,
+Output_section::add_input_section_for_script(const Simple_input_section& sis,
                                             off_t data_size,
                                             uint64_t addralign)
 {
@@ -2589,8 +2940,60 @@ Output_section::add_input_section_for_script(Relobj* object,
   this->set_current_data_size_for_child(aligned_offset_in_section
                                        + data_size);
 
-  this->input_sections_.push_back(Input_section(object, shndx,
-                                               data_size, addralign));
+  Input_section is =
+    (sis.is_relaxed_input_section()
+     ? Input_section(sis.relaxed_input_section())
+     : Input_section(sis.relobj(), sis.shndx(), data_size, addralign));
+  this->input_sections_.push_back(is);
+}
+
+//
+
+void
+Output_section::save_states()
+{
+  gold_assert(this->checkpoint_ == NULL);
+  Checkpoint_output_section* checkpoint =
+    new Checkpoint_output_section(this->addralign_, this->flags_,
+                                 this->input_sections_,
+                                 this->first_input_offset_,
+                                 this->attached_input_sections_are_sorted_);
+  this->checkpoint_ = checkpoint;
+  gold_assert(this->fills_.empty());
+}
+
+void
+Output_section::restore_states()
+{
+  gold_assert(this->checkpoint_ != NULL);
+  Checkpoint_output_section* checkpoint = this->checkpoint_;
+
+  this->addralign_ = checkpoint->addralign();
+  this->flags_ = checkpoint->flags();
+  this->first_input_offset_ = checkpoint->first_input_offset();
+
+  if (!checkpoint->input_sections_saved())
+    {
+      // If we have not copied the input sections, just resize it.
+      size_t old_size = checkpoint->input_sections_size();
+      gold_assert(this->input_sections_.size() >= old_size);
+      this->input_sections_.resize(old_size);
+    }
+  else
+    {
+      // We need to copy the whole list.  This is not efficient for
+      // extremely large output with hundreads of thousands of input
+      // objects.  We may need to re-think how we should pass sections
+      // to scripts.
+      this->input_sections_ = *checkpoint->input_sections();
+    }
+
+  this->attached_input_sections_are_sorted_ =
+    checkpoint->attached_input_sections_are_sorted();
+
+  // Simply invalidate the relaxed input section map since we do not keep
+  // track of it.
+  this->is_relaxed_input_section_map_valid_ = false;
 }
 
 // Print to the map file.
@@ -2697,36 +3100,41 @@ Output_segment::add_output_section(Output_section* os,
       && (os->flags() & elfcpp::SHF_TLS) != 0)
     {
       pdl = &this->output_data_;
-      bool nobits = os->type() == elfcpp::SHT_NOBITS;
-      bool sawtls = false;
-      Output_segment::Output_data_list::iterator p = pdl->end();
-      do
+      if (!pdl->empty())
        {
-         --p;
-         bool insert;
-         if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
-           {
-             sawtls = true;
-             // Put a NOBITS section after the first TLS section.
-             // Put a PROGBITS section after the first TLS/PROGBITS
-             // section.
-             insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
-           }
-         else
+         bool nobits = os->type() == elfcpp::SHT_NOBITS;
+         bool sawtls = false;
+         Output_segment::Output_data_list::iterator p = pdl->end();
+         gold_assert(p != pdl->begin());
+         do
            {
-             // If we've gone past the TLS sections, but we've seen a
-             // TLS section, then we need to insert this section now.
-             insert = sawtls;
-           }
-
-         if (insert)
-           {
-             ++p;
-             pdl->insert(p, os);
-             return;
+             --p;
+             bool insert;
+             if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+               {
+                 sawtls = true;
+                 // Put a NOBITS section after the first TLS section.
+                 // Put a PROGBITS section after the first
+                 // TLS/PROGBITS section.
+                 insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
+               }
+             else
+               {
+                 // If we've gone past the TLS sections, but we've
+                 // seen a TLS section, then we need to insert this
+                 // section now.
+                 insert = sawtls;
+               }
+
+             if (insert)
+               {
+                 ++p;
+                 pdl->insert(p, os);
+                 return;
+               }
            }
+         while (p != pdl->begin());
        }
-      while (p != pdl->begin());
 
       // There are no TLS sections yet; put this one at the requested
       // location in the section list.
@@ -3086,8 +3494,26 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
        {
          // The script may have inserted a skip forward, but it
          // better not have moved backward.
-         gold_assert((*p)->address() >= addr + (off - startoff));
-         off += (*p)->address() - (addr + (off - startoff));
+         if ((*p)->address() >= addr + (off - startoff))
+           off += (*p)->address() - (addr + (off - startoff));
+         else
+           {
+             if (!layout->script_options()->saw_sections_clause())
+               gold_unreachable();
+             else
+               {
+                 Output_section* os = (*p)->output_section();
+                 if (os == NULL)
+                   gold_error(_("dot moves backward in linker script "
+                                "from 0x%llx to 0x%llx"),
+                              addr + (off - startoff), (*p)->address());
+                 else
+                   gold_error(_("address of section '%s' moves backward "
+                                "from 0x%llx to 0x%llx"),
+                              os->name(), addr + (off - startoff),
+                              (*p)->address());
+               }
+           }
          (*p)->set_file_offset(off);
          (*p)->finalize_data_size();
        }
@@ -3461,8 +3887,22 @@ Output_file::open(off_t file_size)
       else
        {
          struct stat s;
-         if (::stat(this->name_, &s) == 0 && s.st_size != 0)
-           unlink_if_ordinary(this->name_);
+         if (::stat(this->name_, &s) == 0
+             && (S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
+           {
+             if (s.st_size != 0)
+               ::unlink(this->name_);
+             else if (!parameters->options().relocatable())
+               {
+                 // If we don't unlink the existing file, add execute
+                 // permission where read permissions already exist
+                 // and where the umask permits.
+                 int mask = ::umask(0);
+                 ::umask(mask);
+                 s.st_mode |= (s.st_mode & 0444) >> 2;
+                 ::chmod(this->name_, s.st_mode & ~mask);
+               }
+           }
 
          int mode = parameters->options().relocatable() ? 0666 : 0777;
          int o = open_descriptor(-1, this->name_, O_RDWR | O_CREAT | O_TRUNC,
index 7bd0cf31bba327593b27bdce3610ffb310e1d766..bc109509cf82e3bd13ed9ff45a01ce644e2c61ae 100644 (file)
@@ -38,6 +38,7 @@ class General_options;
 class Object;
 class Symbol;
 class Output_file;
+class Output_merge_base;
 class Output_section;
 class Relocatable_relocs;
 class Target;
@@ -46,6 +47,71 @@ class Sized_target;
 template<int size, bool big_endian>
 class Sized_relobj;
 
+// This class specifies an input section.  It is used as a key type
+// for maps.
+
+class Input_section_specifier
+{
+ public:
+  Input_section_specifier(const Relobj* relobj, unsigned int shndx)
+    : relobj_(relobj), shndx_(shndx)
+  { }
+   
+  // Return Relobj of this.
+  const Relobj*
+  relobj() const
+  { return this->relobj_; }
+
+  // Return section index of this.
+  unsigned int
+  shndx() const
+  { return this->shndx_; }
+
+  // Whether this equals to another specifier ISS.
+  bool
+  eq(const Input_section_specifier& iss) const
+  { return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; }
+
+  // Compute a hash value of this.
+  size_t
+  hash_value() const
+  { return this->string_hash(this->relobj_->name().c_str()) ^ this->shndx_; }
+
+  // Functors for containers.
+  struct equal_to
+  {
+    bool
+    operator()(const Input_section_specifier& iss1,
+              const Input_section_specifier& iss2) const
+    { return iss1.eq(iss2); }
+  };
+  struct hash
+  {
+    size_t
+    operator()(const Input_section_specifier& iss) const
+    { return iss.hash_value(); }
+  };
+
+ private:
+  // For portability, we use our own string hash function instead of assuming
+  // __gnu_cxx::hash or std::tr1::hash is available.  This is the same hash
+  // function used in Stringpool_template::string_hash.
+  static size_t
+  string_hash(const char* s)
+  {
+    size_t h = 5381;
+    while (*s != '\0')
+      h = h * 33 + *s++;
+    return h;
+  }
+
+  // An object.
+  const Relobj* relobj_;
+  // A section index. 
+  unsigned int shndx_;
+};
+
 // An abtract class for data which has to go into the output file.
 
 class Output_data
@@ -54,7 +120,7 @@ class Output_data
   explicit Output_data()
     : address_(0), data_size_(0), offset_(-1),
       is_address_valid_(false), is_data_size_valid_(false),
-      is_offset_valid_(false),
+      is_offset_valid_(false), is_data_size_fixed_(false),
       dynamic_reloc_count_(0)
   { }
 
@@ -80,6 +146,11 @@ class Output_data
     return this->data_size_;
   }
 
+  // Return true if data size is fixed.
+  bool
+  is_data_size_fixed() const
+  { return this->is_data_size_fixed_; }
+  
   // Return the file offset.  This is only valid after
   // Layout::finalize is finished.  For some non-allocated sections,
   // it may not be valid until near the end of the link.
@@ -97,10 +168,17 @@ class Output_data
   {
     this->is_address_valid_ = false;
     this->is_offset_valid_ = false;
-    this->is_data_size_valid_ = false;
+    if (!this->is_data_size_fixed_)
+      this->is_data_size_valid_ = false;
     this->do_reset_address_and_file_offset();
   }
 
+  // Return true if address and file offset already have reset values. In
+  // other words, calling reset_address_and_file_offset will not change them.
+  bool
+  address_and_file_offset_have_reset_values() const
+  { return this->do_address_and_file_offset_have_reset_values(); }
+
   // Return the required alignment.
   uint64_t
   addralign() const
@@ -311,6 +389,14 @@ class Output_data
   do_reset_address_and_file_offset()
   { }
 
+  // Return true if address and file offset already have reset values. In
+  // other words, calling reset_address_and_file_offset will not change them.
+  // A child class overriding do_reset_address_and_file_offset may need to
+  // also override this.
+  virtual bool
+  do_address_and_file_offset_have_reset_values() const
+  { return !this->is_address_valid_ && !this->is_offset_valid_; }
+
   // Set the TLS offset.  Called only for SHT_TLS sections.
   virtual void
   do_set_tls_offset(uint64_t)
@@ -341,11 +427,21 @@ class Output_data
   void
   set_data_size(off_t data_size)
   {
-    gold_assert(!this->is_data_size_valid_);
+    gold_assert(!this->is_data_size_valid_
+               && !this->is_data_size_fixed_);
     this->data_size_ = data_size;
     this->is_data_size_valid_ = true;
   }
 
+  // Fix the data size.  Once it is fixed, it cannot be changed
+  // and the data size remains always valid. 
+  void
+  fix_data_size()
+  {
+    gold_assert(this->is_data_size_valid_);
+    this->is_data_size_fixed_ = true;
+  }
+
   // Get the current data size--this is for the convenience of
   // sections which build up their size over time.
   off_t
@@ -390,6 +486,8 @@ class Output_data
   bool is_data_size_valid_;
   // Whether offset_ is valid.
   bool is_offset_valid_;
+  // Whether data size is fixed.
+  bool is_data_size_fixed_;
   // Count of dynamic relocations applied to this section.
   unsigned int dynamic_reloc_count_;
 };
@@ -421,12 +519,21 @@ class Output_section_headers : public Output_data
   do_print_to_mapfile(Mapfile* mapfile) const
   { mapfile->print_output_data(this, _("** section headers")); }
 
+  // Set final data size.
+  void
+  set_final_data_size()
+  { this->set_data_size(this->do_size()); }
+
  private:
   // Write the data to the file with the right size and endianness.
   template<int size, bool big_endian>
   void
   do_sized_write(Output_file*);
 
+  // Compute data size.
+  off_t
+  do_size() const;
+
   const Layout* layout_;
   const Layout::Segment_list* segment_list_;
   const Layout::Section_list* section_list_;
@@ -457,12 +564,21 @@ class Output_segment_headers : public Output_data
   do_print_to_mapfile(Mapfile* mapfile) const
   { mapfile->print_output_data(this, _("** segment headers")); }
 
+  // Set final data size.
+  void
+  set_final_data_size()
+  { this->set_data_size(this->do_size()); }
+
  private:
   // Write the data to the file with the right size and endianness.
   template<int size, bool big_endian>
   void
   do_sized_write(Output_file*);
 
+  // Compute the current size.
+  off_t
+  do_size() const;
+
   const Layout::Segment_list& segment_list_;
 };
 
@@ -496,6 +612,11 @@ class Output_file_header : public Output_data
   do_print_to_mapfile(Mapfile* mapfile) const
   { mapfile->print_output_data(this, _("** file header")); }
 
+  // Set final data size.
+  void
+  set_final_data_size(void)
+  { this->set_data_size(this->do_size()); }
+
  private:
   // Write the data to the file with the right size and endianness.
   template<int size, bool big_endian>
@@ -507,6 +628,10 @@ class Output_file_header : public Output_data
   typename elfcpp::Elf_types<size>::Elf_Addr
   entry();
 
+  // Compute the current data size.
+  off_t
+  do_size() const;
+
   const Target* target_;
   const Symbol_table* symtab_;
   const Output_segment_headers* segment_header_;
@@ -523,9 +648,14 @@ class Output_file_header : public Output_data
 class Output_section_data : public Output_data
 {
  public:
-  Output_section_data(off_t data_size, uint64_t addralign)
+  Output_section_data(off_t data_size, uint64_t addralign,
+                     bool is_data_size_fixed)
     : Output_data(), output_section_(NULL), addralign_(addralign)
-  { this->set_data_size(data_size); }
+  {
+    this->set_data_size(data_size);
+    if (is_data_size_fixed)
+      this->fix_data_size();
+  }
 
   Output_section_data(uint64_t addralign)
     : Output_data(), output_section_(NULL), addralign_(addralign)
@@ -675,15 +805,15 @@ class Output_data_const : public Output_section_data
 {
  public:
   Output_data_const(const std::string& data, uint64_t addralign)
-    : Output_section_data(data.size(), addralign), data_(data)
+    : Output_section_data(data.size(), addralign, true), data_(data)
   { }
 
   Output_data_const(const char* p, off_t len, uint64_t addralign)
-    : Output_section_data(len, addralign), data_(p, len)
+    : Output_section_data(len, addralign, true), data_(p, len)
   { }
 
   Output_data_const(const unsigned char* p, off_t len, uint64_t addralign)
-    : Output_section_data(len, addralign),
+    : Output_section_data(len, addralign, true),
       data_(reinterpret_cast<const char*>(p), len)
   { }
 
@@ -714,7 +844,7 @@ class Output_data_const_buffer : public Output_section_data
  public:
   Output_data_const_buffer(const unsigned char* p, off_t len,
                           uint64_t addralign, const char* map_name)
-    : Output_section_data(len, addralign),
+    : Output_section_data(len, addralign, true),
       p_(p), map_name_(map_name)
   { }
 
@@ -749,7 +879,7 @@ class Output_data_fixed_space : public Output_section_data
  public:
   Output_data_fixed_space(off_t data_size, uint64_t addralign,
                          const char* map_name)
-    : Output_section_data(data_size, addralign),
+    : Output_section_data(data_size, addralign, true),
       map_name_(map_name)
   { }
 
@@ -812,7 +942,7 @@ class Output_data_zero_fill : public Output_section_data
 {
  public:
   Output_data_zero_fill(off_t data_size, uint64_t addralign)
-    : Output_section_data(data_size, addralign)
+    : Output_section_data(data_size, addralign, true)
   { }
 
  protected:
@@ -1531,6 +1661,11 @@ class Output_data_group : public Output_section_data
   do_print_to_mapfile(Mapfile* mapfile) const
   { mapfile->print_output_data(this, _("** group")); }
 
+  // Set final data size.
+  void
+  set_final_data_size()
+  { this->set_data_size((this->input_shndxes_.size() + 1) * 4); }
+
  private:
   // The input object.
   Sized_relobj<size, big_endian>* relobj_;
@@ -1814,6 +1949,11 @@ class Output_data_dynamic : public Output_section_data
       : tag_(tag), offset_(DYNAMIC_STRING)
     { this->u_.str = str; }
 
+    // Return the tag of this entry.
+    elfcpp::DT
+    tag() const
+    { return this->tag_; }
+
     // Write the dynamic entry to an output view.
     template<int size, bool big_endian>
     void
@@ -1880,7 +2020,7 @@ class Output_symtab_xindex : public Output_section_data
 {
  public:
   Output_symtab_xindex(size_t symcount)
-    : Output_section_data(symcount * 4, 4),
+    : Output_section_data(symcount * 4, 4, true),
       entries_()
   { }
 
@@ -1912,6 +2052,33 @@ class Output_symtab_xindex : public Output_section_data
   Xindex_entries entries_;
 };
 
+// A relaxed input section.
+class Output_relaxed_input_section : public Output_section_data_build
+{
+ public:
+  // We would like to call relobj->section_addralign(shndx) to get the
+  // alignment but we do not want the constructor to fail.  So callers
+  // are repsonsible for ensuring that.
+  Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
+                              uint64_t addralign)
+    : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
+  { }
+  // Return the Relobj of this relaxed input section.
+  Relobj*
+  relobj() const
+  { return this->relobj_; }
+  // Return the section index of this relaxed input section.
+  unsigned int
+  shndx() const
+  { return this->shndx_; }
+
+ private:
+  Relobj* relobj_;
+  unsigned int shndx_;
+};
+
 // 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.
 
@@ -1940,6 +2107,10 @@ class Output_section : public Output_data
   void
   add_output_section_data(Output_section_data* posd);
 
+  // Add a relaxed input section PORIS to this output section.
+  void
+  add_relaxed_input_section(Output_relaxed_input_section* poris);
+
   // Return the section name.
   const char*
   name() const
@@ -2310,6 +2481,69 @@ class Output_section : public Output_data
 
   // The next few calls are for linker script support.
 
+  // We need to export the input sections to linker scripts.  Previously
+  // we export a pair of Relobj pointer and section index.  We now need to
+  // handle relaxed input sections as well.  So we use this class.
+  class Simple_input_section
+  {
+   private:
+    static const unsigned int invalid_shndx = static_cast<unsigned int>(-1);
+
+   public:
+    Simple_input_section(Relobj *relobj, unsigned int shndx)
+      : shndx_(shndx)
+    {
+      gold_assert(shndx != invalid_shndx);
+      this->u_.relobj = relobj;
+    }
+    Simple_input_section(Output_relaxed_input_section* section)
+      : shndx_(invalid_shndx)
+    { this->u_.relaxed_input_section = section; }
+
+    // Whether this is a relaxed section.
+    bool
+    is_relaxed_input_section() const
+    { return this->shndx_ == invalid_shndx; }
+
+    // Return object of an input section.
+    Relobj*
+    relobj() const
+    {
+      return ((this->shndx_ != invalid_shndx)
+             ? this->u_.relobj
+             : this->u_.relaxed_input_section->relobj());
+    }
+
+    // Return index of an input section.
+    unsigned int
+    shndx() const
+    {
+      return ((this->shndx_ != invalid_shndx)
+             ? this->shndx_
+             : this->u_.relaxed_input_section->shndx());
+    }
+
+    // Return the Output_relaxed_input_section object of a relaxed section.
+    Output_relaxed_input_section*
+    relaxed_input_section() const
+    {
+      gold_assert(this->shndx_ == invalid_shndx);
+      return this->u_.relaxed_input_section;
+    }
+
+   private:
+    // Pointer to either an Relobj or an Output_relaxed_input_section.
+    union
+    {
+      Relobj* relobj;
+      Output_relaxed_input_section* relaxed_input_section;
+    } u_;
+    // Section index for an non-relaxed section or invalid_shndx for
+    // a relaxed section.
+    unsigned int shndx_;
+  };
   // Store the list of input sections for this Output_section into the
   // list passed in.  This removes the input sections, leaving only
   // any Output_section_data elements.  This returns the size of those
@@ -2318,11 +2552,11 @@ class Output_section : public Output_data
   // any spaces between the remaining Output_section_data elements.
   uint64_t
   get_input_sections(uint64_t address, const std::string& fill,
-                    std::list<std::pair<Relobj*, unsigned int > >*);
+                    std::list<Simple_input_section>*);
 
   // Add an input section from a script.
   void
-  add_input_section_for_script(Relobj* object, unsigned int shndx,
+  add_input_section_for_script(const Simple_input_section& input_section,
                               off_t data_size, uint64_t addralign);
 
   // Set the current size of the output section.
@@ -2337,6 +2571,20 @@ class Output_section : public Output_data
 
   // End of linker script support.
 
+  // Save states before doing section layout.
+  // This is used for relaxation.
+  void
+  save_states();
+
+  // Restore states prior to section layout.
+  void
+  restore_states();
+
+  // Convert existing input sections to relaxed input sections.
+  void
+  convert_input_sections_to_relaxed_sections(
+      const std::vector<Output_relaxed_input_section*>& sections);
+
   // Print merge statistics to stderr.
   void
   print_merge_stats();
@@ -2374,6 +2622,11 @@ class Output_section : public Output_data
   void
   do_reset_address_and_file_offset();
 
+  // Return true if address and file offset already have reset values. In
+  // other words, calling reset_address_and_file_offset will not change them.
+  bool
+  do_address_and_file_offset_have_reset_values() const;
+
   // Write the data to the file.  For a typical Output_section, this
   // does nothing: the data is written out by calling Object::Relocate
   // on each input object.  But if there are any Output_section_data
@@ -2447,7 +2700,6 @@ class Output_section : public Output_data
   void
   write_to_postprocessing_buffer();
 
- private:
   // In some cases we need to keep a list of the input sections
   // associated with this output section.  We only need the list if we
   // might have to change the offsets of the input section within the
@@ -2476,7 +2728,8 @@ class Output_section : public Output_data
     {
       gold_assert(shndx != OUTPUT_SECTION_CODE
                  && shndx != MERGE_DATA_SECTION_CODE
-                 && shndx != MERGE_STRING_SECTION_CODE);
+                 && shndx != MERGE_STRING_SECTION_CODE
+                 && shndx != RELAXED_INPUT_SECTION_CODE);
       this->u1_.data_size = data_size;
       this->u2_.object = object;
     }
@@ -2500,6 +2753,14 @@ class Output_section : public Output_data
       this->u2_.posd = posd;
     }
 
+    // For a relaxed input section.
+    Input_section(Output_relaxed_input_section *psection)
+      : shndx_(RELAXED_INPUT_SECTION_CODE), p2align_(0)
+    {
+      this->u1_.data_size = 0;
+      this->u2_.poris = psection;
+    }
+
     // The required alignment.
     uint64_t
     addralign() const
@@ -2521,7 +2782,8 @@ class Output_section : public Output_data
     {
       return (this->shndx_ != OUTPUT_SECTION_CODE
              && this->shndx_ != MERGE_DATA_SECTION_CODE
-             && this->shndx_ != MERGE_STRING_SECTION_CODE);
+             && this->shndx_ != MERGE_STRING_SECTION_CODE
+             && this->shndx_ != RELAXED_INPUT_SECTION_CODE);
     }
 
     // Return whether this is a merge section which matches the
@@ -2537,20 +2799,57 @@ class Output_section : public Output_data
               && this->addralign() == addralign);
     }
 
+    // Return whether this is a relaxed input section.
+    bool
+    is_relaxed_input_section() const
+    { return this->shndx_ == RELAXED_INPUT_SECTION_CODE; }
+
+    // Return whether this is a generic Output_section_data.
+    bool
+    is_output_section_data() const
+    {
+      return this->shndx_ == OUTPUT_SECTION_CODE;
+    }
+
     // Return the object for an input section.
     Relobj*
     relobj() const
     {
-      gold_assert(this->is_input_section());
-      return this->u2_.object;
+      if (this->is_input_section())
+        return this->u2_.object;
+      else if (this->is_relaxed_input_section())
+       return this->u2_.poris->relobj();
+      else
+       gold_unreachable();
     }
 
     // Return the input section index for an input section.
     unsigned int
     shndx() const
     {
-      gold_assert(this->is_input_section());
-      return this->shndx_;
+      if (this->is_input_section())
+        return this->shndx_;
+      else if (this->is_relaxed_input_section())
+       return this->u2_.poris->shndx();
+      else
+       gold_unreachable();
+    }
+
+    // For non-input-sections, return the associated Output_section_data
+    // object.
+    Output_section_data*
+    output_section_data() const
+    {
+      gold_assert(!this->is_input_section());
+      return this->u2_.posd;
+    }
+    // Return the Output_relaxed_input_section object.
+    Output_relaxed_input_section*
+    relaxed_input_section() const
+    {
+      gold_assert(this->is_relaxed_input_section());
+      return this->u2_.poris;
     }
 
     // Set the output section.
@@ -2558,7 +2857,9 @@ class Output_section : public Output_data
     set_output_section(Output_section* os)
     {
       gold_assert(!this->is_input_section());
-      this->u2_.posd->set_output_section(os);
+      Output_section_data *posd = 
+        this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd;
+      posd->set_output_section(os);
     }
 
     // Set the address and file offset.  This is called during
@@ -2636,7 +2937,9 @@ class Output_section : public Output_data
       MERGE_DATA_SECTION_CODE = -2U,
       // An Output_section_data for an SHF_MERGE section with
       // SHF_STRINGS set.
-      MERGE_STRING_SECTION_CODE = -3U
+      MERGE_STRING_SECTION_CODE = -3U,
+      // An Output_section_data for a relaxed input section.
+      RELAXED_INPUT_SECTION_CODE = -4U
     };
 
     // For an ordinary input section, this is the section index in the
@@ -2650,8 +2953,8 @@ class Output_section : public Output_data
     {
       // For an ordinary input section, the section size.
       off_t data_size;
-      // For OUTPUT_SECTION_CODE, this is not used.  For
-      // MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
+      // For OUTPUT_SECTION_CODE or RELAXED_INPUT_SECTION_CODE, this is not
+      // used.  For MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the
       // entity size.
       uint64_t entsize;
     } u1_;
@@ -2663,11 +2966,102 @@ class Output_section : public Output_data
       // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
       // MERGE_STRING_SECTION_CODE, the data.
       Output_section_data* posd;
+      // For RELAXED_INPUT_SECTION_CODE, the data.
+      Output_relaxed_input_section* poris;
     } u2_;
   };
 
   typedef std::vector<Input_section> Input_section_list;
 
+  // Allow a child class to access the input sections.
+  const Input_section_list&
+  input_sections() const
+  { return this->input_sections_; }
+
+ private:
+  // We only save enough information to undo the effects of section layout.
+  class Checkpoint_output_section
+  {
+   public:
+    Checkpoint_output_section(uint64_t addralign, elfcpp::Elf_Xword flags,
+                             const Input_section_list& input_sections,
+                             off_t first_input_offset,
+                             bool attached_input_sections_are_sorted)
+      : addralign_(addralign), flags_(flags),
+       input_sections_(input_sections),
+       input_sections_size_(input_sections_.size()),
+       input_sections_copy_(), first_input_offset_(first_input_offset),
+       attached_input_sections_are_sorted_(attached_input_sections_are_sorted)
+    { }
+
+    virtual
+    ~Checkpoint_output_section()
+    { }
+
+    // Return the address alignment.
+    uint64_t
+    addralign() const
+    { return this->addralign_; }
+
+    // Return the section flags.
+    elfcpp::Elf_Xword
+    flags() const
+    { return this->flags_; }
+
+    // Return a reference to the input section list copy.
+    Input_section_list*
+    input_sections()
+    { return &this->input_sections_copy_; }
+
+    // Return the size of input_sections at the time when checkpoint is
+    // taken.
+    size_t
+    input_sections_size() const
+    { return this->input_sections_size_; }
+
+    // Whether input sections are copied.
+    bool
+    input_sections_saved() const
+    { return this->input_sections_copy_.size() == this->input_sections_size_; }
+
+    off_t
+    first_input_offset() const
+    { return this->first_input_offset_; }
+
+    bool
+    attached_input_sections_are_sorted() const
+    { return this->attached_input_sections_are_sorted_; }
+
+    // Save input sections.
+    void
+    save_input_sections()
+    {
+      this->input_sections_copy_.reserve(this->input_sections_size_);
+      this->input_sections_copy_.clear();
+      Input_section_list::const_iterator p = this->input_sections_.begin();
+      gold_assert(this->input_sections_size_ >= this->input_sections_.size());
+      for(size_t i = 0; i < this->input_sections_size_ ; i++, ++p)
+       this->input_sections_copy_.push_back(*p);
+    }
+
+   private:
+    // The section alignment.
+    uint64_t addralign_;
+    // The section flags.
+    elfcpp::Elf_Xword flags_;
+    // Reference to the input sections to be checkpointed.
+    const Input_section_list& input_sections_;
+    // Size of the checkpointed portion of input_sections_;
+    size_t input_sections_size_;
+    // Copy of input sections.
+    Input_section_list input_sections_copy_;
+    // The offset of the first entry in input_sections_.
+    off_t first_input_offset_;
+    // True if the input sections attached to this output section have
+    // already been sorted.
+    bool attached_input_sections_are_sorted_;
+  };
+
   // This class is used to sort the input sections.
   class Input_section_sort_entry;
 
@@ -2711,6 +3105,82 @@ class Output_section : public Output_data
 
   typedef std::vector<Fill> Fill_list;
 
+  // This class describes properties of merge data sections.  It is used
+  // as a key type for maps.
+  class Merge_section_properties
+  {
+   public:
+    Merge_section_properties(bool is_string, uint64_t entsize,
+                            uint64_t addralign)
+      : is_string_(is_string), entsize_(entsize), addralign_(addralign)
+    { }
+
+    // Whether this equals to another Merge_section_properties MSP.
+    bool
+    eq(const Merge_section_properties& msp) const
+    {
+      return ((this->is_string_ == msp.is_string_)
+             && (this->entsize_ == msp.entsize_)
+             && (this->addralign_ == msp.addralign_));
+    }
+
+    // Compute a hash value for this using 64-bit FNV-1a hash.
+    size_t
+    hash_value() const
+    {
+      uint64_t h = 14695981039346656037ULL;    // FNV offset basis.
+      uint64_t prime = 1099511628211ULL;
+      h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
+      h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
+      h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
+      return h;
+    }
+    
+    // Functors for associative containers.
+    struct equal_to
+    {
+      bool
+      operator()(const Merge_section_properties& msp1,
+                const Merge_section_properties& msp2) const
+      { return msp1.eq(msp2); }
+    };
+
+    struct hash
+    {
+      size_t
+      operator()(const Merge_section_properties& msp) const
+      { return msp.hash_value(); }
+    };
+
+   private:
+    // Whether this merge data section is for strings.
+    bool is_string_;
+    // Entsize of this merge data section.
+    uint64_t entsize_;
+    // Address alignment.
+    uint64_t addralign_;
+  };
+
+  // Map that link Merge_section_properties to Output_merge_base.
+  typedef Unordered_map<Merge_section_properties, Output_merge_base*,
+                       Merge_section_properties::hash,
+                       Merge_section_properties::equal_to>
+    Merge_section_by_properties_map;
+
+  // Map that link Input_section_specifier to Output_section_data.
+  typedef Unordered_map<Input_section_specifier, Output_section_data*,
+                       Input_section_specifier::hash,
+                       Input_section_specifier::equal_to>
+    Output_section_data_by_input_section_map;
+
+  // Map used during relaxation of existing sections.  This map
+  // an input section specifier to an input section list index.
+  // We assume that Input_section_list is a vector.
+  typedef Unordered_map<Input_section_specifier, size_t,
+                       Input_section_specifier::hash,
+                       Input_section_specifier::equal_to>
+    Relaxation_map;
+
   // Add a new output section by Input_section.
   void
   add_output_section_data(Input_section*);
@@ -2733,6 +3203,30 @@ class Output_section : public Output_data
   void
   sort_attached_input_sections();
 
+  // Find the merge section into which an input section with index SHNDX in
+  // OBJECT has been added.  Return NULL if none found.
+  Output_section_data*
+  find_merge_section(const Relobj* object, unsigned int shndx) const;
+
+  // Find a relaxed input section to an input section in OBJECT
+  // with index SHNDX.  Return NULL if none is found.
+  const Output_section_data*
+  find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
+  
+  // Build a relaxation map.
+  void
+  build_relaxation_map(
+      const Input_section_list& input_sections,
+      size_t limit,
+      Relaxation_map* map) const;
+
+  // Convert input sections in an input section list into relaxed sections.
+  void
+  convert_input_sections_in_list_to_relaxed_sections(
+      const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+      const Relaxation_map& map,
+      Input_section_list* input_sections);
+
   // Most of these fields are only valid after layout.
 
   // The name of the section.  This will point into a Stringpool.
@@ -2836,11 +3330,31 @@ class Output_section : public Output_data
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
+  // Saved checkpoint.
+  Checkpoint_output_section* checkpoint_;
+  // Map from input sections to merge sections.
+  Output_section_data_by_input_section_map merge_section_map_;
+  // Map from merge section properties to merge_sections;
+  Merge_section_by_properties_map merge_section_by_properties_map_;
+  // Map from input sections to relaxed input sections.  This is mutable
+  // beacause it is udpated lazily.  We may need to update it in a
+  // const qualified method.
+  mutable Output_section_data_by_input_section_map relaxed_input_section_map_;
+  // Whether relaxed_input_section_map_ is valid.
+  mutable bool is_relaxed_input_section_map_valid_;
+  // Whether code-fills are generated at write.
+  bool generate_code_fills_at_write_;
 };
 
 // An output segment.  PT_LOAD segments are built from collections of
 // output sections.  Other segments typically point within PT_LOAD
 // segments, and are built directly as needed.
+//
+// NOTE: We want to use the copy constructor for this class.  During
+// relaxation, we may try built the segments multiple times.  We do
+// that by copying the original segment list before lay-out, doing
+// a trial lay-out and roll-back to the saved copied if we need to
+// to the lay-out again.
 
 class Output_segment
 {
@@ -2998,9 +3512,6 @@ class Output_segment
   print_sections_to_mapfile(Mapfile*) const;
 
  private:
-  Output_segment(const Output_segment&);
-  Output_segment& operator=(const Output_segment&);
-
   typedef std::list<Output_data*> Output_data_list;
 
   // Find the maximum alignment in an Output_data_list.
@@ -3043,6 +3554,9 @@ class Output_segment
   void
   print_section_list_to_mapfile(Mapfile*, const Output_data_list*) const;
 
+  // NOTE: We want to use the copy constructor.  Currently, shallow copy
+  // works for us so we do not need to write our own copy constructor.
+  
   // The list of output data with contents attached to this segment.
   Output_data_list output_data_;
   // The list of output data without contents attached to this segment.
@@ -3114,6 +3628,11 @@ class Output_file
   void
   close();
 
+  // Return the size of this file.
+  off_t
+  filesize()
+  { return this->file_size_; }
+
   // We currently always use mmap which makes the view handling quite
   // simple.  In the future we may support other approaches.
 
index 0164265bf04eb7f88dd42dbe059d3107d765ac2a..2a53998bebc356009c999c55a59849a194907f90 100644 (file)
@@ -59,7 +59,7 @@ Parameters::set_doing_static_link(bool doing_static_link)
 }
 
 void
-Parameters::set_target(const Target* target)
+Parameters::set_target(Target* target)
 {
   if (!this->target_valid())
     this->target_ = target;
@@ -67,37 +67,6 @@ Parameters::set_target(const Target* target)
     gold_assert(target == this->target_);
 }
 
-// The x86_64 kernel build converts a binary file to an object file
-// using -r --format binary --oformat elf32-i386 foo.o.  In order to
-// support that for gold we support determining the default target
-// choice from the output format.  We recognize names that the GNU
-// linker uses.
-
-const Target&
-Parameters::default_target() const
-{
-  gold_assert(this->options_valid());
-  if (this->options().user_set_oformat())
-    {
-      const Target* target
-          = select_target_by_name(this->options().oformat());
-      if (target != NULL)
-       return *target;
-
-      gold_error(_("unrecognized output format %s"),
-                 this->options().oformat());
-    }
-
-  // The GOLD_DEFAULT_xx macros are defined by the configure script.
-  const Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
-                                       GOLD_DEFAULT_SIZE,
-                                       GOLD_DEFAULT_BIG_ENDIAN,
-                                      elfcpp::GOLD_DEFAULT_OSABI,
-                                      0);
-  gold_assert(target != NULL);
-  return *target;
-}
-
 // Return whether TARGET is compatible with the target we are using.
 
 bool
@@ -171,11 +140,55 @@ set_parameters_options(const General_options* options)
 { static_parameters.set_options(options); }
 
 void
-set_parameters_target(const Target* target)
+set_parameters_target(Target* target)
 { static_parameters.set_target(target); }
 
 void
 set_parameters_doing_static_link(bool doing_static_link)
 { static_parameters.set_doing_static_link(doing_static_link); }
 
+// Force the target to be valid by using the default.  Use the
+// --oformat option is set; this supports the x86_64 kernel build,
+// which converts a binary file to an object file using -r --format
+// binary --oformat elf32-i386 foo.o.  Otherwise use the configured
+// default.
+
+void
+parameters_force_valid_target()
+{
+  if (parameters->target_valid())
+    return;
+
+  gold_assert(parameters->options_valid());
+  if (parameters->options().user_set_oformat())
+    {
+      Target* target = select_target_by_name(parameters->options().oformat());
+      if (target != NULL)
+       {
+         set_parameters_target(target);
+         return;
+       }
+
+      gold_error(_("unrecognized output format %s"),
+                 parameters->options().oformat());
+    }
+
+  // The GOLD_DEFAULT_xx macros are defined by the configure script.
+  Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
+                                GOLD_DEFAULT_SIZE,
+                                GOLD_DEFAULT_BIG_ENDIAN,
+                                elfcpp::GOLD_DEFAULT_OSABI,
+                                0);
+  gold_assert(target != NULL);
+  set_parameters_target(target);
+}
+
+// Clear the current target, for testing.
+
+void
+parameters_clear_target()
+{
+  static_parameters.clear_target();
+}
+
 } // End namespace gold.
index 921a990efa46e13be2255d93e3c867378f25303c..88d8a870323cff9727cac299d7d5ee1476143472 100644 (file)
@@ -29,6 +29,8 @@ namespace gold
 class General_options;
 class Errors;
 class Target;
+template<int size, bool big_endian>
+class Sized_target;
 
 // Here we define the Parameters class which simply holds simple
 // general parameters which apply to the entire link.  We use a global
@@ -61,7 +63,7 @@ class Parameters
   set_options(const General_options* options);
 
   void
-  set_target(const Target* target);
+  set_target(Target* target);
 
   void
   set_doing_static_link(bool doing_static_link);
@@ -98,10 +100,20 @@ class Parameters
     return *this->target_;
   }
 
-  // When we don't have an output file to associate a target, make a
-  // default one, with guesses about size and endianness.
-  const Target&
-  default_target() const;
+  // The Sized_target of the output file.  The caller must request the
+  // right size and endianness.
+  template<int size, bool big_endian>
+  Sized_target<size, big_endian>*
+  sized_target() const
+  {
+    gold_assert(this->target_valid());
+    return static_cast<Sized_target<size, big_endian>*>(this->target_);
+  }
+
+  // Clear the target, for testing.
+  void
+  clear_target()
+  { this->target_ = NULL; }
 
   // Return true if TARGET is compatible with the current target.
   bool
@@ -140,7 +152,7 @@ class Parameters
  private:
   Errors* errors_;
   const General_options* options_;
-  const Target* target_;
+  Target* target_;
   bool doing_static_link_valid_;
   bool doing_static_link_;
   int debug_;
@@ -159,11 +171,22 @@ extern void
 set_parameters_options(const General_options* options);
 
 extern void
-set_parameters_target(const Target* target);
+set_parameters_target(Target* target);
 
 extern void
 set_parameters_doing_static_link(bool doing_static_link);
-  
+
+// Ensure that the target to be valid by using the default target if
+// necessary.
+
+extern void
+parameters_force_valid_target();
+
+// Clear the current target, for testing.
+
+extern void
+parameters_clear_target();
+
 // Return whether we are doing a particular debugging type.  The
 // argument is one of the flags from debug.h.
 
index 7aee46f7126ff08822acdfdb6fb15e62b7161219..ed334ab8ee7227819fd7b16a351826d4cc4f08da 100644 (file)
 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
 // MA 02110-1301, USA.
 
+#include "gold.h"
+
 #include <cstdio>
 #include <cstdarg>
 #include <cstring>
 #include <string>
 #include <vector>
+
+#ifdef ENABLE_PLUGINS
 #include <dlfcn.h>
+#endif
 
-#include "gold.h"
 #include "parameters.h"
 #include "errors.h"
 #include "fileread.h"
@@ -73,6 +77,9 @@ get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
 static enum ld_plugin_status
 add_input_file(char *pathname);
 
+static enum ld_plugin_status
+add_input_library(char *pathname);
+
 static enum ld_plugin_status
 message(int level, const char *format, ...);
 
@@ -118,7 +125,7 @@ Plugin::load()
   sscanf(ver, "%d.%d", &major, &minor);
 
   // Allocate and populate a transfer vector.
-  const int tv_fixed_size = 13;
+  const int tv_fixed_size = 14;
   int tv_size = this->args_.size() + tv_fixed_size;
   ld_plugin_tv *tv = new ld_plugin_tv[tv_size];
 
@@ -184,6 +191,10 @@ Plugin::load()
   tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
   tv[i].tv_u.tv_add_input_file = add_input_file;
 
+  ++i;
+  tv[i].tv_tag = LDPT_ADD_INPUT_LIBRARY;
+  tv[i].tv_u.tv_add_input_library = add_input_library;
+
   ++i;
   tv[i].tv_tag = LDPT_NULL;
   tv[i].tv_u.tv_val = 0;
@@ -401,9 +412,13 @@ Plugin_manager::release_input_file(unsigned int handle)
 // Add a new input file.
 
 ld_plugin_status
-Plugin_manager::add_input_file(char *pathname)
+Plugin_manager::add_input_file(char *pathname, bool is_lib)
 {
-  Input_file_argument file(pathname, false, "", false, this->options_);
+  Input_file_argument file(pathname,
+                           (is_lib
+                            ? Input_file_argument::INPUT_FILE_TYPE_LIBRARY
+                            : Input_file_argument::INPUT_FILE_TYPE_FILE),
+                           "", false, this->options_);
   Input_argument* input_argument = new Input_argument(file);
   Task_token* next_blocker = new Task_token(true);
   next_blocker->add_blocker();
@@ -941,7 +956,16 @@ static enum ld_plugin_status
 add_input_file(char *pathname)
 {
   gold_assert(parameters->options().has_plugins());
-  return parameters->options().plugins()->add_input_file(pathname);
+  return parameters->options().plugins()->add_input_file(pathname, false);
+}
+
+// Add a new (real) library required by a plugin.
+
+static enum ld_plugin_status
+add_input_library(char *pathname)
+{
+  gold_assert(parameters->options().has_plugins());
+  return parameters->options().plugins()->add_input_file(pathname, true);
 }
 
 // Issue a diagnostic message from a plugin.
@@ -980,17 +1004,14 @@ message(int level, const char * format, ...)
 static Pluginobj*
 make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
 {
-  Target* target;
   Pluginobj* obj = NULL;
 
-  if (parameters->target_valid())
-    target = const_cast<Target*>(&parameters->target());
-  else
-    target = const_cast<Target*>(&parameters->default_target());
+  parameters_force_valid_target();
+  const Target& target(parameters->target());
 
-  if (target->get_size() == 32)
+  if (target.get_size() == 32)
     {
-      if (target->is_big_endian())
+      if (target.is_big_endian())
 #ifdef HAVE_TARGET_32_BIG
         obj = new Sized_pluginobj<32, true>(input_file->filename(),
                                             input_file, offset, filesize);
@@ -1009,9 +1030,9 @@ make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
                   input_file->filename().c_str());
 #endif
     }
-  else if (target->get_size() == 64)
+  else if (target.get_size() == 64)
     {
-      if (target->is_big_endian())
+      if (target.is_big_endian())
 #ifdef HAVE_TARGET_64_BIG
         obj = new Sized_pluginobj<64, true>(input_file->filename(),
                                             input_file, offset, filesize);
@@ -1032,7 +1053,6 @@ make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
     }
 
   gold_assert(obj != NULL);
-  obj->set_target(target);
   return obj;
 }
 
index 6a98ac8d8bc19f700a763ad5b6a16770be5f05a7..965b38903e5b6894d774824f1b4117b09448b912 100644 (file)
@@ -227,7 +227,7 @@ class Plugin_manager
 
   // Add a new input file.
   ld_plugin_status
-  add_input_file(char *pathname);
+  add_input_file(char *pathname, bool is_lib);
 
   // Return TRUE if we are in the replacement phase.
   bool
index a940fd853fd422fa934871f59dba356e98e3c9cc..71f2ae468e535bfbdfd6ec4a45025aa0fb68d44d 100644 (file)
@@ -37,6 +37,7 @@
 #include "target-select.h"
 #include "tls.h"
 #include "errors.h"
+#include "gc.h"
 
 namespace
 {
@@ -110,7 +111,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-                  section_size_type view_size);
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -284,17 +286,6 @@ class Target_powerpc : public Sized_target<size, big_endian>
   Reloc_section*
   rela_dyn_section(Layout*);
 
-  // Return true if the symbol may need a COPY relocation.
-  // References from an executable object to non-function symbols
-  // defined in a dynamic object may need a COPY relocation.
-  bool
-  may_need_copy_reloc(Symbol* gsym)
-  {
-    return (!parameters->options().shared()
-            && gsym->is_from_dynobj()
-            && gsym->type() != elfcpp::STT_FUNC);
-  }
-
   // Copy a relocation against a global symbol.
   void
   copy_reloc(Symbol_table* symtab, Layout* layout,
@@ -1311,7 +1302,7 @@ Target_powerpc<size, big_endian>::Scan::global(
         // Make a dynamic relocation if necessary.
         if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -1364,7 +1355,7 @@ Target_powerpc<size, big_endian>::Scan::global(
          flags |= Symbol::FUNCTION_CALL;
        if (gsym->needs_dynamic_reloc(flags))
          {
-           if (target->may_need_copy_reloc(gsym))
+           if (gsym->may_need_copy_reloc())
              {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym,
@@ -1865,7 +1856,8 @@ Target_powerpc<size, big_endian>::relocate_section(
                        bool needs_special_offset_handling,
                        unsigned char* view,
                        typename elfcpp::Elf_types<size>::Elf_Addr address,
-                       section_size_type view_size)
+                       section_size_type view_size,
+                       const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef Target_powerpc<size, big_endian> Powerpc;
   typedef typename Target_powerpc<size, big_endian>::Relocate Powerpc_relocate;
@@ -1882,7 +1874,8 @@ Target_powerpc<size, big_endian>::relocate_section(
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
index a7a7d9c63e49473c3073e8c2469144b6839a9956..2f47565e0b7ef1540f929a2935d58cecd56b0ad9 100644 (file)
@@ -1,6 +1,6 @@
 /* pread.c -- version of pread for gold.  */
 
-/* Copyright 2006, 2007 Free Software Foundation, Inc.
+/* Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <iant@google.com>.
 
    This file is part of gold.
@@ -27,6 +27,7 @@
 
 #include "config.h"
 
+#include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
index c05d5a39aefa0c4b82cb92d83e3757fac722f939..6cff8534bb9ff679bac69211bcf88723144c3598 100644 (file)
@@ -266,13 +266,16 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
     {
       // This is an ELF object.
 
-      bool unconfigured;
+      bool unconfigured = false;
+      bool* punconfigured = (input_file->will_search_for()
+                            ? &unconfigured
+                            : NULL);
       Object* obj = make_elf_object(input_file->filename(),
                                    input_file, 0, ehdr, read_size,
-                                   &unconfigured);
+                                   punconfigured);
       if (obj == NULL)
        {
-         if (unconfigured && input_file->will_search_for())
+         if (unconfigured)
            {
              Read_symbols::incompatible_warning(this->input_argument_,
                                                 input_file);
@@ -395,6 +398,8 @@ Read_symbols::get_name() const
       std::string ret("Read_symbols ");
       if (this->input_argument_->file().is_lib())
        ret += "-l";
+      else if (this->input_argument_->file().is_searched_file())
+       ret += "-l:";
       ret += this->input_argument_->file().name();
       return ret;
     }
@@ -447,7 +452,7 @@ Add_symbols::locks(Task_locker* tl)
 // Add the symbols in the object to the symbol table.
 
 void
-Add_symbols::run(Workqueue* workqueue)
+Add_symbols::run(Workqueue*)
 {
   Pluginobj* pluginobj = this->object_->pluginobj();
   if (pluginobj != NULL)
@@ -456,21 +461,7 @@ Add_symbols::run(Workqueue* workqueue)
       return;
     }
 
-  // If this file has an incompatible format, try for another file
-  // with the same name.
-  if (this->object_->searched_for()
-      && !parameters->is_compatible_target(this->object_->target()))
-    {
-      Read_symbols::incompatible_warning(this->input_argument_,
-                                        this->object_->input_file());
-      Read_symbols::requeue(workqueue, this->input_objects_, this->symtab_,
-                           this->layout_, this->dirpath_, this->dirindex_,
-                           this->mapfile_, this->input_argument_,
-                           this->input_group_, this->next_blocker_);
-      this->object_->release();
-      delete this->object_;
-    }
-  else if (!this->input_objects_->add_object(this->object_))
+  if (!this->input_objects_->add_object(this->object_))
     {
       this->object_->release();
       delete this->object_;
@@ -601,6 +592,8 @@ Read_script::get_name() const
   std::string ret("Read_script ");
   if (this->input_argument_->file().is_lib())
     ret += "-l";
+  else if (this->input_argument_->file().is_searched_file())
+    ret += "-l:";
   ret += this->input_argument_->file().name();
   return ret;
 }
index 0842a73ca83a78d7725a1fbf0ea9343bae6777dc..3018dc3daf5f497c6c7358ad95bc841a631a0ffe 100644 (file)
@@ -31,6 +31,7 @@
 #include "object.h"
 #include "target-reloc.h"
 #include "reloc.h"
+#include "icf.h"
 
 namespace gold
 {
@@ -68,7 +69,8 @@ Read_relocs::run(Workqueue* workqueue)
   // If garbage collection or identical comdat folding is desired, we  
   // process the relocs first before scanning them.  Scanning of relocs is
   // done only after garbage or identical sections is identified.
-  if (parameters->options().gc_sections() || parameters->options().icf())
+  if (parameters->options().gc_sections()
+      || parameters->options().icf_enabled())
     {
       workqueue->queue_next(new Gc_process_relocs(this->options_,
                                                   this->symtab_,
@@ -363,7 +365,8 @@ Sized_relobj<size, big_endian>::do_gc_process_relocs(const General_options& opti
                                               Layout* layout,
                                               Read_relocs_data* rd)
 {  
-  Sized_target<size, big_endian>* target = this->sized_target();
+  Sized_target<size, big_endian>* target =
+    parameters->sized_target<size, big_endian>();
 
   const unsigned char* local_symbols;
   if (rd->local_symbols == NULL)
@@ -403,7 +406,8 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
                                               Layout* layout,
                                               Read_relocs_data* rd)
 {
-  Sized_target<size, big_endian>* target = this->sized_target();
+  Sized_target<size, big_endian>* target =
+    parameters->sized_target<size, big_endian>();
 
   const unsigned char* local_symbols;
   if (rd->local_symbols == NULL)
@@ -418,7 +422,8 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
       // When garbage collection is on, unreferenced sections are not included
       // in the link that would have been included normally. This is known only
       // after Read_relocs hence this check has to be done again.
-      if (parameters->options().gc_sections() || parameters->options().icf())
+      if (parameters->options().gc_sections()
+         || parameters->options().icf_enabled())
         {
           if (p->output_section == NULL)
             continue;
@@ -802,7 +807,8 @@ Sized_relobj<size, big_endian>::relocate_sections(
     Views* pviews)
 {
   unsigned int shnum = this->shnum();
-  Sized_target<size, big_endian>* target = this->sized_target();
+  Sized_target<size, big_endian>* target =
+    parameters->sized_target<size, big_endian>();
 
   const Output_sections& out_sections(this->output_sections());
   const std::vector<Address>& out_offsets(this->section_offsets_);
@@ -884,40 +890,39 @@ Sized_relobj<size, big_endian>::relocate_sections(
                  || this->relocs_must_follow_section_writes());
 
       relinfo.reloc_shndx = i;
+      relinfo.reloc_shdr = p;
       relinfo.data_shndx = index;
+      relinfo.data_shdr = pshdrs + index * This::shdr_size;
+      unsigned char* view = (*pviews)[index].view;
+      Address address = (*pviews)[index].address;
+      section_size_type view_size = (*pviews)[index].view_size;
+
+      Reloc_symbol_changes* reloc_map = NULL;
+      if (this->uses_split_stack() && output_offset != invalid_address)
+       {
+         typename This::Shdr data_shdr(pshdrs + index * This::shdr_size);
+         if ((data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+           this->split_stack_adjust(symtab, pshdrs, sh_type, index,
+                                    prelocs, reloc_count, view, view_size,
+                                    &reloc_map);
+       }
+
       if (!parameters->options().relocatable())
        {
-         target->relocate_section(&relinfo,
-                                  sh_type,
-                                  prelocs,
-                                  reloc_count,
-                                  os,
+         target->relocate_section(&relinfo, sh_type, prelocs, reloc_count, os,
                                   output_offset == invalid_address,
-                                  (*pviews)[index].view,
-                                  (*pviews)[index].address,
-                                  (*pviews)[index].view_size);
+                                  view, address, view_size, reloc_map);
          if (parameters->options().emit_relocs())
            this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
-                             os, output_offset,
-                             (*pviews)[index].view,
-                             (*pviews)[index].address,
-                             (*pviews)[index].view_size,
-                             (*pviews)[i].view,
-                             (*pviews)[i].view_size);
+                             os, output_offset, view, address, view_size,
+                             (*pviews)[i].view, (*pviews)[i].view_size);
        }
       else
        {
          Relocatable_relocs* rr = this->relocatable_relocs(i);
-         target->relocate_for_relocatable(&relinfo,
-                                          sh_type,
-                                          prelocs,
-                                          reloc_count,
-                                          os,
-                                          output_offset,
-                                          rr,
-                                          (*pviews)[index].view,
-                                          (*pviews)[index].address,
-                                          (*pviews)[index].view_size,
+         target->relocate_for_relocatable(&relinfo, sh_type, prelocs,
+                                          reloc_count, os, output_offset, rr,
+                                          view, address, view_size,
                                           (*pviews)[i].view,
                                           (*pviews)[i].view_size);
        }
@@ -1022,6 +1027,244 @@ Sized_relobj<size, big_endian>::free_input_to_output_maps()
     }
 }
 
+// If an object was compiled with -fsplit-stack, this is called to
+// check whether any relocations refer to functions defined in objects
+// which were not compiled with -fsplit-stack.  If they were, then we
+// need to apply some target-specific adjustments to request
+// additional stack space.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::split_stack_adjust(
+    const Symbol_table* symtab,
+    const unsigned char* pshdrs,
+    unsigned int sh_type,
+    unsigned int shndx,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    unsigned char* view,
+    section_size_type view_size,
+    Reloc_symbol_changes** reloc_map)
+{
+  if (sh_type == elfcpp::SHT_REL)
+    this->split_stack_adjust_reltype<elfcpp::SHT_REL>(symtab, pshdrs, shndx,
+                                                     prelocs, reloc_count,
+                                                     view, view_size,
+                                                     reloc_map);
+  else
+    {
+      gold_assert(sh_type == elfcpp::SHT_RELA);
+      this->split_stack_adjust_reltype<elfcpp::SHT_RELA>(symtab, pshdrs, shndx,
+                                                        prelocs, reloc_count,
+                                                        view, view_size,
+                                                        reloc_map);
+    }
+}
+
+// Adjust for -fsplit-stack, templatized on the type of the relocation
+// section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj<size, big_endian>::split_stack_adjust_reltype(
+    const Symbol_table* symtab,
+    const unsigned char* pshdrs,
+    unsigned int shndx,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    unsigned char* view,
+    section_size_type view_size,
+    Reloc_symbol_changes** reloc_map)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+  size_t local_count = this->local_symbol_count();
+
+  std::vector<section_offset_type> non_split_refs;
+
+  const unsigned char* pr = prelocs;
+  for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+    {
+      Reltype reloc(pr);
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      if (r_sym < local_count)
+       continue;
+
+      const Symbol* gsym = this->global_symbol(r_sym);
+      gold_assert(gsym != NULL);
+      if (gsym->is_forwarder())
+       gsym = symtab->resolve_forwards(gsym);
+
+      // See if this relocation refers to a function defined in an
+      // object compiled without -fsplit-stack.  Note that we don't
+      // care about the type of relocation--this means that in some
+      // cases we will ask for a large stack unnecessarily, but this
+      // is not fatal.  FIXME: Some targets have symbols which are
+      // functions but are not type STT_FUNC, e.g., STT_ARM_TFUNC.
+      if (gsym->type() == elfcpp::STT_FUNC
+         && !gsym->is_undefined()
+         && gsym->source() == Symbol::FROM_OBJECT
+         && !gsym->object()->uses_split_stack())
+       {
+         section_offset_type offset =
+           convert_to_section_size_type(reloc.get_r_offset());
+         non_split_refs.push_back(offset);
+       }
+    }
+
+  if (non_split_refs.empty())
+    return;
+
+  // At this point, every entry in NON_SPLIT_REFS indicates a
+  // relocation which refers to a function in an object compiled
+  // without -fsplit-stack.  We now have to convert that list into a
+  // set of offsets to functions.  First, we find all the functions.
+
+  Function_offsets function_offsets;
+  this->find_functions(pshdrs, shndx, &function_offsets);
+  if (function_offsets.empty())
+    return;
+
+  // Now get a list of the function with references to non split-stack
+  // code.
+
+  Function_offsets calls_non_split;
+  for (std::vector<section_offset_type>::const_iterator p
+        = non_split_refs.begin();
+       p != non_split_refs.end();
+       ++p)
+    {
+      Function_offsets::const_iterator low = function_offsets.lower_bound(*p);
+      if (low == function_offsets.end())
+       --low;
+      else if (low->first == *p)
+       ;
+      else if (low == function_offsets.begin())
+       continue;
+      else
+       --low;
+
+      calls_non_split.insert(*low);
+    }
+  if (calls_non_split.empty())
+    return;
+
+  // Now we have a set of functions to adjust.  The adjustments are
+  // target specific.  Besides changing the output section view
+  // however, it likes, the target may request a relocation change
+  // from one global symbol name to another.
+
+  for (Function_offsets::const_iterator p = calls_non_split.begin();
+       p != calls_non_split.end();
+       ++p)
+    {
+      std::string from;
+      std::string to;
+      parameters->target().calls_non_split(this, shndx, p->first, p->second,
+                                          view, view_size, &from, &to);
+      if (!from.empty())
+       {
+         gold_assert(!to.empty());
+         Symbol* tosym = NULL;
+
+         // Find relocations in the relevant function which are for
+         // FROM.
+         pr = prelocs;
+         for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+           {
+             Reltype reloc(pr);
+
+             typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+               reloc.get_r_info();
+             unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+             if (r_sym < local_count)
+               continue;
+
+             section_offset_type offset =
+               convert_to_section_size_type(reloc.get_r_offset());
+             if (offset < p->first
+                 || (offset
+                     >= (p->first
+                         + static_cast<section_offset_type>(p->second))))
+               continue;
+
+             const Symbol* gsym = this->global_symbol(r_sym);
+             if (from == gsym->name())
+               {
+                 if (tosym == NULL)
+                   {
+                     tosym = symtab->lookup(to.c_str());
+                     if (tosym == NULL)
+                       {
+                         this->error(_("could not convert call "
+                                       "to '%s' to '%s'"),
+                                     from.c_str(), to.c_str());
+                         break;
+                       }
+                   }
+
+                 if (*reloc_map == NULL)
+                   *reloc_map = new Reloc_symbol_changes(reloc_count);
+                 (*reloc_map)->set(i, tosym);
+               }
+           }
+       }
+    }
+}
+
+// Find all the function in this object defined in section SHNDX.
+// Store their offsets in the section in FUNCTION_OFFSETS.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::find_functions(
+    const unsigned char* pshdrs,
+    unsigned int shndx,
+    Sized_relobj<size, big_endian>::Function_offsets* function_offsets)
+{
+  // We need to read the symbols to find the functions.  If we wanted
+  // to, we could cache reading the symbols across all sections in the
+  // object.
+  const unsigned int symtab_shndx = this->symtab_shndx_;
+  typename This::Shdr symtabshdr(pshdrs + symtab_shndx * This::shdr_size);
+  gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+  typename elfcpp::Elf_types<size>::Elf_WXword sh_size =
+    symtabshdr.get_sh_size();
+  const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+                                             sh_size, true, true);
+
+  const int sym_size = This::sym_size;
+  const unsigned int symcount = sh_size / sym_size;
+  for (unsigned int i = 0; i < symcount; ++i, psyms += sym_size)
+    {
+      typename elfcpp::Sym<size, big_endian> isym(psyms);
+
+      // FIXME: Some targets can have functions which do not have type
+      // STT_FUNC, e.g., STT_ARM_TFUNC.
+      if (isym.get_st_type() != elfcpp::STT_FUNC
+         || isym.get_st_size() == 0)
+       continue;
+
+      bool is_ordinary;
+      unsigned int sym_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+                                                     &is_ordinary);
+      if (!is_ordinary || sym_shndx != shndx)
+       continue;
+
+      section_offset_type value =
+       convert_to_section_size_type(isym.get_st_value());
+      section_size_type fnsize =
+       convert_to_section_size_type(isym.get_st_size());
+
+      (*function_offsets)[value] = fnsize;
+    }
+}
+
 // Class Merged_symbol_value.
 
 template<int size>
index 45a4a7aabda34571be6bfeff74225ed46a02b720..82af9b4c6e83afc800cc6932185a3f573a8ea235 100644 (file)
@@ -244,10 +244,10 @@ Symbol_table::resolve(Sized_symbol<size>* to,
                      unsigned int orig_st_shndx,
                      Object* object, const char* version)
 {
-  if (object->target()->has_resolve())
+  if (parameters->target().has_resolve())
     {
       Sized_target<size, big_endian>* sized_target;
-      sized_target = object->sized_target<size, big_endian>();
+      sized_target = parameters->sized_target<size, big_endian>();
       sized_target->resolve(to, sym, object, version);
       return;
     }
index 7396b3bf2485362b6f795225bd0fa2f470292447..a541e9aa13ed3756ed11860990f70d80c9d965bd 100644 (file)
@@ -524,7 +524,7 @@ class Output_section_element
 {
  public:
   // A list of input sections.
-  typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list;
+  typedef std::list<Output_section::Simple_input_section> Input_section_list;
 
   Output_section_element()
   { }
@@ -701,6 +701,7 @@ Output_section_element_dot_assignment::set_section_addresses(
          posd = new Output_data_const(this_fill, 0);
        }
       output_section->add_output_section_data(posd);
+      layout->new_output_section_data_from_script(posd);
     }
   *dot_value = next_dot;
 }
@@ -736,7 +737,7 @@ class Output_data_expression : public Output_section_data
   Output_data_expression(int size, bool is_signed, Expression* val,
                         const Symbol_table* symtab, const Layout* layout,
                         uint64_t dot_value, Output_section* dot_section)
-    : Output_section_data(size, 0),
+    : Output_section_data(size, 0, true),
       is_signed_(is_signed), val_(val), symtab_(symtab),
       layout_(layout), dot_value_(dot_value), dot_section_(dot_section)
   { }
@@ -877,13 +878,11 @@ Output_section_element_data::set_section_addresses(
     Input_section_list*)
 {
   gold_assert(os != NULL);
-  os->add_output_section_data(new Output_data_expression(this->size_,
-                                                        this->is_signed_,
-                                                        this->val_,
-                                                        symtab,
-                                                        layout,
-                                                        *dot_value,
-                                                        *dot_section));
+  Output_data_expression* expression =
+    new Output_data_expression(this->size_, this->is_signed_, this->val_,
+                              symtab, layout, *dot_value, *dot_section);
+  os->add_output_section_data(expression);
+  layout->new_output_section_data_from_script(expression);
   *dot_value += this->size_;
 }
 
@@ -1169,13 +1168,68 @@ Output_section_element_input::match_name(const char* file_name,
 
 // Information we use to sort the input sections.
 
-struct Input_section_info
+class Input_section_info
 {
-  Relobj* relobj;
-  unsigned int shndx;
-  std::string section_name;
-  uint64_t size;
-  uint64_t addralign;
+ public:
+  Input_section_info(const Output_section::Simple_input_section& input_section)
+    : input_section_(input_section), section_name_(),
+      size_(0), addralign_(1)
+  { }
+
+  // Return the simple input section.
+  const Output_section::Simple_input_section&
+  input_section() const
+  { return this->input_section_; }
+
+  // Return the object.
+  Relobj*
+  relobj() const
+  { return this->input_section_.relobj(); }
+
+  // Return the section index.
+  unsigned int
+  shndx()
+  { return this->input_section_.shndx(); }
+
+  // Return the section name.
+  const std::string&
+  section_name() const
+  { return this->section_name_; }
+
+  // Set the section name.
+  void
+  set_section_name(const std::string name)
+  { this->section_name_ = name; }
+
+  // Return the section size.
+  uint64_t
+  size() const
+  { return this->size_; }
+
+  // Set the section size.
+  void
+  set_size(uint64_t size)
+  { this->size_ = size; }
+
+  // Return the address alignment.
+  uint64_t
+  addralign() const
+  { return this->addralign_; }
+
+  // Set the address alignment.
+  void
+  set_addralign(uint64_t addralign)
+  { this->addralign_ = addralign; }
+
+ private:
+  // Input section, can be a relaxed section.
+  Output_section::Simple_input_section input_section_;
+  // Name of the section. 
+  std::string section_name_;
+  // Section size.
+  uint64_t size_;
+  // Address alignment.
+  uint64_t addralign_;
 };
 
 // A class to sort the input sections.
@@ -1202,22 +1256,22 @@ Input_section_sorter::operator()(const Input_section_info& isi1,
   if (this->section_sort_ == SORT_WILDCARD_BY_NAME
       || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
       || (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME
-         && isi1.addralign == isi2.addralign))
+         && isi1.addralign() == isi2.addralign()))
     {
-      if (isi1.section_name != isi2.section_name)
-       return isi1.section_name < isi2.section_name;
+      if (isi1.section_name() != isi2.section_name())
+       return isi1.section_name() < isi2.section_name();
     }
   if (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT
       || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
       || this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME)
     {
-      if (isi1.addralign != isi2.addralign)
-       return isi1.addralign < isi2.addralign;
+      if (isi1.addralign() != isi2.addralign())
+       return isi1.addralign() < isi2.addralign();
     }
   if (this->filename_sort_ == SORT_WILDCARD_BY_NAME)
     {
-      if (isi1.relobj->name() != isi2.relobj->name())
-       return isi1.relobj->name() < isi2.relobj->name();
+      if (isi1.relobj()->name() != isi2.relobj()->name())
+       return (isi1.relobj()->name() < isi2.relobj()->name());
     }
 
   // Otherwise we leave them in the same order.
@@ -1231,7 +1285,7 @@ Input_section_sorter::operator()(const Input_section_info& isi1,
 void
 Output_section_element_input::set_section_addresses(
     Symbol_table*,
-    Layout*,
+    Layout* layout,
     Output_section* output_section,
     uint64_t subalign,
     uint64_t* dot_value,
@@ -1255,25 +1309,36 @@ Output_section_element_input::set_section_addresses(
   Input_section_list::iterator p = input_sections->begin();
   while (p != input_sections->end())
     {
+      Relobj* relobj = p->relobj();
+      unsigned int shndx = p->shndx();      
+      Input_section_info isi(*p);
+
       // Calling section_name and section_addralign is not very
       // efficient.
-      Input_section_info isi;
-      isi.relobj = p->first;
-      isi.shndx = p->second;
 
       // Lock the object so that we can get information about the
       // section.  This is OK since we know we are single-threaded
       // here.
       {
        const Task* task = reinterpret_cast<const Task*>(-1);
-       Task_lock_obj<Object> tl(task, p->first);
-
-       isi.section_name = p->first->section_name(p->second);
-       isi.size = p->first->section_size(p->second);
-       isi.addralign = p->first->section_addralign(p->second);
+       Task_lock_obj<Object> tl(task, relobj);
+
+       isi.set_section_name(relobj->section_name(shndx));
+       if (p->is_relaxed_input_section())
+         {
+           // We use current data size because relxed section sizes may not
+           // have finalized yet.
+           isi.set_size(p->relaxed_input_section()->current_data_size());
+           isi.set_addralign(p->relaxed_input_section()->addralign());
+         }
+       else
+         {
+           isi.set_size(relobj->section_size(shndx));
+           isi.set_addralign(relobj->section_addralign(shndx));
+         }
       }
 
-      if (!this->match_file_name(isi.relobj->name().c_str()))
+      if (!this->match_file_name(relobj->name().c_str()))
        ++p;
       else if (this->input_section_patterns_.empty())
        {
@@ -1287,7 +1352,7 @@ Output_section_element_input::set_section_addresses(
            {
              const Input_section_pattern&
                isp(this->input_section_patterns_[i]);
-             if (match(isi.section_name.c_str(), isp.pattern.c_str(),
+             if (match(isi.section_name().c_str(), isp.pattern.c_str(),
                        isp.pattern_is_wildcard))
                break;
            }
@@ -1307,6 +1372,7 @@ Output_section_element_input::set_section_addresses(
   // sections are otherwise equal.  Add each input section to the
   // output section.
 
+  uint64_t dot = *dot_value;
   for (size_t i = 0; i < input_pattern_count; ++i)
     {
       if (matching_sections[i].empty())
@@ -1327,30 +1393,37 @@ Output_section_element_input::set_section_addresses(
           p != matching_sections[i].end();
           ++p)
        {
-         uint64_t this_subalign = p->addralign;
+         uint64_t this_subalign = p->addralign();
          if (this_subalign < subalign)
            this_subalign = subalign;
 
-         uint64_t address = align_address(*dot_value, this_subalign);
+         uint64_t address = align_address(dot, this_subalign);
 
-         if (address > *dot_value && !fill->empty())
+         if (address > dot && !fill->empty())
            {
              section_size_type length =
-               convert_to_section_size_type(address - *dot_value);
+               convert_to_section_size_type(address - dot);
              std::string this_fill = this->get_fill_string(fill, length);
              Output_section_data* posd = new Output_data_const(this_fill, 0);
              output_section->add_output_section_data(posd);
+             layout->new_output_section_data_from_script(posd);
            }
 
-         output_section->add_input_section_for_script(p->relobj,
-                                                      p->shndx,
-                                                      p->size,
+         output_section->add_input_section_for_script(p->input_section(),
+                                                      p->size(),
                                                       this_subalign);
 
-         *dot_value = address + p->size;
+         dot = address + p->size();
        }
     }
 
+  // An SHF_TLS/SHT_NOBITS section does not take up any
+  // address space.
+  if (output_section == NULL
+      || (output_section->flags() & elfcpp::SHF_TLS) == 0
+      || output_section->type() != elfcpp::SHT_NOBITS)
+    *dot_value = dot;
+
   this->final_dot_value_ = *dot_value;
   this->final_dot_section_ = *dot_section;
 }
@@ -2202,7 +2275,7 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
                                             uint64_t* dot_value,
                                              uint64_t* load_address)
 {
-  typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list;
+  typedef std::list<Output_section::Simple_input_section> Input_section_list;
 
   bool have_load_address = *load_address != *dot_value;
 
@@ -2231,23 +2304,33 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
       // object.
       {
        const Task* task = reinterpret_cast<const Task*>(-1);
-       Task_lock_obj<Object> tl(task, p->first);
-       addralign = p->first->section_addralign(p->second);
-       size = p->first->section_size(p->second);
+       Task_lock_obj<Object> tl(task, p->relobj());
+       addralign = p->relobj()->section_addralign(p->shndx());
+       if (p->is_relaxed_input_section())
+         // We use current data size because relxed section sizes may not
+         // have finalized yet.
+         size = p->relaxed_input_section()->current_data_size();
+       else
+         size = p->relobj()->section_size(p->shndx());
       }
 
       address = align_address(address, addralign);
-      this->os_->add_input_section_for_script(p->first, p->second, size,
-                                              addralign);
+      this->os_->add_input_section_for_script(*p, size, addralign);
       address += size;
     }
 
-  if (!have_load_address)
-    *load_address = address;
-  else
-    *load_address += address - *dot_value;
+  // An SHF_TLS/SHT_NOBITS section does not take up any address space.
+  if (this->os_ == NULL
+      || (this->os_->flags() & elfcpp::SHF_TLS) == 0
+      || this->os_->type() != elfcpp::SHT_NOBITS)
+    {
+      if (!have_load_address)
+       *load_address = address;
+      else
+       *load_address += address - *dot_value;
 
-  *dot_value = address;
+      *dot_value = address;
+    }
 }
 
 // Get the list of segments to use for an allocated section when using
@@ -2333,6 +2416,11 @@ class Phdrs_element
   segment()
   { return this->segment_; }
 
+  // Release the segment.
+  void
+  release_segment()
+  { this->segment_ = NULL; }
+
   // Set the segment flags if appropriate.
   void
   set_flags_if_valid()
@@ -2452,6 +2540,15 @@ Script_sections::add_dot_assignment(Expression* val)
     this->output_section_->add_dot_assignment(val);
   else
     {
+      // The GNU linker permits assignments to . to appears outside of
+      // a SECTIONS clause, and treats it as appearing inside, so
+      // sections_elements_ may be NULL here.
+      if (this->sections_elements_ == NULL)
+       {
+         this->sections_elements_ = new Sections_elements;
+         this->saw_sections_clause_ = true;
+       }
+
       Sections_element* p = new Sections_element_dot_assignment(val);
       this->sections_elements_->push_back(p);
     }
@@ -3165,12 +3262,15 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
   // Output sections in the script which do not list segments are
   // attached to the same set of segments as the immediately preceding
   // output section.
+  
   String_list* phdr_names = NULL;
+  bool load_segments_only = false;
   for (Sections_elements::const_iterator p = this->sections_elements_->begin();
        p != this->sections_elements_->end();
        ++p)
     {
       bool orphan;
+      String_list* old_phdr_names = phdr_names;
       Output_section* os = (*p)->allocate_to_segment(&phdr_names, &orphan);
       if (os == NULL)
        continue;
@@ -3181,6 +3281,11 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
          continue;
        }
 
+      // We see a list of segments names.  Disable PT_LOAD segment only
+      // filtering.
+      if (old_phdr_names != phdr_names)
+       load_segments_only = false;
+               
       // If this is an orphan section--one that was not explicitly
       // mentioned in the linker script--then it should not inherit
       // any segment type other than PT_LOAD.  Otherwise, e.g., the
@@ -3189,17 +3294,9 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
       // we trust the linker script.
       if (orphan)
        {
-         String_list::iterator q = phdr_names->begin();
-         while (q != phdr_names->end())
-           {
-             Name_to_segment::const_iterator r = name_to_segment.find(*q);
-             // We give errors about unknown segments below.
-             if (r == name_to_segment.end()
-                 || r->second->type() == elfcpp::PT_LOAD)
-               ++q;
-             else
-               q = phdr_names->erase(q);
-           }
+         // Enable PT_LOAD segments only filtering until we see another
+         // list of segment names.
+         load_segments_only = true;
        }
 
       bool in_load_segment = false;
@@ -3212,6 +3309,10 @@ Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
            gold_error(_("no segment %s"), q->c_str());
          else
            {
+             if (load_segments_only
+                 && r->second->type() != elfcpp::PT_LOAD)
+               continue;
+
              elfcpp::Elf_Word seg_flags =
                Layout::section_flags_to_segment(os->flags());
              r->second->add_output_section(os, seg_flags);
@@ -3366,6 +3467,21 @@ Script_sections::get_output_section_info(const char* name, uint64_t* address,
   return false;
 }
 
+// Release all Output_segments.  This remove all pointers to all
+// Output_segments.
+
+void
+Script_sections::release_segments()
+{
+  if (this->saw_phdrs_clause())
+    {
+      for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
+          p != this->phdrs_elements_->end();
+          ++p)
+       (*p)->release_segment();
+    }
+}
+
 // Print the SECTIONS clause to F for debugging.
 
 void
index 390c35089678cb301ae3c08f8ead73b84dc2e512..b326eae4bd9e1865893480b74cb1f1e996c04167 100644 (file)
@@ -187,6 +187,10 @@ class Script_sections
                           uint64_t* load_address, uint64_t* addralign,
                           uint64_t* size) const;
 
+  // Release all Output_segments.  This is used in relaxation.
+  void
+  release_segments();
+
   // Print the contents to the FILE.  This is for debugging.
   void
   print(FILE*) const;
index 05a39e7d4b5dfa0312a3d2d28e9511ecc558607f..d0ffe41a6158a479c6dbdb6d5cc835d4e95d487a 100644 (file)
@@ -1,6 +1,6 @@
 // script.cc -- handle linker scripts for gold.
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -743,7 +743,7 @@ Lex::get_token(const char** pp)
        }
 
       // Skip whitespace quickly.
-      while (*p == ' ' || *p == '\t')
+      while (*p == ' ' || *p == '\t' || *p == '\r')
        ++p;
 
       if (*p == '\n')
@@ -1070,10 +1070,11 @@ Script_options::add_symbol_assignment(const char* name, size_t length,
     {
       if (provide || hidden)
        gold_error(_("invalid use of PROVIDE for dot symbol"));
-      if (!this->script_sections_.in_sections_clause())
-       gold_error(_("invalid assignment to dot outside of SECTIONS"));
-      else
-       this->script_sections_.add_dot_assignment(value);
+
+      // The GNU linker permits assignments to dot outside of SECTIONS
+      // clauses and treats them as occurring inside, so we don't
+      // check in_sections_clause here.
+      this->script_sections_.add_dot_assignment(value);
     }
 }
 
@@ -1452,7 +1453,9 @@ read_script_file(const char* filename, Command_line* cmdline,
   Position_dependent_options posdep = cmdline->position_dependent_options();
   if (posdep.format_enum() == General_options::OBJECT_FORMAT_BINARY)
     posdep.set_format_enum(General_options::OBJECT_FORMAT_ELF);
-  Input_file_argument input_argument(filename, false, "", false, posdep);
+  Input_file_argument input_argument(filename,
+                                    Input_file_argument::INPUT_FILE_TYPE_FILE,
+                                    "", false, posdep);
   Input_file input_file(&input_argument);
   int dummy = 0;
   if (!input_file.open(dirsearch, task, &dummy))
@@ -2179,8 +2182,10 @@ script_add_file(void* closurev, const char* name, size_t length)
        }
     }
 
-  Input_file_argument file(name_string.c_str(), false, extra_search_path,
-                          false, closure->position_dependent_options());
+  Input_file_argument file(name_string.c_str(),
+                          Input_file_argument::INPUT_FILE_TYPE_FILE,
+                          extra_search_path, false,
+                          closure->position_dependent_options());
   closure->inputs()->add_file(file);
 }
 
index 34288dea66d71a3de213551d12a9c56a8feaeb18..eac983f8ef908406855db9771352ca31c00f24ff 100644 (file)
@@ -40,6 +40,7 @@
 #include "target-select.h"
 #include "tls.h"
 #include "errors.h"
+#include "gc.h"
 
 namespace
 {
@@ -112,7 +113,8 @@ class Target_sparc : public Sized_target<size, big_endian>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-                  section_size_type view_size);
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -305,17 +307,6 @@ class Target_sparc : public Sized_target<size, big_endian>
   Reloc_section*
   rela_dyn_section(Layout*);
 
-  // Return true if the symbol may need a COPY relocation.
-  // References from an executable object to non-function symbols
-  // defined in a dynamic object may need a COPY relocation.
-  bool
-  may_need_copy_reloc(Symbol* gsym)
-  {
-    return (!parameters->options().shared()
-            && gsym->is_from_dynobj()
-            && gsym->type() != elfcpp::STT_FUNC);
-  }
-
   // Copy a relocation against a global symbol.
   void
   copy_reloc(Symbol_table* symtab, Layout* layout,
@@ -1984,7 +1975,7 @@ Target_sparc<size, big_endian>::Scan::global(
          flags |= Symbol::FUNCTION_CALL;
        if (gsym->needs_dynamic_reloc(flags))
          {
-           if (target->may_need_copy_reloc(gsym))
+           if (gsym->may_need_copy_reloc())
              {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym,
@@ -2040,7 +2031,7 @@ Target_sparc<size, big_endian>::Scan::global(
         // Make a dynamic relocation if necessary.
         if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -3117,7 +3108,8 @@ Target_sparc<size, big_endian>::relocate_section(
                        bool needs_special_offset_handling,
                        unsigned char* view,
                        typename elfcpp::Elf_types<size>::Elf_Addr address,
-                       section_size_type view_size)
+                       section_size_type view_size,
+                       const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef Target_sparc<size, big_endian> Sparc;
   typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
@@ -3134,7 +3126,8 @@ Target_sparc<size, big_endian>::relocate_section(
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
index 292a26275dec2b3e224fe778019b2bbf256d678a..5dbab35b73b4c79509102576456bc08ac822bd22 100644 (file)
@@ -394,7 +394,8 @@ Symbol::final_value_is_known() const
 {
   // If we are not generating an executable, then no final values are
   // known, since they will change at runtime.
-  if (parameters->options().shared() || parameters->options().relocatable())
+  if (parameters->options().output_is_position_independent()
+      || parameters->options().relocatable())
     return false;
 
   // If the symbol is not from an object file, and is not undefined,
@@ -519,7 +520,7 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
 bool
 Symbol_table::is_section_folded(Object* obj, unsigned int shndx) const
 {
-  return (parameters->options().icf()
+  return (parameters->options().icf_enabled()
           && this->icf_->is_section_folded(obj, shndx));
 }
 
@@ -688,13 +689,12 @@ Symbol_table::force_local(Symbol* sym)
 // option was used.
 
 const char*
-Symbol_table::wrap_symbol(Object* object, const char* name,
-                         Stringpool::Key* name_key)
+Symbol_table::wrap_symbol(const char* name, Stringpool::Key* name_key)
 {
   // For some targets, we need to ignore a specific character when
   // wrapping, and add it back later.
   char prefix = '\0';
-  if (name[0] == object->target()->wrap_char())
+  if (name[0] == parameters->target().wrap_char())
     {
       prefix = name[0];
       ++name;
@@ -864,7 +864,7 @@ Symbol_table::add_from_object(Object* object,
   if (orig_st_shndx == elfcpp::SHN_UNDEF
       && parameters->options().any_wrap())
     {
-      const char* wrap_name = this->wrap_symbol(object, name, &name_key);
+      const char* wrap_name = this->wrap_symbol(name, &name_key);
       if (wrap_name != name)
        {
          // If we see a reference to malloc with version GLIBC_2.0,
@@ -945,7 +945,7 @@ Symbol_table::add_from_object(Object* object,
          was_common = false;
 
          Sized_target<size, big_endian>* target =
-           object->sized_target<size, big_endian>();
+           parameters->sized_target<size, big_endian>();
          if (!target->has_make_symbol())
            ret = new Sized_symbol<size>();
          else
@@ -1033,7 +1033,6 @@ Symbol_table::add_from_relobj(
 {
   *defined = 0;
 
-  gold_assert(size == relobj->target()->get_size());
   gold_assert(size == parameters->target().get_size());
 
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
@@ -1272,7 +1271,6 @@ Symbol_table::add_from_dynobj(
 {
   *defined = 0;
 
-  gold_assert(size == dynobj->target()->get_size());
   gold_assert(size == parameters->target().get_size());
 
   if (dynobj->just_symbols())
@@ -1661,11 +1659,8 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
     sym = new Sized_symbol<size>();
   else
     {
-      gold_assert(target.get_size() == size);
-      gold_assert(target.is_big_endian() ? big_endian : !big_endian);
-      typedef Sized_target<size, big_endian> My_target;
-      const My_target* sized_target =
-          static_cast<const My_target*>(&target);
+      Sized_target<size, big_endian>* sized_target =
+       parameters->sized_target<size, big_endian>();
       sym = sized_target->make_symbol();
       if (sym == NULL)
         return NULL;
@@ -2361,30 +2356,17 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool,
   return off;
 }
 
-// Finalize the symbol SYM.  This returns true if the symbol should be
-// added to the symbol table, false otherwise.
+// Compute the final value of SYM and store status in location PSTATUS.
+// During relaxation, this may be called multiple times for a symbol to
+// compute its would-be final value in each relaxation pass.
 
 template<int size>
-bool
-Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+typename Sized_symbol<size>::Value_type
+Symbol_table::compute_final_value(
+    const Sized_symbol<size>* sym,
+    Compute_final_value_status* pstatus) const
 {
   typedef typename Sized_symbol<size>::Value_type Value_type;
-
-  Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
-
-  // The default version of a symbol may appear twice in the symbol
-  // table.  We only need to finalize it once.
-  if (sym->has_symtab_index())
-    return false;
-
-  if (!sym->in_reg())
-    {
-      gold_assert(!sym->has_symtab_index());
-      sym->set_symtab_index(-1U);
-      gold_assert(sym->dynsym_index() == -1U);
-      return false;
-    }
-
   Value_type value;
 
   switch (sym->source())
@@ -2398,9 +2380,8 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
            && shndx != elfcpp::SHN_ABS
            && !Symbol::is_common_shndx(shndx))
          {
-           gold_error(_("%s: unsupported symbol section 0x%x"),
-                      sym->demangled_name().c_str(), shndx);
-           shndx = elfcpp::SHN_UNDEF;
+           *pstatus = CFVS_UNSUPPORTED_SYMBOL_SECTION;
+           return 0;
          }
 
        Object* symobj = sym->object();
@@ -2441,12 +2422,12 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
 
            if (os == NULL)
              {
-               sym->set_symtab_index(-1U);
                 bool static_or_reloc = (parameters->doing_static_link() ||
                                         parameters->options().relocatable());
                 gold_assert(static_or_reloc || sym->dynsym_index() == -1U);
 
-               return false;
+               *pstatus = CFVS_NO_OUTPUT_SECTION;
+               return 0;
              }
 
             if (secoff64 == -1ULL)
@@ -2519,9 +2500,61 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
       gold_unreachable();
     }
 
+  *pstatus = CFVS_OK;
+  return value;
+}
+
+// Finalize the symbol SYM.  This returns true if the symbol should be
+// added to the symbol table, false otherwise.
+
+template<int size>
+bool
+Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+{
+  typedef typename Sized_symbol<size>::Value_type Value_type;
+
+  Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
+
+  // The default version of a symbol may appear twice in the symbol
+  // table.  We only need to finalize it once.
+  if (sym->has_symtab_index())
+    return false;
+
+  if (!sym->in_reg())
+    {
+      gold_assert(!sym->has_symtab_index());
+      sym->set_symtab_index(-1U);
+      gold_assert(sym->dynsym_index() == -1U);
+      return false;
+    }
+
+  // Compute final symbol value.
+  Compute_final_value_status status;
+  Value_type value = this->compute_final_value(sym, &status);
+
+  switch (status)
+    {
+    case CFVS_OK:
+      break;
+    case CFVS_UNSUPPORTED_SYMBOL_SECTION:
+      {
+       bool is_ordinary;
+       unsigned int shndx = sym->shndx(&is_ordinary);
+       gold_error(_("%s: unsupported symbol section 0x%x"),
+                  sym->demangled_name().c_str(), shndx);
+      }
+      break;
+    case CFVS_NO_OUTPUT_SECTION:
+      sym->set_symtab_index(-1U);
+      return false;
+    default:
+      gold_unreachable();
+    }
+
   sym->set_value(value);
 
-  if (parameters->options().strip_all())
+  if (parameters->options().strip_all()
+      || !parameters->options().should_retain_symbol(sym->name()))
     {
       sym->set_symtab_index(-1U);
       return false;
index b89fd6641316667f7679637fcb04ffbc438818ec..d1cd64761ccabc389a1f39e93fab7e3c840d603f 100644 (file)
 // Symbol_table
 //   The symbol table.
 
+#ifndef GOLD_SYMTAB_H
+#define GOLD_SYMTAB_H
+
 #include <string>
 #include <utility>
 #include <vector>
 
-#include "gc.h"
-#include "icf.h"
 #include "elfcpp.h"
 #include "parameters.h"
 #include "stringpool.h"
 #include "object.h"
 
-#ifndef GOLD_SYMTAB_H
-#define GOLD_SYMTAB_H
-
 namespace gold
 {
 
@@ -535,7 +533,7 @@ class Symbol
   // Return true if this symbol is a function that needs a PLT entry.
   // If the symbol is defined in a dynamic object or if it is subject
   // to pre-emption, we need to make a PLT entry. If we're doing a
-  // static link, we don't create PLT entries.
+  // static link or a -pie link, we don't create PLT entries.
   bool
   needs_plt_entry() const
   {
@@ -544,6 +542,7 @@ class Symbol
       return false;
 
     return (!parameters->doing_static_link()
+           && !parameters->options().pie()
             && this->type() == elfcpp::STT_FUNC
             && (this->is_from_dynobj()
                 || this->is_undefined()
@@ -726,6 +725,18 @@ class Symbol
   set_is_forced_local()
   { this->is_forced_local_ = true; }
 
+  // Return true if this may need a COPY relocation.
+  // References from an executable object to non-function symbols
+  // defined in a dynamic object may need a COPY relocation.
+  bool
+  may_need_copy_reloc() const
+  {
+    return (!parameters->options().shared()
+           && parameters->options().copyreloc()
+           && this->is_from_dynobj()
+           && this->type() != elfcpp::STT_FUNC);
+  }
+
  protected:
   // Instances of this class should always be created at a specific
   // size.
@@ -1365,6 +1376,26 @@ class Symbol_table
   finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount,
           Stringpool* pool, unsigned int *plocal_symcount);
 
+  // Status code of Symbol_table::compute_final_value.
+  enum Compute_final_value_status
+  {
+    // No error.
+    CFVS_OK,
+    // Unspported symbol section.
+    CFVS_UNSUPPORTED_SYMBOL_SECTION,
+    // No output section.
+    CFVS_NO_OUTPUT_SECTION
+  };
+
+  // Compute the final value of SYM and store status in location PSTATUS.
+  // During relaxation, this may be called multiple times for a symbol to 
+  // compute its would-be final value in each relaxation pass.
+
+  template<int size>
+  typename Sized_symbol<size>::Value_type
+  compute_final_value(const Sized_symbol<size>* sym,
+                     Compute_final_value_status* pstatus) const;
+
   // Write out the global symbols.
   void
   write_globals(const Stringpool*, const Stringpool*,
@@ -1450,7 +1481,7 @@ class Symbol_table
 
   // Adjust NAME and *NAME_KEY for wrapping.
   const char*
-  wrap_symbol(Object* object, const char*, Stringpool::Key* name_key);
+  wrap_symbol(const char* name, Stringpool::Key* name_key);
 
   // Whether we should override a symbol, based on flags in
   // resolve.cc.
index d93e7552888bb71a432d7cc8324964e967354c45..bc001232f5799b02938a0f4d9cbfd2e41d265c4d 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "elfcpp.h"
 #include "symtab.h"
+#include "object.h"
 #include "reloc.h"
 #include "reloc-types.h"
 
@@ -163,6 +164,12 @@ get_comdat_behavior(const char* name)
 // NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
 // the output section.
 
+// RELOC_SYMBOL_CHANGES is used for -fsplit-stack support.  If it is
+// not NULL, it is a vector indexed by relocation index.  If that
+// entry is not NULL, it points to a global symbol which used as the
+// symbol for the relocation, ignoring the symbol index in the
+// relocation.
+
 template<int size, bool big_endian, typename Target_type, int sh_type,
         typename Relocate>
 inline void
@@ -175,7 +182,8 @@ relocate_section(
     bool needs_special_offset_handling,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-    section_size_type view_size)
+    section_size_type view_size,
+    const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
@@ -210,7 +218,9 @@ relocate_section(
 
       Symbol_value<size> symval;
       const Symbol_value<size> *psymval;
-      if (r_sym < local_count)
+      if (r_sym < local_count
+         && (reloc_symbol_changes == NULL
+             || (*reloc_symbol_changes)[i] == NULL))
        {
          sym = NULL;
          psymval = object->local_symbol(r_sym);
@@ -246,7 +256,7 @@ relocate_section(
                {
                  if (comdat_behavior == CB_WARNING)
                     gold_warning_at_location(relinfo, i, offset,
-                                             _("Relocation refers to discarded "
+                                             _("relocation refers to discarded "
                                                "comdat section"));
                   symval.set_output_value(0);
                }
@@ -256,10 +266,17 @@ relocate_section(
        }
       else
        {
-         const Symbol* gsym = object->global_symbol(r_sym);
-         gold_assert(gsym != NULL);
-         if (gsym->is_forwarder())
-           gsym = relinfo->symtab->resolve_forwards(gsym);
+         const Symbol* gsym;
+         if (reloc_symbol_changes != NULL
+             && (*reloc_symbol_changes)[i] != NULL)
+           gsym = (*reloc_symbol_changes)[i];
+         else
+           {
+             gsym = object->global_symbol(r_sym);
+             gold_assert(gsym != NULL);
+             if (gsym->is_forwarder())
+               gsym = relinfo->symtab->resolve_forwards(gsym);
+           }
 
          sym = static_cast<const Sized_symbol<size>*>(gsym);
          if (sym->has_symtab_index())
index 2dca98a06ec503a7150e0898702e29a7508224e3..0ddc13d68ed91b0a67afa6d8f60d187e705cd733 100644 (file)
@@ -23,6 +23,8 @@
 #include "gold.h"
 #include "target.h"
 #include "dynobj.h"
+#include "output.h"
+#include "elfcpp.h"
 
 namespace gold
 {
@@ -73,14 +75,14 @@ Target::do_make_elf_object_implementation(
     {
       Sized_relobj<size, big_endian>* obj =
        new Sized_relobj<size, big_endian>(name, input_file, offset, ehdr);
-      obj->setup(this);
+      obj->setup();
       return obj;
     }
   else if (et == elfcpp::ET_DYN)
     {
       Sized_dynobj<size, big_endian>* obj =
        new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
-      obj->setup(this);
+      obj->setup();
       return obj;
     }
   else
@@ -135,4 +137,57 @@ Target::do_make_elf_object(const std::string& name, Input_file* input_file,
 }
 #endif
 
+Output_section*
+Target::do_make_output_section(const char* name, elfcpp::Elf_Word type,
+                              elfcpp::Elf_Xword flags)
+{
+  return new Output_section(name, type, flags);
+}
+
+// Default conversion for -fsplit-stack is to give an error.
+
+void
+Target::do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+                          section_size_type, unsigned char*, section_size_type,
+                          std::string*, std::string*) const
+{
+  static bool warned;
+  if (!warned)
+    {
+      gold_error(_("linker does not include stack split support "
+                  "required by %s"),
+                object->name().c_str());
+      warned = true;
+    }
+}
+
+//  Return whether BYTES/LEN matches VIEW/VIEW_SIZE at OFFSET.
+
+bool
+Target::match_view(const unsigned char* view, section_size_type view_size,
+                  section_offset_type offset, const char* bytes,
+                  size_t len) const
+{
+  if (offset + len > view_size)
+    return false;
+  return memcmp(view + offset, bytes, len) == 0;
+}
+
+// Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+// for LEN bytes.
+
+void
+Target::set_view_to_nop(unsigned char* view, section_size_type view_size,
+                       section_offset_type offset, size_t len) const
+{
+  gold_assert(offset >= 0 && offset + len <= view_size);
+  if (!this->has_code_fill())
+    memset(view + offset, 0, len);
+  else
+    {
+      std::string fill = this->code_fill(len);
+      memcpy(view + offset, fill.data(), len);
+    }
+}
+
 } // End namespace gold.
index c9b07a81bc461ef6eb17a2ac118fc466beffabca..67397c31502ea4fb17b81d939bfba775acd874b3 100644 (file)
 #include "elfcpp.h"
 #include "options.h"
 #include "parameters.h"
+#include "debug.h"
 
 namespace gold
 {
 
 class General_options;
 class Object;
+class Relobj;
 template<int size, bool big_endian>
 class Sized_relobj;
 class Relocatable_relocs;
 template<int size, bool big_endian>
 class Relocate_info;
+class Reloc_symbol_changes;
 class Symbol;
 template<int size>
 class Sized_symbol;
@@ -216,6 +219,22 @@ class Target
   is_local_label_name(const char* name) const
   { return this->do_is_local_label_name(name); }
 
+  // A function starts at OFFSET in section SHNDX in OBJECT.  That
+  // function was compiled with -fsplit-stack, but it refers to a
+  // function which was compiled without -fsplit-stack.  VIEW is a
+  // modifiable view of the section; VIEW_SIZE is the size of the
+  // view.  The target has to adjust the function so that it allocates
+  // enough stack.
+  void
+  calls_non_split(Relobj* object, unsigned int shndx,
+                 section_offset_type fnoffset, section_size_type fnsize,
+                 unsigned char* view, section_size_type view_size,
+                 std::string* from, std::string* to) const
+  {
+    this->do_calls_non_split(object, shndx, fnoffset, fnsize, view, view_size,
+                            from, to);
+  }
+
   // Make an ELF object.
   template<int size, bool big_endian>
   Object*
@@ -223,6 +242,35 @@ class Target
                  off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
   { return this->do_make_elf_object(name, input_file, offset, ehdr); }
 
+  // Make an output section.
+  Output_section*
+  make_output_section(const char* name, elfcpp::Elf_Word type,
+                     elfcpp::Elf_Xword flags)
+  { return this->do_make_output_section(name, type, flags); }
+
+  // Return true if target wants to perform relaxation.
+  bool
+  may_relax() const
+  {
+    // Run the dummy relaxation pass twice if relaxation debugging is enabled.
+    if (is_debugging_enabled(DEBUG_RELAXATION))
+      return true;
+
+     return this->do_may_relax();
+  }
+
+  // Perform a relaxation pass.  Return true if layout may be changed.
+  bool
+  relax(int pass, const Input_objects* input_objects, Symbol_table* symtab,
+       Layout* layout)
+  {
+    // Run the dummy relaxation pass twice if relaxation debugging is enabled.
+    if (is_debugging_enabled(DEBUG_RELAXATION))
+      return pass < 2;
+
+    return this->do_relax(pass, input_objects, symtab, layout);
+  } 
+
  protected:
   // This struct holds the constant information for a child class.  We
   // use a struct to avoid the overhead of virtual function calls for
@@ -308,9 +356,15 @@ class Target
   virtual bool
   do_is_local_label_name(const char*) const;
 
+  // Virtual function which may be overridden by the child class.
+  virtual void
+  do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+                    section_size_type, unsigned char*, section_size_type,
+                    std::string*, std::string*) const;
+
   // make_elf_object hooks.  There are four versions of these for
   // different address sizes and endianities.
-  
+
 #ifdef HAVE_TARGET_32_LITTLE
   // Virtual functions which may be overriden by the child class.
   virtual Object*
@@ -339,6 +393,33 @@ class Target
                     off_t offset, const elfcpp::Ehdr<64, true>& ehdr);
 #endif
 
+  // Virtual functions which may be overriden by the child class.
+  virtual Output_section*
+  do_make_output_section(const char* name, elfcpp::Elf_Word type,
+                        elfcpp::Elf_Xword flags);
+
+  // Virtual function which may be overriden by the child class.
+  virtual bool
+  do_may_relax() const
+  { return parameters->options().relax(); }
+
+  // Virtual function which may be overriden by the child class.
+  virtual bool
+  do_relax(int, const Input_objects*, Symbol_table*, Layout*)
+  { return false; }
+
+  // A function for targets to call.  Return whether BYTES/LEN matches
+  // VIEW/VIEW_SIZE at OFFSET.
+  bool
+  match_view(const unsigned char* view, section_size_type view_size,
+            section_offset_type offset, const char* bytes, size_t len) const;
+
+  // Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+  // for LEN bytes.
+  void
+  set_view_to_nop(unsigned char* view, section_size_type view_size,
+                 section_offset_type offset, size_t len) const;
+
  private:
   // The implementations of the four do_make_elf_object virtual functions are
   // almost identical except for their sizes and endianity.  We use a template.
@@ -445,7 +526,8 @@ class Sized_target : public Target
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-                  section_size_type view_size) = 0;
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*) = 0;
 
   // Scan the relocs during a relocatable link.  The parameters are
   // like scan_relocs, with an additional Relocatable_relocs
index 1d6d06b24495628f5b999bdf9d9f337673028d35..09d7325cb3df1aa302ba16f0798e71a491c64aa4 100644 (file)
@@ -25,6 +25,7 @@ TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
 TEST_STRIP = $(top_builddir)/../binutils/strip-new
 TEST_AR = $(top_builddir)/../binutils/ar
 TEST_NM = $(top_builddir)/../binutils/nm-new
+TEST_AS = $(top_builddir)/../gas/as-new
 
 if PLUGINS
 LIBDL = -ldl
@@ -42,7 +43,7 @@ endif
 # .o's), but not all of them (such as .so's and .err files).  We
 # improve on that here.  automake-1.9 info docs say "mostlyclean" is
 # the right choice for files 'make' builds that people rebuild.
-MOSTLYCLEANFILES = *.so
+MOSTLYCLEANFILES = *.so *.syms *.stdout
 
 
 # We will add to these later, for each individual test.  Note
@@ -107,6 +108,7 @@ flagstest_ndebug.o: constructor_test.cc
 
 check_SCRIPTS += gc_comdat_test.sh
 check_DATA += gc_comdat_test.stdout
+MOSTLYCLEANFILES += gc_comdat_test
 gc_comdat_test_1.o: gc_comdat_test_1.cc 
        $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
 gc_comdat_test_2.o: gc_comdat_test_2.cc 
@@ -118,6 +120,7 @@ gc_comdat_test.stdout: gc_comdat_test
 
 check_SCRIPTS += gc_tls_test.sh
 check_DATA += gc_tls_test.stdout
+MOSTLYCLEANFILES += gc_tls_test
 gc_tls_test.o: gc_tls_test.cc
        $(CXXCOMPILE) -O0 -c -g -o $@ $<
 gc_tls_test:gc_tls_test.o gcctestdir/ld
@@ -127,22 +130,34 @@ gc_tls_test.stdout: gc_tls_test
 
 check_SCRIPTS += icf_test.sh
 check_DATA += icf_test.stdout
+MOSTLYCLEANFILES += icf_test
 icf_test.o: icf_test.cc 
        $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
 icf_test: icf_test.o gcctestdir/ld
-       $(CXXLINK) -Bgcctestdir/ -Wl,--icf icf_test.o
+       $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_test.o
 icf_test.stdout: icf_test
        $(TEST_NM) -C icf_test > icf_test.stdout
 
 check_SCRIPTS += icf_keep_unique_test.sh
 check_DATA += icf_keep_unique_test.stdout
+MOSTLYCLEANFILES += icf_keep_unique_test
 icf_keep_unique_test.o: icf_keep_unique_test.cc
        $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
 icf_keep_unique_test: icf_keep_unique_test.o gcctestdir/ld
-       $(CXXLINK) -Bgcctestdir/ -Wl,--icf -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
+       $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
 icf_keep_unique_test.stdout: icf_keep_unique_test
        $(TEST_NM) -C icf_keep_unique_test > icf_keep_unique_test.stdout
 
+check_SCRIPTS += icf_safe_test.sh
+check_DATA += icf_safe_test.stdout
+MOSTLYCLEANFILES += icf_safe_test
+icf_safe_test.o: icf_safe_test.cc 
+       $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+icf_safe_test: icf_safe_test.o gcctestdir/ld
+       $(CXXLINK) -Bgcctestdir/ -Wl,--icf=safe icf_safe_test.o
+icf_safe_test.stdout: icf_safe_test
+       $(TEST_NM) icf_safe_test > icf_safe_test.stdout
+
 check_PROGRAMS += basic_test
 check_PROGRAMS += basic_static_test
 check_PROGRAMS += basic_pic_test
@@ -161,6 +176,11 @@ basic_pic_test: basic_pic_test.o gcctestdir/ld
 basic_static_pic_test: basic_pic_test.o gcctestdir/ld
        $(CXXLINK) -Bgcctestdir/ -static basic_pic_test.o
 
+check_PROGRAMS += basic_pie_test
+basic_pie_test.o: basic_test.cc
+       $(CXXCOMPILE) -O0 -c -fpie -o $@ $<
+basic_pie_test: basic_pie_test.o gcctestdir/ld
+       $(CXXLINK) -Bgcctestdir/ -pie basic_pie_test.o
 
 check_PROGRAMS += constructor_test
 check_PROGRAMS += constructor_static_test
@@ -266,8 +286,22 @@ two_file_relocatable_test_LDADD = two_file_relocatable.o
 two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
        gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
 
+check_PROGRAMS += two_file_pie_test
+two_file_test_1_pie.o: two_file_test_1.cc
+       $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_1b_pie.o: two_file_test_1b.cc
+       $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_2_pie.o: two_file_test_2.cc
+       $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_test_main_pie.o: two_file_test_main.cc
+       $(CXXCOMPILE) -c -fpie -o $@ $<
+two_file_pie_test: two_file_test_1_pie.o two_file_test_1b_pie.o \
+               two_file_test_2_pie.o two_file_test_main_pie.o gcctestdir/ld
+       $(CXXLINK) -Bgcctestdir/ -pie two_file_test_1_pie.o two_file_test_1b_pie.o two_file_test_2_pie.o two_file_test_main_pie.o
+
 check_SCRIPTS += two_file_shared.sh
 check_DATA += two_file_shared.dbg
+MOSTLYCLEANFILES += two_file_shared.dbg
 two_file_shared.dbg: two_file_shared.so
        $(TEST_READELF) -w $< >$@ 2>/dev/null
 
@@ -423,6 +457,7 @@ weak_test_DEPENDENCIES = gcctestdir/ld
 weak_test_LDFLAGS = -Bgcctestdir/
 
 check_PROGRAMS += weak_undef_test
+MOSTLYCLEANFILES += alt/weak_undef_lib.so
 weak_undef_test_SOURCES = weak_undef_test.cc
 weak_undef_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib.so alt/weak_undef_lib.so
 weak_undef_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
@@ -439,6 +474,7 @@ alt/weak_undef_lib.so: weak_undef_file2.o
 
 if FN_PTRS_IN_SO_WITHOUT_PIC
 check_PROGRAMS += weak_undef_nonpic_test
+MOSTLYCLEANFILES += alt/weak_undef_lib_nonpic.so
 weak_undef_nonpic_test_SOURCES = weak_undef_test.cc
 weak_undef_nonpic_test_DEPENDENCIES = gcctestdir/ld weak_undef_lib_nonpic.so alt/weak_undef_lib_nonpic.so
 weak_undef_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,alt
@@ -633,6 +669,7 @@ many_sections_test_DEPENDENCIES = gcctestdir/ld
 many_sections_test_LDFLAGS = -Bgcctestdir/ -rdynamic
 
 BUILT_SOURCES += many_sections_define.h
+MOSTLYCLEANFILES += many_sections_define.h
 many_sections_define.h:
        (for i in `seq 1 70000`; do \
           echo "int var_$$i __attribute__((section(\"section_$$i\"))) = $$i;"; \
@@ -640,6 +677,7 @@ many_sections_define.h:
        mv -f $@.tmp $@
 
 BUILT_SOURCES += many_sections_check.h
+MOSTLYCLEANFILES += many_sections_check.h
 many_sections_check.h:
        (for i in `seq 1 1000 70000`; do \
           echo "assert(var_$$i == $$i);"; \
@@ -860,6 +898,7 @@ ver_test_10.so: gcctestdir/ld ver_test_2.o ver_test_10.script
        $(CXXLINK) -Bgcctestdir/ -shared -Wl,--version-script,$(srcdir)/ver_test_10.script ver_test_2.o
 
 check_PROGRAMS += ver_test_11
+MOSTLYCLEANFILES += ver_test_11.a
 ver_test_11_SOURCES = ver_test_main_2.cc
 ver_test_11_DEPENDENCIES = gcctestdir/ld ver_test_11.a
 ver_test_11_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
@@ -927,6 +966,7 @@ justsyms_2r.o: justsyms_2.o gcctestdir/ld $(srcdir)/justsyms.t
        gcctestdir/ld -o $@ -r -T $(srcdir)/justsyms.t justsyms_2.o
 
 check_PROGRAMS += binary_test
+MOSTLYCLEANFILES += binary.txt
 binary_test_SOURCES = binary_test.cc
 binary_test_DEPENDENCIES = gcctestdir/ld binary.txt
 binary_test_LDFLAGS = -Bgcctestdir/ -Wl,--format,binary,binary.txt,--format,elf
@@ -955,7 +995,7 @@ script_test_3.stdout: script_test_3
 
 check_SCRIPTS += script_test_4.sh
 check_DATA += script_test_4.stdout
-MOSTLYCLEANFILES += script_test_4.stdout
+MOSTLYCLEANFILES += script_test_4
 script_test_4: basic_test.o gcctestdir/ld $(srcdir)/script_test_4.t
        $(CXXLINK) -Bgcctestdir/ basic_test.o -T $(srcdir)/script_test_4.t
 script_test_4.stdout: script_test_4
@@ -963,7 +1003,7 @@ script_test_4.stdout: script_test_4
 
 check_SCRIPTS += script_test_5.sh
 check_DATA += script_test_5.stdout
-MOSTLYCLEANFILES += script_test_5.stdout
+MOSTLYCLEANFILES += script_test_5
 script_test_5: script_test_5.o gcctestdir/ld $(srcdir)/script_test_5.t
        $(CXXLINK) -Bgcctestdir/ script_test_5.o -T $(srcdir)/script_test_5.t
 script_test_5.stdout: script_test_5
@@ -974,7 +1014,7 @@ script_test_5.stdout: script_test_5
 
 check_SCRIPTS += dynamic_list.sh
 check_DATA += dynamic_list.stdout
-MOSTLYCLEANFILES += dynamic_list.stdout
+MOSTLYCLEANFILES += dynamic_list dynamic_list.stdout
 dynamic_list: basic_test.o gcctestdir/ld $(srcdir)/dynamic_list.t
        $(CXXLINK) -Bgcctestdir/ basic_test.o \
          -Wl,--dynamic-list $(srcdir)/dynamic_list.t \
@@ -985,6 +1025,9 @@ dynamic_list.stdout: dynamic_list
        $(TEST_READELF) -DWs dynamic_list > dynamic_list.stdout
 
 check_PROGRAMS += thin_archive_test_1
+MOSTLYCLEANFILES += libthin1.a libthin3.a libthinall.a \
+       alt/thin_archive_test_2.o alt/thin_archive_test_4.o \
+       alt/libthin2.a alt/libthin4.a
 thin_archive_test_1_SOURCES = thin_archive_main.cc
 thin_archive_test_1_DEPENDENCIES = gcctestdir/ld libthin1.a alt/libthin2.a
 thin_archive_test_1_LDFLAGS = -Bgcctestdir/ -Lalt
@@ -1050,7 +1093,7 @@ plugin_test_3.err: plugin_test_3
 check_PROGRAMS += plugin_test_4
 check_SCRIPTS += plugin_test_4.sh
 check_DATA += plugin_test_4.err
-MOSTLYCLEANFILES += plugin_test_4.err
+MOSTLYCLEANFILES += plugin_test_4.a plugin_test_4.err
 plugin_test_4: two_file_test_main.o plugin_test_4.a gcctestdir/ld plugin_test.so
        $(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so",--plugin-opt,"_Z4f13iv" two_file_test_main.o -Wl,--whole-archive,plugin_test_4.a,--no-whole-archive 2>plugin_test_4.err
 plugin_test_4.err: plugin_test_4
@@ -1139,5 +1182,122 @@ hidden_test: hidden_test_main.o libhidden.so gcctestdir/ld
 hidden_test.err: hidden_test
        @touch hidden_test.err
 
+# Test -retain-symbols-file.
+check_SCRIPTS += retain_symbols_file_test.sh
+check_DATA += retain_symbols_file_test.stdout
+MOSTLYCLEANFILES += retain_symbols_file_test retain_symbols_file_test.in \
+                    retain_symbols_file_test.stdout
+retain_symbols_file_test.so: basic_pic_test.o gcctestdir/ld
+       echo 'main' > retain_symbols_file_test.in
+       echo 't1' >> retain_symbols_file_test.in
+       echo '_ZN4t16bC1Ev' >> retain_symbols_file_test.in
+       echo '_ZNK4t20a3getEv' >> retain_symbols_file_test.in
+       echo '_Z3t18v' >> retain_symbols_file_test.in
+       echo '__tcf_0' >> retain_symbols_file_test.in   
+       $(CXXLINK) -Bgcctestdir/ -shared -Wl,-retain-symbols-file,retain_symbols_file_test.in basic_pic_test.o
+retain_symbols_file_test.stdout: retain_symbols_file_test.so
+       $(TEST_NM) -C retain_symbols_file_test.so > $@
+
+
+# Test that if the output file already exists and is empty,
+# it will get execute permission.
+check_PROGRAMS += permission_test
+permission_test: basic_test.o gcctestdir/ld
+       umask 022; \
+       rm -f $@; \
+       touch $@; \
+       chmod 600 $@; \
+       $(CXXLINK) -Bgcctestdir/ basic_test.o
+
+# Check -l:foo.a
+check_PROGRAMS += searched_file_test
+MOSTLYCLEANFILES += searched_file_test searched_file_test_lib.o \
+                    alt/searched_file_test_lib.a
+searched_file_test_SOURCES = searched_file_test.cc
+searched_file_test_DEPENDENCIES = alt/searched_file_test_lib.a
+searched_file_test_LDFLAGS = -Bgcctestdir/ -Lalt
+searched_file_test_LDADD = -l:searched_file_test_lib.a
+searched_file_test_lib.o: searched_file_test_lib.cc
+       $(CXXCOMPILE) -c -o $@ $<
+alt/searched_file_test_lib.a: searched_file_test_lib.o
+       test -d alt || mkdir -p alt
+       $(TEST_AR) rc $@ $^
+
 endif GCC
 endif NATIVE_LINKER
+
+# These tests work with cross linkers.
+
+if DEFAULT_TARGET_I386
+
+check_SCRIPTS += split_i386.sh
+check_DATA += split_i386_1.stdout split_i386_2.stdout \
+       split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_i386_1.o: split_i386_1.s
+       $(TEST_AS) -o $@ $<
+split_i386_2.o: split_i386_2.s
+       $(TEST_AS) -o $@ $<
+split_i386_3.o: split_i386_3.s
+       $(TEST_AS) -o $@ $<
+split_i386_4.o: split_i386_4.s
+       $(TEST_AS) -o $@ $<
+split_i386_n.o: split_i386_n.s
+       $(TEST_AS) -o $@ $<
+split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
+split_i386_1.stdout: split_i386_1
+       $(TEST_OBJDUMP) -d $< > $@
+split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
+split_i386_2.stdout: split_i386_2
+       $(TEST_OBJDUMP) -d $< > $@
+split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
+split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
+split_i386_4.stdout: split_i386_4
+       $(TEST_OBJDUMP) -d $< > $@
+split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
+       ../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_i386_1 split_i386_2 split_i386_3 \
+       split_i386_4 split_i386_r
+
+endif DEFAULT_TARGET_I386
+
+if DEFAULT_TARGET_X86_64
+
+check_SCRIPTS += split_x86_64.sh
+check_DATA += split_x86_64_1.stdout split_x86_64_2.stdout \
+       split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_x86_64_1.o: split_x86_64_1.s
+       $(TEST_AS) -o $@ $<
+split_x86_64_2.o: split_x86_64_2.s
+       $(TEST_AS) -o $@ $<
+split_x86_64_3.o: split_x86_64_3.s
+       $(TEST_AS) -o $@ $<
+split_x86_64_4.o: split_x86_64_4.s
+       $(TEST_AS) -o $@ $<
+split_x86_64_n.o: split_x86_64_n.s
+       $(TEST_AS) -o $@ $<
+split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
+split_x86_64_1.stdout: split_x86_64_1
+       $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
+split_x86_64_2.stdout: split_x86_64_2
+       $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
+split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
+       ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
+split_x86_64_4.stdout: split_x86_64_4
+       $(TEST_OBJDUMP) -d $< > $@
+split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+       ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+       split_x86_64_4 split_x86_64_r
+
+endif DEFAULT_TARGET_X86_64
index 461ee73a2c6688c96821b79836515bdcd198184e..3f5459f707a4dd327fd5e8dd6583ec882ea2a66c 100644 (file)
@@ -46,7 +46,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
        $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
        $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \
        $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15) \
-       $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18)
+       $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) \
+       $(am__EXEEXT_19)
 
 # Test --detect-odr-violations
 
@@ -57,6 +58,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = gc_comdat_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test.sh icf_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.sh weak_plt.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.sh undef_symbol.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_1.sh ver_test_2.sh \
@@ -77,6 +79,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_test.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt_shared.so debug_msg.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
@@ -90,10 +93,16 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_5.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = basic_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = gc_comdat_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_tls_test icf_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/weak_undef_lib.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = basic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pie_test constructor_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_static_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_static_test \
@@ -105,7 +114,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pie_test
 @GCC_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
 @GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
 @GCC_FALSE@    $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -145,14 +155,14 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 
 # The nonpic tests will fail on platforms which can not put non-PIC
 # code into shared libraries, so we just don't run them in that case.
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = two_file_shared_1_nonpic_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_5 = two_file_shared_1_nonpic_test \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_nonpic_test \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_nonpic_test \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_nonpic_test \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_shared_test \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_mixed_2_shared_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_5 = two_file_strip_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_6 = two_file_strip_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_strip_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ common_test_1 exception_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ exception_static_test \
@@ -196,20 +206,21 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_6 = weak_undef_nonpic_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_7 = weak_alias_test weak_plt \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_7 = weak_undef_nonpic_test
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_8 = alt/weak_undef_lib_nonpic.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_9 = weak_alias_test weak_plt \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ copy_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_8 = tls_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_10 = tls_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_pic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_ie_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_gd_to_ie_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_9 = tls_shared_gnu2_gd_to_ie_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_10 = tls_shared_gnu2_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_11 = tls_static_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_11 = tls_shared_gnu2_gd_to_ie_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_12 = tls_shared_gnu2_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_13 = tls_static_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@      tls_static_pic_test
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_12 = tls_shared_nonpic_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_13 = many_sections_test \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_14 = tls_shared_nonpic_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = many_sections_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_r_test
 @GCC_FALSE@many_sections_test_DEPENDENCIES = libgoldtest.a \
 @GCC_FALSE@    ../libgold.a ../../libiberty/libiberty.a \
@@ -220,9 +231,24 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_14 = many_sections_define.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = many_sections_define.h \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h
-@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = initpri1
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = many_sections_define.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ many_sections_check.h \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.err debug_msg_so.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err ver_test_11.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary.txt \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4 script_test_5 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list dynamic_list.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthin1.a libthin3.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthinall.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_2.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_4.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libthin2.a alt/libthin4.a
+@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_18 = initpri1
 @CONSTRUCTOR_PRIORITY_FALSE@initpri1_DEPENDENCIES = libgoldtest.a \
 @CONSTRUCTOR_PRIORITY_FALSE@   ../libgold.a \
 @CONSTRUCTOR_PRIORITY_FALSE@   ../../libiberty/libiberty.a \
@@ -237,28 +263,19 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_16 = debug_msg.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_5.stdout \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout
 
 # Test -o when emitting to a special file (such as something in /dev).
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_17 = flagstest_o_specialfile
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_19 = flagstest_o_specialfile
 
 # Test --compress-debug-sections.  FIXME: check we actually compress.
 
 # The specialfile output has a tricky case when we also compress debug
 # sections, because it requires output-file resizing.
-@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_18 = flagstest_compress_debug_sections \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_20 = flagstest_compress_debug_sections \
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections
 
 # Test symbol versioning.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_19 = ver_test ver_test_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_21 = ver_test ver_test_2 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6 ver_test_8 ver_test_9 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_11 protected_1 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ protected_2 relro_test \
@@ -301,45 +318,56 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 @GCC_FALSE@thin_archive_test_2_DEPENDENCIES =
 @NATIVE_LINKER_FALSE@thin_archive_test_2_DEPENDENCIES =
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_20 =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_22 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_1 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_2 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_3 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_4
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_21 =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_23 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_1.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_2.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_3.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_4.sh
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_22 =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_24 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_1.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_2.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_3.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_4.err
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_23 =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_25 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_1.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_2.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_3.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_4.a \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@   plugin_test_4.err
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_24 = exclude_libs_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = exclude_libs_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test
 
 # Test that hidden and internal symbols in the main program cannot be
 # referenced by a shared library.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_25 = exclude_libs_test.sh \
+
+# Test -retain-symbols-file.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = exclude_libs_test.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.sh \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.sh
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_28 = exclude_libs_test.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.err
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_29 = exclude_libs_test.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_1.a \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ libexclude_libs_test_2.a \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libexclude_libs_test_3.a \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test.syms \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test hidden_test.err
-@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_28 = large
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ hidden_test hidden_test.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.in \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ retain_symbols_file_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test_lib.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/searched_file_test_lib.a
+@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__append_30 = large
 @GCC_FALSE@large_DEPENDENCIES = libgoldtest.a ../libgold.a \
 @GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
 @GCC_FALSE@    $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -353,6 +381,31 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
+
+# Test that if the output file already exists and is empty,
+# it will get execute permission.
+
+# Check -l:foo.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_31 = permission_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test
+@GCC_FALSE@searched_file_test_DEPENDENCIES =
+@NATIVE_LINKER_FALSE@searched_file_test_DEPENDENCIES =
+
+# These tests work with cross linkers.
+@DEFAULT_TARGET_I386_TRUE@am__append_32 = split_i386.sh
+@DEFAULT_TARGET_I386_TRUE@am__append_33 = split_i386_1.stdout split_i386_2.stdout \
+@DEFAULT_TARGET_I386_TRUE@     split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
+
+@DEFAULT_TARGET_I386_TRUE@am__append_34 = split_i386_1 split_i386_2 split_i386_3 \
+@DEFAULT_TARGET_I386_TRUE@     split_i386_4 split_i386_r
+
+@DEFAULT_TARGET_X86_64_TRUE@am__append_35 = split_x86_64.sh
+@DEFAULT_TARGET_X86_64_TRUE@am__append_36 = split_x86_64_1.stdout split_x86_64_2.stdout \
+@DEFAULT_TARGET_X86_64_TRUE@   split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
+
+@DEFAULT_TARGET_X86_64_TRUE@am__append_37 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+@DEFAULT_TARGET_X86_64_TRUE@   split_x86_64_4 split_x86_64_r
+
 subdir = testsuite
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -381,6 +434,7 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pic_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pie_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_static_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test$(EXEEXT) \
@@ -393,7 +447,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test$(EXEEXT) \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_pie_test$(EXEEXT)
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_2 = two_file_shared_1_nonpic_test$(EXEEXT) \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test$(EXEEXT) \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_nonpic_test$(EXEEXT) \
@@ -462,6 +517,9 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ discard_locals_test$(EXEEXT)
 @GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_18 = large$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_19 =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ permission_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test$(EXEEXT)
 basic_pic_test_SOURCES = basic_pic_test.c
 basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
 basic_pic_test_LDADD = $(LDADD)
@@ -469,6 +527,12 @@ am__DEPENDENCIES_1 =
 basic_pic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
        ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+basic_pie_test_SOURCES = basic_pie_test.c
+basic_pie_test_OBJECTS = basic_pie_test.$(OBJEXT)
+basic_pie_test_LDADD = $(LDADD)
+basic_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+       ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 basic_static_pic_test_SOURCES = basic_static_pic_test.c
 basic_static_pic_test_OBJECTS = basic_static_pic_test.$(OBJEXT)
 basic_static_pic_test_LDADD = $(LDADD)
@@ -678,6 +742,12 @@ object_unittest_LDADD = $(LDADD)
 object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
        ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+permission_test_SOURCES = permission_test.c
+permission_test_OBJECTS = permission_test.$(OBJEXT)
+permission_test_LDADD = $(LDADD)
+permission_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+       ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 plugin_test_1_SOURCES = plugin_test_1.c
 plugin_test_1_OBJECTS = plugin_test_1.$(OBJEXT)
 plugin_test_1_LDADD = $(LDADD)
@@ -753,6 +823,12 @@ script_test_3_LDADD = $(LDADD)
 script_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
        ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__searched_file_test_SOURCES_DIST = searched_file_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_searched_file_test_OBJECTS =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ searched_file_test.$(OBJEXT)
+searched_file_test_OBJECTS = $(am_searched_file_test_OBJECTS)
+searched_file_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+       $(searched_file_test_LDFLAGS) $(LDFLAGS) -o $@
 am__thin_archive_test_1_SOURCES_DIST = thin_archive_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_thin_archive_test_1_OBJECTS =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ thin_archive_main.$(OBJEXT)
@@ -853,6 +929,12 @@ am__two_file_pic_test_SOURCES_DIST = two_file_test_main.cc
 two_file_pic_test_OBJECTS = $(am_two_file_pic_test_OBJECTS)
 two_file_pic_test_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
        $(two_file_pic_test_LDFLAGS) $(LDFLAGS) -o $@
+two_file_pie_test_SOURCES = two_file_pie_test.c
+two_file_pie_test_OBJECTS = two_file_pie_test.$(OBJEXT)
+two_file_pie_test_LDADD = $(LDADD)
+two_file_pie_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+       ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am__two_file_relocatable_test_SOURCES_DIST = two_file_test_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_relocatable_test_OBJECTS =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
@@ -1081,7 +1163,7 @@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 CXXLD = $(CXX)
 CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
        -o $@
-SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
+SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c basic_pie_test.c \
        basic_static_pic_test.c basic_static_test.c basic_test.c \
        $(binary_test_SOURCES) $(binary_unittest_SOURCES) \
        $(common_test_1_SOURCES) $(constructor_static_test_SOURCES) \
@@ -1099,11 +1181,12 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(initpri1_SOURCES) $(justsyms_SOURCES) $(large_SOURCES) \
        local_labels_test.c many_sections_r_test.c \
        $(many_sections_test_SOURCES) $(object_unittest_SOURCES) \
-       plugin_test_1.c plugin_test_2.c plugin_test_3.c \
-       plugin_test_4.c $(protected_1_SOURCES) $(protected_2_SOURCES) \
-       $(relro_script_test_SOURCES) $(relro_test_SOURCES) \
-       $(script_test_1_SOURCES) $(script_test_2_SOURCES) \
-       script_test_3.c $(thin_archive_test_1_SOURCES) \
+       permission_test.c plugin_test_1.c plugin_test_2.c \
+       plugin_test_3.c plugin_test_4.c $(protected_1_SOURCES) \
+       $(protected_2_SOURCES) $(relro_script_test_SOURCES) \
+       $(relro_test_SOURCES) $(script_test_1_SOURCES) \
+       $(script_test_2_SOURCES) script_test_3.c \
+       $(searched_file_test_SOURCES) $(thin_archive_test_1_SOURCES) \
        $(thin_archive_test_2_SOURCES) $(tls_pic_test_SOURCES) \
        $(tls_shared_gd_to_ie_test_SOURCES) \
        $(tls_shared_gnu2_gd_to_ie_test_SOURCES) \
@@ -1112,7 +1195,7 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(tls_static_pic_test_SOURCES) $(tls_static_test_SOURCES) \
        $(tls_test_SOURCES) $(two_file_mixed_2_shared_test_SOURCES) \
        $(two_file_mixed_shared_test_SOURCES) \
-       $(two_file_pic_test_SOURCES) \
+       $(two_file_pic_test_SOURCES) two_file_pie_test.c \
        $(two_file_relocatable_test_SOURCES) \
        $(two_file_same_shared_nonpic_test_SOURCES) \
        $(two_file_same_shared_strip_test_SOURCES) \
@@ -1135,9 +1218,9 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(weak_test_SOURCES) $(weak_undef_nonpic_test_SOURCES) \
        $(weak_undef_test_SOURCES)
 DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
-       basic_static_pic_test.c basic_static_test.c basic_test.c \
-       $(am__binary_test_SOURCES_DIST) $(binary_unittest_SOURCES) \
-       $(am__common_test_1_SOURCES_DIST) \
+       basic_pie_test.c basic_static_pic_test.c basic_static_test.c \
+       basic_test.c $(am__binary_test_SOURCES_DIST) \
+       $(binary_unittest_SOURCES) $(am__common_test_1_SOURCES_DIST) \
        $(am__constructor_static_test_SOURCES_DIST) \
        $(am__constructor_test_SOURCES_DIST) \
        $(am__copy_test_SOURCES_DIST) \
@@ -1155,14 +1238,15 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(am__initpri1_SOURCES_DIST) $(am__justsyms_SOURCES_DIST) \
        $(am__large_SOURCES_DIST) local_labels_test.c \
        many_sections_r_test.c $(am__many_sections_test_SOURCES_DIST) \
-       $(object_unittest_SOURCES) plugin_test_1.c plugin_test_2.c \
-       plugin_test_3.c plugin_test_4.c \
+       $(object_unittest_SOURCES) permission_test.c plugin_test_1.c \
+       plugin_test_2.c plugin_test_3.c plugin_test_4.c \
        $(am__protected_1_SOURCES_DIST) \
        $(am__protected_2_SOURCES_DIST) \
        $(am__relro_script_test_SOURCES_DIST) \
        $(am__relro_test_SOURCES_DIST) \
        $(am__script_test_1_SOURCES_DIST) \
        $(am__script_test_2_SOURCES_DIST) script_test_3.c \
+       $(am__searched_file_test_SOURCES_DIST) \
        $(am__thin_archive_test_1_SOURCES_DIST) \
        $(am__thin_archive_test_2_SOURCES_DIST) \
        $(am__tls_pic_test_SOURCES_DIST) \
@@ -1177,7 +1261,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(am__tls_test_SOURCES_DIST) \
        $(am__two_file_mixed_2_shared_test_SOURCES_DIST) \
        $(am__two_file_mixed_shared_test_SOURCES_DIST) \
-       $(am__two_file_pic_test_SOURCES_DIST) \
+       $(am__two_file_pic_test_SOURCES_DIST) two_file_pie_test.c \
        $(am__two_file_relocatable_test_SOURCES_DIST) \
        $(am__two_file_same_shared_nonpic_test_SOURCES_DIST) \
        $(am__two_file_same_shared_strip_test_SOURCES_DIST) \
@@ -1356,6 +1440,7 @@ TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
 TEST_STRIP = $(top_builddir)/../binutils/strip-new
 TEST_AR = $(top_builddir)/../binutils/ar
 TEST_NM = $(top_builddir)/../binutils/nm-new
+TEST_AS = $(top_builddir)/../gas/as-new
 @PLUGINS_TRUE@LIBDL = -ldl
 @THREADS_TRUE@THREADSLIB = -lpthread
 @OMP_SUPPORT_TRUE@TLS_TEST_C_CFLAGS = -fopenmp
@@ -1364,15 +1449,18 @@ TEST_NM = $(top_builddir)/../binutils/nm-new
 # .o's), but not all of them (such as .so's and .err files).  We
 # improve on that here.  automake-1.9 info docs say "mostlyclean" is
 # the right choice for files 'make' builds that people rebuild.
-MOSTLYCLEANFILES = *.so $(am__append_16) $(am__append_23) \
-       $(am__append_27)
+MOSTLYCLEANFILES = *.so *.syms *.stdout $(am__append_3) \
+       $(am__append_8) $(am__append_17) $(am__append_25) \
+       $(am__append_29) $(am__append_34) $(am__append_37)
 
 # We will add to these later, for each individual test.  Note
 # that we add each test under check_SCRIPTS or check_PROGRAMS;
 # the TESTS variable is automatically populated from these.
-check_SCRIPTS = $(am__append_1) $(am__append_21) $(am__append_25)
-check_DATA = $(am__append_2) $(am__append_22) $(am__append_26)
-BUILT_SOURCES = $(am__append_14)
+check_SCRIPTS = $(am__append_1) $(am__append_23) $(am__append_27) \
+       $(am__append_32) $(am__append_35)
+check_DATA = $(am__append_2) $(am__append_24) $(am__append_28) \
+       $(am__append_33) $(am__append_36)
+BUILT_SOURCES = $(am__append_16)
 TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
 
 # ---------------------------------------------------------------------
@@ -1715,6 +1803,12 @@ binary_unittest_SOURCES = binary_unittest.cc
 @GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_CFLAGS = -mcmodel=medium
 @GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_DEPENDENCIES = gcctestdir/ld
 @GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_LDFLAGS = -Bgcctestdir/
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_SOURCES = searched_file_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_DEPENDENCIES = alt/searched_file_test_lib.a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_LDFLAGS = -Bgcctestdir/ -Lalt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_LDADD = -l:searched_file_test_lib.a
+@DEFAULT_TARGET_I386_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+@DEFAULT_TARGET_X86_64_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
 all: $(BUILT_SOURCES)
        $(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -1766,6 +1860,12 @@ clean-checkPROGRAMS:
 @NATIVE_LINKER_FALSE@basic_pic_test$(EXEEXT): $(basic_pic_test_OBJECTS) $(basic_pic_test_DEPENDENCIES) 
 @NATIVE_LINKER_FALSE@  @rm -f basic_pic_test$(EXEEXT)
 @NATIVE_LINKER_FALSE@  $(LINK) $(basic_pic_test_OBJECTS) $(basic_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@basic_pie_test$(EXEEXT): $(basic_pie_test_OBJECTS) $(basic_pie_test_DEPENDENCIES) 
+@GCC_FALSE@    @rm -f basic_pie_test$(EXEEXT)
+@GCC_FALSE@    $(LINK) $(basic_pie_test_OBJECTS) $(basic_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@basic_pie_test$(EXEEXT): $(basic_pie_test_OBJECTS) $(basic_pie_test_DEPENDENCIES) 
+@NATIVE_LINKER_FALSE@  @rm -f basic_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@  $(LINK) $(basic_pie_test_OBJECTS) $(basic_pie_test_LDADD) $(LIBS)
 @GCC_FALSE@basic_static_pic_test$(EXEEXT): $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_DEPENDENCIES) 
 @GCC_FALSE@    @rm -f basic_static_pic_test$(EXEEXT)
 @GCC_FALSE@    $(LINK) $(basic_static_pic_test_OBJECTS) $(basic_static_pic_test_LDADD) $(LIBS)
@@ -1880,6 +1980,12 @@ many_sections_test$(EXEEXT): $(many_sections_test_OBJECTS) $(many_sections_test_
 object_unittest$(EXEEXT): $(object_unittest_OBJECTS) $(object_unittest_DEPENDENCIES) 
        @rm -f object_unittest$(EXEEXT)
        $(CXXLINK) $(object_unittest_OBJECTS) $(object_unittest_LDADD) $(LIBS)
+@GCC_FALSE@permission_test$(EXEEXT): $(permission_test_OBJECTS) $(permission_test_DEPENDENCIES) 
+@GCC_FALSE@    @rm -f permission_test$(EXEEXT)
+@GCC_FALSE@    $(LINK) $(permission_test_OBJECTS) $(permission_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@permission_test$(EXEEXT): $(permission_test_OBJECTS) $(permission_test_DEPENDENCIES) 
+@NATIVE_LINKER_FALSE@  @rm -f permission_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@  $(LINK) $(permission_test_OBJECTS) $(permission_test_LDADD) $(LIBS)
 @GCC_FALSE@plugin_test_1$(EXEEXT): $(plugin_test_1_OBJECTS) $(plugin_test_1_DEPENDENCIES) 
 @GCC_FALSE@    @rm -f plugin_test_1$(EXEEXT)
 @GCC_FALSE@    $(LINK) $(plugin_test_1_OBJECTS) $(plugin_test_1_LDADD) $(LIBS)
@@ -1940,6 +2046,9 @@ script_test_2$(EXEEXT): $(script_test_2_OBJECTS) $(script_test_2_DEPENDENCIES)
 @NATIVE_LINKER_FALSE@script_test_3$(EXEEXT): $(script_test_3_OBJECTS) $(script_test_3_DEPENDENCIES) 
 @NATIVE_LINKER_FALSE@  @rm -f script_test_3$(EXEEXT)
 @NATIVE_LINKER_FALSE@  $(LINK) $(script_test_3_OBJECTS) $(script_test_3_LDADD) $(LIBS)
+searched_file_test$(EXEEXT): $(searched_file_test_OBJECTS) $(searched_file_test_DEPENDENCIES) 
+       @rm -f searched_file_test$(EXEEXT)
+       $(searched_file_test_LINK) $(searched_file_test_OBJECTS) $(searched_file_test_LDADD) $(LIBS)
 thin_archive_test_1$(EXEEXT): $(thin_archive_test_1_OBJECTS) $(thin_archive_test_1_DEPENDENCIES) 
        @rm -f thin_archive_test_1$(EXEEXT)
        $(thin_archive_test_1_LINK) $(thin_archive_test_1_OBJECTS) $(thin_archive_test_1_LDADD) $(LIBS)
@@ -1985,6 +2094,12 @@ two_file_mixed_shared_test$(EXEEXT): $(two_file_mixed_shared_test_OBJECTS) $(two
 two_file_pic_test$(EXEEXT): $(two_file_pic_test_OBJECTS) $(two_file_pic_test_DEPENDENCIES) 
        @rm -f two_file_pic_test$(EXEEXT)
        $(two_file_pic_test_LINK) $(two_file_pic_test_OBJECTS) $(two_file_pic_test_LDADD) $(LIBS)
+@GCC_FALSE@two_file_pie_test$(EXEEXT): $(two_file_pie_test_OBJECTS) $(two_file_pie_test_DEPENDENCIES) 
+@GCC_FALSE@    @rm -f two_file_pie_test$(EXEEXT)
+@GCC_FALSE@    $(LINK) $(two_file_pie_test_OBJECTS) $(two_file_pie_test_LDADD) $(LIBS)
+@NATIVE_LINKER_FALSE@two_file_pie_test$(EXEEXT): $(two_file_pie_test_OBJECTS) $(two_file_pie_test_DEPENDENCIES) 
+@NATIVE_LINKER_FALSE@  @rm -f two_file_pie_test$(EXEEXT)
+@NATIVE_LINKER_FALSE@  $(LINK) $(two_file_pie_test_OBJECTS) $(two_file_pie_test_LDADD) $(LIBS)
 two_file_relocatable_test$(EXEEXT): $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_DEPENDENCIES) 
        @rm -f two_file_relocatable_test$(EXEEXT)
        $(two_file_relocatable_test_LINK) $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_LDADD) $(LIBS)
@@ -2083,6 +2198,7 @@ distclean-compile:
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_pic_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_pie_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_pic_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_test.Po@am__quote@
@@ -2106,6 +2222,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_r_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/many_sections_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/permission_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_test_3.Po@am__quote@
@@ -2120,6 +2237,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2a.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2b.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/searched_file_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testfile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmain.Po@am__quote@
@@ -2127,6 +2245,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_file2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_pie_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_strip_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/two_file_test_1b.Po@am__quote@
@@ -2519,15 +2638,21 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.o: icf_test.cc 
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test: icf_test.o gcctestdir/ld
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf icf_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_test.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_test.stdout: icf_test
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C icf_test > icf_test.stdout
 @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test.o: icf_keep_unique_test.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test: icf_keep_unique_test.o gcctestdir/ld
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all -Wl,--keep-unique,_Z11unique_funcv icf_keep_unique_test.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_keep_unique_test.stdout: icf_keep_unique_test
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C icf_keep_unique_test > icf_keep_unique_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test.o: icf_safe_test.cc 
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test: icf_safe_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=safe icf_safe_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_test.stdout: icf_safe_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_safe_test > icf_safe_test.stdout
 @GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test.o: basic_test.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test: basic_test.o gcctestdir/ld
@@ -2541,6 +2666,10 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_pic_test.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@basic_static_pic_test: basic_pic_test.o gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -static basic_pic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pie_test.o: basic_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_pie_test: basic_pie_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie basic_pie_test.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_pic.o: two_file_test_1.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1b_pic.o: two_file_test_1b.cc
@@ -2555,6 +2684,17 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1_pie.o: two_file_test_1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_1b_pie.o: two_file_test_1b.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_2_pie.o: two_file_test_2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_main_pie.o: two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpie -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_pie_test: two_file_test_1_pie.o two_file_test_1b_pie.o \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@         two_file_test_2_pie.o two_file_test_main_pie.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -pie two_file_test_1_pie.o two_file_test_1b_pie.o two_file_test_2_pie.o two_file_test_main_pie.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.dbg: two_file_shared.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -w $< >$@ 2>/dev/null
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld
@@ -2922,6 +3062,79 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,-R,. hidden_test_main.o libhidden.so 2>hidden_test.err
 @GCC_TRUE@@NATIVE_LINKER_TRUE@hidden_test.err: hidden_test
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ @touch hidden_test.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@retain_symbols_file_test.so: basic_pic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 'main' > retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 't1' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_ZN4t16bC1Ev' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_ZNK4t20a3getEv' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '_Z3t18v' >> retain_symbols_file_test.in
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo '__tcf_0' >> retain_symbols_file_test.in   
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared -Wl,-retain-symbols-file,retain_symbols_file_test.in basic_pic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@retain_symbols_file_test.stdout: retain_symbols_file_test.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) -C retain_symbols_file_test.so > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@permission_test: basic_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ umask 022; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ touch $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod 600 $@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@searched_file_test_lib.o: searched_file_test_lib.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@alt/searched_file_test_lib.a: searched_file_test_lib.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d alt || mkdir -p alt
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AR) rc $@ $^
+@DEFAULT_TARGET_I386_TRUE@split_i386_1.o: split_i386_1.s
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_2.o: split_i386_2.s
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_3.o: split_i386_3.s
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_4.o: split_i386_4.s
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_n.o: split_i386_n.s
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_I386_TRUE@split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@     ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@split_i386_1.stdout: split_i386_1
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@     ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@split_i386_2.stdout: split_i386_2
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@     ../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_I386_TRUE@split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@     ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
+@DEFAULT_TARGET_I386_TRUE@split_i386_4.stdout: split_i386_4
+@DEFAULT_TARGET_I386_TRUE@     $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_I386_TRUE@split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
+@DEFAULT_TARGET_I386_TRUE@     ../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1.o: split_x86_64_1.s
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2.o: split_x86_64_2.s
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_3.o: split_x86_64_3.s
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4.o: split_x86_64_4.s
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_n.o: split_x86_64_n.s
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_AS) -o $@ $<
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@   ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1.stdout: split_x86_64_1
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@   ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2.stdout: split_x86_64_2
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@   ../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@   ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4.stdout: split_x86_64_4
+@DEFAULT_TARGET_X86_64_TRUE@   $(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+@DEFAULT_TARGET_X86_64_TRUE@   ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 2645e0b91575b359fc637f84be78d688b164e42c..b2e14df645f1ea0d109347e6ee250ca0e108560f 100644 (file)
@@ -44,8 +44,9 @@ using namespace gold;
 
 template<int size, bool big_endian>
 bool
-Sized_binary_test(Target* target)
+Sized_binary_test()
 {
+  parameters_clear_target();
   // We need a pretend Task.
   const Task* task = reinterpret_cast<const Task*>(-1);
 
@@ -73,7 +74,6 @@ Sized_binary_test(Target* target)
     return false;
 
   CHECK(!object->is_dynamic());
-  CHECK(object->target() == target);
   CHECK(object->shnum() == 5);
   CHECK(object->section_name(1) == ".data");
   CHECK(object->section_flags(1) == (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE));
@@ -125,23 +125,27 @@ Binary_test(Test_report*)
   int fail = 0;
 
 #ifdef HAVE_TARGET_32_LITTLE
-  if (!Sized_binary_test<32, false>(target_test_pointer_32_little))
+  if (!Sized_binary_test<32, false>())
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_32_little);
 #endif
 
 #ifdef HAVE_TARGET_32_BIG
-  if (!Sized_binary_test<32, true>(target_test_pointer_32_big))
+  if (!Sized_binary_test<32, true>())
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_32_big);
 #endif
 
 #ifdef HAVE_TARGET_64_LITTLE
-  if (!Sized_binary_test<64, false>(target_test_pointer_64_little))
+  if (!Sized_binary_test<64, false>())
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_64_little);
 #endif
 
 #ifdef HAVE_TARGET_64_BIG
-  if (!Sized_binary_test<64, true>(target_test_pointer_64_big))
+  if (!Sized_binary_test<64, true>())
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_64_big);
 #endif
 
   return fail == 0;
index 28c6c917d9ac4b69f95976385fb308bd25c02eb3..1c5252d873d210608215398fce80e88d7e335b97 100644 (file)
@@ -1,6 +1,6 @@
 /* initpri1.c -- test constructor priorities.
 
-   Copyright 2007, 2008 Free Software Foundation, Inc.
+   Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
    Copied from the gcc testsuite, where the test was contributed by
    Mark Mitchell <mark@codesourcery.com>.
 
    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.
+   MA 02110-1301, USA.  */
 
-   This is a test of a common symbol in the main program and a
-   versioned symbol in a shared library.  The common symbol in the
-   main program should override the shared library symbol.  */
+/* This tests that the linker handles constructor and destructor
+   priorities correctly.  */
 
 #include <stdlib.h>
 
+/* Constructor priorities in attributes were added in gcc 4.3.  */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)
+
 int i;
 int j;
 
@@ -93,3 +95,11 @@ int main (void) {
     abort ();
   return 0;
 }
+
+#else /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */
+
+int main (void) {
+  exit (0);
+}
+
+#endif /* !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) */
index b36997e597e2716710815a46af8bc57ec68146e8..0451addc21e97e1304357dbe768c9b2290fe0fb6 100644 (file)
@@ -36,9 +36,9 @@ using namespace gold;
 
 template<int size, bool big_endian>
 bool
-Sized_object_test(const unsigned char* test_file, unsigned int test_file_size,
-                 Target* target_test_pointer)
+Sized_object_test(const unsigned char* test_file, unsigned int test_file_size)
 {
+  parameters_clear_target();
   // We need a pretend Task.
   const Task* task = reinterpret_cast<const Task*>(-1);
   Input_file input_file(task, "test.o", test_file, test_file_size);
@@ -46,7 +46,6 @@ Sized_object_test(const unsigned char* test_file, unsigned int test_file_size,
                                   test_file, test_file_size, NULL);
   CHECK(object->name() == "test.o");
   CHECK(!object->is_dynamic());
-  CHECK(object->target() == target_test_pointer);
   CHECK(object->is_locked());
   object->unlock(task);
   CHECK(!object->is_locked());
@@ -67,30 +66,30 @@ Object_test(Test_report*)
 
 #ifdef HAVE_TARGET_32_LITTLE
   if (!Sized_object_test<32, false>(test_file_1_32_little,
-                                   test_file_1_size_32_little,
-                                   target_test_pointer_32_little))
+                                   test_file_1_size_32_little))
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_32_little);
 #endif
 
 #ifdef HAVE_TARGET_32_BIG
   if (!Sized_object_test<32, true>(test_file_1_32_big,
-                                  test_file_1_size_32_big,
-                                  target_test_pointer_32_big))
+                                  test_file_1_size_32_big))
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_32_big);
 #endif
 
 #ifdef HAVE_TARGET_64_LITTLE
   if (!Sized_object_test<64, false>(test_file_1_64_little,
-                                   test_file_1_size_64_little,
-                                   target_test_pointer_64_little))
+                                   test_file_1_size_64_little))
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_64_little);
 #endif
 
 #ifdef HAVE_TARGET_64_BIG
   if (!Sized_object_test<64, true>(test_file_1_64_big,
-                                  test_file_1_size_64_big,
-                                  target_test_pointer_64_big))
+                                  test_file_1_size_64_big))
     ++fail;
+  CHECK(&parameters->target() == target_test_pointer_64_big);
 #endif
 
   return fail == 0;
index 2532307994f5c9c981ed964164e02da965f22108..d66189a8c79ff162796760c9b330307f9bfd9503 100644 (file)
@@ -61,7 +61,7 @@ class Target_test : public Sized_target<size, big_endian>
   relocate_section(const Relocate_info<size, big_endian>*, unsigned int,
                   const unsigned char*, size_t, Output_section*, bool,
                   unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
-                  section_size_type)
+                  section_size_type, const Reloc_symbol_changes*)
   { ERROR("call to Target_test::relocate_section"); }
 
   void
index 9287d581b1d1b16711164c479baf90c64c8e2318..3562065611b56bb59bcb6b859854bba6807b448b 100644 (file)
@@ -38,6 +38,7 @@
 #include "target-select.h"
 #include "tls.h"
 #include "freebsd.h"
+#include "gc.h"
 
 namespace
 {
@@ -120,7 +121,8 @@ class Target_x86_64 : public Target_freebsd<64, false>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   elfcpp::Elf_types<64>::Elf_Addr view_address,
-                  section_size_type view_size);
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -162,6 +164,13 @@ class Target_x86_64 : public Target_freebsd<64, false>
   do_is_defined_by_abi(const Symbol* sym) const
   { return strcmp(sym->name(), "__tls_get_addr") == 0; }
 
+  // Adjust -fstack-split code which calls non-stack-split code.
+  void
+  do_calls_non_split(Relobj* object, unsigned int shndx,
+                    section_offset_type fnoffset, section_size_type fnsize,
+                    unsigned char* view, section_size_type view_size,
+                    std::string* from, std::string* to) const;
+
   // Return the size of the GOT section.
   section_size_type
   got_size()
@@ -375,17 +384,6 @@ class Target_x86_64 : public Target_freebsd<64, false>
   Reloc_section*
   rela_dyn_section(Layout*);
 
-  // Return true if the symbol may need a COPY relocation.
-  // References from an executable object to non-function symbols
-  // defined in a dynamic object may need a COPY relocation.
-  bool
-  may_need_copy_reloc(Symbol* gsym)
-  {
-    return (!parameters->options().shared()
-            && gsym->is_from_dynobj()
-            && gsym->type() != elfcpp::STT_FUNC);
-  }
-
   // Add a potential copy relocation.
   void
   copy_reloc(Symbol_table* symtab, Layout* layout,
@@ -1323,7 +1321,7 @@ Target_x86_64::Scan::global(const General_options&,
         // Make a dynamic relocation if necessary.
         if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                 target->copy_reloc(symtab, layout, object,
                                    data_shndx, output_section, gsym, reloc);
@@ -1363,7 +1361,7 @@ Target_x86_64::Scan::global(const General_options&,
           flags |= Symbol::FUNCTION_CALL;
         if (gsym->needs_dynamic_reloc(flags))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                 target->copy_reloc(symtab, layout, object,
                                    data_shndx, output_section, gsym, reloc);
@@ -2428,15 +2426,17 @@ Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
 // Relocate section data.
 
 void
-Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
-                                unsigned int sh_type,
-                                const unsigned char* prelocs,
-                                size_t reloc_count,
-                               Output_section* output_section,
-                               bool needs_special_offset_handling,
-                                unsigned char* view,
-                                elfcpp::Elf_types<64>::Elf_Addr address,
-                                section_size_type view_size)
+Target_x86_64::relocate_section(
+    const Relocate_info<64, false>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    unsigned char* view,
+    elfcpp::Elf_types<64>::Elf_Addr address,
+    section_size_type view_size,
+    const Reloc_symbol_changes* reloc_symbol_changes)
 {
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
@@ -2450,7 +2450,8 @@ Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
@@ -2668,6 +2669,63 @@ Target_x86_64::do_code_fill(section_size_type length) const
   return std::string(nops[length], length);
 }
 
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fstack-split.  The function calls non-stack-split
+// code.  We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+void
+Target_x86_64::do_calls_non_split(Relobj* object, unsigned int shndx,
+                                 section_offset_type fnoffset,
+                                 section_size_type fnsize,
+                                 unsigned char* view,
+                                 section_size_type view_size,
+                                 std::string* from,
+                                 std::string* to) const
+{
+  // The function starts with a comparison of the stack pointer and a
+  // field in the TCB.  This is followed by a jump.
+
+  // cmp %fs:NN,%rsp
+  if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5)
+      && fnsize > 9)
+    {
+      // We will call __morestack if the carry flag is set after this
+      // comparison.  We turn the comparison into an stc instruction
+      // and some nops.
+      view[fnoffset] = '\xf9';
+      this->set_view_to_nop(view, view_size, fnoffset + 1, 8);
+    }
+  // lea NN(%rsp),%r10
+  else if (this->match_view(view, view_size, fnoffset, "\x4c\x8d\x94\x24", 4)
+          && fnsize > 8)
+    {
+      // This is loading an offset from the stack pointer for a
+      // comparison.  The offset is negative, so we decrease the
+      // offset by the amount of space we need for the stack.  This
+      // means we will avoid calling __morestack if there happens to
+      // be plenty of space on the stack already.
+      unsigned char* pval = view + fnoffset + 4;
+      uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
+      val -= parameters->options().split_stack_adjust_size();
+      elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
+    }
+  else
+    {
+      if (!object->has_no_split_stack())
+       object->error(_("failed to match split-stack sequence at "
+                       "section %u offset %0zx"),
+                     shndx, fnoffset);
+      return;
+    }
+
+  // We have to change the function so that it calls
+  // __morestack_non_split instead of __morestack.  The former will
+  // allocate additional stack space.
+  *from = "__morestack";
+  *to = "__morestack_non_split";
+}
+
 // The selector for x86_64 object files.
 
 class Target_selector_x86_64 : public Target_selector_freebsd