This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Implement --exclude-libs for ELF
- From: Daniel Jacobowitz <drow at false dot org>
- To: binutils at sources dot redhat dot com
- Date: Wed, 13 Oct 2004 12:38:22 -0400
- Subject: Implement --exclude-libs for ELF
The i386 PE port has an option, --exclude-libs, which lets the linker
default to not exporting symbols imported from archives. I came across a
need for this for ELF - much like the .oS stubs from libgcc, but in a case
where changing the archive wasn't feasible in the build procedure. So I
implemented --exclude-libs for ELF.
As the documentation says, it's not 100% the same as the PE version; in PE,
a .def file overrides --exclude-libs, but in ELF, it doesn't. This is
mostly because it was easier to implement.
OK? Fundamental problems?
--
Daniel Jacobowitz
2004-10-13 Daniel Jacobowitz <dan@debian.org>
* bfd-in2.h: Regenerate.
* bfd.c (struct bfd): Add no_export.
* elflink.c (elf_link_add_object_symbols): Handle no_export.
2004-10-13 Daniel Jacobowitz <dan@debian.org>
* ldlang.c (struct excluded_lib, excluded_libs, add_excluded_libs)
(check_excluded_libs): New.
(load_symbols): Call check_excluded_libs.
* ldlang.h (add_excluded_libs): New prototype.
* emultempl/elf32.em (OPTION_EXCLUDED_LIBS): Define.
(gld${EMULATION_NAME}_add_options): Add --exclude-libs.
(gld${EMULATION_NAME}_handle_option): Handle --exclude-libs.
* ld.texinfo (Command Line Variables): Document --exclude-libs.
(Options Specific to i386 PE Targets): Remove --exclude-libs.
2004-10-13 Daniel Jacobowitz <dan@debian.org>
* ld-elf/exclude1.s, ld-elf/exclude2.s, ld-elf/exclude.exp: New.
Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.304
diff -u -p -r1.304 bfd-in2.h
--- bfd/bfd-in2.h 8 Oct 2004 14:53:55 -0000 1.304
+++ bfd/bfd-in2.h 13 Oct 2004 16:23:25 -0000
@@ -3962,6 +3962,9 @@ struct bfd
/* Pointer to structure which contains architecture information. */
const struct bfd_arch_info *arch_info;
+ /* Flag set if symbols from this BFD should not be exported. */
+ bfd_boolean no_export;
+
/* Stuff only useful for archives. */
void *arelt_data;
struct bfd *my_archive; /* The containing archive BFD. */
Index: bfd/bfd.c
===================================================================
RCS file: /cvs/src/src/bfd/bfd.c,v
retrieving revision 1.69
diff -u -p -r1.69 bfd.c
--- bfd/bfd.c 4 Sep 2004 01:30:21 -0000 1.69
+++ bfd/bfd.c 13 Oct 2004 16:23:26 -0000
@@ -133,6 +133,9 @@ CODE_FRAGMENT
. {* Pointer to structure which contains architecture information. *}
. const struct bfd_arch_info *arch_info;
.
+. {* Flag set if symbols from this BFD should not be exported. *}
+. bfd_boolean no_export;
+.
. {* Stuff only useful for archives. *}
. void *arelt_data;
. struct bfd *my_archive; {* The containing archive BFD. *}
Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.110
diff -u -p -r1.110 elflink.c
--- bfd/elflink.c 12 Oct 2004 02:27:53 -0000 1.110
+++ bfd/elflink.c 13 Oct 2004 16:23:26 -0000
@@ -3778,6 +3778,14 @@ elf_link_add_object_symbols (bfd *abfd,
(*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
dynamic);
+ /* If this symbol has default visibility and the user has requested
+ we not re-export it, then mark it as hidden. */
+ if (definition && !dynamic
+ && (abfd->no_export
+ || (abfd->my_archive && abfd->my_archive->no_export))
+ && ELF_ST_VISIBILITY (isym->st_other) == STV_DEFAULT)
+ isym->st_other = STV_HIDDEN | (isym->st_other & ~ ELF_ST_VISIBILITY (-1));
+
if (isym->st_other != 0 && !dynamic)
{
unsigned char hvis, symvis, other, nvis;
Index: ld/ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.126
diff -u -p -r1.126 ld.texinfo
--- ld/ld.texinfo 8 Oct 2004 00:22:13 -0000 1.126
+++ ld/ld.texinfo 13 Oct 2004 16:31:47 -0000
@@ -449,6 +449,17 @@ base 10; you may use a leading @samp{0x}
@samp{0} for base 8). @xref{Entry Point}, for a discussion of defaults
and other ways of specifying the entry point.
+@kindex --exclude-libs
+@item --exclude-libs @var{lib},@var{lib},...
+Specifies a list of archive libraries from which symbols should not be automatically
+exported. The library names may be delimited by commas or colons. Specifying
+@code{--exclude-libs ALL} excludes symbols in all archive libraries from
+automatic export. This option is available only for the i386 PE targeted
+port of the linker and for ELF targeted ports. For i386 PE, symbols
+explicitly listed in a .def file are still exported, regardless of this
+option. For ELF targeted ports, symbols affected by this option will
+be treated as hidden.
+
@cindex dynamic symbol table
@kindex -E
@kindex --export-dynamic
@@ -1884,15 +1895,6 @@ Specifies a list of symbols which should
exported. The symbol names may be delimited by commas or colons.
[This option is specific to the i386 PE targeted port of the linker]
-@kindex --exclude-libs
-@item --exclude-libs @var{lib},@var{lib},...
-Specifies a list of archive libraries from which symbols should not be automatically
-exported. The library names may be delimited by commas or colons. Specifying
-@code{--exclude-libs ALL} excludes symbols in all archive libraries from
-automatic export. Symbols explicitly listed in a .def file are still exported,
-regardless of this option.
-[This option is specific to the i386 PE targeted port of the linker]
-
@kindex --file-alignment
@item --file-alignment
Specify the file alignment. Sections in the file will always begin at
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.164
diff -u -p -r1.164 ldlang.c
--- ld/ldlang.c 4 Oct 2004 16:45:51 -0000 1.164
+++ ld/ldlang.c 13 Oct 2004 16:23:34 -0000
@@ -1310,6 +1310,67 @@ lookup_name (const char *name)
return search;
}
+/* Save LIST as a list of libraries whose symbols should not be exported. */
+
+struct excluded_lib
+{
+ char *name;
+ struct excluded_lib *next;
+};
+static struct excluded_lib *excluded_libs;
+
+void
+add_excluded_libs (const char *list)
+{
+ const char *p = list, *end;
+
+ while (*p != '\0')
+ {
+ struct excluded_lib *entry;
+ end = strpbrk (p, ",:");
+ if (end == NULL)
+ end = p + strlen (p);
+ entry = xmalloc (sizeof (*entry));
+ entry->next = excluded_libs;
+ entry->name = xmalloc (end - p + 1);
+ memcpy (entry->name, p, end - p);
+ entry->name[end - p] = '\0';
+ excluded_libs = entry;
+ if (*end == '\0')
+ break;
+ p = end + 1;
+ }
+}
+
+static void
+check_excluded_libs (bfd *abfd)
+{
+ struct excluded_lib *lib = excluded_libs;
+
+ while (lib)
+ {
+ int len = strlen (lib->name);
+ const char *filename = lbasename (abfd->filename);
+
+ if (strcmp (lib->name, "ALL") == 0)
+ {
+ abfd->no_export = TRUE;
+ return;
+ }
+
+ if (strncmp (lib->name, filename, len) == 0
+ && (filename[len] == '\0'
+ || (filename[len] == '.' && filename[len + 1] == 'a'
+ && filename[len + 2] == '\0')))
+ {
+ abfd->no_export = TRUE;
+ return;
+ }
+
+ lib = lib->next;
+ }
+}
+
/* Get the symbols for an input file. */
static bfd_boolean
@@ -1394,6 +1455,8 @@ load_symbols (lang_input_statement_type
break;
case bfd_archive:
+ check_excluded_libs (entry->the_bfd);
+
if (entry->whole_archive)
{
bfd *member = NULL;
Index: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.39
diff -u -p -r1.39 ldlang.h
--- ld/ldlang.h 19 Jul 2004 16:40:52 -0000 1.39
+++ ld/ldlang.h 13 Oct 2004 16:23:34 -0000
@@ -572,4 +572,6 @@ extern int lang_symbol_definition_iterat
extern void lang_update_definedness
(const char *, struct bfd_link_hash_entry *);
+extern void add_excluded_libs (const char *);
+
#endif
Index: ld/emultempl/elf32.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/elf32.em,v
retrieving revision 1.123
diff -u -p -r1.123 elf32.em
--- ld/emultempl/elf32.em 11 Oct 2004 14:42:30 -0000 1.123
+++ ld/emultempl/elf32.em 13 Oct 2004 16:23:34 -0000
@@ -1730,7 +1730,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1)
#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1)
#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1)
-
+#define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1)
+
static void
gld${EMULATION_NAME}_add_options
(int ns, char **shortopts, int nl, struct option **longopts,
@@ -1745,6 +1746,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
{"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
{"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
{"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
+ {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS},
{"Bgroup", no_argument, NULL, OPTION_GROUP},
EOF
fi
@@ -1797,6 +1799,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR;
break;
+ case OPTION_EXCLUDE_LIBS:
+ add_excluded_libs (optarg);
+ break;
+
case 'z':
if (strcmp (optarg, "initfirst") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST;
Index: ld/testsuite/ld-elf/exclude.exp
===================================================================
RCS file: ld/testsuite/ld-elf/exclude.exp
diff -N ld/testsuite/ld-elf/exclude.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-elf/exclude.exp 13 Oct 2004 16:23:34 -0000
@@ -0,0 +1,137 @@
+# Expect script for --exclude-libs tests
+# Copyright 2004 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Make sure that ld can hide symbols from libraries when building a shared
+# library.
+
+# This test can only be run on ELF platforms.
+if ![is_elf_format] {
+ return
+}
+
+# No shared lib support on this target.
+if { [istarget "mcore-*-*"] } {
+ return
+}
+
+global ar
+global as
+global ld
+global nm
+global nm_output
+
+set test1 "ld link shared library"
+set test2 "ld export symbols from archive"
+set test3 "ld link shared library with --exclude-libs"
+set test4 "ld exclude symbols from archive - --exclude-libs libexclude"
+set test5 "ld exclude symbols from archive - --exclude-libs libexclude.a"
+set test6 "ld exclude symbols from archive - --exclude-libs ALL"
+set test7 "ld exclude symbols from archive - --exclude-libs foo:libexclude.a"
+set test8 "ld exclude symbols from archive - --exclude-libs foo,libexclude.a"
+set test9 "ld don't exclude symbols from archive - --exclude-libs foo:bar"
+
+if { ![ld_assemble $as $srcdir/$subdir/exclude1.s tmpdir/exclude1.o ]
+ || ![ld_assemble $as $srcdir/$subdir/exclude2.s tmpdir/exclude2.o] } {
+ unresolved $test1
+ return
+}
+
+catch "exec rm -f tmpdir/libexclude.a" catch_output
+catch "exec $ar cq tmpdir/libexclude.a tmpdir/exclude2.o" catch_output
+if {![string match "" $catch_output]} {
+ unresolved $test1
+ return
+}
+
+# Test that the symbol is normally exported.
+
+if { [ld_simple_link $ld tmpdir/exclude.so "--shared tmpdir/exclude1.o -Ltmpdir -lexclude"] } {
+ pass $test1
+} else {
+ if [string match "*shared not supported*" $link_output] {
+ unsupported "$test1 - -shared is not supported by this target"
+ } else {
+ fail $test1
+ }
+ return
+}
+
+if ![ld_nm $nm "-D" tmpdir/exclude.so] {
+ unresolved $test2
+} elseif { [info exists nm_output(exclude_sym)] } {
+ pass $test2
+} else {
+ fail $test2
+}
+
+# Test --exclude-libs libexclude
+
+if { [ld_simple_link $ld tmpdir/exclude.so "--exclude-libs libexclude --shared tmpdir/exclude1.o -Ltmpdir -lexclude"] } {
+ pass $test3
+} else {
+ fail $test3
+}
+
+if ![ld_nm $nm "-D" tmpdir/exclude.so] {
+ unresolved $test4
+} elseif { ! [info exists nm_output(exclude_sym)] } {
+ pass $test4
+} else {
+ fail $test4
+}
+
+# Test alternate spellings of --exclude-libs
+
+if { [ld_simple_link $ld tmpdir/exclude.so "--exclude-libs libexclude.a --shared tmpdir/exclude1.o -Ltmpdir -lexclude"]
+ && [ld_nm $nm "-D" tmpdir/exclude.so]
+ && ! [info exists nm_output(exclude_sym)] } {
+ pass $test5
+} else {
+ fail $test5
+}
+
+if { [ld_simple_link $ld tmpdir/exclude.so "--exclude-libs ALL --shared tmpdir/exclude1.o -Ltmpdir -lexclude"]
+ && [ld_nm $nm "-D" tmpdir/exclude.so]
+ && ! [info exists nm_output(exclude_sym)] } {
+ pass $test6
+} else {
+ fail $test6
+}
+
+if { [ld_simple_link $ld tmpdir/exclude.so "--exclude-libs foo:libexclude.a --shared tmpdir/exclude1.o -Ltmpdir -lexclude"]
+ && [ld_nm $nm "-D" tmpdir/exclude.so]
+ && ! [info exists nm_output(exclude_sym)] } {
+ pass $test7
+} else {
+ fail $test7
+}
+
+if { [ld_simple_link $ld tmpdir/exclude.so "--exclude-libs foo,libexclude.a --shared tmpdir/exclude1.o -Ltmpdir -lexclude"]
+ && [ld_nm $nm "-D" tmpdir/exclude.so]
+ && ! [info exists nm_output(exclude_sym)] } {
+ pass $test8
+} else {
+ fail $test8
+}
+
+if { [ld_simple_link $ld tmpdir/exclude.so "--exclude-libs foo:bar --shared tmpdir/exclude1.o -Ltmpdir -lexclude"]
+ && [ld_nm $nm "-D" tmpdir/exclude.so]
+ && [info exists nm_output(exclude_sym)] } {
+ pass $test9
+} else {
+ fail $test9
+}
Index: ld/testsuite/ld-elf/exclude1.s
===================================================================
RCS file: ld/testsuite/ld-elf/exclude1.s
diff -N ld/testsuite/ld-elf/exclude1.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-elf/exclude1.s 13 Oct 2004 16:23:34 -0000
@@ -0,0 +1,3 @@
+ .globl include_sym
+include_sym:
+ .long exclude_sym - include_sym
Index: ld/testsuite/ld-elf/exclude2.s
===================================================================
RCS file: ld/testsuite/ld-elf/exclude2.s
diff -N ld/testsuite/ld-elf/exclude2.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-elf/exclude2.s 13 Oct 2004 16:23:34 -0000
@@ -0,0 +1,3 @@
+ .globl exclude_sym
+exclude_sym:
+ .long 0