Add heuristics for undefined symbol warnings.
authorIan Lance Taylor <iant@google.com>
Wed, 14 Nov 2007 16:53:25 +0000 (16:53 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 14 Nov 2007 16:53:25 +0000 (16:53 +0000)
13 files changed:
gold/gold.cc
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/options.cc
gold/symtab.cc
gold/symtab.h
gold/target.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/x86_64.cc

index d0c2095c3f0c521e3aad85d5d8ab3af9a3f466cc..2f17add31221c96b3d121182a3359331004b317c 100644 (file)
@@ -286,7 +286,7 @@ queue_final_tasks(const General_options& options,
   // Queue a task to write out the symbol table.
   final_blocker->add_blocker();
   workqueue->queue(new Write_symbols_task(symtab,
-                                         input_objects->target(),
+                                         input_objects,
                                          layout->sympool(),
                                          layout->dynpool(),
                                          of,
index eae6b7fa3397bf9efc1e1b369f81d0e712ccf401..7bd5a3a30bd36bb99114a1317165792b8fd0bc82 100644 (file)
@@ -100,6 +100,11 @@ class Target_i386 : public Sized_target<32, false>
   std::string
   do_code_fill(off_t length);
 
+  // Return whether SYM is defined by the ABI.
+  bool
+  do_is_defined_by_abi(Symbol* sym) const
+  { return strcmp(sym->name(), "___tls_get_addr") == 0; }
+
   // Return the size of the GOT section.
   off_t
   got_size()
index 6894264272caddb15a2124fbcac630c807633649..fea056d1a31650dcc17e61efe61b10713b9358fc 100644 (file)
@@ -1928,8 +1928,8 @@ Write_symbols_task::locks(Workqueue* workqueue)
 void
 Write_symbols_task::run(Workqueue*)
 {
-  this->symtab_->write_globals(this->target_, this->sympool_, this->dynpool_,
-                              this->of_);
+  this->symtab_->write_globals(this->input_objects_, this->sympool_,
+                              this->dynpool_, this->of_);
 }
 
 // Write_after_input_sections_task methods.
index fa804ad45f19c0cbb448d04a446412651292625b..5b9f28defe6bea23055a7ae44f0196f38abb8960 100644 (file)
@@ -506,11 +506,12 @@ class Write_data_task : public Task
 class Write_symbols_task : public Task
 {
  public:
-  Write_symbols_task(const Symbol_table* symtab, const Target* target,
+  Write_symbols_task(const Symbol_table* symtab,
+                    const Input_objects* input_objects,
                     const Stringpool* sympool, const Stringpool* dynpool,
                     Output_file* of, Task_token* final_blocker)
-    : symtab_(symtab), target_(target), sympool_(sympool), dynpool_(dynpool),
-      of_(of), final_blocker_(final_blocker)
+    : symtab_(symtab), input_objects_(input_objects), sympool_(sympool),
+      dynpool_(dynpool), of_(of), final_blocker_(final_blocker)
   { }
 
   // The standard Task methods.
@@ -526,7 +527,7 @@ class Write_symbols_task : public Task
 
  private:
   const Symbol_table* symtab_;
-  const Target* target_;
+  const Input_objects* input_objects_;
   const Stringpool* sympool_;
   const Stringpool* dynpool_;
   Output_file* of_;
index fa16d138549b3e62fab6d874a19336a4f552019c..7a4b1fb41e090c813da70ae22f8d31650af6393a 100644 (file)
@@ -25,6 +25,7 @@
 #include <cerrno>
 #include <cstring>
 #include <cstdarg>
+#include "libiberty.h"
 
 #include "target-select.h"
 #include "dwarf_reader.h"
@@ -1062,9 +1063,10 @@ Input_objects::add_object(Object* obj)
     {
       // See if this is a duplicate SONAME.
       Dynobj* dynobj = static_cast<Dynobj*>(obj);
+      const char* soname = dynobj->soname();
 
       std::pair<Unordered_set<std::string>::iterator, bool> ins =
-       this->sonames_.insert(dynobj->soname());
+       this->sonames_.insert(soname);
       if (!ins.second)
        {
          // We have already seen a dynamic object with this soname.
@@ -1072,6 +1074,19 @@ Input_objects::add_object(Object* obj)
        }
 
       this->dynobj_list_.push_back(dynobj);
+
+      // If this is -lc, remember the directory in which we found it.
+      // We use this when issuing warnings about undefined symbols: as
+      // a heuristic, we don't warn about system libraries found in
+      // the same directory as -lc.
+      if (strncmp(soname, "libc.so", 7) == 0)
+       {
+         const char* object_name = dynobj->name().c_str();
+         const char* base = lbasename(object_name);
+         if (base != object_name)
+           this->system_library_directory_.assign(object_name,
+                                                  base - 1 - object_name);
+       }
     }
 
   set_parameters_size_and_endianness(target->get_size(),
@@ -1080,6 +1095,17 @@ Input_objects::add_object(Object* obj)
   return true;
 }
 
+// Return whether an object was found in the system library directory.
+
+bool
+Input_objects::found_in_system_library_directory(const Object* object) const
+{
+  return (!this->system_library_directory_.empty()
+         && object->name().compare(0,
+                                   this->system_library_directory_.size(),
+                                   this->system_library_directory_) == 0);
+}
+
 // For each dynamic object, record whether we've seen all of its
 // explicit dependencies.
 
index 332739295f2e85c96c6ea6e391613a835495878d..61b40358dde92734f921cce298b14d7a62112c00 100644 (file)
@@ -930,7 +930,8 @@ class Input_objects
 {
  public:
   Input_objects()
-    : relobj_list_(), dynobj_list_(), target_(NULL), sonames_()
+    : relobj_list_(), dynobj_list_(), target_(NULL), sonames_(),
+      system_library_directory_()
   { }
 
   // The type of the list of input relocateable objects.
@@ -956,6 +957,11 @@ class Input_objects
   void
   check_dynamic_dependencies() const;
 
+  // Return whether an object was found in the system library
+  // directory.
+  bool
+  found_in_system_library_directory(const Object*) const;
+
   // Iterate over all regular objects.
 
   Relobj_iterator
@@ -998,6 +1004,8 @@ class Input_objects
   Target* target_;
   // SONAMEs that we have seen.
   Unordered_set<std::string> sonames_;
+  // The directory in which we find the libc.so.
+  std::string system_library_directory_;
 };
 
 // Some of the information we pass to the relocation routines.  We
index eff126381b8a3a5b496b2407f2de33bcbdaa62c6..69f452dd380bd9ca1e6021d6b875ef3a54254a80 100644 (file)
@@ -483,7 +483,7 @@ General_options::General_options()
     output_file_name_("a.out"),
     is_relocatable_(false),
     strip_(STRIP_NONE),
-    allow_shlib_undefined_(true),
+    allow_shlib_undefined_(false),
     symbolic_(false),
     detect_odr_violations_(false),
     create_eh_frame_hdr_(false),
index f5e21322b78eb1f5f1863c3941f85b3430b0a6be..539bf328c5b592fa521766aed48210e6c4847d07 100644 (file)
@@ -1524,7 +1524,8 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
 // Write out the global symbols.
 
 void
-Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
+Symbol_table::write_globals(const Input_objects* input_objects,
+                           const Stringpool* sympool,
                            const Stringpool* dynpool, Output_file* of) const
 {
   if (parameters->get_size() == 32)
@@ -1532,7 +1533,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
       if (parameters->is_big_endian())
        {
 #ifdef HAVE_TARGET_32_BIG
-         this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+         this->sized_write_globals<32, true>(input_objects, sympool,
+                                             dynpool, of);
 #else
          gold_unreachable();
 #endif
@@ -1540,7 +1542,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
       else
        {
 #ifdef HAVE_TARGET_32_LITTLE
-         this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+         this->sized_write_globals<32, false>(input_objects, sympool,
+                                              dynpool, of);
 #else
          gold_unreachable();
 #endif
@@ -1551,7 +1554,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
       if (parameters->is_big_endian())
        {
 #ifdef HAVE_TARGET_64_BIG
-         this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+         this->sized_write_globals<64, true>(input_objects, sympool,
+                                             dynpool, of);
 #else
          gold_unreachable();
 #endif
@@ -1559,7 +1563,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
       else
        {
 #ifdef HAVE_TARGET_64_LITTLE
-         this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+         this->sized_write_globals<64, false>(input_objects, sympool,
+                                              dynpool, of);
 #else
          gold_unreachable();
 #endif
@@ -1573,11 +1578,13 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
 
 template<int size, bool big_endian>
 void
-Symbol_table::sized_write_globals(const Target* target,
+Symbol_table::sized_write_globals(const Input_objects* input_objects,
                                  const Stringpool* sympool,
                                  const Stringpool* dynpool,
                                  Output_file* of) const
 {
+  const Target* const target = input_objects->target();
+
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
   unsigned int index = this->first_global_index_;
   const off_t oview_size = this->output_count_ * sym_size;
@@ -1599,25 +1606,8 @@ Symbol_table::sized_write_globals(const Target* target,
     {
       Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
 
-      // Optionally check for unresolved symbols in shared libraries.
-      // This is controlled by the --allow-shlib-undefined option.  We
-      // only warn about libraries for which we have seen all the
-      // DT_NEEDED entries.  We don't try to track down DT_NEEDED
-      // entries which were not seen in this link.  If we didn't see a
-      // DT_NEEDED entry, we aren't going to be able to reliably
-      // report whether the symbol is undefined.
-      if (sym->source() == Symbol::FROM_OBJECT
-          && sym->object()->is_dynamic()
-          && sym->shndx() == elfcpp::SHN_UNDEF
-         && sym->binding() != elfcpp::STB_WEAK
-         && !parameters->allow_shlib_undefined())
-       {
-         // A very ugly cast.
-         Dynobj* dynobj = static_cast<Dynobj*>(sym->object());
-         if (!dynobj->has_unknown_needed_entries())
-           gold_error(_("%s: undefined reference to '%s'"),
-                      sym->object()->name().c_str(), sym->name());
-       }
+      // Possibly warn about unresolved symbols in shared libraries.
+      this->warn_about_undefined_dynobj_symbol(input_objects, sym);
 
       unsigned int sym_index = sym->symtab_index();
       unsigned int dynsym_index;
@@ -1749,6 +1739,42 @@ Symbol_table::sized_write_symbol(
   osym.put_st_shndx(shndx);
 }
 
+// Check for unresolved symbols in shared libraries.  This is
+// controlled by the --allow-shlib-undefined option.
+
+// We only warn about libraries for which we have seen all the
+// DT_NEEDED entries.  We don't try to track down DT_NEEDED entries
+// which were not seen in this link.  If we didn't see a DT_NEEDED
+// entry, we aren't going to be able to reliably report whether the
+// symbol is undefined.
+
+// We also don't warn about libraries found in the system library
+// directory (the directory were we find libc.so); we assume that
+// those libraries are OK.  This heuristic avoids problems in
+// GNU/Linux, in which -ldl can have undefined references satisfied by
+// ld-linux.so.
+
+inline void
+Symbol_table::warn_about_undefined_dynobj_symbol(
+    const Input_objects* input_objects,
+    Symbol* sym) const
+{
+  if (sym->source() == Symbol::FROM_OBJECT
+      && sym->object()->is_dynamic()
+      && sym->shndx() == elfcpp::SHN_UNDEF
+      && sym->binding() != elfcpp::STB_WEAK
+      && !parameters->allow_shlib_undefined()
+      && !input_objects->target()->is_defined_by_abi(sym)
+      && !input_objects->found_in_system_library_directory(sym->object()))
+    {
+      // A very ugly cast.
+      Dynobj* dynobj = static_cast<Dynobj*>(sym->object());
+      if (!dynobj->has_unknown_needed_entries())
+       gold_error(_("%s: undefined reference to '%s'"),
+                  sym->object()->name().c_str(), sym->name());
+    }
+}
+
 // Write out a section symbol.  Return the update offset.
 
 void
index 367813fc617170f4d0e938099814a80406536eb8..d32112256abd4be4f1747912c8f7a48b829667c4 100644 (file)
@@ -46,6 +46,7 @@ class Dynobj;
 template<int size, bool big_endian>
 class Sized_dynobj;
 class Versions;
+class Input_objects;
 class Output_data;
 class Output_section;
 class Output_segment;
@@ -1055,7 +1056,7 @@ class Symbol_table
 
   // Write out the global symbols.
   void
-  write_globals(const Target*, const Stringpool*, const Stringpool*,
+  write_globals(const Input_objects*, const Stringpool*, const Stringpool*,
                Output_file*) const;
 
   // Write out a section symbol.  Return the updated offset.
@@ -1177,8 +1178,8 @@ class Symbol_table
   // Write globals specialized for size and endianness.
   template<int size, bool big_endian>
   void
-  sized_write_globals(const Target*, const Stringpool*, const Stringpool*,
-                     Output_file*) const;
+  sized_write_globals(const Input_objects*, const Stringpool*,
+                     const Stringpool*, Output_file*) const;
 
   // Write out a symbol to P.
   template<int size, bool big_endian>
@@ -1189,6 +1190,10 @@ class Symbol_table
                     const Stringpool*, unsigned char* p
                      ACCEPT_SIZE_ENDIAN) const;
 
+  // Possibly warn about an undefined symbol from a dynamic object.
+  void
+  warn_about_undefined_dynobj_symbol(const Input_objects*, Symbol*) const;
+
   // Write out a section symbol, specialized for size and endianness.
   template<int size, bool big_endian>
   void
index 8ecc078330d76efeace35f8dfd10e1bd57459586..e385c555d815f40703bc9bc4669a4079d6472441 100644 (file)
@@ -137,6 +137,12 @@ class Target
   code_fill(off_t length)
   { return this->do_code_fill(length); }
 
+  // Return whether SYM is known to be defined by the ABI.  This is
+  // used to avoid inappropriate warnings about undefined symbols.
+  bool
+  is_defined_by_abi(Symbol* sym) const
+  { return this->do_is_defined_by_abi(sym); }
+
  protected:
   // This struct holds the constant information for a child class.  We
   // use a struct to avoid the overhead of virtual function calls for
@@ -188,6 +194,11 @@ class Target
   do_code_fill(off_t)
   { gold_unreachable(); }
 
+  // Virtual function which may be implemented by the child class.
+  virtual bool
+  do_is_defined_by_abi(Symbol*) const
+  { return false; }
+
  private:
   Target(const Target&);
   Target& operator=(const Target&);
index 202f3be4e7d67ca2dc43e4fa2f47e40b8270404b..520863fba6c0fd97110b01a754ba9aac7a63771b 100644 (file)
@@ -30,12 +30,9 @@ if GCC
 
 if NATIVE_LINKER
 
-TESTS += debug_msg.sh
+TESTS += debug_msg.sh undef_symbol.sh
 
-check_DATA += debug_msg.err
-
-# TESTS += undef_symbol.sh
-# check_DATA +=undef_symbol.err
+check_DATA += debug_msg.err undef_symbol.err
 
 NATIVE_PROGS = \
        constructor_test \
index 5f860bec382c1057933241d5b5c2edd63bc98a49..b20142391694bbdb81f28795efe8ce3268bb92d9 100644 (file)
@@ -42,8 +42,8 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = debug_msg.sh
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_2 = debug_msg.err
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = debug_msg.sh undef_symbol.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_2 = debug_msg.err undef_symbol.err
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_1_nonpic_test \
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test \
@@ -573,9 +573,6 @@ INCLUDES = \
 check_SCRIPTS = debug_msg.sh
 check_DATA = $(am__append_2)
 TESTS = object_unittest $(am__append_1) $(NATIVE_TESTING)
-
-# TESTS += undef_symbol.sh
-# check_DATA +=undef_symbol.err
 @GCC_TRUE@@NATIVE_LINKER_TRUE@NATIVE_PROGS = constructor_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_static_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test \
index 0614e89c6064acc7b7f707ac86b6fcb3b1d89488..349d8c1407f02dec52a3ab21c29eecfd3db6ee62 100644 (file)
@@ -113,6 +113,11 @@ class Target_x86_64 : public Sized_target<64, false>
   std::string
   do_code_fill(off_t length);
 
+  // Return whether SYM is defined by the ABI.
+  bool
+  do_is_defined_by_abi(Symbol* sym) const
+  { return strcmp(sym->name(), "__tls_get_addr") == 0; }
+
   // Return the size of the GOT section.
   off_t
   got_size()
This page took 0.038096 seconds and 4 git commands to generate.