This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: RFC: linker enhancements
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: Jakub Jelinek <jakub at redhat dot com>,Marcus Meissner <meissner at suse dot de>
- Cc: Michael Matz <matz at suse dot de>,Zack Weinberg <zack at codesourcery dot com>, binutils at sources dot redhat dot com
- Date: Wed, 17 Mar 2004 14:54:18 +1030
- Subject: Re: RFC: linker enhancements
- References: <20031212112448.GI12344@sunsite.ms.mff.cuni.cz> <87wu92xan5.fsf@egil.codesourcery.com> <20031212142914.GK12344@sunsite.ms.mff.cuni.cz>
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}
};