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


On Fri, Dec 12, 2003 at 03:29:14PM +0100, Jakub Jelinek wrote:
> On Fri, Dec 12, 2003 at 08:29:18AM -0800, Zack Weinberg wrote:
> > >    E.g. for libgcc_s for C dynamically linked programs which are using
> > >    -fexceptions (which is quite rare these days), GCC currently links
> > >    in libgcc_eh.a.  It would be better to link against libgcc_s in that
> > >    case (so that there is just one unwinder etc.), on the other side
> > >    for the 99% of C dynamically linked programs which don't need it
> > >    linking against a shared library they don't use is a waste.
> > 
> > I've suggested before that *all* shared libraries should get
> > DT_NEEDED-ed into the executable only if they resolve undefined
> > symbols - "just like" static libraries.  (Check over your system and
> > see how many applications load libnsl, though it's totally
> > unnecessary, because they used AC_CHECK_LIB instead of AC_SEARCH_LIBS
> > in their configure script.)
> 
> That would break a lot of programs which assume -lfoo means the library
> will be in DT_NEEDED.
> Which is why I think it should be user selectable.  You could enable that
> behaviour on the start of the cmd line for all libraries if you want, etc.

I've just thrown together a linker change to implement an as-needed
DT_NEEDED tag.  Most of the infrastructure was already in the linker,
so it wasn't too difficult.  The options I chose, --only-if-needed and
--no-only-if-needed sound somewhat illiterate, but follow the tradition
of --whole-archive and --no-whole-archive.  Better ideas on naming
welcomed.

One side-effect of this patch is that when --only-if-needed is in
effect, weak definitions in normal files won't be overridden by
a strong definition in a shared library.  I'm not sure whether that's
a bug or a feature..

$ gcc -B./ -O2 -o hello /src/tmp/hello.c -lm
$ readelf -d hello

Dynamic segment at offset 0x47c contains 21 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libm.so.6]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x8048260
[snip]
$ gcc -B./ -O2 -o hello /src/tmp/hello.c -Wl,--only-if-needed -lm
$ readelf -d hello

Dynamic segment at offset 0x46c contains 20 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x8048258
[snip]

Testing so far has been very light..  I'm aiming to test this as part of
a fix for http://sources.redhat.com/ml/libc-alpha/2004-01/msg00300.html

	* ldmain.c (only_if_needed): New global var.
	* ldmain.h (only_if_needed): Declare.
	* lexsup.c (option_values): Add OPTION_ONLY_IF_NEEDED and
	OPTION_NO_ONLY_IF_NEEDED.
	(ld_options): Likewise.
	(parse_args): Handle them.
	* ldlang.h (lang_input_statement_type): Add only_if_needed field.
	* ldlang.c (new_afile): Set p->only_if_needed.
	* emultempl/elf32.em (gld${EMULATION_NAME}_load_symbols): New function.
	(ld_${EMULATION_NAME}_emulation): Set LDEMUL_RECOGNIZED_FILE entry.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

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	17 Mar 2004 04:00:51 -0000
@@ -445,6 +445,7 @@ new_afile (const char *name,
   p->next = NULL;
   p->symbol_count = 0;
   p->dynamic = config.dynamic_link;
+  p->only_if_needed = only_if_needed;
   p->whole_archive = whole_archive;
   p->loaded = FALSE;
   lang_statement_append (&input_file_chain,
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	17 Mar 2004 04:00:51 -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 only_if_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	17 Mar 2004 04:00:52 -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 only_if_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	17 Mar 2004 04:00:52 -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 only_if_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	17 Mar 2004 04:00:53 -0000
@@ -112,6 +112,8 @@ enum option_values
   OPTION_SPLIT_BY_RELOC,
   OPTION_SPLIT_BY_FILE ,
   OPTION_WHOLE_ARCHIVE,
+  OPTION_ONLY_IF_NEEDED,
+  OPTION_NO_ONLY_IF_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 },
+  { {"only-if-needed", no_argument, NULL, OPTION_ONLY_IF_NEEDED},
+      '\0', NULL, N_("Only set DT_NEEDED for following dynamic libs if used"), TWO_DASHES },
+  { {"no-only-if-needed", no_argument, NULL, OPTION_NO_ONLY_IF_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_ONLY_IF_NEEDED:
+	  only_if_needed = TRUE;
+	  break;
+	case OPTION_NO_ONLY_IF_NEEDED:
+	  only_if_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	17 Mar 2004 04:00:54 -0000
@@ -89,6 +89,35 @@ 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 only_if_needed DT_NEEDED.  */
+
+static bfd_boolean
+gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
+{
+  const char *soname;
+
+  if (!entry->only_if_needed
+      || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0)
+    return FALSE;
+
+  soname = bfd_elf_get_dt_soname (entry->the_bfd);
+  if (soname == NULL)
+    soname = lbasename (bfd_get_filename (entry->the_bfd));
+
+  /* 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_dt_needed_name (entry->the_bfd, "");
+  bfd_elf_set_dt_needed_soname (entry->the_bfd, soname);
+
+  /* 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
@@ -1752,7 +1781,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}
 };


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