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]

Re: RFC: linker enhancements


I've renamed the option from --only-if-needed to --as-needed, and done
some surgery to elf_link_add_object_symbols.  Some changes were
necessary to have the right behaviour for weak syms in shared libs, and
to handle multiple inclusion of the same shared lib.  I've also removed
bfd_elf_set_dt_needed_soname and the hack that set an empty soname in
elf_dt_name for DT_NEEDED shared libs.  Instead, we call a new function,
bfd_elf_set_dyn_lib_class, to specify any special linker behaviour.

Applying mainline.

bfd/ChangeLog
	* elf-bfd.h (struct elf_obj_tdata): Delete dt_soname field.  Add
	dyn_lib_class field.  Rearrange for better packing.
	(elf_dt_soname): Delete.
	(elf_dyn_lib_class): Define.
	* elf.c (bfd_elf_set_dt_needed_name): Update comment.
	(bfd_elf_set_dt_needed_soname): Delete.
	(bfd_elf_set_dyn_lib_class): New function.
	* elflink.h (add_dt_needed_tag): New function.  Split out from..
	(elf_link_add_object_symbols): ..here.  Rename "name" to "soname".
	Use elf_dyn_lib_class to set dt_needed and add_needed.  Move fallback
	initialization of soname.
	(elf_link_check_versioned_symbol): Test elf_dyn_lib_class instead of
	elf_dt_soname.
	* bfd-in.h (enum dynamic_lib_link_class): New.
	(bfd_elf_set_dt_needed_soname): Delete.
	(bfd_elf_set_dyn_lib_class): Declare.
	* bfd-in2.h: Regenerate.

ld/ChangeLog
	* ld.texinfo: Add --as-needed doco.
	* ldmain.c (as_needed): New global var.
	* ldmain.h (as_needed): Declare.
	* lexsup.c (option_values): Add OPTION_AS_NEEDED and
	OPTION_NO_AS_NEEDED.
	(ld_options): Likewise.
	(parse_args): Handle them.
	* ldlang.h (lang_input_statement_type): Add as_needed field.
	* ldlang.c (new_afile): Set p->as_needed.
	* emultempl/elf32.em (gld${EMULATION_NAME}_load_symbols): New function.
	(gld${EMULATION_NAME}_try_needed): Use bfd_elf_set_dyn_lib_class.
	(ld_${EMULATION_NAME}_emulation): Set LDEMUL_RECOGNIZED_FILE entry.

	* ldlang.c (open_input_bfds): Remove useless cast.
	(lang_do_assignments_1): Likewise.
	(lang_for_each_input_section): Delete.

Index: bfd/bfd-in.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in.h,v
retrieving revision 1.74
diff -u -p -r1.74 bfd-in.h
--- bfd/bfd-in.h	15 Mar 2004 14:21:42 -0000	1.74
+++ bfd/bfd-in.h	18 Mar 2004 12:15:00 -0000
@@ -599,6 +599,12 @@ struct bfd_link_needed_list
   const char *name;
 };
 
+enum dynamic_lib_link_class {
+  DYN_NORMAL = 0,
+  DYN_AS_NEEDED = 1,
+  DYN_DT_NEEDED = 2
+};
+
 extern bfd_boolean bfd_elf_record_link_assignment
   (bfd *, struct bfd_link_info *, const char *, bfd_boolean);
 extern struct bfd_link_needed_list *bfd_elf_get_needed_list
@@ -613,10 +619,10 @@ extern bfd_boolean bfd_elf64_size_dynami
    struct bfd_link_info *, struct bfd_section **, struct bfd_elf_version_tree *);
 extern void bfd_elf_set_dt_needed_name
   (bfd *, const char *);
-extern void bfd_elf_set_dt_needed_soname
-  (bfd *, const char *);
 extern const char *bfd_elf_get_dt_soname
   (bfd *);
+extern void bfd_elf_set_dyn_lib_class
+  (bfd *, int);
 extern struct bfd_link_needed_list *bfd_elf_get_runpath_list
   (bfd *, struct bfd_link_info *);
 extern bfd_boolean bfd_elf32_discard_info
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.127
diff -u -p -r1.127 elf-bfd.h
--- bfd/elf-bfd.h	29 Feb 2004 06:11:52 -0000	1.127
+++ bfd/elf-bfd.h	18 Mar 2004 12:15:05 -0000
@@ -1132,9 +1132,6 @@ struct elf_obj_tdata
   bfd_vma gp;				/* The gp value */
   unsigned int gp_size;			/* The gp size */
 
-  Elf_Internal_Shdr **group_sect_ptr;
-  int num_group;
-
   /* Information grabbed from an elf core file.  */
   int core_signal;
   int core_pid;
@@ -1142,10 +1139,6 @@ struct elf_obj_tdata
   char* core_program;
   char* core_command;
 
-  /* This is set to TRUE if the object was created by the backend
-     linker.  */
-  bfd_boolean linker;
-
   /* A mapping from external symbols to entries in the linker hash
      table, used when linking.  This is indexed by the symbol index
      minus the sh_info field of the symbol table header.  */
@@ -1171,21 +1164,6 @@ struct elf_obj_tdata
      one.  */
   const char *dt_name;
 
-  /* When a reference in a regular object is resolved by a shared
-     object is loaded into via the DT_NEEDED entries by the linker
-     ELF emulation code, we need to add the shared object to the
-     DT_NEEDED list of the resulting binary to indicate the dependency
-     as if the -l option is passed to the linker. This field holds the
-     name of the loaded shared object.  */
-  const char *dt_soname;
-
-  /* Irix 5 often screws up the symbol table, sorting local symbols
-     after global symbols.  This flag is set if the symbol table in
-     this BFD appears to be screwed up.  If it is, we ignore the
-     sh_info field in the symbol table header, and always read all the
-     symbols.  */
-  bfd_boolean bad_symtab;
-
   /* Records the result of `get_program_header_size'.  */
   bfd_size_type program_header_size;
 
@@ -1213,8 +1191,8 @@ struct elf_obj_tdata
      created.  */
   asection *eh_frame_hdr;
 
-  /* Used to determine if the e_flags field has been initialized */
-  bfd_boolean flags_init;
+  Elf_Internal_Shdr **group_sect_ptr;
+  int num_group;
 
   /* Number of symbol version definitions we are about to emit.  */
   unsigned int cverdefs;
@@ -1237,6 +1215,25 @@ struct elf_obj_tdata
   asymbol *elf_text_symbol;
   asection *elf_data_section;
   asection *elf_text_section;
+
+  /* Whether a dyanmic object was specified normally on the linker
+     command line, or was specified when --as-needed was in effect,
+     or was found via a DT_NEEDED entry.  */
+  enum dynamic_lib_link_class dyn_lib_class;
+
+  /* This is set to TRUE if the object was created by the backend
+     linker.  */
+  bfd_boolean linker;
+
+  /* Irix 5 often screws up the symbol table, sorting local symbols
+     after global symbols.  This flag is set if the symbol table in
+     this BFD appears to be screwed up.  If it is, we ignore the
+     sh_info field in the symbol table header, and always read all the
+     symbols.  */
+  bfd_boolean bad_symtab;
+
+  /* Used to determine if the e_flags field has been initialized */
+  bfd_boolean flags_init;
 };
 
 #define elf_tdata(bfd)		((bfd) -> tdata.elf_obj_data)
@@ -1263,7 +1260,7 @@ struct elf_obj_tdata
 #define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets)
 #define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents)
 #define elf_dt_name(bfd)	(elf_tdata(bfd) -> dt_name)
-#define elf_dt_soname(bfd)	(elf_tdata(bfd) -> dt_soname)
+#define elf_dyn_lib_class(bfd)	(elf_tdata(bfd) -> dyn_lib_class)
 #define elf_bad_symtab(bfd)	(elf_tdata(bfd) -> bad_symtab)
 #define elf_flags_init(bfd)	(elf_tdata(bfd) -> flags_init)
 
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.218
diff -u -p -r1.218 elf.c
--- bfd/elf.c	5 Mar 2004 11:26:04 -0000	1.218
+++ bfd/elf.c	18 Mar 2004 12:15:08 -0000
@@ -1479,8 +1479,7 @@ _bfd_elf_link_hash_table_create (bfd *ab
 
 /* This is a hook for the ELF emulation code in the generic linker to
    tell the backend linker what file name to use for the DT_NEEDED
-   entry for a dynamic object.  The generic linker passes name as an
-   empty string to indicate that no DT_NEEDED entry should be made.  */
+   entry for a dynamic object.  */
 
 void
 bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
@@ -1491,11 +1490,11 @@ bfd_elf_set_dt_needed_name (bfd *abfd, c
 }
 
 void
-bfd_elf_set_dt_needed_soname (bfd *abfd, const char *name)
+bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class)
 {
   if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
       && bfd_get_format (abfd) == bfd_object)
-    elf_dt_soname (abfd) = name;
+    elf_dyn_lib_class (abfd) = lib_class;
 }
 
 /* Get the list of DT_NEEDED entries for a link.  This is a hook for
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.255
diff -u -p -r1.255 elflink.h
--- bfd/elflink.h	18 Mar 2004 04:32:17 -0000	1.255
+++ bfd/elflink.h	18 Mar 2004 12:15:11 -0000
@@ -68,6 +68,59 @@ sort_symbol (const void *arg1, const voi
     }
 }
 
+/* Add a DT_NEEDED entry for this dynamic object.  Returns -1 on error,
+   1 if a DT_NEEDED tag already exists, and 0 on success.  */
+
+static int
+add_dt_needed_tag (struct bfd_link_info *info, const char *soname,
+		   bfd_boolean do_it)
+{
+  struct elf_link_hash_table *hash_table;
+  bfd_size_type oldsize;
+  bfd_size_type strindex;
+
+  hash_table = elf_hash_table (info);
+  oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+  strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
+  if (strindex == (bfd_size_type) -1)
+    return -1;
+
+  if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
+    {
+      asection *sdyn;
+      Elf_External_Dyn *dyncon, *dynconend;
+
+      sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
+      BFD_ASSERT (sdyn != NULL);
+
+      dyncon = (Elf_External_Dyn *) sdyn->contents;
+      dynconend = (Elf_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+      for (; dyncon < dynconend; dyncon++)
+	{
+	  Elf_Internal_Dyn dyn;
+
+	  elf_swap_dyn_in (hash_table->dynobj, dyncon, & 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 (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+	return -1;
+    }
+  else
+    /* We were just checking for existence of the tag.  */
+    _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+
+  return 0;
+}
+
 /* Add symbols from an ELF object file to the linker hash table.  */
 
 static bfd_boolean
@@ -202,7 +255,7 @@ elf_link_add_object_symbols (bfd *abfd, 
     }
 
   dt_needed = FALSE;
-  add_needed = FALSE;
+  add_needed = TRUE;
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
@@ -224,10 +277,9 @@ elf_link_add_object_symbols (bfd *abfd, 
   else
     {
       asection *s;
-      const char *name;
-      bfd_size_type oldsize;
-      bfd_size_type strindex;
+      const char *soname = NULL;
       struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
+      int ret;
 
       /* ld --just-symbols and dynamic objects don't mix very well.
 	 Test for --just-symbols by looking at info set up by
@@ -236,26 +288,22 @@ elf_link_add_object_symbols (bfd *abfd, 
 	  && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
 	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
-	 elf_dt_name, we use that.  Otherwise, we just use the file
-	 name.  If the generic linker put a null string into
-	 elf_dt_name, we don't make a DT_NEEDED entry at all, even if
-	 there is a DT_SONAME entry.  */
-      add_needed = TRUE;
-      name = bfd_get_filename (abfd);
-      if (elf_dt_name (abfd) != NULL)
+      /* If this dynamic lib was specified on the command line with
+	 --as-needed in effect, then we don't want to add a DT_NEEDED
+	 tag unless the lib is actually used.
+	 For libs brought in by another lib's DT_NEEDED we do the same,
+	 and also modify handling of weak syms.  */
+      switch elf_dyn_lib_class (abfd)
 	{
-	  name = elf_dt_name (abfd);
-	  if (*name == '\0')
-	    {
-	      if (elf_dt_soname (abfd) != NULL)
-		dt_needed = TRUE;
-
-	      add_needed = FALSE;
-	    }
+	case DYN_NORMAL:
+	  break;
+	case DYN_DT_NEEDED:
+	  dt_needed = TRUE;
+	  /* Fall thru */
+	case DYN_AS_NEEDED:
+	  add_needed = FALSE;
 	}
+
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
 	{
@@ -287,8 +335,8 @@ elf_link_add_object_symbols (bfd *abfd, 
 	      if (dyn.d_tag == DT_SONAME)
 		{
 		  unsigned int tagv = dyn.d_un.d_val;
-		  name = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-		  if (name == NULL)
+		  soname = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+		  if (soname == NULL)
 		    goto error_free_dyn;
 		}
 	      if (dyn.d_tag == DT_NEEDED)
@@ -405,53 +453,31 @@ elf_link_add_object_symbols (bfd *abfd, 
       if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
 	goto error_return;
 
-      if (add_needed)
+      /* 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
+	 elf_dt_name, we use that.  Otherwise, we just use the file
+	 name.  */
+      if (soname == NULL || *soname == '\0')
 	{
-	  /* Add a DT_NEEDED entry for this dynamic object.  */
-	  oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
-	  strindex = _bfd_elf_strtab_add (hash_table->dynstr, name, FALSE);
-	  if (strindex == (bfd_size_type) -1)
-	    goto error_return;
-
-	  if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
-	    {
-	      asection *sdyn;
-	      Elf_External_Dyn *dyncon, *dynconend;
+	  soname = elf_dt_name (abfd);
+	  if (soname == NULL || *soname == '\0')
+	    soname = bfd_get_filename (abfd);
+	}
 
-	      /* The hash table size did not change, which means that
-		 the dynamic object name was already entered.  If we
-		 have already included this dynamic object in the
-		 link, just ignore it.  There is no reason to include
-		 a particular dynamic object more than once.  */
-	      sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
-	      BFD_ASSERT (sdyn != NULL);
-
-	      dyncon = (Elf_External_Dyn *) sdyn->contents;
-	      dynconend = (Elf_External_Dyn *) (sdyn->contents +
-						sdyn->_raw_size);
-	      for (; dyncon < dynconend; dyncon++)
-		{
-		  Elf_Internal_Dyn dyn;
-
-		  elf_swap_dyn_in (hash_table->dynobj, dyncon, & dyn);
-		  if (dyn.d_tag == DT_NEEDED
-		      && dyn.d_un.d_val == strindex)
-		    {
-		      _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
-		      return TRUE;
-		    }
-		}
-	    }
+      /* Save the SONAME because sometimes the linker emulation code
+	 will need to know it.  */
+      elf_dt_name (abfd) = soname;
 
-	  if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
-	    goto error_return;
-	}
+      ret = add_dt_needed_tag (info, soname, add_needed);
+      if (ret < 0)
+	goto error_return;
 
-      /* Save the SONAME, if there is one, because sometimes the
-	 linker emulation code will need to know it.  */
-      if (*name == '\0')
-	name = basename (bfd_get_filename (abfd));
-      elf_dt_name (abfd) = name;
+      /* If we have already included this dynamic object in the
+	 link, just ignore it.  There is no reason to include a
+	 particular dynamic object more than once.  */
+      if (ret > 0)
+	return TRUE;
     }
 
   /* If this is a dynamic object, we always link against the .dynsym
@@ -1051,49 +1077,21 @@ elf_link_add_object_symbols (bfd *abfd, 
 		break;
 	      }
 
-	  if (dt_needed && !add_needed && definition
+	  if (!add_needed && definition
 	      && (h->elf_link_hash_flags
 		  & ELF_LINK_HASH_REF_REGULAR) != 0)
 	    {
-	      bfd_size_type oldsize;
-	      bfd_size_type strindex;
-
-	      /* The symbol from a DT_NEEDED object is referenced from
-		 the regular object to create a dynamic executable. We
-		 have to make sure there is a DT_NEEDED entry for it.  */
+	      int ret;
 
+	      /* A symbol from a library loaded via DT_NEEDED of some
+		 other library is referenced by a regular object.
+		 Add a DT_NEEDED entry for it.  */
 	      add_needed = TRUE;
-	      oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
-	      strindex = _bfd_elf_strtab_add (hash_table->dynstr,
-					      elf_dt_soname (abfd), FALSE);
-	      if (strindex == (bfd_size_type) -1)
+	      ret = add_dt_needed_tag (info, elf_dt_name (abfd), add_needed);
+	      if (ret < 0)
 		goto error_free_vers;
 
-	      if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
-		{
-		  asection *sdyn;
-		  Elf_External_Dyn *dyncon, *dynconend;
-
-		  sdyn = bfd_get_section_by_name (hash_table->dynobj,
-						  ".dynamic");
-		  BFD_ASSERT (sdyn != NULL);
-
-		  dyncon = (Elf_External_Dyn *) sdyn->contents;
-		  dynconend = (Elf_External_Dyn *) (sdyn->contents +
-						    sdyn->_raw_size);
-		  for (; dyncon < dynconend; dyncon++)
-		    {
-		      Elf_Internal_Dyn dyn;
-
-		      elf_swap_dyn_in (hash_table->dynobj,
-				       dyncon, &dyn);
-		      BFD_ASSERT (dyn.d_tag != DT_NEEDED ||
-				  dyn.d_un.d_val != strindex);
-		    }
-		}
-
-	      if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
-		goto error_free_vers;
+	      BFD_ASSERT (ret == 0);
 	    }
 	}
     }
@@ -3950,7 +3948,8 @@ elf_link_check_versioned_symbol (struct 
     case bfd_link_hash_undefined:
     case bfd_link_hash_undefweak:
       abfd = h->root.u.undef.abfd;
-      if ((abfd->flags & DYNAMIC) == 0 || elf_dt_soname (abfd) == NULL)
+      if ((abfd->flags & DYNAMIC) == 0
+	  || elf_dyn_lib_class (abfd) != DYN_DT_NEEDED)
 	return FALSE;
       break;
 
Index: ld/ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.106
diff -u -p -r1.106 ld.texinfo
--- ld/ld.texinfo	1 Mar 2004 17:33:36 -0000	1.106
+++ ld/ld.texinfo	18 Mar 2004 12:15:41 -0000
@@ -972,6 +972,18 @@ behaviour from release 2.14 onwards is t
 so the @samp{--accept-unknown-input-arch} option has been added to
 restore the old behaviour.
 
+@kindex --as-needed
+@kindex --no-as-needed
+@item --as-needed
+@itemx --no-as-needed
+This option affects ELF DT_NEEDED tags for dynamic libraries mentioned
+on the command line after the @option{--as-needed} option.  Normally,
+the linker will add a DT_NEEDED tag for each dynamic library mentioned
+on the command line, regardless of whether the library is actually
+needed. @option{--as-needed} causes DT_NEEDED tags to only be emitted
+for libraries that satisfy some reference from regular objects.
+@option{--no-as-needed} restores the default behaviour.
+
 @kindex -assert @var{keyword}
 @item -assert @var{keyword}
 This option is ignored for SunOS compatibility.
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.140
diff -u -p -r1.140 ldlang.c
--- ld/ldlang.c	5 Mar 2004 11:26:04 -0000	1.140
+++ ld/ldlang.c	18 Mar 2004 12:15:43 -0000
@@ -445,6 +445,7 @@ new_afile (const char *name,
   p->next = NULL;
   p->symbol_count = 0;
   p->dynamic = config.dynamic_link;
+  p->as_needed = as_needed;
   p->whole_archive = whole_archive;
   p->loaded = FALSE;
   lang_statement_append (&input_file_chain,
@@ -1842,7 +1843,7 @@ open_input_bfds (lang_statement_union_ty
 	  /* Maybe we should load the file's symbols.  */
 	  if (s->wild_statement.filename
 	      && ! wildcardp (s->wild_statement.filename))
-	    (void) lookup_name (s->wild_statement.filename);
+	    lookup_name (s->wild_statement.filename);
 	  open_input_bfds (s->wild_statement.children.head, force);
 	  break;
 	case lang_group_statement_enum:
@@ -3348,8 +3349,7 @@ lang_do_assignments_1
 	    if (os->bfd_section != NULL)
 	      {
 		dot = os->bfd_section->vma;
-		(void) lang_do_assignments_1 (os->children.head, os,
-					      os->fill, dot);
+		lang_do_assignments_1 (os->children.head, os, os->fill, dot);
 		dot = (os->bfd_section->vma
 		       + TO_ADDR (os->bfd_section->_raw_size));
 
@@ -3937,24 +3937,6 @@ lang_for_each_file (void (*func) (lang_i
       func (f);
     }
 }
-
-#if 0
-
-/* Not used.  */
-
-void
-lang_for_each_input_section (void (*func) (bfd *ab, asection *as))
-{
-  LANG_FOR_EACH_INPUT_STATEMENT (f)
-    {
-      asection *s;
-
-      for (s = f->the_bfd->sections; s != NULL; s = s->next)
-	func (f->the_bfd, s);
-    }
-}
-
-#endif
 
 void
 ldlang_add_file (lang_input_statement_type *entry)
Index: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.35
diff -u -p -r1.35 ldlang.h
--- ld/ldlang.h	23 Feb 2004 10:10:01 -0000	1.35
+++ ld/ldlang.h	18 Mar 2004 12:15:44 -0000
@@ -264,6 +264,10 @@ typedef struct lang_input_statement_stru
   /* Whether to search for this entry as a dynamic archive.  */
   bfd_boolean dynamic;
 
+  /* Whether this entry should cause a DT_NEEDED tag only when
+     satisfying references from regular files, or always.  */
+  bfd_boolean as_needed;
+
   /* Whether to include the entire contents of an archive.  */
   bfd_boolean whole_archive;
 
Index: ld/ldmain.c
===================================================================
RCS file: /cvs/src/src/ld/ldmain.c,v
retrieving revision 1.78
diff -u -p -r1.78 ldmain.c
--- ld/ldmain.c	15 Feb 2004 02:24:53 -0000	1.78
+++ ld/ldmain.c	18 Mar 2004 12:15:45 -0000
@@ -93,6 +93,10 @@ bfd_boolean version_printed;
 /* Nonzero means link in every member of an archive.  */
 bfd_boolean whole_archive;
 
+/* Nonzero means create DT_NEEDED entries only if a dynamic library
+   actually satisfies some reference in a regular object.  */
+bfd_boolean as_needed;
+
 /* TRUE if we should demangle symbol names.  */
 bfd_boolean demangling;
 
Index: ld/ldmain.h
===================================================================
RCS file: /cvs/src/src/ld/ldmain.h,v
retrieving revision 1.7
diff -u -p -r1.7 ldmain.h
--- ld/ldmain.h	28 Jun 2003 05:28:54 -0000	1.7
+++ ld/ldmain.h	18 Mar 2004 12:15:45 -0000
@@ -32,6 +32,7 @@ extern bfd_boolean trace_files;
 extern bfd_boolean trace_file_tries;
 extern bfd_boolean version_printed;
 extern bfd_boolean whole_archive;
+extern bfd_boolean as_needed;
 extern bfd_boolean demangling;
 extern int g_switch_value;
 extern const char *output_filename;
Index: ld/lexsup.c
===================================================================
RCS file: /cvs/src/src/ld/lexsup.c,v
retrieving revision 1.70
diff -u -p -r1.70 lexsup.c
--- ld/lexsup.c	7 Dec 2003 00:08:41 -0000	1.70
+++ ld/lexsup.c	18 Mar 2004 12:15:45 -0000
@@ -112,6 +112,8 @@ enum option_values
   OPTION_SPLIT_BY_RELOC,
   OPTION_SPLIT_BY_FILE ,
   OPTION_WHOLE_ARCHIVE,
+  OPTION_AS_NEEDED,
+  OPTION_NO_AS_NEEDED,
   OPTION_WRAP,
   OPTION_FORCE_EXE_SUFFIX,
   OPTION_GC_SECTIONS,
@@ -438,6 +440,10 @@ static const struct ld_option ld_options
      TWO_DASHES },
   { {"whole-archive", no_argument, NULL, OPTION_WHOLE_ARCHIVE},
       '\0', NULL, N_("Include all objects from following archives"), TWO_DASHES },
+  { {"as-needed", no_argument, NULL, OPTION_AS_NEEDED},
+      '\0', NULL, N_("Only set DT_NEEDED for following dynamic libs if used"), TWO_DASHES },
+  { {"no-as-needed", no_argument, NULL, OPTION_NO_AS_NEEDED},
+      '\0', NULL, N_("Always set DT_NEEDED for following dynamic libs"), TWO_DASHES },
   { {"wrap", required_argument, NULL, OPTION_WRAP},
       '\0', N_("SYMBOL"), N_("Use wrapper functions for SYMBOL"), TWO_DASHES }
 };
@@ -1155,6 +1161,12 @@ parse_args (unsigned argc, char **argv)
 	  break;
 	case OPTION_WHOLE_ARCHIVE:
 	  whole_archive = TRUE;
+	  break;
+	case OPTION_AS_NEEDED:
+	  as_needed = TRUE;
+	  break;
+	case OPTION_NO_AS_NEEDED:
+	  as_needed = FALSE;
 	  break;
 	case OPTION_WRAP:
 	  add_wrap (optarg);
Index: ld/emultempl/elf32.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/elf32.em,v
retrieving revision 1.108
diff -u -p -r1.108 elf32.em
--- ld/emultempl/elf32.em	3 Jan 2004 12:39:07 -0000	1.108
+++ ld/emultempl/elf32.em	18 Mar 2004 12:15:47 -0000
@@ -89,6 +89,28 @@ gld${EMULATION_NAME}_before_parse (void)
 EOF
 fi
 
+if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then
+cat >>e${EMULATION_NAME}.c <<EOF
+/* Handle as_needed DT_NEEDED.  */
+
+static bfd_boolean
+gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
+{
+  if (!entry->as_needed
+      || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0)
+    return FALSE;
+
+  /* Tell the ELF linker that we don't want the output file to have a
+     DT_NEEDED entry for this file, unless it is used to resolve
+     references in a regular object.  */
+  bfd_elf_set_dyn_lib_class (entry->the_bfd, DYN_AS_NEEDED);
+
+  /* Continue on with normal load_symbols processing.  */
+  return FALSE;
+}
+EOF
+fi
+
 cat >>e${EMULATION_NAME}.c <<EOF
 
 /* These variables are required to pass information back and forth
@@ -336,14 +358,13 @@ cat >>e${EMULATION_NAME}.c <<EOF
       return TRUE;
     }
 
-  /* Tell the ELF backend that we don't want the output file to have a
-     DT_NEEDED entry for this file.  */
-  bfd_elf_set_dt_needed_name (abfd, "");
-
-  /* Tell the ELF backend that the output file needs a DT_NEEDED
-     entry for this file if it is used to resolve the reference in
-     a regular object.  */
-  bfd_elf_set_dt_needed_soname (abfd, soname);
+  /* Specify the soname to use.  */
+  bfd_elf_set_dt_needed_name (abfd, soname);
+
+  /* Tell the ELF linker that we don't want the output file to have a
+     DT_NEEDED entry for this file, unless it is used to resolve
+     references in a regular object.  */
+  bfd_elf_set_dyn_lib_class (abfd, DYN_DT_NEEDED);
 
   /* Add this file into the symbol table.  */
   if (! bfd_link_add_symbols (abfd, &link_info))
@@ -1752,7 +1773,7 @@ struct ld_emulation_xfer_struct ld_${EMU
   gld${EMULATION_NAME}_handle_option,
   ${LDEMUL_UNRECOGNIZED_FILE-NULL},
   ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
-  ${LDEMUL_RECOGNIZED_FILE-NULL},
+  ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL}
 };

-- 
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]