Warn about undefined references in shared libraries if we have seen
authorIan Lance Taylor <iant@google.com>
Wed, 14 Nov 2007 07:34:53 +0000 (07:34 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 14 Nov 2007 07:34:53 +0000 (07:34 +0000)
all the DT_NEEDED entries for that library.

15 files changed:
gold/dynobj.cc
gold/dynobj.h
gold/gold.cc
gold/object.cc
gold/object.h
gold/options.cc
gold/options.h
gold/parameters.cc
gold/parameters.h
gold/symtab.cc
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/undef_symbol.cc [new file with mode: 0644]
gold/testsuite/undef_symbol.sh [new file with mode: 0755]
gold/testsuite/undef_symbol_main.cc [new file with mode: 0644]

index 9845194b3b6a87a4cf92c4e66b30dba83a01e983..a6f3588f48c9ad306e110e2456d74d060d2722d7 100644 (file)
@@ -39,7 +39,9 @@ namespace gold
 // see a DT_SONAME entry.
 
 Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset)
-  : Object(name, input_file, true, offset)
+  : Object(name, input_file, true, offset),
+    needed_(),
+    unknown_needed_(UNKNOWN_NEEDED_UNSET)
 {
   // This will be overridden by a DT_SONAME entry, hopefully.  But if
   // we never see a DT_SONAME entry, our rule is to use the dynamic
@@ -60,14 +62,6 @@ Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset)
     }
 }
 
-// Return the string to use in a DT_NEEDED entry.
-
-const char*
-Dynobj::soname() const
-{
-  return this->soname_.c_str();
-}
-
 // Class Sized_dynobj.
 
 template<int size, bool big_endian>
@@ -193,19 +187,20 @@ Sized_dynobj<size, big_endian>::read_dynsym_section(
   *view_info = shdr.get_sh_info();
 }
 
-// Set the soname field if this shared object has a DT_SONAME tag.
-// PSHDRS points to the section headers.  DYNAMIC_SHNDX is the section
-// index of the SHT_DYNAMIC section.  STRTAB_SHNDX, STRTAB, and
-// STRTAB_SIZE are the section index and contents of a string table
-// which may be the one associated with the SHT_DYNAMIC section.
+// Read the dynamic tags.  Set the soname field if this shared object
+// has a DT_SONAME tag.  Record the DT_NEEDED tags.  PSHDRS points to
+// the section headers.  DYNAMIC_SHNDX is the section index of the
+// SHT_DYNAMIC section.  STRTAB_SHNDX, STRTAB, and STRTAB_SIZE are the
+// section index and contents of a string table which may be the one
+// associated with the SHT_DYNAMIC section.
 
 template<int size, bool big_endian>
 void
-Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs,
-                                          unsigned int dynamic_shndx,
-                                          unsigned int strtab_shndx,
-                                          const unsigned char* strtabu,
-                                          off_t strtab_size)
+Sized_dynobj<size, big_endian>::read_dynamic(const unsigned char* pshdrs,
+                                            unsigned int dynamic_shndx,
+                                            unsigned int strtab_shndx,
+                                            const unsigned char* strtabu,
+                                            off_t strtab_size)
 {
   typename This::Shdr dynamicshdr(pshdrs + dynamic_shndx * This::shdr_size);
   gold_assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC);
@@ -236,30 +231,48 @@ Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs,
       strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false);
     }
 
+  const char* const strtab = reinterpret_cast<const char*>(strtabu);
+
   for (const unsigned char* p = pdynamic;
        p < pdynamic + dynamic_size;
        p += This::dyn_size)
     {
       typename This::Dyn dyn(p);
 
-      if (dyn.get_d_tag() == elfcpp::DT_SONAME)
+      switch (dyn.get_d_tag())
        {
-         off_t val = dyn.get_d_val();
-         if (val >= strtab_size)
-           {
+       case elfcpp::DT_NULL:
+         // We should always see DT_NULL at the end of the dynamic
+         // tags.
+         return;
+
+       case elfcpp::DT_SONAME:
+         {
+           off_t val = dyn.get_d_val();
+           if (val >= strtab_size)
              this->error(_("DT_SONAME value out of range: %lld >= %lld"),
-                        static_cast<long long>(val),
-                        static_cast<long long>(strtab_size));
-             return;
-           }
+                         static_cast<long long>(val),
+                         static_cast<long long>(strtab_size));
+           else
+             this->set_soname_string(strtab + val);
+         }
+         break;
 
-         const char* strtab = reinterpret_cast<const char*>(strtabu);
-         this->set_soname_string(strtab + val);
-         return;
-       }
+       case elfcpp::DT_NEEDED:
+         {
+           off_t val = dyn.get_d_val();
+           if (val >= strtab_size)
+             this->error(_("DT_NEEDED value out of range: %lld >= %lld"),
+                         static_cast<long long>(val),
+                         static_cast<long long>(strtab_size));
+           else
+             this->add_needed(strtab + val);
+         }
+         break;
 
-      if (dyn.get_d_tag() == elfcpp::DT_NULL)
-       return;
+       default:
+         break;
+       }
     }
 
   this->error(_("missing DT_NULL in dynamic segment"));
@@ -346,15 +359,15 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
     }
 
   // Read the SHT_DYNAMIC section to find whether this shared object
-  // has a DT_SONAME tag.  This doesn't really have anything to do
-  // with reading the symbols, but this is a convenient place to do
-  // it.
+  // has a DT_SONAME tag and to record any DT_NEEDED tags.  This
+  // doesn't really have anything to do with reading the symbols, but
+  // this is a convenient place to do it.
   if (dynamic_shndx != -1U)
-    this->set_soname(pshdrs, dynamic_shndx, strtab_shndx,
-                    (sd->symbol_names == NULL
-                     ? NULL
-                     : sd->symbol_names->data()),
-                    sd->symbol_names_size);
+    this->read_dynamic(pshdrs, dynamic_shndx, strtab_shndx,
+                      (sd->symbol_names == NULL
+                       ? NULL
+                       : sd->symbol_names->data()),
+                      sd->symbol_names_size);
 }
 
 // Lay out the input sections for a dynamic object.  We don't want to
index eb6eb5c1cf5dadd01169cce5cdb50db64f09d1d8..1fe37a4b600d4e5cac470034ee39bcc1770eaec2 100644 (file)
@@ -39,11 +39,38 @@ class General_options;
 class Dynobj : public Object
 {
  public:
+  // We keep a list of all the DT_NEEDED entries we find.
+  typedef std::vector<std::string> Needed;
+
   Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0);
 
   // Return the name to use in a DT_NEEDED entry for this object.
   const char*
-  soname() const;
+  soname() const
+  { return this->soname_.c_str(); }
+
+  // Return the list of DT_NEEDED strings.
+  const Needed&
+  needed() const
+  { return this->needed_; }
+
+  // Return whether this dynamic object has any DT_NEEDED entries
+  // which were not seen during the link.
+  bool
+  has_unknown_needed_entries() const
+  {
+    gold_assert(this->unknown_needed_ != UNKNOWN_NEEDED_UNSET);
+    return this->unknown_needed_ == UNKNOWN_NEEDED_TRUE;
+  }
+
+  // Set whether this dynamic object has any DT_NEEDED entries which
+  // were not seen during the link.
+  void
+  set_has_unknown_needed_entries(bool set)
+  {
+    gold_assert(this->unknown_needed_ == UNKNOWN_NEEDED_UNSET);
+    this->unknown_needed_ = set ? UNKNOWN_NEEDED_TRUE : UNKNOWN_NEEDED_FALSE;
+  }
 
   // Compute the ELF hash code for a string.
   static uint32_t
@@ -74,6 +101,11 @@ class Dynobj : public Object
   set_soname_string(const char* s)
   { this->soname_.assign(s); }
 
+  // Add an entry to the list of DT_NEEDED strings.
+  void
+  add_needed(const char* s)
+  { this->needed_.push_back(std::string(s)); }
+
  private:
   // Compute the GNU hash code for a string.
   static uint32_t
@@ -101,8 +133,21 @@ class Dynobj : public Object
                              unsigned char** pphash,
                              unsigned int* phashlen);
 
+  // Values for the has_unknown_needed_entries_ field.
+  enum Unknown_needed
+  {
+    UNKNOWN_NEEDED_UNSET,
+    UNKNOWN_NEEDED_TRUE,
+    UNKNOWN_NEEDED_FALSE
+  };
+
   // The DT_SONAME name, if any.
   std::string soname_;
+  // The list of DT_NEEDED entries.
+  Needed needed_;
+  // Whether this dynamic object has any DT_NEEDED entries not seen
+  // during the link.
+  Unknown_needed unknown_needed_;
 };
 
 // A dynamic object, size and endian specific version.
@@ -187,12 +232,11 @@ class Sized_dynobj : public Dynobj
                      File_view** view, off_t* view_size,
                      unsigned int* view_info);
 
-  // Set the SONAME from the SHT_DYNAMIC section at DYNAMIC_SHNDX.
-  // The STRTAB parameters may have the relevant string table.
+  // Read the dynamic tags.
   void
-  set_soname(const unsigned char* pshdrs, unsigned int dynamic_shndx,
-            unsigned int strtab_shndx, const unsigned char* strtabu,
-            off_t strtab_size);
+  read_dynamic(const unsigned char* pshdrs, unsigned int dynamic_shndx,
+              unsigned int strtab_shndx, const unsigned char* strtabu,
+              off_t strtab_size);
 
   // Mapping from version number to version name.
   typedef std::vector<const char*> Version_map;
index a215d0f31dc85b42e35aff1386152004e71fa178..d0c2095c3f0c521e3aad85d5d8ab3af9a3f466cc 100644 (file)
@@ -180,6 +180,10 @@ queue_middle_tasks(const General_options& options,
                 (*input_objects->dynobj_begin())->name().c_str());
     }
 
+  // For each dynamic object, record whether we've seen all the
+  // dynamic objects that it depends upon.
+  input_objects->check_dynamic_dependencies();
+
   // See if any of the input definitions violate the One Definition Rule.
   // TODO: if this is too slow, do this as a task, rather than inline.
   symtab->detect_odr_violations();
index c0e2acd4e77f5c92c97aa1ac15bf6d24922caf30..fa16d138549b3e62fab6d874a19336a4f552019c 100644 (file)
@@ -1080,6 +1080,32 @@ Input_objects::add_object(Object* obj)
   return true;
 }
 
+// For each dynamic object, record whether we've seen all of its
+// explicit dependencies.
+
+void
+Input_objects::check_dynamic_dependencies() const
+{
+  for (Dynobj_list::const_iterator p = this->dynobj_list_.begin();
+       p != this->dynobj_list_.end();
+       ++p)
+    {
+      const Dynobj::Needed& needed((*p)->needed());
+      bool found_all = true;
+      for (Dynobj::Needed::const_iterator pneeded = needed.begin();
+          pneeded != needed.end();
+          ++pneeded)
+       {
+         if (this->sonames_.find(*pneeded) == this->sonames_.end())
+           {
+             found_all = false;
+             break;
+           }
+       }
+      (*p)->set_has_unknown_needed_entries(!found_all);
+    }
+}
+
 // Relocate_info methods.
 
 // Return a string describing the location of a relocation.  This is
index b8bc65c90980f213646b1295252095294f9e58b5..332739295f2e85c96c6ea6e391613a835495878d 100644 (file)
@@ -951,6 +951,11 @@ class Input_objects
   target() const
   { return this->target_; }
 
+  // For each dynamic object, check whether we've seen all of its
+  // explicit dependencies.
+  void
+  check_dynamic_dependencies() const;
+
   // Iterate over all regular objects.
 
   Relobj_iterator
index d4d9e16cc2b353c41a30eed3a7788b89d8fb208a..69f452dd380bd9ca1e6021d6b875ef3a54254a80 100644 (file)
@@ -337,6 +337,14 @@ namespace gold
 const options::One_option
 options::Command_line_options::options[] =
 {
+  GENERAL_NOARG('\0', "allow-shlib-undefined",
+               N_("Allow unresolved references in shared libraries"),
+               NULL, TWO_DASHES,
+               &General_options::set_allow_shlib_undefined),
+  GENERAL_NOARG('\0', "no-allow-shlib-undefined",
+               N_("Do not allow unresolved references in shared libraries"),
+               NULL, TWO_DASHES,
+               &General_options::set_no_allow_shlib_undefined),
   POSDEP_NOARG('\0', "as-needed",
               N_("Only set DT_NEEDED for dynamic libs if used"),
               NULL, TWO_DASHES, &Position_dependent_options::set_as_needed),
@@ -475,6 +483,7 @@ General_options::General_options()
     output_file_name_("a.out"),
     is_relocatable_(false),
     strip_(STRIP_NONE),
+    allow_shlib_undefined_(false),
     symbolic_(false),
     detect_odr_violations_(false),
     create_eh_frame_hdr_(false),
index c54af7781d200f11bbea65979bb1aa1865760656..b5d2328a1a63171de604fa7ad6ebf4c505bf0a75 100644 (file)
@@ -148,6 +148,12 @@ class General_options
   strip_debug() const
   { return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG; }
 
+  // --allow-shlib-undefined: do not warn about unresolved symbols in
+  // --shared libraries.
+  bool
+  allow_shlib_undefined() const
+  { return this->allow_shlib_undefined_; }
+
   // -Bsymbolic: bind defined symbols locally.
   bool
   symbolic() const
@@ -300,6 +306,14 @@ class General_options
   set_strip_debug()
   { this->strip_ = STRIP_DEBUG; }
 
+  void
+  set_allow_shlib_undefined()
+  { this->allow_shlib_undefined_ = true; }
+
+  void
+  set_no_allow_shlib_undefined()
+  { this->allow_shlib_undefined_ = false; }
+
   void
   set_symbolic()
   { this->symbolic_ = true; }
@@ -420,6 +434,7 @@ class General_options
   const char* output_file_name_;
   bool is_relocatable_;
   Strip strip_;
+  bool allow_shlib_undefined_;
   bool symbolic_;
   bool detect_odr_violations_;
   bool create_eh_frame_hdr_;
index f332134d4b6018951fe477b6e2e848e4f2e0cd29..b96221a8b2449764b6b93e089b595e76093d97d7 100644 (file)
@@ -33,7 +33,8 @@ namespace gold
 Parameters::Parameters(Errors* errors)
   : errors_(errors), output_file_name_(NULL),
     output_file_type_(OUTPUT_INVALID), sysroot_(),
-    strip_(STRIP_INVALID), symbolic_(false), detect_odr_violations_(false),
+    strip_(STRIP_INVALID), allow_shlib_undefined_(false),
+    symbolic_(false), detect_odr_violations_(false),
     optimization_level_(0), export_dynamic_(false),
     is_doing_static_link_valid_(false), doing_static_link_(false),
     is_size_and_endian_valid_(false), size_(0), is_big_endian_(false)
@@ -47,6 +48,7 @@ Parameters::set_from_options(const General_options* options)
 {
   this->output_file_name_ = options->output_file_name();
   this->sysroot_ = options->sysroot();
+  this->allow_shlib_undefined_ = options->allow_shlib_undefined();
   this->symbolic_ = options->symbolic();
   this->detect_odr_violations_ = options->detect_odr_violations();
   this->optimization_level_ = options->optimization_level();
index 353f01f2ba80986b48e738478628679fd1c0b425..ee60b10b4a0de868100903b88ec86f337c7b4c1d 100644 (file)
@@ -112,6 +112,14 @@ class Parameters
     return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG;
   }
 
+  // Whether to permit unresolved references from shared libraries.
+  bool
+  allow_shlib_undefined() const
+  {
+    gold_assert(this->options_valid_);
+    return this->allow_shlib_undefined_;
+  }
+
   // Whether we are doing a symbolic link, in which all defined
   // symbols are bound locally.
   bool
@@ -224,6 +232,8 @@ class Parameters
   std::string sysroot_;
   // Which symbols to strip.
   Strip strip_;
+  // Whether to allow undefined references from shared libraries.
+  bool allow_shlib_undefined_;
   // Whether we are doing a symbolic link.
   bool symbolic_;
   // Whether we try to detect One Definition Rule violations.
index 9bee2837db339fcb0ba83b9bba8d14e35063e6be..f5e21322b78eb1f5f1863c3941f85b3430b0a6be 100644 (file)
@@ -1599,6 +1599,26 @@ 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());
+       }
+
       unsigned int sym_index = sym->symtab_index();
       unsigned int dynsym_index;
       if (dynamic_view == NULL)
index e193fc560282e62beb2bfef2688e46efb393b0ea..520863fba6c0fd97110b01a754ba9aac7a63771b 100644 (file)
@@ -28,11 +28,11 @@ TESTS = object_unittest
 
 if GCC
 
-TESTS += debug_msg.sh
+if NATIVE_LINKER
 
-check_DATA += debug_msg.err
+TESTS += debug_msg.sh undef_symbol.sh
 
-if NATIVE_LINKER
+check_DATA += debug_msg.err undef_symbol.err
 
 NATIVE_PROGS = \
        constructor_test \
@@ -116,25 +116,38 @@ object_unittest_SOURCES = object_unittest.cc
 
 if GCC
 
+if NATIVE_LINKER
+
+gcctestdir/ld: ../ld-new
+       test -d gcctestdir || mkdir -p gcctestdir
+       rm -f gcctestdir/ld
+       (cd gcctestdir && $(LN_S) ../../ld-new ld)
+
 debug_msg.o: debug_msg.cc
        $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc
 odr_violation1.o: odr_violation1.cc
        $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc
 odr_violation2.o: odr_violation2.cc
        $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation2.cc
-debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o
-       if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \
+debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o gcctestdir/ld
+       @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o "2>$@"
+       @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \
        then \
-         echo 2>&1 "Link of debug_msg.o should have failed"; \
+         echo 1>&2 "Link of debug_msg.o should have failed"; \
          exit 1; \
        fi
 
-if NATIVE_LINKER
-
-gcctestdir/ld: ../ld-new
-       test -d gcctestdir || mkdir -p gcctestdir
-       rm -f gcctestdir/ld
-       (cd gcctestdir && $(LN_S) ../../ld-new ld)
+undef_symbol.o: undef_symbol.cc
+       $(CXXCOMPILE) -O0 -g -c -fPIC $<
+undef_symbol.so: undef_symbol.o
+       $(CXXLINK) -shared undef_symbol.o
+undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld
+       @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@"
+       @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \
+       then \
+         echo 1>&2 "Link of undef_symbol_test should have failed"; \
+         exit 1; \
+       fi
 
 # Override the default CXXFLAGS--we don't want any optimization
 basic_test.o: basic_test.cc
index dcbbf520044de9138e073c42b80921f8c931017b..b20142391694bbdb81f28795efe8ce3268bb92d9 100644 (file)
@@ -42,8 +42,8 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-@GCC_TRUE@am__append_1 = debug_msg.sh
-@GCC_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 \
@@ -1204,24 +1204,37 @@ uninstall-am: uninstall-info-am
        tags uninstall uninstall-am uninstall-info-am
 
 
-@GCC_TRUE@debug_msg.o: debug_msg.cc
-@GCC_TRUE@     $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc
-@GCC_TRUE@odr_violation1.o: odr_violation1.cc
-@GCC_TRUE@     $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc
-@GCC_TRUE@odr_violation2.o: odr_violation2.cc
-@GCC_TRUE@     $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation2.cc
-@GCC_TRUE@debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o
-@GCC_TRUE@     if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \
-@GCC_TRUE@     then \
-@GCC_TRUE@       echo 2>&1 "Link of debug_msg.o should have failed"; \
-@GCC_TRUE@       exit 1; \
-@GCC_TRUE@     fi
-
 @GCC_TRUE@@NATIVE_LINKER_TRUE@gcctestdir/ld: ../ld-new
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d gcctestdir || mkdir -p gcctestdir
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ (cd gcctestdir && $(LN_S) ../../ld-new ld)
 
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.o: debug_msg.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation1.o: odr_violation1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation2.o: odr_violation2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@   echo 1>&2 "Link of debug_msg.o should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@   exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.o: undef_symbol.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -fPIC $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.so: undef_symbol.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared undef_symbol.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@"
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@   echo 1>&2 "Link of undef_symbol_test should have failed"; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@   exit 1; \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi
+
 # Override the default CXXFLAGS--we don't want any optimization
 @GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test.o: basic_test.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
diff --git a/gold/testsuite/undef_symbol.cc b/gold/testsuite/undef_symbol.cc
new file mode 100644 (file)
index 0000000..25fd181
--- /dev/null
@@ -0,0 +1,38 @@
+// undef_symbol.cc -- a test case for undefined references
+
+// Copyright 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// This file is constructed to have an undefined reference to the
+// global variable a.  We should get an error when we link.
+
+extern int a;
+
+class Foo
+{
+ public:
+  Foo()
+    : a_(a)
+  { }
+ private:
+  int a_;
+};
+
+static Foo foo;
diff --git a/gold/testsuite/undef_symbol.sh b/gold/testsuite/undef_symbol.sh
new file mode 100755 (executable)
index 0000000..bc9eb57
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# undef_symbol.sh -- a test case for undefined symbols in shared libraries
+
+# Copyright 2007 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This file goes with debug_msg.cc, a C++ source file constructed to
+# have undefined references.  We compile that file with debug
+# information and then try to link it, and make sure the proper errors
+# are displayed.  The errors will be found in debug_msg.err.
+
+check()
+{
+    if ! grep -q "$1" undef_symbol.err
+    then
+       echo "Did not find expected error:"
+       echo "   $1"
+       echo ""
+       echo "Actual error output below:"
+       cat undef_symbol.err
+       exit 1
+    fi
+}
+
+check "undef_symbol.so: undefined reference to 'a'"
+
+exit 0
diff --git a/gold/testsuite/undef_symbol_main.cc b/gold/testsuite/undef_symbol_main.cc
new file mode 100644 (file)
index 0000000..90f97e0
--- /dev/null
@@ -0,0 +1,29 @@
+// undef_symbol_1.cc -- a test case for undefined references
+
+// Copyright 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// Main function for undefined symbol test.
+
+int
+main()
+{
+  return 0;
+}
This page took 0.037673 seconds and 4 git commands to generate.