From Cary Coutant: preliminary shared library support.
authorIan Lance Taylor <iant@google.com>
Tue, 16 Oct 2007 23:23:08 +0000 (23:23 +0000)
committerIan Lance Taylor <iant@google.com>
Tue, 16 Oct 2007 23:23:08 +0000 (23:23 +0000)
gold/gold.cc
gold/i386.cc
gold/layout.cc
gold/output.cc
gold/parameters.cc
gold/parameters.h
gold/symtab.cc
gold/symtab.h
gold/target-reloc.h

index 139652430b020fa2bf6fd0ba5cecdea9e42ea154..8c86b9ed72ef22ca265c3944d0ea9f7b46537e3b 100644 (file)
@@ -153,7 +153,8 @@ queue_middle_tasks(const General_options& options,
                   Workqueue* workqueue)
 {
   // Now we have seen all the input files.
-  const bool doing_static_link = !input_objects->any_dynamic();
+  const bool doing_static_link = (!input_objects->any_dynamic()
+                                 && !parameters->output_is_shared());
   set_parameters_doing_static_link(doing_static_link);
   if (!doing_static_link && options.is_static())
     {
index 3dda0c2e30e9517eba1546272d6d64865ab5d886..e091f1889b15543e349d8c39678297c285f88c44 100644 (file)
@@ -752,9 +752,18 @@ Target_i386::Scan::local(const General_options&,
     case elfcpp::R_386_32:
     case elfcpp::R_386_16:
     case elfcpp::R_386_8:
-      // FIXME: If we are generating a shared object we need to copy
-      // this relocation into the object.
-      gold_assert(!parameters->output_is_shared());
+      // If building a shared library (or a position-independent
+      // executable), we need to create a dynamic relocation for
+      // this location. The relocation applied at link time will
+      // apply the link-time value, so we flag the location with
+      // an R_386_RELATIVE relocation so the dynamic loader can
+      // relocate it easily.
+      if (parameters->output_is_position_independent())
+        {
+          Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+          rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx,
+                             reloc.get_r_offset());
+        }
       break;
 
     case elfcpp::R_386_PC32:
@@ -777,7 +786,7 @@ Target_i386::Scan::local(const General_options&,
           {
             // If we are generating a shared object, we need to add a
             // dynamic RELATIVE relocation for this symbol.
-            if (parameters->output_is_shared())
+            if (parameters->output_is_position_independent())
               {
                 Reloc_section* rel_dyn = target->rel_dyn_section(layout);
                 rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE,
@@ -915,17 +924,17 @@ Target_i386::Scan::global(const General_options& options,
     case elfcpp::R_386_PC16:
     case elfcpp::R_386_8:
     case elfcpp::R_386_PC8:
-      // FIXME: If we are generating a shared object we may need to
-      // copy this relocation into the object.  If this symbol is
-      // defined in a shared object, we may need to copy this
-      // relocation in order to avoid a COPY relocation.
-      gold_assert(!parameters->output_is_shared());
-
-      if (gsym->is_from_dynobj())
+      if (gsym->is_from_dynobj()
+          || (parameters->output_is_shared()
+              && gsym->is_preemptible()))
        {
-         // This symbol is defined in a dynamic object.  If it is a
+         // (a) This symbol is defined in a dynamic object.  If it is a
          // function, we make a PLT entry.  Otherwise we need to
          // either generate a COPY reloc or copy this reloc.
+         // (b) We are building a shared object and this symbol is
+         // preemptible. If it is a function, we make a PLT entry.
+         // Otherwise, we copy the reloc. We do not make COPY relocs
+         // in shared objects.
          if (gsym->type() == elfcpp::STT_FUNC)
            {
              target->make_plt_entry(symtab, layout, gsym);
@@ -936,9 +945,16 @@ Target_i386::Scan::global(const General_options& options,
              // to the address of the PLT entry.
              if (r_type != elfcpp::R_386_PC32
                  && r_type != elfcpp::R_386_PC16
-                 && r_type != elfcpp::R_386_PC8)
+                 && r_type != elfcpp::R_386_PC8
+                 && gsym->is_from_dynobj())
                gsym->set_needs_dynsym_value();
            }
+         else if (parameters->output_is_shared())
+           {
+              Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+              rel_dyn->add_global(gsym, r_type, object, data_shndx, 
+                                  reloc.get_r_offset());
+           }
          else
            target->copy_reloc(&options, symtab, layout, object, data_shndx,
                               gsym, reloc);
@@ -969,6 +985,13 @@ Target_i386::Scan::global(const General_options& options,
       // Otherwise we need a PLT entry.
       if (gsym->final_value_is_known())
        break;
+      // If building a shared library, we can also skip the PLT entry
+      // if the symbol is defined in the output file and is protected
+      // or hidden.
+      if (gsym->is_defined()
+          && !gsym->is_from_dynobj()
+          && !gsym->is_preemptible())
+       break;
       target->make_plt_entry(symtab, layout, gsym);
       break;
 
@@ -1185,7 +1208,11 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
 
   // Pick the value to use for symbols defined in shared objects.
   Symbol_value<32> symval;
-  if (gsym != NULL && gsym->is_from_dynobj() && gsym->has_plt_offset())
+  if (gsym != NULL
+      && (gsym->is_from_dynobj()
+          || (parameters->output_is_shared()
+              && gsym->is_preemptible()))
+      && gsym->has_plt_offset())
     {
       symval.set_output_value(target->plt_section()->address()
                              + gsym->plt_offset());
@@ -1250,7 +1277,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
 
     case elfcpp::R_386_PLT32:
       gold_assert(gsym->has_plt_offset()
-                 || gsym->final_value_is_known());
+                 || gsym->final_value_is_known());
       Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
       break;
 
@@ -1352,7 +1379,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
   elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0);
 
   const bool is_final = (gsym == NULL
-                        ? !parameters->output_is_shared()
+                        ? !parameters->output_is_position_independent()
                         : gsym->final_value_is_known());
   const tls::Tls_optimization optimized_type
       = Target_i386::optimize_tls_reloc(is_final, r_type);
index 4f5abac98f28aea1bd972e2c8c8616ff5bdc934d..8fafdcbaabf11305cf1be7f24b8e73ad4e8fdfbb 100644 (file)
@@ -411,7 +411,7 @@ void
 Layout::create_initial_dynamic_sections(const Input_objects* input_objects,
                                        Symbol_table* symtab)
 {
-  if (!input_objects->any_dynamic())
+  if (parameters->doing_static_link())
     return;
 
   const char* dynamic_name = this->namepool_.add(".dynamic", false, NULL);
@@ -545,7 +545,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   this->create_note_section();
 
   Output_segment* phdr_seg = NULL;
-  if (input_objects->any_dynamic())
+  if (!parameters->doing_static_link())
     {
       // There was a dynamic object in the link.  We need to create
       // some information for the dynamic linker.
index 6406c780e0a2ea5cc29446716dac3a1aad792801..9aaa7e97410f994b46044fb65804e12fe83640bf 100644 (file)
@@ -401,9 +401,10 @@ Output_file_header::do_sized_write(Output_file* of)
   oehdr.put_e_ident(e_ident);
 
   elfcpp::ET e_type;
-  // FIXME: ET_DYN.
   if (parameters->output_is_object())
     e_type = elfcpp::ET_REL;
+  else if (parameters->output_is_shared())
+    e_type = elfcpp::ET_DYN;
   else
     e_type = elfcpp::ET_EXEC;
   oehdr.put_e_type(e_type);
@@ -531,6 +532,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
        index = this->u1_.os->symtab_index();
       break;
 
+    case 0:
+      // Relocations without symbols use a symbol index of 0.
+      index = 0;
+      break;
+
     default:
       if (dynamic)
        {
index 817268b1624d0e69caeee172a3936cd1b7a88d64..7fe9ceb1c764ab181de4e8329c554427d89803cb 100644 (file)
@@ -35,7 +35,8 @@ Parameters::Parameters(const General_options* options, Errors* errors)
     sysroot_(options->sysroot()),
     is_doing_static_link_valid_(false), doing_static_link_(false),
     is_size_and_endian_valid_(false), size_(0), is_big_endian_(false),
-    optimization_level_(options->optimization_level())
+    optimization_level_(options->optimization_level()),
+    export_dynamic_(options->export_dynamic())
 {
   if (options->is_shared())
     this->output_file_type_ = OUTPUT_SHARED;
index c4e3fe311e98d5641d355684863fc4508f3bfeed..4a19cb672174f1626afc3ee4decc7756c62df2dd 100644 (file)
@@ -67,6 +67,14 @@ class Parameters
   output_is_object() const
   { return this->output_file_type_ == OUTPUT_OBJECT; }
 
+  // Whether we are generating position-independent output.
+  // This is the case when generating either a shared library
+  // or a regular executable with the --pic-executable option.
+  // FIXME: support --pic-executable
+  bool
+  output_is_position_independent() const
+  { return output_is_shared(); }
+
   // The target system root directory.  This is NULL if there isn't
   // one.
   const std::string&
@@ -115,6 +123,11 @@ class Parameters
   optimization_level() const
   { return this->optimization_level_; }
 
+  // Whether the -E/--export-dynamic flag is set.
+  bool
+  export_dynamic() const
+  { return this->export_dynamic_; }
+
   // Set whether we are doing a static link.
   void
   set_doing_static_link(bool doing_static_link);
@@ -170,6 +183,8 @@ class Parameters
   bool is_big_endian_;
   // The optimization level.
   int optimization_level_;
+  // Whether the -E/--export-dynamic flag is set.
+  bool export_dynamic_;
 };
 
 // This is a global variable.
index 7e0af342a88c6388d671aec88b53f29f16e3b30c..3eee9be85456b299823f57b9c9db9de07afdbc75 100644 (file)
@@ -188,6 +188,27 @@ Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
   this->symsize_ = symsize;
 }
 
+// Return true if this symbol should be added to the dynamic symbol
+// table.
+
+inline bool
+Symbol::should_add_dynsym_entry() const
+{
+  // If the symbol is used by a dynamic relocation, we need to add it.
+  if (this->needs_dynsym_entry())
+    return true;
+
+  // If exporting all symbols or building a shared library,
+  // and the symbol is defined in a regular object and is
+  // externally visible, we need to add it.
+  if ((parameters->export_dynamic() || parameters->output_is_shared())
+      && !this->is_from_dynobj()
+      && this->is_externally_visible())
+    return true;
+
+  return false;
+}
+
 // Return true if the final value of this symbol is known at link
 // time.
 
@@ -1225,10 +1246,7 @@ Symbol_table::set_dynsym_indexes(const General_options* options,
       // some symbols appear more than once in the symbol table, with
       // and without a version.
 
-      if (!sym->needs_dynsym_entry()
-          && (!options->export_dynamic()
-              || !sym->in_reg()
-              || !sym->is_externally_visible()))
+      if (!sym->should_add_dynsym_entry())
        sym->set_dynsym_index(-1U);
       else if (!sym->has_dynsym_index())
        {
index b46510d4c9dd563e04438634d121e903d9725161..d8e68a0276975c2767cf29532f66e4ab2aa4c3d2 100644 (file)
@@ -220,6 +220,11 @@ class Symbol
   set_needs_dynsym_entry()
   { this->needs_dynsym_entry_ = true; }
 
+  // Return whether this symbol should be added to the dynamic symbol
+  // table.
+  bool
+  should_add_dynsym_entry() const;
+
   // Return whether this symbol has been seen in a regular object.
   bool
   in_reg() const
@@ -395,6 +400,16 @@ class Symbol
             || this->visibility_ == elfcpp::STV_PROTECTED);
   }
 
+  // Return true if this symbol can be preempted by a definition in
+  // another link unit.
+  bool
+  is_preemptible() const
+  {
+    return (this->visibility_ != elfcpp::STV_INTERNAL
+            && this->visibility_ != elfcpp::STV_HIDDEN
+            && this->visibility_ != elfcpp::STV_PROTECTED);
+  }
+
   // Return whether there should be a warning for references to this
   // symbol.
   bool
index 8b87963f57b5370e3cd52d61a4363fb09903643e..c38d5f6a74ba3dcb243a15914f01f9893a771e48 100644 (file)
@@ -32,10 +32,10 @@ namespace gold
 {
 
 // This function implements the generic part of reloc scanning.  This
-// is an inline function which takes a class whose operator()
-// implements 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.
+// 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.
 
 template<int size, bool big_endian, typename Target_type, int sh_type,
         typename Scan>
@@ -195,7 +195,8 @@ relocate_section(
 
       if (sym != NULL
          && sym->is_undefined()
-         && sym->binding() != elfcpp::STB_WEAK)
+         && sym->binding() != elfcpp::STB_WEAK
+         && !parameters->output_is_shared())
        gold_undefined_symbol(sym, relinfo, i, offset);
 
       if (sym != NULL && sym->has_warning())