Initial -r support.
authorIan Lance Taylor <iant@google.com>
Wed, 6 Feb 2008 08:13:50 +0000 (08:13 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 6 Feb 2008 08:13:50 +0000 (08:13 +0000)
18 files changed:
gold/gold.cc
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/options.cc
gold/output.cc
gold/output.h
gold/reloc-types.h
gold/reloc.cc
gold/reloc.h
gold/target-reloc.h
gold/target.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/testfile.cc
gold/x86_64.cc

index aa6f32a87fed6a197122a2521d0f647913f9e290..2aee1b76c81ea9ab71ff0709a9fdcd51cbe0ac20 100644 (file)
@@ -182,6 +182,9 @@ queue_middle_tasks(const General_options& options,
       gold_error(_("cannot mix -static with dynamic object %s"),
                 (*input_objects->dynobj_begin())->name().c_str());
     }
+  if (!doing_static_link && parameters->output_is_object())
+    gold_error(_("cannot mix -r with dynamic object %s"),
+              (*input_objects->dynobj_begin())->name().c_str());
 
   if (is_debugging_enabled(DEBUG_SCRIPT))
     layout->script_options()->print(stderr);
@@ -201,12 +204,15 @@ queue_middle_tasks(const General_options& options,
   // Define symbols from any linker scripts.
   layout->define_script_symbols(symtab);
 
-  // Predefine standard symbols.
-  define_standard_symbols(symtab, layout);
+  if (!parameters->output_is_object())
+    {
+      // Predefine standard symbols.
+      define_standard_symbols(symtab, layout);
 
-  // Define __start and __stop symbols for output sections where
-  // appropriate.
-  layout->define_section_symbols(symtab);
+      // Define __start and __stop symbols for output sections where
+      // appropriate.
+      layout->define_section_symbols(symtab);
+    }
 
   // Read the relocations of the input files.  We do this to find
   // which symbols are used by relocations which require a GOT and/or
@@ -237,9 +243,14 @@ queue_middle_tasks(const General_options& options,
 
   // Allocate common symbols.  This requires write access to the
   // symbol table, but is independent of the relocation processing.
-  blocker->add_blocker();
-  workqueue->queue(new Allocate_commons_task(options, symtab, layout,
-                                            symtab_lock, blocker));
+  // FIXME: We should have an option to do this even for a relocatable
+  // link.
+  if (!parameters->output_is_object())
+    {
+      blocker->add_blocker();
+      workqueue->queue(new Allocate_commons_task(options, symtab, layout,
+                                                symtab_lock, blocker));
+    }
 
   // When all those tasks are complete, we can start laying out the
   // output file.
index ca68a3fe456fac913a1830d23ccd0956fdfe1d51..3bcfa4c6ec1e87cc0fbea5a1e908aab15cc272eb 100644 (file)
@@ -96,6 +96,37 @@ class Target_i386 : public Sized_target<32, false>
                   elfcpp::Elf_types<32>::Elf_Addr view_address,
                   section_size_type view_size);
 
+  // Scan the relocs during a relocatable link.
+  void
+  scan_relocatable_relocs(const General_options& options,
+                         Symbol_table* symtab,
+                         Layout* layout,
+                         Sized_relobj<32, false>* object,
+                         unsigned int data_shndx,
+                         unsigned int sh_type,
+                         const unsigned char* prelocs,
+                         size_t reloc_count,
+                         Output_section* output_section,
+                         bool needs_special_offset_handling,
+                         size_t local_symbol_count,
+                         const unsigned char* plocal_symbols,
+                         Relocatable_relocs*);
+
+  // Relocate a section during a relocatable link.
+  void
+  relocate_for_relocatable(const Relocate_info<32, false>*,
+                          unsigned int sh_type,
+                          const unsigned char* prelocs,
+                          size_t reloc_count,
+                          Output_section* output_section,
+                          off_t offset_in_output_section,
+                          const Relocatable_relocs*,
+                          unsigned char* view,
+                          elfcpp::Elf_types<32>::Elf_Addr view_address,
+                          section_size_type view_size,
+                          unsigned char* reloc_view,
+                          section_size_type reloc_view_size);
+
   // Return a string used to fill a code section with nops.
   std::string
   do_code_fill(section_size_type length);
@@ -240,6 +271,15 @@ class Target_i386 : public Sized_target<32, false>
     Local_dynamic_type local_dynamic_type_;
   };
 
+  // A class which returns the size required for a relocation type,
+  // used while scanning relocs during a relocatable link.
+  class Relocatable_size_for_reloc
+  {
+   public:
+    unsigned int
+    get_size_for_reloc(unsigned int, Relobj*);
+  };
+
   // Adjust TLS relocation type based on the options and whether this
   // is a local symbol.
   static tls::Tls_optimization
@@ -2151,6 +2191,148 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
     view_size);
 }
 
+// Return the size of a relocation while scanning during a relocatable
+// link.
+
+unsigned int
+Target_i386::Relocatable_size_for_reloc::get_size_for_reloc(
+    unsigned int r_type,
+    Relobj* object)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_386_NONE:
+    case elfcpp::R_386_GNU_VTINHERIT:
+    case elfcpp::R_386_GNU_VTENTRY:
+    case elfcpp::R_386_TLS_GD:            // Global-dynamic
+    case elfcpp::R_386_TLS_GOTDESC:       // Global-dynamic (from ~oliva url)
+    case elfcpp::R_386_TLS_DESC_CALL:
+    case elfcpp::R_386_TLS_LDM:           // Local-dynamic
+    case elfcpp::R_386_TLS_LDO_32:        // Alternate local-dynamic
+    case elfcpp::R_386_TLS_IE:            // Initial-exec
+    case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:            // Local-exec
+    case elfcpp::R_386_TLS_LE_32:
+      return 0;
+
+    case elfcpp::R_386_32:
+    case elfcpp::R_386_PC32:
+    case elfcpp::R_386_GOT32:
+    case elfcpp::R_386_PLT32:
+    case elfcpp::R_386_GOTOFF:
+    case elfcpp::R_386_GOTPC:
+     return 4;
+
+    case elfcpp::R_386_16:
+    case elfcpp::R_386_PC16:
+      return 2;
+
+    case elfcpp::R_386_8:
+    case elfcpp::R_386_PC8:
+      return 1;
+
+      // These are relocations which should only be seen by the
+      // dynamic linker, and should never be seen here.
+    case elfcpp::R_386_COPY:
+    case elfcpp::R_386_GLOB_DAT:
+    case elfcpp::R_386_JUMP_SLOT:
+    case elfcpp::R_386_RELATIVE:
+    case elfcpp::R_386_TLS_TPOFF:
+    case elfcpp::R_386_TLS_DTPMOD32:
+    case elfcpp::R_386_TLS_DTPOFF32:
+    case elfcpp::R_386_TLS_TPOFF32:
+    case elfcpp::R_386_TLS_DESC:
+      object->error(_("unexpected reloc %u in object file"), r_type);
+      return 0;
+
+    case elfcpp::R_386_32PLT:
+    case elfcpp::R_386_TLS_GD_32:
+    case elfcpp::R_386_TLS_GD_PUSH:
+    case elfcpp::R_386_TLS_GD_CALL:
+    case elfcpp::R_386_TLS_GD_POP:
+    case elfcpp::R_386_TLS_LDM_32:
+    case elfcpp::R_386_TLS_LDM_PUSH:
+    case elfcpp::R_386_TLS_LDM_CALL:
+    case elfcpp::R_386_TLS_LDM_POP:
+    case elfcpp::R_386_USED_BY_INTEL_200:
+    default:
+      object->error(_("unsupported reloc %u in object file"), r_type);
+      return 0;
+    }
+}
+
+// Scan the relocs during a relocatable link.
+
+void
+Target_i386::scan_relocatable_relocs(const General_options& options,
+                                    Symbol_table* symtab,
+                                    Layout* layout,
+                                    Sized_relobj<32, false>* object,
+                                    unsigned int data_shndx,
+                                    unsigned int sh_type,
+                                    const unsigned char* prelocs,
+                                    size_t reloc_count,
+                                    Output_section* output_section,
+                                    bool needs_special_offset_handling,
+                                    size_t local_symbol_count,
+                                    const unsigned char* plocal_symbols,
+                                    Relocatable_relocs* rr)
+{
+  gold_assert(sh_type == elfcpp::SHT_REL);
+
+  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_REL,
+    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+  gold::scan_relocatable_relocs<32, false, Target_i386, elfcpp::SHT_REL,
+      Scan_relocatable_relocs>(
+    options,
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols,
+    rr);
+}
+
+// Relocate a section during a relocatable link.
+
+void
+Target_i386::relocate_for_relocatable(
+    const Relocate_info<32, false>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    off_t offset_in_output_section,
+    const Relocatable_relocs* rr,
+    unsigned char* view,
+    elfcpp::Elf_types<32>::Elf_Addr view_address,
+    section_size_type view_size,
+    unsigned char* reloc_view,
+    section_size_type reloc_view_size)
+{
+  gold_assert(sh_type == elfcpp::SHT_REL);
+
+  gold::relocate_for_relocatable<32, false, Target_i386, elfcpp::SHT_REL>(
+    relinfo,
+    prelocs,
+    reloc_count,
+    output_section,
+    offset_in_output_section,
+    rr,
+    view,
+    view_address,
+    view_size,
+    reloc_view,
+    reloc_view_size);
+}
+
 // Return the value to use for a dynamic which requires special
 // treatment.  This is how we support equality comparisons of function
 // pointers across shared library boundaries, as described in the
index a532e09f716b7fafc81a3ffefd55c1c1d65883b6..006a3842daf6d9f188344f3fceefbb59429927f8 100644 (file)
@@ -36,6 +36,7 @@
 #include "dynobj.h"
 #include "ehframe.h"
 #include "compressed_output.h"
+#include "reloc.h"
 #include "layout.h"
 
 namespace gold
@@ -138,8 +139,6 @@ bool
 Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
                        const elfcpp::Shdr<size, big_endian>& shdr)
 {
-  // Some section types are never linked.  Some are only linked when
-  // doing a relocateable link.
   switch (shdr.get_sh_type())
     {
     case elfcpp::SHT_NULL:
@@ -154,7 +153,9 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
     case elfcpp::SHT_RELA:
     case elfcpp::SHT_REL:
     case elfcpp::SHT_GROUP:
-      return parameters->output_is_object();
+      // For a relocatable link these should be handled elsewhere.
+      gold_assert(!parameters->output_is_object());
+      return false;
 
     case elfcpp::SHT_PROGBITS:
       if (parameters->strip_debug()
@@ -330,13 +331,24 @@ Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx,
   if (!this->include_section(object, name, shdr))
     return NULL;
 
-  Output_section* os = this->choose_output_section(object,
-                                                  name,
-                                                  shdr.get_sh_type(),
-                                                  shdr.get_sh_flags(),
-                                                  true);
-  if (os == NULL)
-    return NULL;
+  Output_section* os;
+
+  // In a relocatable link a grouped section must not be combined with
+  // any other sections.
+  if (parameters->output_is_object()
+      && (shdr.get_sh_flags() & elfcpp::SHF_GROUP) != 0)
+    {
+      name = this->namepool_.add(name, true, NULL);
+      os = this->make_output_section(name, shdr.get_sh_type(),
+                                    shdr.get_sh_flags());
+    }
+  else
+    {
+      os = this->choose_output_section(object, name, shdr.get_sh_type(),
+                                      shdr.get_sh_flags(), true);
+      if (os == NULL)
+       return NULL;
+    }
 
   // FIXME: Handle SHF_LINK_ORDER somewhere.
 
@@ -346,6 +358,100 @@ Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx,
   return os;
 }
 
+// Handle a relocation section when doing a relocatable link.
+
+template<int size, bool big_endian>
+Output_section*
+Layout::layout_reloc(Sized_relobj<size, big_endian>* object,
+                    unsigned int,
+                    const elfcpp::Shdr<size, big_endian>& shdr,
+                    Output_section* data_section,
+                    Relocatable_relocs* rr)
+{
+  gold_assert(parameters->output_is_object());
+
+  int sh_type = shdr.get_sh_type();
+
+  std::string name;
+  if (sh_type == elfcpp::SHT_REL)
+    name = ".rel";
+  else if (sh_type == elfcpp::SHT_RELA)
+    name = ".rela";
+  else
+    gold_unreachable();
+  name += data_section->name();
+
+  Output_section* os = this->choose_output_section(object, name.c_str(),
+                                                  sh_type,
+                                                  shdr.get_sh_flags(),
+                                                  false);
+
+  os->set_should_link_to_symtab();
+  os->set_info_section(data_section);
+
+  Output_section_data* posd;
+  if (sh_type == elfcpp::SHT_REL)
+    {
+      os->set_entsize(elfcpp::Elf_sizes<size>::rel_size);
+      posd = new Output_relocatable_relocs<elfcpp::SHT_REL,
+                                          size,
+                                          big_endian>(rr);
+    }
+  else if (sh_type == elfcpp::SHT_RELA)
+    {
+      os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
+      posd = new Output_relocatable_relocs<elfcpp::SHT_RELA,
+                                          size,
+                                          big_endian>(rr);
+    }
+  else
+    gold_unreachable();
+
+  os->add_output_section_data(posd);
+  rr->set_output_data(posd);
+
+  return os;
+}
+
+// Handle a group section when doing a relocatable link.
+
+template<int size, bool big_endian>
+void
+Layout::layout_group(Symbol_table* symtab,
+                    Sized_relobj<size, big_endian>* object,
+                    unsigned int,
+                    const char* group_section_name,
+                    const char* signature,
+                    const elfcpp::Shdr<size, big_endian>& shdr,
+                    const elfcpp::Elf_Word* contents)
+{
+  gold_assert(parameters->output_is_object());
+  gold_assert(shdr.get_sh_type() == elfcpp::SHT_GROUP);
+  group_section_name = this->namepool_.add(group_section_name, true, NULL);
+  Output_section* os = this->make_output_section(group_section_name,
+                                                elfcpp::SHT_GROUP,
+                                                shdr.get_sh_flags());
+
+  // We need to find a symbol with the signature in the symbol table.
+  // This is a hack to force that to happen.
+  Symbol* sym = symtab->lookup(signature, NULL);
+  if (sym == NULL)
+    sym = symtab->define_as_constant(signature, NULL, 0, 0,
+                                    elfcpp::STT_NOTYPE,
+                                    elfcpp::STB_WEAK,
+                                    elfcpp::STV_HIDDEN, 0, false);
+
+  os->set_should_link_to_symtab();
+  os->set_info_symndx(sym);
+  os->set_entsize(4);
+
+  section_size_type entry_count =
+    convert_to_section_size_type(shdr.get_sh_size() / 4);
+  Output_section_data* posd =
+    new Output_data_group<size, big_endian>(object, entry_count, contents);
+  os->add_output_section_data(posd);
+}
+
 // Special GNU handling of sections name .eh_frame.  They will
 // normally hold exception frame data as defined by the C++ ABI
 // (http://codesourcery.com/cxx-abi/).
@@ -496,6 +602,9 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
     this->unattached_section_list_.push_back(os);
   else
     {
+      if (parameters->output_is_object())
+       return os;
+
       // If we have a SECTIONS clause, we can't handle the attachment
       // to segments until after we've seen all the sections.
       if (this->script_options_->saw_sections_clause())
@@ -799,7 +908,9 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   // 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())
+  if (parameters->output_is_object())
+    load_seg = NULL;
+  else if (this->script_options_->saw_sections_clause())
     load_seg = this->set_section_addresses_from_script(symtab);
   else
     load_seg = this->find_first_load_seg();
@@ -808,11 +919,16 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
 
   // Lay out the segment headers.
   Output_segment_headers* segment_headers;
-  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);
+  if (parameters->output_is_object())
+    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);
+    }
 
   // Lay out the file header.
   Output_file_header* file_header;
@@ -822,9 +938,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
     load_seg->add_initial_output_data(file_header);
 
   this->special_output_list_.push_back(file_header);
-  this->special_output_list_.push_back(segment_headers);
+  if (segment_headers != NULL)
+    this->special_output_list_.push_back(segment_headers);
 
-  if (this->script_options_->saw_phdrs_clause())
+  if (this->script_options_->saw_phdrs_clause()
+      && !parameters->output_is_object())
     {
       // Support use of FILEHDRS and PHDRS attachments in a PHDRS
       // clause in a linker script.
@@ -838,7 +956,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
 
   // Set the file offsets of all the segments, and all the sections
   // they contain.
-  off_t off = this->set_segment_offsets(target, load_seg, &shndx);
+  off_t off;
+  if (!parameters->output_is_object())
+    off = this->set_segment_offsets(target, load_seg, &shndx);
+  else
+    off = this->set_relocatable_section_offsets(file_header, &shndx);
 
   // 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
@@ -1272,6 +1394,45 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
   return off;
 }
 
+// Set the offsets of all the allocated sections when doing a
+// relocatable link.  This does the same jobs as set_segment_offsets,
+// only for a relocatable link.
+
+off_t
+Layout::set_relocatable_section_offsets(Output_data* file_header,
+                                       unsigned int *pshndx)
+{
+  off_t off = 0;
+
+  file_header->set_address_and_file_offset(0, 0);
+  off += file_header->data_size();
+
+  for (Section_list::iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      // We skip unallocated sections here, except that group sections
+      // have to come first.
+      if (((*p)->flags() & elfcpp::SHF_ALLOC) == 0
+         && (*p)->type() != elfcpp::SHT_GROUP)
+       continue;
+
+      off = align_address(off, (*p)->addralign());
+
+      // The linker script might have set the address.
+      if (!(*p)->is_address_valid())
+       (*p)->set_address(0);
+      (*p)->set_file_offset(off);
+      (*p)->finalize_data_size();
+      off += (*p)->data_size();
+
+      (*p)->set_out_shndx(*pshndx);
+      ++*pshndx;
+    }
+
+  return off;
+}
+
 // Set the file offset of all the sections not associated with a
 // segment.
 
@@ -1327,10 +1488,16 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
 unsigned int
 Layout::set_section_indexes(unsigned int shndx)
 {
+  const bool output_is_object = parameters->output_is_object();
   for (Section_list::iterator p = this->unattached_section_list_.begin();
        p != this->unattached_section_list_.end();
        ++p)
     {
+      // In a relocatable link, we already did group sections.
+      if (output_is_object
+         && (*p)->type() == elfcpp::SHT_GROUP)
+       continue;
+
       (*p)->set_out_shndx(shndx);
       ++shndx;
     }
@@ -1545,6 +1712,7 @@ Layout::create_shdrs(off_t* poff)
   Output_section_headers* oshdrs;
   oshdrs = new Output_section_headers(this,
                                      &this->segment_list_,
+                                     &this->section_list_,
                                      &this->unattached_section_list_,
                                      &this->namepool_);
   off_t off = align_address(*poff, oshdrs->addralign());
@@ -2177,6 +2345,7 @@ Layout::get_allocated_sections(Section_list* section_list) const
 Output_segment*
 Layout::make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
 {
+  gold_assert(!parameters->output_is_object());
   Output_segment* oseg = new Output_segment(type, flags);
   this->segment_list_.push_back(oseg);
   return oseg;
@@ -2456,6 +2625,94 @@ Layout::layout<64, true>(Sized_relobj<64, true>* object, unsigned int shndx,
                         unsigned int, unsigned int, off_t*);
 #endif
 
+#ifdef HAVE_TARGET_32_LITTLE
+template
+Output_section*
+Layout::layout_reloc<32, false>(Sized_relobj<32, false>* object,
+                               unsigned int reloc_shndx,
+                               const elfcpp::Shdr<32, false>& shdr,
+                               Output_section* data_section,
+                               Relocatable_relocs* rr);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+Output_section*
+Layout::layout_reloc<32, true>(Sized_relobj<32, true>* object,
+                              unsigned int reloc_shndx,
+                              const elfcpp::Shdr<32, true>& shdr,
+                              Output_section* data_section,
+                              Relocatable_relocs* rr);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+Output_section*
+Layout::layout_reloc<64, false>(Sized_relobj<64, false>* object,
+                               unsigned int reloc_shndx,
+                               const elfcpp::Shdr<64, false>& shdr,
+                               Output_section* data_section,
+                               Relocatable_relocs* rr);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+Output_section*
+Layout::layout_reloc<64, true>(Sized_relobj<64, true>* object,
+                              unsigned int reloc_shndx,
+                              const elfcpp::Shdr<64, true>& shdr,
+                              Output_section* data_section,
+                              Relocatable_relocs* rr);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+void
+Layout::layout_group<32, false>(Symbol_table* symtab,
+                               Sized_relobj<32, false>* object,
+                               unsigned int,
+                               const char* group_section_name,
+                               const char* signature,
+                               const elfcpp::Shdr<32, false>& shdr,
+                               const elfcpp::Elf_Word* contents);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+void
+Layout::layout_group<32, true>(Symbol_table* symtab,
+                              Sized_relobj<32, true>* object,
+                              unsigned int,
+                              const char* group_section_name,
+                              const char* signature,
+                              const elfcpp::Shdr<32, true>& shdr,
+                              const elfcpp::Elf_Word* contents);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+void
+Layout::layout_group<64, false>(Symbol_table* symtab,
+                               Sized_relobj<64, false>* object,
+                               unsigned int,
+                               const char* group_section_name,
+                               const char* signature,
+                               const elfcpp::Shdr<64, false>& shdr,
+                               const elfcpp::Elf_Word* contents);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+void
+Layout::layout_group<64, true>(Symbol_table* symtab,
+                              Sized_relobj<64, true>* object,
+                              unsigned int,
+                              const char* group_section_name,
+                              const char* signature,
+                              const elfcpp::Shdr<64, true>& shdr,
+                              const elfcpp::Elf_Word* contents);
+#endif
+
 #ifdef HAVE_TARGET_32_LITTLE
 template
 Output_section*
index d7f59650432e928ec0e1cb3a3ada4077a5d46d17..e050df36b925380215b0ce8e891a5897ecb7520e 100644 (file)
@@ -100,6 +100,29 @@ class Layout
         const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
         unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
 
+  // Layout an input reloc section when doing a relocatable link.  The
+  // section is RELOC_SHNDX in OBJECT, with data in SHDR.
+  // DATA_SECTION is the reloc section to which it refers.  RR is the
+  // relocatable information.
+  template<int size, bool big_endian>
+  Output_section*
+  layout_reloc(Sized_relobj<size, big_endian>* object,
+              unsigned int reloc_shndx,
+              const elfcpp::Shdr<size, big_endian>& shdr,
+              Output_section* data_section,
+              Relocatable_relocs* rr);
+
+  // Layout a group section when doing a relocatable link.
+  template<int size, bool big_endian>
+  void
+  layout_group(Symbol_table* symtab,
+              Sized_relobj<size, big_endian>* object,
+              unsigned int group_shndx,
+              const char* group_section_name,
+              const char* signature,
+              const elfcpp::Shdr<size, big_endian>& shdr,
+              const elfcpp::Elf_Word* contents);
+
   // Like layout, only for exception frame sections.  OBJECT is an
   // object file.  SYMBOLS is the contents of the symbol table
   // section, with size SYMBOLS_SIZE.  SYMBOL_NAMES is the contents of
@@ -413,6 +436,11 @@ class Layout
   off_t
   set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
 
+  // Set the file offsets of the sections when doing a relocatable
+  // link.
+  off_t
+  set_relocatable_section_offsets(Output_data*, unsigned int* pshndx);
+
   // Set the final file offsets of all the sections not associated
   // with a segment.  We set section offsets in three passes: the
   // first handles all allocated sections, the second sections that
index e56f6a4c7cc025b9c6c80ab08ae95887d7c2bf2a..433fbc842c5ff912c3901f71379cb9e53b1e21b4 100644 (file)
@@ -378,8 +378,10 @@ Sized_relobj<size, big_endian>::symbol_section_and_value(unsigned int sym,
 template<int size, bool big_endian>
 bool
 Sized_relobj<size, big_endian>::include_section_group(
+    Symbol_table* symtab,
     Layout* layout,
     unsigned int index,
+    const char* name,
     const elfcpp::Shdr<size, big_endian>& shdr,
     std::vector<bool>* omit)
 {
@@ -393,13 +395,11 @@ Sized_relobj<size, big_endian>::include_section_group(
   // groups.  Other section groups are always included in the link
   // just like ordinary sections.
   elfcpp::Elf_Word flags = elfcpp::Swap<32, big_endian>::readval(pword);
-  if ((flags & elfcpp::GRP_COMDAT) == 0)
-    return true;
 
   // Look up the group signature, which is the name of a symbol.  This
   // is a lot of effort to go to to read a string.  Why didn't they
-  // just use the name of the SHT_GROUP section as the group
-  // signature?
+  // just have the group signature point into the string table, rather
+  // than indirect through a symbol?
 
   // Get the appropriate symbol table header (this will normally be
   // the single SHT_SYMTAB section, but in principle it need not be).
@@ -447,8 +447,15 @@ Sized_relobj<size, big_endian>::include_section_group(
 
   // Record this section group, and see whether we've already seen one
   // with the same signature.
-  if (layout->add_comdat(signature, true))
-    return true;
+
+  if ((flags & elfcpp::GRP_COMDAT) == 0
+      || layout->add_comdat(signature, true))
+    {
+      if (parameters->output_is_object())
+       layout->layout_group(symtab, this, index, name, signature, shdr,
+                            pword);
+      return true;
+    }
 
   // This is a duplicate.  We want to discard the sections in this
   // group.
@@ -575,6 +582,10 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
   // Keep track of which sections to omit.
   std::vector<bool> omit(shnum, false);
 
+  // Keep track of reloc sections when doing a relocatable link.
+  const bool output_is_object = parameters->output_is_object();
+  std::vector<unsigned int> reloc_sections;
+
   // Keep track of .eh_frame sections.
   std::vector<unsigned int> eh_frame_sections;
 
@@ -595,7 +606,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
 
       if (this->handle_gnu_warning_section(name, i, symtab))
        {
-         if (!parameters->output_is_object())
+         if (!output_is_object)
            omit[i] = true;
        }
 
@@ -614,7 +625,8 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
        {
          if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
            {
-             if (!this->include_section_group(layout, i, shdr, &omit))
+             if (!this->include_section_group(symtab, layout, i, name, shdr,
+                                              &omit))
                discard = true;
            }
           else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
@@ -632,13 +644,29 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
          continue;
        }
 
+      // When doing a relocatable link we are going to copy input
+      // reloc sections into the output.  We only want to copy the
+      // ones associated with sections which are not being discarded.
+      // However, we don't know that yet for all sections.  So save
+      // reloc sections and process them later.
+      if (output_is_object
+         && (shdr.get_sh_type() == elfcpp::SHT_REL
+             || shdr.get_sh_type() == elfcpp::SHT_RELA))
+       {
+         reloc_sections.push_back(i);
+         continue;
+       }
+
+      if (output_is_object && shdr.get_sh_type() == elfcpp::SHT_GROUP)
+       continue;
+
       // The .eh_frame section is special.  It holds exception frame
       // information that we need to read in order to generate the
       // exception frame header.  We process these after all the other
       // sections so that the exception frame reader can reliably
       // determine which sections are being discarded, and discard the
       // corresponding information.
-      if (!parameters->output_is_object()
+      if (!output_is_object
          && strcmp(name, ".eh_frame") == 0
          && this->check_eh_frame_flags(&shdr))
        {
@@ -663,6 +691,42 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
 
   layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags);
 
+  // When doing a relocatable link handle the reloc sections at the
+  // end.
+  if (output_is_object)
+    this->size_relocatable_relocs();
+  for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin();
+       p != reloc_sections.end();
+       ++p)
+    {
+      unsigned int i = *p;
+      const unsigned char* pshdr;
+      pshdr = sd->section_headers->data() + i * This::shdr_size;
+      typename This::Shdr shdr(pshdr);
+
+      unsigned int data_shndx = shdr.get_sh_info();
+      if (data_shndx >= shnum)
+       {
+         // We already warned about this above.
+         continue;
+       }
+
+      Output_section* data_section = map_sections[data_shndx].output_section;
+      if (data_section == NULL)
+       {
+         map_sections[i].output_section = NULL;
+         continue;
+       }
+
+      Relocatable_relocs* rr = new Relocatable_relocs();
+      this->set_relocatable_relocs(i, rr);
+
+      Output_section* os = layout->layout_reloc(this, i, shdr, data_section,
+                                               rr);
+      map_sections[i].output_section = os;
+      map_sections[i].offset = -1;
+    }
+
   // Handle the .eh_frame sections at the end.
   for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin();
        p != eh_frame_sections.end();
index 5a6254667086e2c521d93288fbff03e307f61924..dbe0ca1390ebaf4056ae2008736765cd5595fd29 100644 (file)
@@ -41,6 +41,7 @@ class Output_section;
 class Output_file;
 class Dynobj;
 class Object_merge_map;
+class Relocatable_relocs;
 
 template<typename Stringpool_char>
 class Stringpool_template;
@@ -456,6 +457,7 @@ class Relobj : public Object
   Relobj(const std::string& name, Input_file* input_file, off_t offset = 0)
     : Object(name, input_file, false, offset),
       map_to_output_(),
+      map_to_relocatable_relocs_(NULL),
       object_merge_map_(NULL),
       relocs_must_follow_section_writes_(false)
   { }
@@ -562,6 +564,22 @@ class Relobj : public Object
     this->object_merge_map_ = object_merge_map;
   }
 
+  // Record the relocatable reloc info for an input reloc section.
+  void
+  set_relocatable_relocs(unsigned int reloc_shndx, Relocatable_relocs* rr)
+  {
+    gold_assert(reloc_shndx < this->shnum());
+    (*this->map_to_relocatable_relocs_)[reloc_shndx] = rr;
+  }
+
+  // Get the relocatable reloc info for an input reloc section.
+  Relocatable_relocs*
+  relocatable_relocs(unsigned int reloc_shndx)
+  {
+    gold_assert(reloc_shndx < this->shnum());
+    return (*this->map_to_relocatable_relocs_)[reloc_shndx];
+  }
+
  protected:
   // What we need to know to map an input section to an output
   // section.  We keep an array of these, one for each input section,
@@ -592,10 +610,11 @@ class Relobj : public Object
   // Count local symbols--implemented by child class.
   virtual void
   do_count_local_symbols(Stringpool_template<char>*,
-                           Stringpool_template<char>*) = 0;
+                        Stringpool_template<char>*) = 0;
 
-  // Finalize the local symbols.  Set the output symbol table indexes for the local variables, and set the
-  // offset where local symbol information will be stored.
+  // Finalize the local symbols.  Set the output symbol table indexes
+  // for the local variables, and set the offset where local symbol
+  // information will be stored.
   virtual unsigned int
   do_finalize_local_symbols(unsigned int, off_t) = 0;
 
@@ -622,6 +641,14 @@ class Relobj : public Object
   map_to_output() const
   { return this->map_to_output_; }
 
+  // Set the size of the relocatable relocs array.
+  void
+  size_relocatable_relocs()
+  {
+    this->map_to_relocatable_relocs_ =
+      new std::vector<Relocatable_relocs*>(this->shnum());
+  }
+
   // Record that we must wait for the output sections to be written
   // before applying relocations.
   void
@@ -631,6 +658,9 @@ class Relobj : public Object
  private:
   // Mapping from input sections to output section.
   std::vector<Map_to_output> map_to_output_;
+  // Mapping from input section index to the information recorded for
+  // the relocations.  This is only used for a relocatable link.
+  std::vector<Relocatable_relocs*>* map_to_relocatable_relocs_;
   // Mappings for merge sections.  This is managed by the code in the
   // Merge_map class.
   Object_merge_map* object_merge_map_;
@@ -992,6 +1022,14 @@ class Sized_relobj : public Relobj
     return this->local_values_[sym].output_dynsym_index();
   }
 
+  // Return the input section index of local symbol SYM.
+  unsigned int
+  local_symbol_input_shndx(unsigned int sym) const
+  {
+    gold_assert(sym < this->local_values_.size());
+    return this->local_values_[sym].input_shndx();
+  }
+
   // Return the appropriate Sized_target structure.
   Sized_target<size, big_endian>*
   sized_target()
@@ -1218,7 +1256,7 @@ class Sized_relobj : public Relobj
 
   // Whether to include a section group in the link.
   bool
-  include_section_group(Layout*, unsigned int,
+  include_section_group(Symbol_table*, Layout*, unsigned int, const char*,
                        const elfcpp::Shdr<size, big_endian>&,
                        std::vector<bool>*);
 
index b1b428f3b2392d8154a9bfc602fd07f5d9d9698f..a4b4c2f24681f03141ad3df72e1f26502fbf8fe6 100644 (file)
@@ -977,6 +977,9 @@ Command_line::get_special_argument(const char* longname, int argc, char** argv,
 void
 Command_line::normalize_options()
 {
+  if (this->options_.is_shared() && this->options_.is_relocatable())
+    gold_fatal(_("-shared and -r are incompatible"));
+
   // If the user specifies both -s and -r, convert the -s as -S.
   // -r requires us to keep externally visible symbols!
   if (this->options_.strip_all() && this->options_.is_relocatable())
index f0f4de26fdf2cff749b94646b5e78357d709ea6b..0e05ff778ea12d9856464917f569c6427968a116 100644 (file)
@@ -83,20 +83,33 @@ Output_data::default_alignment_for_size(int size)
 Output_section_headers::Output_section_headers(
     const Layout* layout,
     const Layout::Segment_list* segment_list,
+    const Layout::Section_list* section_list,
     const Layout::Section_list* unattached_section_list,
     const Stringpool* secnamepool)
   : layout_(layout),
     segment_list_(segment_list),
+    section_list_(section_list),
     unattached_section_list_(unattached_section_list),
     secnamepool_(secnamepool)
 {
   // Count all the sections.  Start with 1 for the null section.
   off_t count = 1;
-  for (Layout::Segment_list::const_iterator p = segment_list->begin();
-       p != segment_list->end();
-       ++p)
-    if ((*p)->type() == elfcpp::PT_LOAD)
-      count += (*p)->output_section_count();
+  if (!parameters->output_is_object())
+    {
+      for (Layout::Segment_list::const_iterator p = segment_list->begin();
+          p != 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();
+          ++p)
+       if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
+         ++count;
+    }
   count += unattached_section_list->size();
 
   const int size = parameters->get_size();
@@ -184,18 +197,48 @@ Output_section_headers::do_sized_write(Output_file* of)
 
   v += shdr_size;
 
-  unsigned shndx = 1;
-  for (Layout::Segment_list::const_iterator p = this->segment_list_->begin();
-       p != this->segment_list_->end();
-       ++p)
-    v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
-           this->layout_, this->secnamepool_, v, &shndx
-           SELECT_SIZE_ENDIAN(size, big_endian));
+  unsigned int shndx = 1;
+  if (!parameters->output_is_object())
+    {
+      for (Layout::Segment_list::const_iterator p =
+            this->segment_list_->begin();
+          p != this->segment_list_->end();
+          ++p)
+       v = (*p)->write_section_headers<size, big_endian>(this->layout_,
+                                                         this->secnamepool_,
+                                                         v,
+                                                         &shndx);
+    }
+  else
+    {
+      for (Layout::Section_list::const_iterator p =
+            this->section_list_->begin();
+          p != this->section_list_->end();
+          ++p)
+       {
+         // We do unallocated sections below, except that group
+         // sections have to come first.
+         if (((*p)->flags() & elfcpp::SHF_ALLOC) == 0
+             && (*p)->type() != elfcpp::SHT_GROUP)
+           continue;
+         gold_assert(shndx == (*p)->out_shndx());
+         elfcpp::Shdr_write<size, big_endian> oshdr(v);
+         (*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
+         v += shdr_size;
+         ++shndx;
+       }
+    }
+
   for (Layout::Section_list::const_iterator p =
         this->unattached_section_list_->begin();
        p != this->unattached_section_list_->end();
        ++p)
     {
+      // For a relocatable link, we did unallocated group sections
+      // above, since they have to come first.
+      if ((*p)->type() == elfcpp::SHT_GROUP
+         && parameters->output_is_object())
+       continue;
       gold_assert(shndx == (*p)->out_shndx());
       elfcpp::Shdr_write<size, big_endian> oshdr(v);
       (*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
@@ -422,16 +465,30 @@ Output_file_header::do_sized_write(Output_file* of)
 
   oehdr.put_e_entry(this->entry<size>());
 
-  oehdr.put_e_phoff(this->segment_header_->offset());
+  if (this->segment_header_ == NULL)
+    oehdr.put_e_phoff(0);
+  else
+    oehdr.put_e_phoff(this->segment_header_->offset());
+
   oehdr.put_e_shoff(this->section_header_->offset());
 
   // FIXME: The target needs to set the flags.
   oehdr.put_e_flags(0);
 
   oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
-  oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
-  oehdr.put_e_phnum(this->segment_header_->data_size()
-                    / elfcpp::Elf_sizes<size>::phdr_size);
+
+  if (this->segment_header_ == NULL)
+    {
+      oehdr.put_e_phentsize(0);
+      oehdr.put_e_phnum(0);
+    }
+  else
+    {
+      oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
+      oehdr.put_e_phnum(this->segment_header_->data_size()
+                       / elfcpp::Elf_sizes<size>::phdr_size);
+    }
+
   oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
   oehdr.put_e_shnum(this->section_header_->data_size()
                     / elfcpp::Elf_sizes<size>::shdr_size);
@@ -822,6 +879,80 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
   this->relocs_.clear();
 }
 
+// Class Output_relocatable_relocs.
+
+template<int sh_type, int size, bool big_endian>
+void
+Output_relocatable_relocs<sh_type, size, big_endian>::set_final_data_size()
+{
+  this->set_data_size(this->rr_->output_reloc_count()
+                     * Reloc_types<sh_type, size, big_endian>::reloc_size);
+}
+
+// class Output_data_group.
+
+template<int size, bool big_endian>
+Output_data_group<size, big_endian>::Output_data_group(
+    Sized_relobj<size, big_endian>* relobj,
+    section_size_type entry_count,
+    const elfcpp::Elf_Word* contents)
+  : Output_section_data(entry_count * 4, 4),
+    relobj_(relobj)
+{
+  this->flags_ = elfcpp::Swap<32, big_endian>::readval(contents);
+  for (section_size_type i = 1; i < entry_count; ++i)
+    {
+      unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(contents + i);
+      this->input_sections_.push_back(shndx);
+    }
+}
+
+// Write out the section group, which means translating the section
+// indexes to apply to the output file.
+
+template<int size, bool big_endian>
+void
+Output_data_group<size, big_endian>::do_write(Output_file* of)
+{
+  const off_t off = this->offset();
+  const section_size_type oview_size =
+    convert_to_section_size_type(this->data_size());
+  unsigned char* const oview = of->get_output_view(off, oview_size);
+
+  elfcpp::Elf_Word* contents = reinterpret_cast<elfcpp::Elf_Word*>(oview);
+  elfcpp::Swap<32, big_endian>::writeval(contents, this->flags_);
+  ++contents;
+
+  for (std::vector<unsigned int>::const_iterator p =
+        this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p, ++contents)
+    {
+      section_offset_type dummy;
+      Output_section* os = this->relobj_->output_section(*p, &dummy);
+
+      unsigned int output_shndx;
+      if (os != NULL)
+       output_shndx = os->out_shndx();
+      else
+       {
+         this->relobj_->error(_("section group retained but "
+                                "group element discarded"));
+         output_shndx = 0;
+       }
+
+      elfcpp::Swap<32, big_endian>::writeval(contents, output_shndx);
+    }
+
+  size_t wrote = reinterpret_cast<unsigned char*>(contents) - oview;
+  gold_assert(wrote == oview_size);
+
+  of->write_output_view(off, oview_size, oview);
+
+  // We no longer need this information.
+  this->input_sections_.clear();
+}
+
 // Output_data_got::Got_entry methods.
 
 // Write out the entry.
@@ -1460,6 +1591,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     link_section_(NULL),
     link_(0),
     info_section_(NULL),
+    info_symndx_(NULL),
     info_(0),
     type_(type),
     flags_(flags),
@@ -1871,7 +2003,12 @@ Output_section::write_header(const Layout* layout,
 {
   oshdr->put_sh_name(secnamepool->get_offset(this->name_));
   oshdr->put_sh_type(this->type_);
-  oshdr->put_sh_flags(this->flags_);
+
+  elfcpp::Elf_Xword flags = this->flags_;
+  if (this->info_section_ != NULL)
+    flags |= elfcpp::SHF_INFO_LINK;
+  oshdr->put_sh_flags(flags);
+
   oshdr->put_sh_addr(this->address());
   oshdr->put_sh_offset(this->offset());
   oshdr->put_sh_size(this->data_size());
@@ -1885,6 +2022,8 @@ Output_section::write_header(const Layout* layout,
     oshdr->put_sh_link(this->link_);
   if (this->info_section_ != NULL)
     oshdr->put_sh_info(this->info_section_->out_shndx());
+  else if (this->info_symndx_ != NULL)
+    oshdr->put_sh_info(this->info_symndx_->symtab_index());
   else
     oshdr->put_sh_info(this->info_);
   oshdr->put_sh_addralign(this->addralign_);
@@ -2883,6 +3022,66 @@ template
 class Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>;
 #endif
 
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_REL, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_relocatable_relocs<elfcpp::SHT_RELA, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_data_group<32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_data_group<32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_data_group<64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_data_group<64, true>;
+#endif
+
 #ifdef HAVE_TARGET_32_LITTLE
 template
 class Output_data_got<32, false>;
index 032a2bb65c01f19a18babb9725bf7af6e3a041bf..b327eb2b7d1c2147a8d567d9e9da2206d8064a92 100644 (file)
@@ -38,6 +38,7 @@ class Object;
 class Symbol;
 class Output_file;
 class Output_section;
+class Relocatable_relocs;
 class Target;
 template<int size, bool big_endian>
 class Sized_target;
@@ -372,6 +373,7 @@ class Output_section_headers : public Output_data
   Output_section_headers(const Layout*,
                         const Layout::Segment_list*,
                         const Layout::Section_list*,
+                        const Layout::Section_list*,
                         const Stringpool*);
 
  protected:
@@ -392,6 +394,7 @@ class Output_section_headers : public Output_data
 
   const Layout* layout_;
   const Layout::Segment_list* segment_list_;
+  const Layout::Section_list* section_list_;
   const Layout::Section_list* unattached_section_list_;
   const Stringpool* secnamepool_;
 };
@@ -1184,6 +1187,54 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
                                     addend)); }
 };
 
+// Output_relocatable_relocs represents a relocation section in a
+// relocatable link.  The actual data is written out in the target
+// hook relocate_for_relocatable.  This just saves space for it.
+
+template<int sh_type, int size, bool big_endian>
+class Output_relocatable_relocs : public Output_section_data
+{
+ public:
+  Output_relocatable_relocs(Relocatable_relocs* rr)
+    : Output_section_data(Output_data::default_alignment_for_size(size)),
+      rr_(rr)
+  { }
+
+  void
+  set_final_data_size();
+
+  // Write out the data.  There is nothing to do here.
+  void
+  do_write(Output_file*)
+  { }
+
+ private:
+  // The relocs associated with this input section.
+  Relocatable_relocs* rr_;
+};
+
+// Handle a GROUP section.
+
+template<int size, bool big_endian>
+class Output_data_group : public Output_section_data
+{
+ public:
+  Output_data_group(Sized_relobj<size, big_endian>* relobj,
+                   section_size_type entry_count,
+                   const elfcpp::Elf_Word* contents);
+
+  void
+  do_write(Output_file*);
+
+ private:
+  // The input object.
+  Sized_relobj<size, big_endian>* relobj_;
+  // The group flag word.
+  elfcpp::Elf_Word flags_;
+  // The section indexes of the input sections in this group.
+  std::vector<unsigned int> input_sections_;
+};
+
 // Output_data_got is used to manage a GOT.  Each entry in the GOT is
 // for one symbol--either a global symbol or a local symbol in an
 // object.  The target specific code adds entries to the GOT as
@@ -1626,15 +1677,23 @@ class Output_section : public Output_data
   void
   set_info_section(const Output_data* od)
   {
-    gold_assert(this->info_ == 0);
+    gold_assert(this->info_symndx_ == NULL && this->info_ == 0);
     this->info_section_ = od;
   }
 
+  // Set the info field to the symbol table index of a symbol.
+  void
+  set_info_symndx(const Symbol* sym)
+  {
+    gold_assert(this->info_section_ == NULL && this->info_ == 0);
+    this->info_symndx_ = sym;
+  }
+
   // Set the info field to a constant.
   void
   set_info(unsigned int v)
   {
-    gold_assert(this->info_section_ == NULL);
+    gold_assert(this->info_section_ == NULL && this->info_symndx_ == NULL);
     this->info_ = v;
   }
 
@@ -2201,7 +2260,11 @@ class Output_section : public Output_data
   unsigned int link_;
   // Set the section info field to the index of this section.
   const Output_data* info_section_;
-  // If info_section_ is NULL, this is the section info field.
+  // If info_section_ is NULL, set the info field to the symbol table
+  // index of this symbol.
+  const Symbol* info_symndx_;
+  // If info_section_ and info_symndx_ are NULL, this is the section
+  // info field.
   unsigned int info_;
   // The section type.
   const elfcpp::Elf_Word type_;
index e8a0689d0ac7b69b5940e37017092e877c69296e..01f561eb04f76467cbae60ffc029cbf602071720 100644 (file)
@@ -41,14 +41,42 @@ template<int size, bool big_endian>
 struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
 {
   typedef typename elfcpp::Rel<size, big_endian> Reloc;
+  typedef typename elfcpp::Rel_write<size, big_endian> Reloc_write;
   static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+
+  static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+  get_reloc_addend(const Reloc*)
+  { gold_unreachable(); }
+
+  static inline void
+  set_reloc_addend(Reloc_write*,
+                  typename elfcpp::Elf_types<size>::Elf_Swxword)
+  { gold_unreachable(); }
+
+  static inline void
+  copy_reloc_addend(Reloc_write*, const Reloc*)
+  { gold_unreachable(); }
 };
 
 template<int size, bool big_endian>
 struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
 {
   typedef typename elfcpp::Rela<size, big_endian> Reloc;
+  typedef typename elfcpp::Rela_write<size, big_endian> Reloc_write;
   static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+
+  static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+  get_reloc_addend(const Reloc* p)
+  { return p->get_r_addend(); }
+
+  static inline void
+  set_reloc_addend(Reloc_write* p,
+                  typename elfcpp::Elf_types<size>::Elf_Swxword val)
+  { p->put_r_addend(val); }
+
+  static inline void
+  copy_reloc_addend(Reloc_write* to, const Reloc* from)
+  { to->put_r_addend(from->get_r_addend()); }
 };
 
 }; // End namespace gold.
index d361f165d9fc92b6cab74ed947ce756492f11447..1920032e1a62aa0973e26748680d0bdc88e0c82c 100644 (file)
@@ -222,10 +222,14 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
       // We are scanning relocations in order to fill out the GOT and
       // PLT sections.  Relocations for sections which are not
       // allocated (typically debugging sections) should not add new
-      // GOT and PLT entries.  So we skip them.
-      typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
-      if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
-       continue;
+      // GOT and PLT entries.  So we skip them unless this is a
+      // relocatable link.
+      if (!parameters->output_is_object())
+       {
+         typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
+         if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+           continue;
+       }
 
       if (shdr.get_sh_link() != this->symtab_shndx_)
        {
@@ -310,11 +314,29 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
        p != rd->relocs.end();
        ++p)
     {
-      target->scan_relocs(options, symtab, layout, this, p->data_shndx,
-                         p->sh_type, p->contents->data(), p->reloc_count,
-                         p->output_section, p->needs_special_offset_handling,
-                         this->local_symbol_count_,
-                         local_symbols);
+      if (!parameters->output_is_object())
+       target->scan_relocs(options, symtab, layout, this, p->data_shndx,
+                           p->sh_type, p->contents->data(), p->reloc_count,
+                           p->output_section,
+                           p->needs_special_offset_handling,
+                           this->local_symbol_count_,
+                           local_symbols);
+      else
+       {
+         Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx);
+         gold_assert(rr != NULL);
+         rr->set_reloc_count(p->reloc_count);
+         target->scan_relocatable_relocs(options, symtab, layout, this,
+                                         p->data_shndx, p->sh_type,
+                                         p->contents->data(),
+                                         p->reloc_count,
+                                         p->output_section,
+                                         p->needs_special_offset_handling,
+                                         this->local_symbol_count_,
+                                         local_symbols,
+                                         rr);
+       }
+
       delete p->contents;
       p->contents = NULL;
     }
@@ -430,6 +452,29 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
       if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
        continue;
 
+      if (parameters->output_is_object()
+         && (shdr.get_sh_type() == elfcpp::SHT_REL
+             || shdr.get_sh_type() == elfcpp::SHT_RELA)
+         && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+       {
+         // This is a reloc section in a relocatable link.  We don't
+         // need to read the input file.  The size and file offset
+         // are stored in the Relocatable_relocs structure.
+         Relocatable_relocs* rr = this->relocatable_relocs(i);
+         gold_assert(rr != NULL);
+         Output_data* posd = rr->output_data();
+         gold_assert(posd != NULL);
+
+         pvs->offset = posd->offset();
+         pvs->view_size = posd->data_size();
+         pvs->view = of->get_output_view(pvs->offset, pvs->view_size);
+         pvs->address = posd->address();
+         pvs->is_input_output_view = false;
+         pvs->is_postprocessing_view = false;
+
+         continue;
+       }
+
       // In the normal case, this input section is simply mapped to
       // the output section at offset OUTPUT_OFFSET.
 
@@ -582,6 +627,8 @@ Sized_relobj<size, big_endian>::relocate_sections(
       off_t output_offset = map_sections[index].offset;
 
       gold_assert((*pviews)[index].view != NULL);
+      if (parameters->output_is_object())
+       gold_assert((*pviews)[i].view != NULL);
 
       if (shdr.get_sh_link() != this->symtab_shndx_)
        {
@@ -622,15 +669,32 @@ Sized_relobj<size, big_endian>::relocate_sections(
 
       relinfo.reloc_shndx = i;
       relinfo.data_shndx = index;
-      target->relocate_section(&relinfo,
-                              sh_type,
-                              prelocs,
-                              reloc_count,
-                              os,
-                              output_offset == -1,
-                              (*pviews)[index].view,
-                              (*pviews)[index].address,
-                              (*pviews)[index].view_size);
+      if (!parameters->output_is_object())
+       target->relocate_section(&relinfo,
+                                sh_type,
+                                prelocs,
+                                reloc_count,
+                                os,
+                                output_offset == -1,
+                                (*pviews)[index].view,
+                                (*pviews)[index].address,
+                                (*pviews)[index].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,
+                                          (*pviews)[i].view,
+                                          (*pviews)[i].view_size);
+       }
     }
 }
 
index 39ffe4ac229eef971dc8c780d4becd899cc11147..438e8613514de8e2835e0a50987148b909d0ee46 100644 (file)
@@ -38,6 +38,7 @@ class Relobj;
 class Read_relocs_data;
 class Symbol;
 class Layout;
+class Output_data;
 class Output_section;
 
 template<int size>
@@ -170,6 +171,100 @@ class Relocate_task : public Task
   Task_token* final_blocker_;
 };
 
+// During a relocatable link, this class records how relocations
+// should be handled for a single input reloc section.  An instance of
+// this class is created while scanning relocs, and it is used while
+// processing relocs.
+
+class Relocatable_relocs
+{
+ public:
+  // We use a vector of unsigned char to indicate how the input relocs
+  // should be handled.  Each element is one of the following values.
+  // We create this vector when we initially scan the relocations.
+  enum Reloc_strategy
+  {
+    // Copy the input reloc.  Don't modify it other than updating the
+    // r_offset field and the r_sym part of the r_info field.
+    RELOC_COPY,
+    // Copy the input reloc which is against an STT_SECTION symbol.
+    // Update the r_offset and r_sym part of the r_info field.  Adjust
+    // the addend by subtracting the value of the old local symbol and
+    // adding the value of the new local symbol.  The addend is in the
+    // SHT_RELA reloc and the contents of the data section do not need
+    // to be changed.
+    RELOC_ADJUST_FOR_SECTION_RELA,
+    // Like RELOC_ADJUST_FOR_SECTION_RELA but the contents of the
+    // section need to be changed.  The number indicates the number of
+    // bytes in the addend in the section contents.
+    RELOC_ADJUST_FOR_SECTION_1,
+    RELOC_ADJUST_FOR_SECTION_2,
+    RELOC_ADJUST_FOR_SECTION_4,
+    RELOC_ADJUST_FOR_SECTION_8,
+    // Discard the input reloc--process it completely when relocating
+    // the data section contents.
+    RELOC_DISCARD,
+    // An input reloc which is not discarded, but which requires
+    // target specific processing in order to update it.
+    RELOC_SPECIAL
+  };
+
+  Relocatable_relocs()
+    : reloc_strategies_(), output_reloc_count_(0), posd_(NULL)
+  { }
+
+  // Record the number of relocs.
+  void
+  set_reloc_count(size_t reloc_count)
+  { this->reloc_strategies_.reserve(reloc_count); }
+
+  // Record what to do for the next reloc.
+  void
+  set_next_reloc_strategy(Reloc_strategy strategy)
+  {
+    this->reloc_strategies_.push_back(static_cast<unsigned char>(strategy));
+    if (strategy != RELOC_DISCARD)
+      ++this->output_reloc_count_;
+  }
+
+  // Record the Output_data associated with this reloc section.
+  void
+  set_output_data(Output_data* posd)
+  {
+    gold_assert(this->posd_ == NULL);
+    this->posd_ = posd;
+  }
+
+  // Return the Output_data associated with this reloc section.
+  Output_data*
+  output_data() const
+  { return this->posd_; }
+
+  // Return what to do for reloc I.
+  Reloc_strategy
+  strategy(unsigned int i) const
+  {
+    gold_assert(i < this->reloc_strategies_.size());
+    return static_cast<Reloc_strategy>(this->reloc_strategies_[i]);
+  }
+
+  // Return the number of relocations to create in the output file.
+  size_t
+  output_reloc_count() const
+  { return this->output_reloc_count_; }
+
+ private:
+  typedef std::vector<unsigned char> Reloc_strategies;
+
+  // The strategies for the input reloc.  There is one entry in this
+  // vector for each relocation in the input section.
+  Reloc_strategies reloc_strategies_;
+  // The number of relocations to be created in the output file.
+  size_t output_reloc_count_;
+  // The output data structure associated with this relocation.
+  Output_data* posd_;
+};
+
 // Standard relocation routines which are used on many targets.  Here
 // SIZE and BIG_ENDIAN refer to the target, not the relocation type.
 
index 771869149caaac6a35973edcfb822cd24555a673..3fd96c3a52c8185acabc18c6028362325b961315 100644 (file)
 
 #include "elfcpp.h"
 #include "symtab.h"
+#include "reloc.h"
 #include "reloc-types.h"
 
 namespace gold
 {
 
-// This function implements the generic part of reloc scanning.  This
-// is an inline function which takes a class whose member functions
-// local() and global() implement the machine specific part of scanning.
-// We do it this way to avoidmaking a function call for each relocation,
-// and to avoid repeating the generic code for each target.
+// This function implements the generic part of reloc scanning.  The
+// template parameter Scan must be a class type which provides two
+// functions: local() and global().  Those functions implement the
+// machine specific part of scanning.  We do it this way to
+// avoidmaking a function call for each relocation, and to avoid
+// repeating the generic code for each target.
 
 template<int size, bool big_endian, typename Target_type, int sh_type,
         typename Scan>
@@ -116,11 +118,9 @@ scan_relocs(
 }
 
 // This function implements the generic part of relocation processing.
-// This is an inline function which take a class whose relocate()
-// implements the machine specific part of relocation.  We do it this
-// way to avoid making a function call for each relocation, and to
-// avoid repeating the generic relocation handling code for each
-// target.
+// The template parameter Relocate must be a class type which provides
+// a single function, relocate(), which implements the machine
+// specific part of a relocation.
 
 // SIZE is the ELF size: 32 or 64.  BIG_ENDIAN is the endianness of
 // the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.
@@ -225,6 +225,316 @@ relocate_section(
     }
 }
 
+// This class may be used as a typical class for the
+// Scan_relocatable_reloc parameter to scan_relocatable_relocs.  The
+// template parameter Classify_reloc must be a class type which
+// provides a function get_size_for_reloc which returns the number of
+// bytes to which a reloc applies.  This class is intended to capture
+// the most typical target behaviour, while still permitting targets
+// to define their own independent class for Scan_relocatable_reloc.
+
+template<int sh_type, typename Classify_reloc>
+class Default_scan_relocatable_relocs
+{
+ public:
+  // Return the strategy to use for a local symbol which is not a
+  // section symbol, given the relocation type.
+  inline Relocatable_relocs::Reloc_strategy
+  local_non_section_strategy(unsigned int, Relobj*)
+  { return Relocatable_relocs::RELOC_COPY; }
+
+  // Return the strategy to use for a local symbol which is a section
+  // symbol, given the relocation type.
+  inline Relocatable_relocs::Reloc_strategy
+  local_section_strategy(unsigned int r_type, Relobj* object)
+  {
+    if (sh_type == elfcpp::SHT_RELA)
+      return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
+    else
+      {
+       Classify_reloc classify;
+       switch (classify.get_size_for_reloc(r_type, object))
+         {
+         case 0:
+           return Relocatable_relocs::RELOC_COPY;
+         case 1:
+           return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1;
+         case 2:
+           return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2;
+         case 4:
+           return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4;
+         case 8:
+           return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8;
+         default:
+           gold_unreachable();
+         }
+      }
+  }
+
+  // Return the strategy to use for a global symbol, given the
+  // relocation type, the object, and the symbol index.
+  inline Relocatable_relocs::Reloc_strategy
+  global_strategy(unsigned int, Relobj*, unsigned int)
+  { return Relocatable_relocs::RELOC_COPY; }
+};
+
+// Scan relocs during a relocatable link.  This is a default
+// definition which should work for most targets.
+// Scan_relocatable_reloc must name a class type which provides three
+// functions which return a Relocatable_relocs::Reloc_strategy code:
+// global_strategy, local_non_section_strategy, and
+// local_section_strategy.  Most targets should be able to use
+// Default_scan_relocatable_relocs as this class.
+
+template<int size, bool big_endian, typename Target_type, int sh_type,
+        typename Scan_relocatable_reloc>
+void
+scan_relocatable_relocs(
+    const General_options&,
+    Symbol_table*,
+    Layout*,
+    Sized_relobj<size, big_endian>* object,
+    unsigned int data_shndx,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_syms,
+    Relocatable_relocs* rr)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  Scan_relocatable_reloc scan;
+
+  for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+    {
+      Reltype reloc(prelocs);
+
+      Relocatable_relocs::Reloc_strategy strategy;
+
+      if (needs_special_offset_handling
+         && !output_section->is_input_address_mapped(object, data_shndx,
+                                                     reloc.get_r_offset()))
+       strategy = Relocatable_relocs::RELOC_DISCARD;
+      else
+       {
+         typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+           reloc.get_r_info();
+         const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+         const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+         if (r_sym >= local_symbol_count)
+           strategy = scan.global_strategy(r_type, object, r_sym);
+         else
+           {
+             gold_assert(plocal_syms != NULL);
+             typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+                                                         + r_sym * sym_size);
+             const unsigned int shndx = lsym.get_st_shndx();
+             if (shndx < elfcpp::SHN_LORESERVE
+                 && shndx != elfcpp::SHN_UNDEF
+                 && !object->is_section_included(lsym.get_st_shndx()))
+               {
+                 // RELOC is a relocation against a local symbol
+                 // defined in a section we are discarding.  Discard
+                 // the reloc.  FIXME: Should we issue a warning?
+                 strategy = Relocatable_relocs::RELOC_DISCARD;
+               }
+             else if (lsym.get_st_type() != elfcpp::STT_SECTION)
+               strategy = scan.local_non_section_strategy(r_type, object);
+             else
+               {
+                 strategy = scan.local_section_strategy(r_type, object);
+                 if (strategy != Relocatable_relocs::RELOC_DISCARD)
+                   {
+                     section_offset_type dummy;
+                     Output_section* os = object->output_section(shndx,
+                                                                 &dummy);
+                     os->set_needs_symtab_index();
+                   }
+               }
+           }
+       }
+
+      rr->set_next_reloc_strategy(strategy);
+    }
+}
+
+// Relocate relocs during a relocatable link.  This is a default
+// definition which should work for most targets.
+
+template<int size, bool big_endian, typename Target_type, int sh_type>
+void
+relocate_for_relocatable(
+    const Relocate_info<size, big_endian>* relinfo,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    off_t offset_in_output_section,
+    const Relocatable_relocs* rr,
+    unsigned char* view,
+    typename elfcpp::Elf_types<size>::Elf_Addr,
+    section_size_type,
+    unsigned char* reloc_view,
+    section_size_type reloc_view_size)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc_write
+    Reltype_write;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+  Sized_relobj<size, big_endian>* const object = relinfo->object;
+  const unsigned int local_count = object->local_symbol_count();
+
+  unsigned char* pwrite = reloc_view;
+
+  for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+    {
+      Relocatable_relocs::Reloc_strategy strategy = rr->strategy(i);
+      if (strategy == Relocatable_relocs::RELOC_DISCARD)
+       continue;
+
+      Reltype reloc(prelocs);
+      Reltype_write reloc_write(pwrite);
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+      const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+      // Get the new symbol index.
+
+      unsigned int new_symndx;
+      if (r_sym < local_count)
+       {
+         switch (strategy)
+           {
+           case Relocatable_relocs::RELOC_COPY:
+             new_symndx = object->symtab_index(r_sym);
+             gold_assert(new_symndx != -1U);
+             break;
+
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2:
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4:
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8:
+             {
+               // We are adjusting a section symbol.  We need to find
+               // the symbol table index of the section symbol for
+               // the output section corresponding to input section
+               // in which this symbol is defined.
+               gold_assert(r_sym < local_count);
+               unsigned int shndx = object->local_symbol_input_shndx(r_sym);
+               section_offset_type dummy;
+               Output_section* os = object->output_section(shndx, &dummy);
+               gold_assert(os != NULL);
+               gold_assert(os->needs_symtab_index());
+               new_symndx = os->symtab_index();
+             }
+             break;
+
+           default:
+             gold_unreachable();
+           }
+       }
+      else
+       {
+         const Symbol* gsym = object->global_symbol(r_sym);
+         gold_assert(gsym != NULL);
+         if (gsym->is_forwarder())
+           gsym = relinfo->symtab->resolve_forwards(gsym);
+
+         gold_assert(gsym->has_symtab_index());
+         new_symndx = gsym->symtab_index();
+       }
+
+      // Get the new offset--the location in the output section where
+      // this relocation should be applied.
+
+      off_t offset = reloc.get_r_offset();
+      off_t new_offset;
+      if (offset_in_output_section != -1)
+       new_offset = offset + offset_in_output_section;
+      else
+       {
+         new_offset = output_section->output_offset(object,
+                                                    relinfo->data_shndx,
+                                                    offset);
+         gold_assert(new_offset != -1);
+       }
+
+      reloc_write.put_r_offset(new_offset);
+      reloc_write.put_r_info(elfcpp::elf_r_info<size>(new_symndx, r_type));
+
+      // Handle the reloc addend based on the strategy.
+
+      if (strategy == Relocatable_relocs::RELOC_COPY)
+       {
+         if (sh_type == elfcpp::SHT_RELA)
+           Reloc_types<sh_type, size, big_endian>::
+             copy_reloc_addend(&reloc_write,
+                               &reloc);
+       }
+      else
+       {
+         // The relocation uses a section symbol in the input file.
+         // We are adjusting it to use a section symbol in the output
+         // file.  The input section symbol refers to some address in
+         // the input section.  We need the relocation in the output
+         // file to refer to that same address.  This adjustment to
+         // the addend is the same calculation we use for a simple
+         // absolute relocation for the input section symbol.
+
+         const Symbol_value<size>* psymval = object->local_symbol(r_sym);
+
+         unsigned char* padd = view + offset;
+         switch (strategy)
+           {
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
+             {
+               typename elfcpp::Elf_types<size>::Elf_Swxword addend;
+               addend = Reloc_types<sh_type, size, big_endian>::
+                          get_reloc_addend(&reloc);
+               addend = psymval->value(object, addend);
+               Reloc_types<sh_type, size, big_endian>::
+                 set_reloc_addend(&reloc_write, addend);
+             }
+             break;
+
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
+             Relocate_functions<size, big_endian>::rel8(padd, object,
+                                                        psymval);
+             break;
+
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2:
+             Relocate_functions<size, big_endian>::rel16(padd, object,
+                                                         psymval);
+             break;
+
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4:
+             Relocate_functions<size, big_endian>::rel32(padd, object,
+                                                         psymval);
+             break;
+
+           case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8:
+             Relocate_functions<size, big_endian>::rel64(padd, object,
+                                                         psymval);
+             break;
+
+           default:
+             gold_unreachable();
+           }
+       }
+
+      pwrite += reloc_size;
+    }
+
+  gold_assert(static_cast<section_size_type>(pwrite - reloc_view)
+             == reloc_view_size);
+}
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_TARGET_RELOC_H)
index 218d9f757bbdb9d18737afa353c0e17d061c2ae6..c05c821ad2a81d9e59091e2426a72df0d00924a3 100644 (file)
@@ -42,6 +42,7 @@ class General_options;
 class Object;
 template<int size, bool big_endian>
 class Sized_relobj;
+class Relocatable_relocs;
 template<int size, bool big_endian>
 class Relocate_info;
 class Symbol;
@@ -281,6 +282,42 @@ class Sized_target : public Target
                   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
                   section_size_type view_size) = 0;
 
+  // Scan the relocs during a relocatable link.  The parameters are
+  // like scan_relocs, with an additional Relocatable_relocs
+  // parameter, used to record the disposition of the relocs.
+  virtual void
+  scan_relocatable_relocs(const General_options& options,
+                         Symbol_table* symtab,
+                         Layout* layout,
+                         Sized_relobj<size, big_endian>* object,
+                         unsigned int data_shndx,
+                         unsigned int sh_type,
+                         const unsigned char* prelocs,
+                         size_t reloc_count,
+                         Output_section* output_section,
+                         bool needs_special_offset_handling,
+                         size_t local_symbol_count,
+                         const unsigned char* plocal_symbols,
+                         Relocatable_relocs*) = 0;
+
+  // Relocate a section during a relocatable link.  The parameters are
+  // like relocate_section, with additional parameters for the view of
+  // the output reloc section.
+  virtual void
+  relocate_for_relocatable(const Relocate_info<size, big_endian>*,
+                          unsigned int sh_type,
+                          const unsigned char* prelocs,
+                          size_t reloc_count,
+                          Output_section* output_section,
+                          off_t offset_in_output_section,
+                          const Relocatable_relocs*,
+                          unsigned char* view,
+                          typename elfcpp::Elf_types<size>::Elf_Addr
+                            view_address,
+                          section_size_type view_size,
+                          unsigned char* reloc_view,
+                          section_size_type reloc_view_size) = 0;
+
  protected:
   Sized_target(const Target::Target_info* pti)
     : Target(pti)
index b72e300b1dd3853a52fe3f8a6f833f73c00fc25e..b0b149d4fd9939014e34e6759dc1f94d0413b9ff 100644 (file)
@@ -197,6 +197,15 @@ two_file_separate_shared_21_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
 two_file_separate_shared_21_test_LDADD = \
        two_file_shared_2.so two_file_shared_1.so
 
+check_PROGRAMS += two_file_relocatable_test
+two_file_relocatable_test_SOURCES = two_file_test_main.cc
+two_file_relocatable_test_DEPENDENCIES = \
+       gcctestdir/ld two_file_relocatable.o
+two_file_relocatable_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+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
+
 # 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.
 if FN_PTRS_IN_SO_WITHOUT_PIC
index 182c89ed624e8dd43d5e881b6eb76858dbd348af..fe30a06d3117fc85bb58528553bb8f26d01bdb94 100644 (file)
@@ -60,7 +60,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_pic_1_test \
 @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_separate_shared_21_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test
 @GCC_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
 @GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
 @GCC_FALSE@    $(am__DEPENDENCIES_1)
@@ -233,7 +234,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_pic_1_test$(EXEEXT) \
 @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_separate_shared_21_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_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) \
@@ -444,6 +446,11 @@ am__two_file_pic_test_SOURCES_DIST = two_file_test_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_pic_test_OBJECTS =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
 two_file_pic_test_OBJECTS = $(am_two_file_pic_test_OBJECTS)
+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)
+two_file_relocatable_test_OBJECTS =  \
+       $(am_two_file_relocatable_test_OBJECTS)
 am__two_file_same_shared_nonpic_test_SOURCES_DIST =  \
        two_file_test_main.cc
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_same_shared_nonpic_test_OBJECTS = two_file_test_main.$(OBJEXT)
@@ -574,6 +581,7 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(tls_test_SOURCES) $(two_file_mixed_2_shared_test_SOURCES) \
        $(two_file_mixed_shared_test_SOURCES) \
        $(two_file_pic_test_SOURCES) \
+       $(two_file_relocatable_test_SOURCES) \
        $(two_file_same_shared_nonpic_test_SOURCES) \
        $(two_file_same_shared_test_SOURCES) \
        $(two_file_separate_shared_12_nonpic_test_SOURCES) \
@@ -613,6 +621,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(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_relocatable_test_SOURCES_DIST) \
        $(am__two_file_same_shared_nonpic_test_SOURCES_DIST) \
        $(am__two_file_same_shared_test_SOURCES_DIST) \
        $(am__two_file_separate_shared_12_nonpic_test_SOURCES_DIST) \
@@ -866,6 +875,12 @@ object_unittest_SOURCES = object_unittest.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_test_LDADD = \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2.so two_file_shared_1.so
 
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_SOURCES = two_file_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_DEPENDENCIES = \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_relocatable.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_LDADD = two_file_relocatable.o
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic_test_SOURCES = \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.cc two_file_test_main.cc
 
@@ -1152,6 +1167,9 @@ 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)
        $(CXXLINK) $(two_file_pic_test_LDFLAGS) $(two_file_pic_test_OBJECTS) $(two_file_pic_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)
+       $(CXXLINK) $(two_file_relocatable_test_LDFLAGS) $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_LDADD) $(LIBS)
 two_file_same_shared_nonpic_test$(EXEEXT): $(two_file_same_shared_nonpic_test_OBJECTS) $(two_file_same_shared_nonpic_test_DEPENDENCIES) 
        @rm -f two_file_same_shared_nonpic_test$(EXEEXT)
        $(CXXLINK) $(two_file_same_shared_nonpic_test_LDFLAGS) $(two_file_same_shared_nonpic_test_OBJECTS) $(two_file_same_shared_nonpic_test_LDADD) $(LIBS)
@@ -1557,6 +1575,8 @@ uninstall-am: uninstall-info-am
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.so: two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o gcctestdir/ld
 @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
 @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
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b.o
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld
index 75029ad4309916c6a142d083321854d5665e412c..3c989375025050418f4a17115333dce7afc44f3d 100644 (file)
@@ -57,6 +57,24 @@ class Target_test : public Sized_target<size, big_endian>
                   section_size_type)
   { ERROR("call to Target_test::relocate_section"); }
 
+  void
+  scan_relocatable_relocs(const General_options&, Symbol_table*, Layout*,
+                         Sized_relobj<size, big_endian>*, unsigned int,
+                         unsigned int, const unsigned char*,
+                         size_t, Output_section*, bool, size_t,
+                         const unsigned char*, Relocatable_relocs*)
+  { ERROR("call to Target_test::scan_relocatable_relocs"); }
+
+  void
+  relocate_for_relocatable(const Relocate_info<size, big_endian>*,
+                          unsigned int, const unsigned char*, size_t,
+                          Output_section*, off_t, const Relocatable_relocs*,
+                          unsigned char*,
+                          typename elfcpp::Elf_types<size>::Elf_Addr,
+                          section_size_type, unsigned char*,
+                          section_size_type)
+  { ERROR("call to Target_test::relocate_for_relocatable"); }
+
   static const Target::Target_info test_target_info;
 };
 
index 14d29570c82764aee857a5b721ab59e6cef1d518..51a8d84a5b1ecd09c1d05ce966d80f339cbd6013 100644 (file)
@@ -109,6 +109,37 @@ class Target_x86_64 : public Sized_target<64, false>
                   elfcpp::Elf_types<64>::Elf_Addr view_address,
                   section_size_type view_size);
 
+  // Scan the relocs during a relocatable link.
+  void
+  scan_relocatable_relocs(const General_options& options,
+                         Symbol_table* symtab,
+                         Layout* layout,
+                         Sized_relobj<64, false>* object,
+                         unsigned int data_shndx,
+                         unsigned int sh_type,
+                         const unsigned char* prelocs,
+                         size_t reloc_count,
+                         Output_section* output_section,
+                         bool needs_special_offset_handling,
+                         size_t local_symbol_count,
+                         const unsigned char* plocal_symbols,
+                         Relocatable_relocs*);
+
+  // Relocate a section during a relocatable link.
+  void
+  relocate_for_relocatable(const Relocate_info<64, false>*,
+                          unsigned int sh_type,
+                          const unsigned char* prelocs,
+                          size_t reloc_count,
+                          Output_section* output_section,
+                          off_t offset_in_output_section,
+                          const Relocatable_relocs*,
+                          unsigned char* view,
+                          elfcpp::Elf_types<64>::Elf_Addr view_address,
+                          section_size_type view_size,
+                          unsigned char* reloc_view,
+                          section_size_type reloc_view_size);
+
   // Return a string used to fill a code section with nops.
   std::string
   do_code_fill(section_size_type length);
@@ -234,6 +265,15 @@ class Target_x86_64 : public Sized_target<64, false>
     bool skip_call_tls_get_addr_;
   };
 
+  // A class which returns the size required for a relocation type,
+  // used while scanning relocs during a relocatable link.
+  class Relocatable_size_for_reloc
+  {
+   public:
+    unsigned int
+    get_size_for_reloc(unsigned int, Relobj*);
+  };
+
   // Adjust TLS relocation type based on the options and whether this
   // is a local symbol.
   static tls::Tls_optimization
@@ -1941,6 +1981,146 @@ Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
     view_size);
 }
 
+// Return the size of a relocation while scanning during a relocatable
+// link.
+
+unsigned int
+Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc(
+    unsigned int r_type,
+    Relobj* object)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_X86_64_NONE:
+    case elfcpp::R_386_GNU_VTINHERIT:
+    case elfcpp::R_386_GNU_VTENTRY:
+    case elfcpp::R_X86_64_TLSGD:            // Global-dynamic
+    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
+    case elfcpp::R_X86_64_TLSDESC_CALL:
+    case elfcpp::R_X86_64_TLSLD:            // Local-dynamic
+    case elfcpp::R_X86_64_DTPOFF32:
+    case elfcpp::R_X86_64_DTPOFF64:
+    case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
+    case elfcpp::R_X86_64_TPOFF32:          // Local-exec
+      return 0;
+
+    case elfcpp::R_X86_64_64:
+    case elfcpp::R_X86_64_PC64:
+    case elfcpp::R_X86_64_GOTOFF64:
+    case elfcpp::R_X86_64_GOTPC64:
+    case elfcpp::R_X86_64_PLTOFF64:
+    case elfcpp::R_X86_64_GOT64:
+    case elfcpp::R_X86_64_GOTPCREL64:
+    case elfcpp::R_X86_64_GOTPCREL:
+    case elfcpp::R_X86_64_GOTPLT64:
+      return 8;
+
+    case elfcpp::R_X86_64_32:
+    case elfcpp::R_X86_64_32S:
+    case elfcpp::R_X86_64_PC32:
+    case elfcpp::R_X86_64_PLT32:
+    case elfcpp::R_X86_64_GOTPC32:
+    case elfcpp::R_X86_64_GOT32:
+      return 4;
+
+    case elfcpp::R_X86_64_16:
+    case elfcpp::R_X86_64_PC16:
+      return 2;
+
+    case elfcpp::R_X86_64_8:
+    case elfcpp::R_X86_64_PC8:
+      return 1;
+
+    case elfcpp::R_X86_64_COPY:
+    case elfcpp::R_X86_64_GLOB_DAT:
+    case elfcpp::R_X86_64_JUMP_SLOT:
+    case elfcpp::R_X86_64_RELATIVE:
+      // These are outstanding tls relocs, which are unexpected when linking
+    case elfcpp::R_X86_64_TPOFF64:
+    case elfcpp::R_X86_64_DTPMOD64:
+    case elfcpp::R_X86_64_TLSDESC:
+      object->error(_("unexpected reloc %u in object file"), r_type);
+      return 0;
+
+    case elfcpp::R_X86_64_SIZE32:
+    case elfcpp::R_X86_64_SIZE64:
+    default:
+      object->error(_("unsupported reloc %u against local symbol"), r_type);
+      return 0;
+    }
+}
+
+// Scan the relocs during a relocatable link.
+
+void
+Target_x86_64::scan_relocatable_relocs(const General_options& options,
+                                      Symbol_table* symtab,
+                                      Layout* layout,
+                                      Sized_relobj<64, false>* object,
+                                      unsigned int data_shndx,
+                                      unsigned int sh_type,
+                                      const unsigned char* prelocs,
+                                      size_t reloc_count,
+                                      Output_section* output_section,
+                                      bool needs_special_offset_handling,
+                                      size_t local_symbol_count,
+                                      const unsigned char* plocal_symbols,
+                                      Relocatable_relocs* rr)
+{
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+  gold::scan_relocatable_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA,
+      Scan_relocatable_relocs>(
+    options,
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols,
+    rr);
+}
+
+// Relocate a section during a relocatable link.
+
+void
+Target_x86_64::relocate_for_relocatable(
+    const Relocate_info<64, false>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    off_t offset_in_output_section,
+    const Relocatable_relocs* rr,
+    unsigned char* view,
+    elfcpp::Elf_types<64>::Elf_Addr view_address,
+    section_size_type view_size,
+    unsigned char* reloc_view,
+    section_size_type reloc_view_size)
+{
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_for_relocatable<64, false, Target_x86_64, elfcpp::SHT_RELA>(
+    relinfo,
+    prelocs,
+    reloc_count,
+    output_section,
+    offset_in_output_section,
+    rr,
+    view,
+    view_address,
+    view_size,
+    reloc_view,
+    reloc_view_size);
+}
+
 // Return the value to use for a dynamic which requires special
 // treatment.  This is how we support equality comparisons of function
 // pointers across shared library boundaries, as described in the
This page took 0.053542 seconds and 4 git commands to generate.