This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
ld --as-needed fixes (and static libc -z relro)
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sources dot redhat dot com
- Cc: Jakub Jelinek <jakub at redhat dot com>, Olaf Hering <olh at suse dot de>,Jon Grimm <jgrimm at us dot ibm dot com>, Anton Blanchard <antonb at au1 dot ibm dot com>
- Date: Tue, 25 Jan 2005 12:06:31 +1030
- Subject: ld --as-needed fixes (and static libc -z relro)
This patch fixes a number of problems with ld --as-needed. Firstly, if
an as-needed lib was found to be unneeded, its DT_NEEDED entries were
still linked. Easily fixed by the elf32.em:after_open change.
Secondly, dynamic sections were being created for as-needed libs before
the lib was found to be needed. This could result in a dynamic object
when in fact no dynamic libs were linked. Newer glibc ld.so complains
about this situation. Fixed by creating dynamic sections at the time we
add a DT_NEEDED tag for a library.
Finally, the first fix meant undefined symbols in the symbol table from
an as-needed lib that didn't actually get linked. Fixed with the tweak
to output_extsym.
This problem exhibited itself as segfaults trying to run rpcgen in a
static-only current glibc build. An as-needed libgcc_s.so was pulling
in libc.so.6 due to the dependency, which made the rpcgen executable
dynamic. rpcgen is built with -z relro, which makes certain data areas
read-only after relocation. The trouble was that ld.so was making some
variables read-only before the static libc-start.c code ran. When this
code tries to set __libc_stack_end, we get a segfault. I believe this
same segfault could occur if using a static libc, -z relro, and any
shared library. ie. the --as-needed problems just exposed a glibc bug.
bfd/
* elflink.c (elf_link_add_object_symbols): Don't create link dynamic
sections immediately when linking shared libs. Instead, wait until
we know a lib is needed.
(_bfd_elf_link_create_dynstrtab): Extract from..
(_bfd_elf_link_create_dynamic_sections_): ..here.
(elf_add_dt_needed_tag): Call _bfd_elf_link_create_dynstrtab and
_bfd_elf_link_create_dynamic_sections. Add abfd param. Allow
for non-existent .dynamic.
(elf_link_output_extsym): Don't complain about undefined symbols
in as-needed dynamic libs that aren't actually linked.
ld/
* emultempl/elf32.em (gld${EMULATION_NAME}_try_needed): Formatting.
(gld${EMULATION_NAME}_after_open): Ignore needed libs if they were
only needed by an as-needed lib that didn't get linked.
Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.123
diff -u -p -r1.123 elflink.c
--- bfd/elflink.c 19 Jan 2005 16:15:11 -0000 1.123
+++ bfd/elflink.c 24 Jan 2005 22:41:50 -0000
@@ -103,6 +103,25 @@ _bfd_elf_create_got_section (bfd *abfd,
return TRUE;
}
+/* Create a strtab to hold the dynamic symbol names. */
+static bfd_boolean
+_bfd_elf_link_create_dynstrtab (bfd *abfd, struct bfd_link_info *info)
+{
+ struct elf_link_hash_table *hash_table;
+
+ hash_table = elf_hash_table (info);
+ if (hash_table->dynobj == NULL)
+ hash_table->dynobj = abfd;
+
+ if (hash_table->dynstr == NULL)
+ {
+ hash_table->dynstr = _bfd_elf_strtab_init ();
+ if (hash_table->dynstr == NULL)
+ return FALSE;
+ }
+ return TRUE;
+}
+
/* Create some sections which will be filled in with dynamic linking
information. ABFD is an input file which requires dynamic sections
to be created. The dynamic sections take up virtual memory space
@@ -125,12 +144,10 @@ _bfd_elf_link_create_dynamic_sections (b
if (elf_hash_table (info)->dynamic_sections_created)
return TRUE;
- /* Make sure that all dynamic sections use the same input BFD. */
- if (elf_hash_table (info)->dynobj == NULL)
- elf_hash_table (info)->dynobj = abfd;
- else
- abfd = elf_hash_table (info)->dynobj;
+ if (!_bfd_elf_link_create_dynstrtab (abfd, info))
+ return FALSE;
+ abfd = elf_hash_table (info)->dynobj;
bed = get_elf_backend_data (abfd);
flags = bed->dynamic_sec_flags;
@@ -186,14 +203,6 @@ _bfd_elf_link_create_dynamic_sections (b
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY))
return FALSE;
- /* Create a strtab to hold the dynamic symbol names. */
- if (elf_hash_table (info)->dynstr == NULL)
- {
- elf_hash_table (info)->dynstr = _bfd_elf_strtab_init ();
- if (elf_hash_table (info)->dynstr == NULL)
- return FALSE;
- }
-
s = bfd_make_section (abfd, ".dynamic");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags)
@@ -2746,7 +2755,8 @@ _bfd_elf_add_dynamic_entry (struct bfd_l
1 if a DT_NEEDED tag already exists, and 0 on success. */
static int
-elf_add_dt_needed_tag (struct bfd_link_info *info,
+elf_add_dt_needed_tag (bfd *abfd,
+ struct bfd_link_info *info,
const char *soname,
bfd_boolean do_it)
{
@@ -2754,6 +2764,9 @@ elf_add_dt_needed_tag (struct bfd_link_i
bfd_size_type oldsize;
bfd_size_type strindex;
+ if (!_bfd_elf_link_create_dynstrtab (abfd, info))
+ return -1;
+
hash_table = elf_hash_table (info);
oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
@@ -2768,26 +2781,28 @@ elf_add_dt_needed_tag (struct bfd_link_i
bed = get_elf_backend_data (hash_table->dynobj);
sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
- BFD_ASSERT (sdyn != NULL);
-
- for (extdyn = sdyn->contents;
- extdyn < sdyn->contents + sdyn->size;
- extdyn += bed->s->sizeof_dyn)
- {
- Elf_Internal_Dyn dyn;
+ if (sdyn != NULL)
+ for (extdyn = sdyn->contents;
+ extdyn < sdyn->contents + sdyn->size;
+ extdyn += bed->s->sizeof_dyn)
+ {
+ Elf_Internal_Dyn dyn;
- bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn);
- if (dyn.d_tag == DT_NEEDED
- && dyn.d_un.d_val == strindex)
- {
- _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
- return 1;
- }
- }
+ bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn);
+ if (dyn.d_tag == DT_NEEDED
+ && dyn.d_un.d_val == strindex)
+ {
+ _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+ return 1;
+ }
+ }
}
if (do_it)
{
+ if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
+ return -1;
+
if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
return -1;
}
@@ -3282,11 +3297,6 @@ elf_link_add_object_symbols (bfd *abfd,
file. */
bfd_section_list_clear (abfd);
- /* If this is the first dynamic object found in the link, create
- the special sections required for dynamic linking. */
- if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
- goto error_return;
-
/* Find the name to use in a DT_NEEDED entry that refers to this
object. If the object has a DT_SONAME entry, we use it.
Otherwise, if the generic linker stuck something in
@@ -3303,7 +3313,7 @@ elf_link_add_object_symbols (bfd *abfd,
will need to know it. */
elf_dt_name (abfd) = soname;
- ret = elf_add_dt_needed_tag (info, soname, add_needed);
+ ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
if (ret < 0)
goto error_return;
@@ -3953,7 +3963,7 @@ elf_link_add_object_symbols (bfd *abfd,
elf_dyn_lib_class (abfd) &= ~DYN_AS_NEEDED;
add_needed = TRUE;
- ret = elf_add_dt_needed_tag (info, soname, add_needed);
+ ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
if (ret < 0)
goto error_free_vers;
@@ -6160,6 +6170,7 @@ elf_link_output_extsym (struct elf_link_
if (h->root.type == bfd_link_hash_undefined
&& h->ref_dynamic
&& !h->ref_regular
+ && (elf_dyn_lib_class (h->root.u.undef.abfd) & DYN_AS_NEEDED) == 0
&& ! elf_link_check_versioned_symbol (finfo->info, bed, h)
&& finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
{
Index: ld/emultempl/elf32.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/elf32.em,v
retrieving revision 1.125
diff -u -p -r1.125 elf32.em
--- ld/emultempl/elf32.em 16 Oct 2004 18:13:54 -0000 1.125
+++ ld/emultempl/elf32.em 24 Jan 2005 22:42:10 -0000
@@ -398,9 +398,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
/* Tell the ELF linker that we don't want the output file to have a
DT_NEEDED entry for this file at all if the entry is from a file
with DYN_NO_ADD_NEEDED. */
- if (needed->by
- && (bfd_elf_get_dyn_lib_class (needed->by)
- & DYN_NO_ADD_NEEDED) != 0)
+ if (needed->by != NULL
+ && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0)
class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED;
bfd_elf_set_dyn_lib_class (abfd, class);
@@ -785,9 +784,17 @@ gld${EMULATION_NAME}_after_open (void)
struct dt_needed n, nn;
int force;
+ /* If the lib that needs this one was --as-needed and wasn't
+ found to be needed, then this lib isn't needed either. */
+ if (l->by != NULL
+ && (bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0)
+ continue;
+
/* If we've already seen this file, skip it. */
for (ll = needed; ll != l; ll = ll->next)
- if (strcmp (ll->name, l->name) == 0)
+ if ((ll->by == NULL
+ || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0)
+ && strcmp (ll->name, l->name) == 0)
break;
if (ll != l)
continue;
--
Alan Modra
IBM OzLabs - Linux Technology Centre