* symtab.cc (Symbol_table::add_from_object): Rewrite the case
authorIan Lance Taylor <ian@airs.com>
Fri, 18 Jul 2008 07:03:27 +0000 (07:03 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 18 Jul 2008 07:03:27 +0000 (07:03 +0000)
where we see NAME/NULL and NAME/VERSION  as separate symbols.
* testsuite/ver_test_main.cc (main): Call t4.
(t4, t4_2a): Define.
* testsuite/ver_test_2.cc (t4_2): Define.
* testsuite/ver_test_2.script: Put t4_2a in VER2.
* testsuite/ver_test_4.cc (t4_2a): Define.
* testsuite/ver_test_4.script: Put t4_2a in VER2.
* testsuite/ver_test.h (t4, t4_2, t4_2a): Declare.

gold/ChangeLog
gold/symtab.cc
gold/testsuite/ver_test.h
gold/testsuite/ver_test_2.cc
gold/testsuite/ver_test_2.script
gold/testsuite/ver_test_4.cc
gold/testsuite/ver_test_4.script
gold/testsuite/ver_test_main.cc

index 16020c861b3e299a1fea11c693fbcd98f79bf73f..4e4b6907259796c5c110a3baaba0f1c7cf2153c1 100644 (file)
@@ -1,3 +1,15 @@
+2008-07-18  Ian Lance Taylor  <iant@google.com>
+
+       * symtab.cc (Symbol_table::add_from_object): Rewrite the case
+       where we see NAME/NULL and NAME/VERSION  as separate symbols.
+       * testsuite/ver_test_main.cc (main): Call t4.
+       (t4, t4_2a): Define.
+       * testsuite/ver_test_2.cc (t4_2): Define.
+       * testsuite/ver_test_2.script: Put t4_2a in VER2.
+       * testsuite/ver_test_4.cc (t4_2a): Define.
+       * testsuite/ver_test_4.script: Put t4_2a in VER2.
+       * testsuite/ver_test.h (t4, t4_2, t4_2a): Declare.
+
 2008-07-17  Ian Lance Taylor  <iant@google.com>
 
        * dynobj.cc (Versions::add_def): If we give an error about a
index 33a9151c3fd30daf21d65831dc009daebfa33de7..39a0ec3f8de67277593f6f6423947ecfd45cef40 100644 (file)
@@ -687,23 +687,58 @@ Symbol_table::add_from_object(Object* object,
              // NAME/NULL point to NAME/VERSION.
              insdef.first->second = ret;
            }
-         else if (insdef.first->second != ret
-                  && insdef.first->second->is_undefined())
+         else if (insdef.first->second != ret)
            {
              // This is the unfortunate case where we already have
-             // entries for both NAME/VERSION and NAME/NULL.  Note
-             // that we don't want to combine them if the existing
-             // symbol is going to override the new one.  FIXME: We
-             // currently just test is_undefined, but this may not do
-             // the right thing if the existing symbol is from a
-             // shared library and the new one is from a regular
-             // object.
-
-             const Sized_symbol<size>* sym2;
-             sym2 = this->get_sized_symbol<size>(insdef.first->second);
-             Symbol_table::resolve<size, big_endian>(ret, sym2, version);
-             this->make_forwarder(insdef.first->second, ret);
-             insdef.first->second = ret;
+             // entries for both NAME/VERSION and NAME/NULL.  We now
+             // see a symbol NAME/VERSION where VERSION is the
+             // default version.  We have already resolved this new
+             // symbol with the existing NAME/VERSION symbol.
+
+             // It's possible that NAME/NULL and NAME/VERSION are
+             // both defined in regular objects.  This can only
+             // happen if one object file defines foo and another
+             // defines foo@@ver.  This is somewhat obscure, but we
+             // call it a multiple definition error.
+
+             // It's possible that NAME/NULL actually has a version,
+             // in which case it won't be the same as VERSION.  This
+             // happens with ver_test_7.so in the testsuite for the
+             // symbol t2_2.  We see t2_2@@VER2, so we define both
+             // t2_2/VER2 and t2_2/NULL.  We then see an unadorned
+             // t2_2 in an object file and give it version VER1 from
+             // the version script.  This looks like a default
+             // definition for VER1, so it looks like we should merge
+             // t2_2/NULL with t2_2/VER1.  That doesn't make sense,
+             // but it's not obvious that this is an error, either.
+             // So we just punt.
+
+             // If one of the symbols has non-default visibility, and
+             // the other is defined in a shared object, then they
+             // are different symbols.
+
+             // Otherwise, we just resolve the symbols as though they
+             // were the same.
+
+             if (insdef.first->second->version() != NULL)
+               {
+                 gold_assert(insdef.first->second->version() != version);
+                 def = false;
+               }
+             else if (ret->visibility() != elfcpp::STV_DEFAULT
+                 && insdef.first->second->is_from_dynobj())
+               def = false;
+             else if (insdef.first->second->visibility() != elfcpp::STV_DEFAULT
+                      && ret->is_from_dynobj())
+               def = false;
+             else
+               {
+                 const Sized_symbol<size>* sym2;
+                 sym2 = this->get_sized_symbol<size>(insdef.first->second);
+                 Symbol_table::resolve<size, big_endian>(ret, sym2, version);
+                 this->make_forwarder(insdef.first->second, ret);
+                 insdef.first->second = ret;
+               }
            }
          else
            def = false;
index 48dbf41e76f54c861a32ffb725ef528529f152d6..0b1aea8d7305baf8c58ccd559e037a22048879e2 100644 (file)
 extern bool t1();
 extern bool t2();
 extern bool t3();
+extern bool t4();
 
 extern "C" {
 
 extern int t1_2();
 extern int t2_2();
 extern int t3_2();
+extern int t4_2();
+extern int t4_2a();
 
 }
index 1c69264342ccbb0455988e23e050edbd04873360..b81e62e03ae06652cf0ee96255e276f785dbc3d8 100644 (file)
@@ -28,3 +28,13 @@ t3_2()
   TRACE
   return t1_2();
 }
+
+// Calls a versioned function in ver_test_4.cc which should be
+// overridden by an unversioned function in the main program.
+
+int
+t4_2()
+{
+  TRACE
+  return t4_2a();
+}
index d1f83142beaa0c34755896e617433cc5bfc16fbc..15329d70688d0acb8975cd576a4abd5787886b48 100644 (file)
@@ -27,5 +27,5 @@ VER2 {
   global:
     t1_2;
     t3_2;
+    t4_2a;
 } VER1;
-
index 38da421f136e2aa51f2a7da68000d88006b37c26..404dfbc3dd18e091e9fbf372e7baf43c6ac4d66c 100644 (file)
@@ -51,3 +51,14 @@ t2_2_b()
   TRACE
   return 22;
 }
+
+
+// This function is given a version by the version script, and should
+// be overridden by the main program.
+
+int
+t4_2a()
+{
+  TRACE
+  return -42;
+}
index ebcf1e954ec02c05afd5ad16fe5d8c5fbb769915..9f7d3503af97fe024fe7ee0ae2eede6c6b7a67ed 100644 (file)
@@ -31,5 +31,6 @@ VER2 {
   global:
     t1_2;
     t2_2;
+    t4_2a;
 } VER1;
 
index 10649f2baa047692da934d4e6126e9f5127d5561..f8a7b755c9ba827b0d624e1e1fca5cbbccc1d526 100644 (file)
@@ -30,6 +30,7 @@ main()
   assert(t1());
   assert(t2());
   assert(t3());
+  assert(t4());
   return 0;
 }
 
@@ -52,3 +53,22 @@ t3()
   TRACE
   return t3_2() == 12;
 }
+
+// Call a function in a shared library that calls a function which is
+// defined in the main program and defined with a default version in
+// the shared library.  The symbol in the main program should override
+// even though it doesn't have a version.
+
+bool
+t4()
+{
+  TRACE
+  return t4_2() == 42;
+}
+
+int
+t4_2a()
+{
+  TRACE
+  return 42;
+}