[PATCH] Gold: Implement the '--discard-locals' and '-X' options.

Doug Kwan (關振德) dougkwan@google.com
Fri Jun 5 01:58:00 GMT 2009


This patch implements the '--discard-locals' option and an alias of it
'-X' which cause temporary local symbols to be dropped in output.  The
options are intended to match the behaviour of the same options in GNU
ld.  Some of the code was converted to C++ from C code in GNU ld and
libbfd.  This patch was tested on x86_64-unknow-linux-gnu and passed
all gold tests, including a new one in the patch.

-Doug

2009-06-04  Doug Kwan  <dougkwan@google.com>

        * i386.cc (class Target_i386): Define new virtual method to
        override do_is_local_label_name in parent.
        * object.cc (Sized_relobj::do_count_local_symbols): Discard
        local symbols if --discard-locals or -X is given.
        * options.h (class General_options): Declare new options
        '--discard-locals' and '-X' for discarding locals.
        * target.h (class Target): Define new methods is_local_label_name
        and do_is_local_label_name.
        * testsuite/Makefile.am (check_PROGRAMS): Add discard_locals_test.
        (check_SCRIPTS): Add discard_locals_test.sh.
        (check_DATA): Add discard_local_tests.syms.
        (discard_locals_test_SOURCES, discard_locals_test_LDFLAGS): Define.
        (discard_local_tests.syms, discard_locals_test.o): New make rules.
        * testsuite/Makefile.in: Regenerate.
        * testsuite/discard_locals_test.c: New file.
        * testsuite/discard_locals_test.sh: Same.
-------------- next part --------------
Index: gold/i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.86
diff -u -u -p -r1.86 i386.cc
--- gold/i386.cc	24 Mar 2009 00:31:28 -0000	1.86
+++ gold/i386.cc	5 Jun 2009 01:42:09 -0000
@@ -155,6 +155,19 @@ class Target_i386 : public Target_freebs
   do_is_defined_by_abi(const Symbol* sym) const
   { return strcmp(sym->name(), "___tls_get_addr") == 0; }
 
+  // Return whether a symbol name implies a local label.  The UnixWare
+  // 2.1 cc generates temporary symbols that start with .X, so we
+  // recognize them here.  FIXME: do other SVR4 compilers also use .X?.
+  // If so, we should move the .X recognition into
+  // Target::do_is_local_label_name.
+  bool
+  do_is_local_label_name(const char* name) const
+  {
+    if (name[0] == '.' && name[1] == 'X')
+      return true;
+    return Target::do_is_local_label_name(name);
+  }
+
   // Return the size of the GOT section.
   section_size_type
   got_size()
Index: gold/object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.91
diff -u -u -p -r1.91 object.cc
--- gold/object.cc	22 May 2009 18:31:22 -0000	1.91
+++ gold/object.cc	5 Jun 2009 01:42:09 -0000
@@ -1432,6 +1432,7 @@ Sized_relobj<size, big_endian>::do_count
   unsigned int dyncount = 0;
   // Skip the first, dummy, symbol.
   psyms += sym_size;
+  bool discard_locals = parameters->options().discard_locals();
   for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
     {
       elfcpp::Sym<size, big_endian> sym(psyms);
@@ -1476,8 +1477,28 @@ Sized_relobj<size, big_endian>::do_count
 	  continue;
 	}
 
-      // Add the symbol to the symbol table string pool.
+      // If --discard-locals option is used, discard all temporary local
+      // symbols.  These symbols start with system-specific local label
+      // prefixes, typically .L for ELF system.  We want to be compatible
+      // with GNU ld so here we essentially use the same check in
+      // bfd_is_local_label().  The code is different because we already
+      // know that:
+      //
+      //   - the symbol is local and thus cannot have global or weak binding.
+      //   - the symbol is not a section symbol.
+      //   - the symbol has a name.
+      //
       const char* name = pnames + sym.get_st_name();
+      if (discard_locals
+	  && sym.get_st_type() != elfcpp::STT_FILE
+	  && parameters->target().is_local_label_name(name))
+	{
+	  lv.set_no_output_symtab_entry();
+          gold_assert(!lv.needs_output_dynsym_entry());
+	  continue;
+	}
+
+      // Add the symbol to the symbol table string pool.
       pool->add(name, true, NULL);
       ++count;
 
Index: gold/options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.98
diff -u -u -p -r1.98 options.h
--- gold/options.h	19 May 2009 22:14:17 -0000	1.98
+++ gold/options.h	5 Jun 2009 01:42:09 -0000
@@ -645,6 +645,9 @@ class General_options
               N_("Try to detect violations of the One Definition Rule"),
               NULL);
 
+  DEFINE_bool(discard_locals, options::TWO_DASHES, 'X', false,
+              N_("Delete all temporary local symbols"), NULL);
+
   DEFINE_bool(dynamic_list_data, options::TWO_DASHES, '\0', false,
               N_("Add data symbols to dynamic symbols"), NULL);
 
Index: gold/target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.32
diff -u -u -p -r1.32 target.h
--- gold/target.h	24 Mar 2009 00:31:29 -0000	1.32
+++ gold/target.h	5 Jun 2009 01:42:09 -0000
@@ -173,6 +173,12 @@ class Target
   adjust_elf_header(unsigned char* view, int len) const
   { return this->do_adjust_elf_header(view, len); }
 
+  // Return whether NAME is a local label name.  This is used to implement the
+  // --discard-locals options.
+  bool
+  is_local_label_name(const char* name) const
+  { return this->do_is_local_label_name(name); }
+
  protected:
   // This struct holds the constant information for a child class.  We
   // use a struct to avoid the overhead of virtual function calls for
@@ -239,6 +245,33 @@ class Target
   do_adjust_elf_header(unsigned char*, int) const
   { }
 
+  // Virtual function which may be overriden by the child class.
+  virtual bool
+  do_is_local_label_name(const char* name) const
+  {
+    // The logic is the same as that in _bfd_elf_is_local_label_name().
+   
+    // Normal local symbols start with ``.L''.
+    if (name[0] == '.' && name[1] == 'L')
+      return true;
+
+    // At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
+    // DWARF debugging symbols starting with ``..''.
+    if (name[0] == '.' && name[1] == '.')
+      return true;
+
+    // gcc will sometimes generate symbols beginning with ``_.L_'' when
+    // emitting DWARF debugging output.  I suspect this is actually a
+    // small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
+    // ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
+    // underscore to be emitted on some ELF targets).  For ease of use,
+    // we treat such symbols as local.
+    if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+      return true;
+
+    return false;
+  }
+
  private:
   Target(const Target&);
   Target& operator=(const Target&);
Index: gold/testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.91
diff -u -u -p -r1.91 Makefile.am
--- gold/testsuite/Makefile.am	26 May 2009 22:52:56 -0000	1.91
+++ gold/testsuite/Makefile.am	5 Jun 2009 01:42:09 -0000
@@ -1074,5 +1074,17 @@ alt/libexclude_libs_test_3.a: exclude_li
 	test -d alt || mkdir -p alt
 	$(TEST_AR) rc $@ $^
 
+check_PROGRAMS += discard_locals_test
+check_SCRIPTS += discard_locals_test.sh
+check_DATA += discard_locals_test.syms
+MOSTLYCLEANFILES += discard_locals_test.syms
+discard_locals_test_SOURCES = discard_locals_test.c
+discard_locals_test_LDFLAGS = -Bgcctestdir/ -Wl,--discard-locals
+discard_locals_test.syms: discard_locals_test
+	$(TEST_READELF) -sW $< >$@ 2>/dev/null
+# '-Wa,--keep-locals' is required to preserve the local label used for testing.
+discard_locals_test.o: discard_locals_test.c
+	$(COMPILE) -c -Wa,--keep-locals -o $@ $<
+
 endif GCC
 endif NATIVE_LINKER
Index: gold/testsuite/Makefile.in
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.in,v
retrieving revision 1.96
diff -u -u -p -r1.96 Makefile.in
--- gold/testsuite/Makefile.in	26 May 2009 22:52:56 -0000	1.96
+++ gold/testsuite/Makefile.in	5 Jun 2009 01:42:09 -0000
@@ -318,12 +318,17 @@ check_PROGRAMS = object_unittest$(EXEEXT
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_2.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_4.err
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_24 = exclude_libs_test
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_25 = exclude_libs_test.sh
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = exclude_libs_test.syms
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = exclude_libs_test.syms libexclude_libs_test_1.a \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@        libexclude_libs_test_2.a alt/libexclude_libs_test_3.a
-
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_24 = exclude_libs_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	discard_locals_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_25 = exclude_libs_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	discard_locals_test.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_26 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	discard_locals_test.syms
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_27 = exclude_libs_test.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	libexclude_libs_test_1.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	libexclude_libs_test_2.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	alt/libexclude_libs_test_3.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	discard_locals_test.syms
 subdir = testsuite
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -429,7 +434,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_3$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_4$(EXEEXT)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_17 =  \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@	exclude_libs_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	exclude_libs_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	discard_locals_test$(EXEEXT)
 basic_pic_test_SOURCES = basic_pic_test.c
 basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
 basic_pic_test_LDADD = $(LDADD)
@@ -488,6 +494,14 @@ am__copy_test_SOURCES_DIST = copy_test.c
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_copy_test_OBJECTS =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	copy_test.$(OBJEXT)
 copy_test_OBJECTS = $(am_copy_test_OBJECTS)
+am__discard_locals_test_SOURCES_DIST = discard_locals_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am_discard_locals_test_OBJECTS =  \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	discard_locals_test.$(OBJEXT)
+discard_locals_test_OBJECTS = $(am_discard_locals_test_OBJECTS)
+discard_locals_test_LDADD = $(LDADD)
+discard_locals_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
+	../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am__exception_same_shared_test_SOURCES_DIST = exception_test_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_exception_same_shared_test_OBJECTS =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	exception_test_main.$(OBJEXT)
@@ -891,6 +905,7 @@ SOURCES = $(libgoldtest_a_SOURCES) basic
 	$(binary_test_SOURCES) $(binary_unittest_SOURCES) \
 	$(common_test_1_SOURCES) $(constructor_static_test_SOURCES) \
 	$(constructor_test_SOURCES) $(copy_test_SOURCES) \
+	$(discard_locals_test_SOURCES) \
 	$(exception_same_shared_test_SOURCES) \
 	$(exception_separate_shared_12_test_SOURCES) \
 	$(exception_separate_shared_21_test_SOURCES) \
@@ -944,6 +959,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) 
 	$(am__constructor_static_test_SOURCES_DIST) \
 	$(am__constructor_test_SOURCES_DIST) \
 	$(am__copy_test_SOURCES_DIST) \
+	$(am__discard_locals_test_SOURCES_DIST) \
 	$(am__exception_same_shared_test_SOURCES_DIST) \
 	$(am__exception_separate_shared_12_test_SOURCES_DIST) \
 	$(am__exception_separate_shared_21_test_SOURCES_DIST) \
@@ -1519,6 +1535,8 @@ binary_unittest_SOURCES = binary_unittes
 @GCC_TRUE@@NATIVE_LINKER_TRUE@exclude_libs_test_LDADD = -lexclude_libs_test_1 -lexclude_libs_test_2 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	alt/libexclude_libs_test_3.a
 
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test_SOURCES = discard_locals_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test_LDFLAGS = -Bgcctestdir/ -Wl,--discard-locals
 all: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -1605,6 +1623,9 @@ constructor_test$(EXEEXT): $(constructor
 copy_test$(EXEEXT): $(copy_test_OBJECTS) $(copy_test_DEPENDENCIES) 
 	@rm -f copy_test$(EXEEXT)
 	$(CXXLINK) $(copy_test_LDFLAGS) $(copy_test_OBJECTS) $(copy_test_LDADD) $(LIBS)
+discard_locals_test$(EXEEXT): $(discard_locals_test_OBJECTS) $(discard_locals_test_DEPENDENCIES) 
+	@rm -f discard_locals_test$(EXEEXT)
+	$(LINK) $(discard_locals_test_LDFLAGS) $(discard_locals_test_OBJECTS) $(discard_locals_test_LDADD) $(LIBS)
 exception_same_shared_test$(EXEEXT): $(exception_same_shared_test_OBJECTS) $(exception_same_shared_test_DEPENDENCIES) 
 	@rm -f exception_same_shared_test$(EXEEXT)
 	$(CXXLINK) $(exception_same_shared_test_LDFLAGS) $(exception_same_shared_test_OBJECTS) $(exception_same_shared_test_LDADD) $(LIBS)
@@ -1882,6 +1903,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constructor_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/discard_locals_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_main.Po@am__quote@
@@ -2613,6 +2635,11 @@ uninstall-am: uninstall-info-am
 @GCC_TRUE@@NATIVE_LINKER_TRUE@alt/libexclude_libs_test_3.a: exclude_libs_test_3.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	test -d alt || mkdir -p alt
 @GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc $@ $^
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test.syms: discard_locals_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_READELF) -sW $< >$@ 2>/dev/null
+# '-Wa,--keep-locals' is required to preserve the local label used for testing.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@discard_locals_test.o: discard_locals_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(COMPILE) -c -Wa,--keep-locals -o $@ $<
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
Index: gold/testsuite/discard_locals_test.c
===================================================================
RCS file: gold/testsuite/discard_locals_test.c
diff -N gold/testsuite/discard_locals_test.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/discard_locals_test.c	5 Jun 2009 01:42:09 -0000
@@ -0,0 +1,40 @@
+/* discard_locals_test.c -- test --discard-locals option.
+
+   Copyright 2009 Free Software Foundation, Inc.
+   Doug Kwan <dougkwan@google.com>.
+
+   This file is part of gold.
+
+   This program 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.
+
+   This is a test of a common symbol in the main program and a
+   versioned symbol in a shared library.  The common symbol in the
+   main program should override the shared library symbol.  */
+
+int
+main (void)
+{
+  /* local symbol format for generic ELF target. */
+  asm (".Lshould_be_discarded:");
+
+#ifdef __i386__
+  /* additional local symbol format for the i386 target. */
+  asm (".Xshould_be_discarded:");
+#endif
+
+  return 0;
+}
+
Index: gold/testsuite/discard_locals_test.sh
===================================================================
RCS file: gold/testsuite/discard_locals_test.sh
diff -N gold/testsuite/discard_locals_test.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/discard_locals_test.sh	5 Jun 2009 01:42:09 -0000
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# discard_locals_test.sh -- test that local symbols are discarded.
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# This file is part of gold.
+
+# This program 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This file goes with exclude_libs_test.c, a C source file
+# linked with option -Wl,--exclude-libs. We run readelf on
+# the resulting executable and check that symbols from two test library
+# archives are correctly hidden or left unmodified.
+
+check()
+{
+    file=$1
+
+    found=`egrep "should_be_discarded" $file`
+    if test -n "$found"; then
+	echo "These local symbols are not discarded in $file:"
+	echo "$found"
+	exit 1
+    fi
+}
+
+check "discard_locals_test.syms"
+
+exit 0


More information about the Binutils mailing list