This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]