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]

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


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