[PATCH] Fix DT_NEEDED when using -l:namespec

Romain Geissler romain.geissler@amadeus.com
Sun Feb 16 21:03:00 GMT 2014


Hi,

There is a behavior difference between ld (elf 64) and gold when specifying a lib with -l:mylib.so that is not the current working directory.
If y have a lib without DT_SONAME at path lib/liblib.so and if y try to link with both linkers using this command: g++ -o test test.cpp -Ilib -Llib -l:liblib.so

 - with ld.bfd:
readelf -d test|grep "liblib\.so"
 0x0000000000000001 (NEEDED)             Shared library: [lib/liblib.so]  

 - with ld.gold:
readelf -d test|grep "liblib\.so"  
 0x0000000000000001 (NEEDED)             Shared library: [liblib.so]  

In the first case, the search path is prepended to the DT_NEEDED entry. I think it’s a bug from ld.bfd, when we use -l flag, we never want the search path to be present when the lib has no SONAME.

This patch solves this issue, tested on elf x86_64 SLES 11 SP1 without regression.

ld/
2014-02-16  Romain Geissler  <romain.geissler@amadeus.com>

	* ldlang.h (full_name_provided): New input flag.
	* ldlang.c (new_afile): Set full_name_provided flag.
	* ldlfile.c (ldfile_open_file_search): Don't complete lib name if
	full_name_provided flag is set.
	* emultempl/elf32.em (gld${EMULATION_NAME}_open_dynamic_archive):
	Correctly set DT_NEEDED for dynamic libraries with loaded with
	-l:namespec.
	* emultempl/aix.em (ppc_after_open_output): Don't try to load lib specified
	with -l:namespec.
	* emultempl/linux.em (gld${EMULATION_NAME}_open_dynamic_archive): Likewise.
	* emultempl/pe.em (gld${EMULATION_NAME}_open_dynamic_archive): Likewise.
	* emultempl/pep.em (gld${EMULATION_NAME}_open_dynamic_archive): Likewise.
	* emultempl/vms.em (gld${EMULATION_NAME}_open_dynamic_archive): Likewise.

---
 ld/emultempl/aix.em   |  2 +-
 ld/emultempl/elf32.em | 61 ++++++++++++++++++++++++++++++++-------------------
 ld/emultempl/linux.em |  2 +-
 ld/emultempl/pe.em    |  2 +-
 ld/emultempl/pep.em   |  2 +-
 ld/emultempl/vms.em   |  2 +-
 ld/ldfile.c           |  2 +-
 ld/ldlang.c           | 15 ++++++-------
 ld/ldlang.h           |  3 +++
 9 files changed, 55 insertions(+), 36 deletions(-)

diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em
index d080133..4919ae6 100644
--- a/ld/emultempl/aix.em
+++ b/ld/emultempl/aix.em
@@ -1506,7 +1506,7 @@ gld${EMULATION_NAME}_open_dynamic_archive (const char *arch,
 {
   char *path;
 
-  if (!entry->flags.maybe_archive)
+  if (!entry->flags.maybe_archive || entry->flags.full_name_provided)
     return FALSE;
 
   path = concat (search->name, "/lib", entry->filename, arch, ".a", NULL);
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index fda0e68..89ad0d0 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -1664,36 +1664,52 @@ gld${EMULATION_NAME}_open_dynamic_archive
 
   filename = entry->filename;
 
-  /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION
-     is defined, but it does not seem worth the headache to optimize
-     away those two bytes of space.  */
-  string = (char *) xmalloc (strlen (search->name)
-			     + strlen (filename)
-			     + strlen (arch)
+  if (entry->flags.full_name_provided)
+    {
+      string = (char *) xmalloc (strlen (search->name) + strlen (filename));
+      sprintf (string, "%s/%s", search->name, filename);
+
+      if (! (ldfile_try_open_bfd (string, entry)
+             && bfd_check_format (entry->the_bfd, bfd_object)
+             && (entry->the_bfd->flags & DYNAMIC) != 0))
+        {
+          free (string);
+          return FALSE;
+        }
+    }
+  else
+    {
+      /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION
+         is defined, but it does not seem worth the headache to optimize
+         away those two bytes of space.  */
+      string = (char *) xmalloc (strlen (search->name)
+                                + strlen (filename)
+                                + strlen (arch)
 #ifdef EXTRA_SHLIB_EXTENSION
-			     + strlen (EXTRA_SHLIB_EXTENSION)
+                                + strlen (EXTRA_SHLIB_EXTENSION)
 #endif
-			     + sizeof "/lib.so");
+                                + sizeof "/lib.so");
 
-  sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
+      sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
 
 #ifdef EXTRA_SHLIB_EXTENSION
-  /* Try the .so extension first.  If that fails build a new filename
-     using EXTRA_SHLIB_EXTENSION.  */
-  if (! ldfile_try_open_bfd (string, entry))
-    {
-      sprintf (string, "%s/lib%s%s%s", search->name,
-	       filename, arch, EXTRA_SHLIB_EXTENSION);
+      /* Try the .so extension first.  If that fails build a new filename
+         using EXTRA_SHLIB_EXTENSION.  */
+      if (! ldfile_try_open_bfd (string, entry))
+        {
+          sprintf (string, "%s/lib%s%s%s", search->name,
+               filename, arch, EXTRA_SHLIB_EXTENSION);
 #endif
 
-  if (! ldfile_try_open_bfd (string, entry))
-    {
-      free (string);
-      return FALSE;
-    }
+      if (! ldfile_try_open_bfd (string, entry))
+        {
+          free (string);
+          return FALSE;
+        }
 #ifdef EXTRA_SHLIB_EXTENSION
-    }
+        }
 #endif
+    }
 
   entry->filename = string;
 
@@ -1718,7 +1734,8 @@ gld${EMULATION_NAME}_open_dynamic_archive
       /* Rather than duplicating the logic above.  Just use the
 	 filename we recorded earlier.  */
 
-      filename = lbasename (entry->filename);
+      if (!entry->flags.full_name_provided)
+        filename = lbasename (entry->filename);
       bfd_elf_set_dt_needed_name (entry->the_bfd, filename);
     }
 
diff --git a/ld/emultempl/linux.em b/ld/emultempl/linux.em
index 5cf5bfa..d9571ab 100644
--- a/ld/emultempl/linux.em
+++ b/ld/emultempl/linux.em
@@ -62,7 +62,7 @@ gld${EMULATION_NAME}_open_dynamic_archive
 {
   char *string;
 
-  if (! entry->flags.maybe_archive)
+  if (! entry->flags.maybe_archive || entry->flags.full_name_provided)
     return FALSE;
 
   string = (char *) xmalloc (strlen (search->name)
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 5d6da9e..a85c8a3 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -2108,7 +2108,7 @@ gld_${EMULATION_NAME}_open_dynamic_archive
   unsigned int i;
 
 
-  if (! entry->flags.maybe_archive)
+  if (! entry->flags.maybe_archive || entry->flags.full_name_provided)
     return FALSE;
 
   filename = entry->filename;
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index b738800..70469db 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -1879,7 +1879,7 @@ gld_${EMULATION_NAME}_open_dynamic_archive
   unsigned int i;
 
 
-  if (! entry->flags.maybe_archive)
+  if (! entry->flags.maybe_archive || entry->flags.full_name_provided)
     return FALSE;
 
   filename = entry->filename;
diff --git a/ld/emultempl/vms.em b/ld/emultempl/vms.em
index 30c1a16..6682208 100644
--- a/ld/emultempl/vms.em
+++ b/ld/emultempl/vms.em
@@ -58,7 +58,7 @@ gld${EMULATION_NAME}_open_dynamic_archive (const char *arch ATTRIBUTE_UNUSED,
 {
   char *string;
 
-  if (! entry->flags.maybe_archive)
+  if (! entry->flags.maybe_archive || entry->flags.full_name_provided)
     return FALSE;
 
   string = (char *) xmalloc (strlen (search->name)
diff --git a/ld/ldfile.c b/ld/ldfile.c
index 16baef8..0048183 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -369,7 +369,7 @@ ldfile_open_file_search (const char *arch,
 	    return TRUE;
 	}
 
-      if (entry->flags.maybe_archive)
+      if (entry->flags.maybe_archive && !entry->flags.full_name_provided)
 	string = concat (search->name, slash, lib, entry->filename,
 			 arch, suffix, (const char *) NULL);
       else
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 4768af7..e4a595c 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -1063,13 +1063,6 @@ new_afile (const char *name,
   p->flags.whole_archive = input_flags.whole_archive;
   p->flags.sysrooted = input_flags.sysrooted;
 
-  if (file_type == lang_input_file_is_l_enum
-      && name[0] == ':' && name[1] != '\0')
-    {
-      file_type = lang_input_file_is_search_file_enum;
-      name = name + 1;
-    }
-
   switch (file_type)
     {
     case lang_input_file_is_symbols_only_enum:
@@ -1083,7 +1076,13 @@ new_afile (const char *name,
       p->local_sym_name = name;
       break;
     case lang_input_file_is_l_enum:
-      p->filename = name;
+      if (name[0] == ':' && name[1] != '\0')
+        {
+          p->filename = name + 1;
+          p->flags.full_name_provided = TRUE;
+        }
+      else
+        p->filename = name;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
       p->flags.maybe_archive = TRUE;
       p->flags.real = TRUE;
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 7236c1c..b4624d8 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -235,6 +235,9 @@ struct lang_input_statement_flags
   /* 1 means this file was specified in a -l option.  */
   unsigned int maybe_archive : 1;
 
+  /* 1 means this file was specified in a -l:namespec option.  */
+  unsigned int full_name_provided : 1;
+
   /* 1 means search a set of directories for this file.  */
   unsigned int search_dirs : 1;
 
-- 



More information about the Binutils mailing list