[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#508929: mklibs selects symbols from the wrong library



Package: mklibs
Tags: patch

The problem is that mklibs selects either the first symbol of the correct name, or the one in libc, if there is one. It completely disregards the information left by the linker defining where each symbol *should* come from.

The dynamic linker does use this data, so it looks for symbols in specific libraries and complains if they aren't there.

To reproduce the problem:

---8<------------->8------
#include <stdio.h>
#include <math.h>

int main(void)
{
	double x, y, n;

	x = -14.87654321;
	y = modf( x, &n );
	printf("%f, %f, %f\n", x, y, n);

	return 0;
}
---8<------------->8------

gcc modf_test.c -lm
mklibs -d result a.out

Then result/libm.so.6 contains no symbols, and modf is present in result/libc.so.6. This issue may only exist some platforms - mips-linux-gnu is the one with which I have observed the problem. This is because the modf symbol is present in both libm *and* libc, and mklibs always prefers libc.

The problem can be worked around by means of LD_PRELOAD=libm.so (or whatever library), because then the symbol is resolved early, and the dynamic linker does not have to search for it elsewhere. Note that doing this only works if all symbols of the same name have compatible definitions. Otherwise, the program will be silently broken.

This patch modifies mklibs-readelf to extract the library name associated with each undefined symbol (in addition to the version it already gets).

mklibs.py then treats each symbol as a triplet, rather than a pair:

  printf@GLIBC_2.0 -> printf@GLIBC_2.0@libc.so.6

Each symbol can now only match against one library. This should produce the same mapping that the dynamic linker would use (minus LD_PRELOAD).

Andrew Stubbs
---
 src/mklibs-readelf/elf.cpp      |   20 +++++++++++++++++---
 src/mklibs-readelf/elf.hpp      |    8 ++++++++
 src/mklibs-readelf/elf_data.hpp |    2 +-
 src/mklibs-readelf/main.cpp     |    3 ++-
 src/mklibs.py                   |   34 +++++++++++++++++++---------------
 5 files changed, 47 insertions(+), 20 deletions(-)

Index: src/mklibs-readelf/elf.cpp
===================================================================
--- src/mklibs-readelf/elf.cpp.orig	2008-12-16 16:48:07.000000000 +0000
+++ src/mklibs-readelf/elf.cpp	2008-12-16 17:43:42.000000000 +0000
@@ -445,6 +445,14 @@ std::string symbol::get_version () const
   return "Base";
 }
 
+std::string symbol::get_version_file () const throw (std::bad_alloc)
+{
+  if (verneed)
+    return verneed->get_file();
+
+  return "unknown";
+}
+
 std::string symbol::get_name_version () const throw (std::bad_alloc)
 {
   std::string ver;
@@ -539,10 +547,12 @@ version_requirement_data<_class, _data>:
 
   char *act = reinterpret_cast<char *> (verneed) + aux;
 
+  file = convert<_data, typeof (verneed->vn_file)> () (verneed->vn_file);
+
   for (int i = 0; i < cnt; i++)
   {
     Vernaux *vernaux = reinterpret_cast<Vernaux *> (act);
-    entries.push_back(new version_requirement_entry_data<_class, _data> (vernaux));
+    entries.push_back(new version_requirement_entry_data<_class, _data> (this, vernaux));
     uint32_t next = convert<_data, typeof (vernaux->vna_next)> () (vernaux->vna_next);
     act += next;
   }
@@ -551,17 +561,21 @@ version_requirement_data<_class, _data>:
 template <typename _class, typename _data>
 void version_requirement_data<_class, _data>::update_string(const section_type<section_type_STRTAB> &section) throw (std::bad_alloc)
 {
+  file_string = section.get_string(file);
+
   for (std::vector<version_requirement_entry *>::iterator it = entries.begin(); it != entries.end(); ++it)
   {
     version_requirement_entry_data<_class, _data> &vernaux =
-      dynamic_cast<version_requirement_entry_data<_class, _data> &> (**it);
+      dynamic_cast<version_requirement_entry_data<_class, _data> &> (this, **it);
     vernaux.update_string(section);
   }
 }
 
 template <typename _class, typename _data>
-version_requirement_entry_data<_class, _data>::version_requirement_entry_data (Vernaux *vna) throw ()
+version_requirement_entry_data<_class, _data>::version_requirement_entry_data (const version_requirement_data<_class, _data> *parent, Vernaux *vna) throw ()
 {
+  this->parent = parent;
+
   flags = convert<_data, typeof (vna->vna_flags)> () (vna->vna_flags);
   other = convert<_data, typeof (vna->vna_other)> () (vna->vna_other);
   name  = convert<_data, typeof (vna->vna_name)> ()  (vna->vna_name);
Index: src/mklibs-readelf/elf.hpp
===================================================================
--- src/mklibs-readelf/elf.hpp.orig	2008-12-16 16:48:07.000000000 +0000
+++ src/mklibs-readelf/elf.hpp	2008-12-16 17:43:42.000000000 +0000
@@ -264,6 +264,7 @@ namespace Elf
       uint8_t get_type () const throw () { return type; }
       const std::string &get_name_string () const throw () { return name_string; }
       std::string get_version() const throw (std::bad_alloc);
+      std::string get_version_file() const throw (std::bad_alloc);
       uint16_t get_version_data() const throw () { return versym; }
       std::string get_name_version() const throw (std::bad_alloc);
 
@@ -306,9 +307,13 @@ namespace Elf
     public:
       virtual ~version_requirement () throw () { }
 
+      const std::string &get_file() const throw () { return file_string; }
       const std::vector<version_requirement_entry *> &get_entries () const throw () { return entries; }
 
     protected:
+      uint32_t file;
+
+      std::string file_string;
       std::vector<version_requirement_entry *> entries;
   };
 
@@ -319,8 +324,11 @@ namespace Elf
 
       uint16_t get_other () const throw () { return other; }
       const std::string &get_name() const throw () { return name_string; }
+      const std::string &get_file() const throw () { return parent->get_file(); }
 
     protected:
+      const version_requirement *parent;
+
       uint16_t flags;
       uint16_t other;
       uint32_t name;
Index: src/mklibs-readelf/elf_data.hpp
===================================================================
--- src/mklibs-readelf/elf_data.hpp.orig	2008-12-16 16:48:07.000000000 +0000
+++ src/mklibs-readelf/elf_data.hpp	2008-12-16 17:43:42.000000000 +0000
@@ -214,7 +214,7 @@ namespace Elf
       public:
         typedef typename _elfdef<_class>::Vernaux Vernaux;
 
-        version_requirement_entry_data (Vernaux *) throw ();
+        version_requirement_entry_data (const version_requirement_data<_class,_data> *, Vernaux *) throw ();
 
         void update_string(const section_type<section_type_STRTAB> &) throw (std::bad_alloc);
     };
Index: src/mklibs-readelf/main.cpp
===================================================================
--- src/mklibs-readelf/main.cpp.orig	2008-12-16 16:48:07.000000000 +0000
+++ src/mklibs-readelf/main.cpp	2008-12-16 17:43:42.000000000 +0000
@@ -95,7 +95,8 @@ static void process_symbols_undefined (c
       std::cout <<
         symbol->get_name_string () << ' ' <<
         (bind == STB_WEAK ? "True" : "False") << ' ' <<
-        symbol->get_version() << '\n';
+        symbol->get_version() << ' ' <<
+	symbol->get_version_file() << '\n';
   }
 }
 
Index: src/mklibs.py
===================================================================
--- src/mklibs.py.orig	2008-12-16 16:48:07.000000000 +0000
+++ src/mklibs.py	2008-12-16 18:07:45.000000000 +0000
@@ -139,8 +139,8 @@ def undefined_symbols(obj):
     result = []
     output = command("mklibs-readelf", "--print-symbols-undefined", obj)
     for line in output:
-        name, weak_string, version = line.split()[:3]
-        result.append(UndefinedSymbol(name, bool(eval(weak_string)), version))
+        name, weak_string, version, library = line.split()[:4]
+        result.append(UndefinedSymbol(name, bool(eval(weak_string)), "%s@%s" % (version, library)))
     return result
 
 class ProvidedSymbol(Symbol):
@@ -149,14 +149,16 @@ class ProvidedSymbol(Symbol):
         self.default_version = default_version
 
     def base_names(self):
-        if self.default_version and self.version != "Base":
-            return ["%s@%s" % (self.name, self.version), "%s@Base" % self.name]
+        ver, lib = self.version.split('@', 1)[:2]
+        if self.default_version and ver != "Base":
+            return ["%s@%s" % (self.name, self.version), "%s@Base@%s" % (self.name, lib)]
         return ["%s@%s" % (self.name, self.version)]
 
     def linker_name(self):
-        if self.default_version or self.version == "Base":
+        ver, lib = self.version.split('@', 1)[:2]
+        if self.default_version or ver == "Base":
             return self.name
-        return "%s@%s" % (self.name, self.version)
+        return "%s@%s" % (self.name, ver)
 
 # Return a set of symbols provided by a library
 def provided_symbols(obj):
@@ -167,7 +169,7 @@ def provided_symbols(obj):
     output = command("mklibs-readelf", "--print-symbols-provided", obj)
     for line in output:
         name, weak, version, default_version_string = line.split()[:4]
-        result.append(ProvidedSymbol(name, version, bool(eval(default_version_string))))
+        result.append(ProvidedSymbol(name, "%s@%s" % (version, extract_soname(obj)), bool(eval(default_version_string))))
     return result
     
 # Return real target of a symlink
@@ -208,10 +210,17 @@ def find_pic_map(lib):
                 return resolve_link(file)
     return ""
 
+soname_cache = []
 def extract_soname(so_file):
+    for file, name in soname_cache:
+      if file == so_file:
+        return name
     soname_data = command("mklibs-readelf", "--print-soname", so_file)
     if soname_data:
-        return soname_data.pop()
+        name = soname_data.pop()
+        soname_cache.append((so_file, name))
+        return name
+    soname_cache.append((so_file, ""))
     return ""
 
 def usage(was_err):
@@ -479,12 +488,7 @@ while 1:
         for symbol in symbols:
             for name in symbol.base_names():
                 if name in symbol_provider:
-                    # in doubt, prefer symbols from libc
-                    if re.match("^libc[\.-]", library):
-                        library_symbols[library][name] = symbol
-                        symbol_provider[name] = library
-                    else:
-                        debug(DEBUG_SPAM, "duplicate symbol %s in %s and %s" % (symbol, symbol_provider[name], library))
+                    debug(DEBUG_SPAM, "duplicate symbol %s in %s and %s" % (symbol, symbol_provider[name], library))
                 else:
                     library_symbols[library][name] = symbol
                     symbol_provider[name] = library
@@ -540,7 +544,7 @@ while 1:
                 # may segfault in ptmalloc_init due to undefined weak reference
                 extra_pre_obj.append(sysroot + libc_extras_dir + "/soinit.o")
                 extra_post_obj.append(sysroot + libc_extras_dir + "/sofini.o")
-                symbols.add(ProvidedSymbol('__dso_handle', 'Base', True))
+                symbols.add(ProvidedSymbol('__dso_handle', 'Base@%s' % soname, True))
 
             map_file = find_pic_map(library)
             if map_file:

Reply to: