This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] Fix DT_NEEDED when using -l:namespec
- From: Romain Geissler <romain dot geissler at amadeus dot com>
- To: binutils at sourceware dot org
- Cc: lenaic dot huard at laposte dot net
- Date: Sun, 16 Feb 2014 22:02:56 +0100
- Subject: [PATCH] Fix DT_NEEDED when using -l:namespec
- Authentication-results: sourceware.org; auth=none
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;
--