about summary refs log tree commit diff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2012-06-30 12:53:04 -0700
committerH.J. Lu <hjl.tools@gmail.com>2015-09-15 08:56:05 -0700
commit1c810396a130fc4cc8ad0bb7d7438b58bbac6e78 (patch)
treeec708ae4de0493275fece0ef0e92f34cede3d284
parent2ec11c2b6e92b3622f0dc0a970634156b286ccd8 (diff)
downloadglibc-1c810396a130fc4cc8ad0bb7d7438b58bbac6e78.tar.gz
glibc-1c810396a130fc4cc8ad0bb7d7438b58bbac6e78.tar.xz
glibc-1c810396a130fc4cc8ad0bb7d7438b58bbac6e78.zip
Add STB_SECONDARY support to ld.so
Enable STB_SECONDARY if it is supported by binutils.  Add 3 STB_SECONDARY
tests.

	* config.h.in: Add HAVE_ASM_SECONDARY_DIRECTIVE.
	* config.make.in (have-secondary): New macro.
	* configure.in: Check if STB_SECONDARY is supported by as/ld.
	Define HAVE_ASM_SECONDARY_DIRECTIVE and set have-secondary to yes
	if the .secondary assembly directive works.
	* configure: Regenerated.
	* elf/Makefile (tests): Add tst-secondary1 tst-secondary2
	tst-secondary3 if STB_SECONDARY is supported by as/ld.
	(modules-names): Add tst-secondarymod tst-secondary1mod
	tst-secondary2mod tst-secondary3mod if STB_SECONDARY is supported
	by as/ld.
	(LDFLAGS-tst-secondarymod.so): New macro.
	($(objpfx)tst-secondary1): New rule.
	($(objpfx)tst-secondary2): Likewise.
	($(objpfx)tst-secondary3): Likewise.
	* elf/dl-addr.c (determine_info): Also check STB_SECONDARY.
	* elf/dl-lookup.c (do_lookup_x): Handle STB_SECONDARY.
	(_dl_lookup_symbol_x): Likewise.
	* elf/sprof.c (read_symbols): Likewise.
	* elf/elf.h (STB_SECONDARY): New.
	(STB_NUM): Updated.
	* elf/tst-secondary.h: New file.
	* elf/tst-secondary1.c: Likewise.
	* elf/tst-secondary1mod.c: Likewise.
	* elf/tst-secondary2.c: Likewise.
	* elf/tst-secondary2mod.c: Likewise.
	* elf/tst-secondary3.c: Likewise.
	* elf/tst-secondary3mod.c: Likewise.
	* elf/tst-secondarymod.c: Likewise.
-rw-r--r--config.h.in4
-rw-r--r--config.make.in1
-rwxr-xr-xconfigure69
-rw-r--r--configure.ac50
-rw-r--r--elf/Makefile17
-rw-r--r--elf/dl-addr.c3
-rw-r--r--elf/dl-lookup.c9
-rw-r--r--elf/elf.h3
-rw-r--r--elf/sprof.c6
-rw-r--r--elf/tst-secondary.h3
-rw-r--r--elf/tst-secondary1.c13
-rw-r--r--elf/tst-secondary1mod.c4
-rw-r--r--elf/tst-secondary2.c13
-rw-r--r--elf/tst-secondary2mod.c12
-rw-r--r--elf/tst-secondary3.c13
-rw-r--r--elf/tst-secondary3mod.c13
-rw-r--r--elf/tst-secondarymod.c9
17 files changed, 237 insertions, 5 deletions
diff --git a/config.h.in b/config.h.in
index 2b9aa1a986..a1588561b7 100644
--- a/config.h.in
+++ b/config.h.in
@@ -24,6 +24,10 @@
 /* Define if weak symbols are available via the `.weakext' directive.  */
 #undef	HAVE_ASM_WEAKEXT_DIRECTIVE
 
+/* Define if secondary symbols are available via the `.secondary'
+   directive.  */
+#undef	HAVE_ASM_SECONDARY_DIRECTIVE
+
 /* Define to the assembler line separator character for multiple
    assembler instructions per line.  Default is `;'  */
 #undef ASM_LINE_SEP
diff --git a/config.make.in b/config.make.in
index a9f5696077..ac115f085f 100644
--- a/config.make.in
+++ b/config.make.in
@@ -56,6 +56,7 @@ old-glibc-headers = @old_glibc_headers@
 unwind-find-fde = @libc_cv_gcc_unwind_find_fde@
 have-forced-unwind = @libc_cv_forced_unwind@
 have-fpie = @libc_cv_fpie@
+have-secondary = @libc_cv_ld_secondary@
 gnu89-inline-CFLAGS = @gnu89_inline@
 have-ssp = @libc_cv_ssp@
 have-selinux = @have_selinux@
diff --git a/configure b/configure
index 45cc7cba2b..86feb6a79f 100755
--- a/configure
+++ b/configure
@@ -624,6 +624,7 @@ libc_cv_cc_loop_to_function
 libc_cv_cc_submachine
 libc_cv_cc_nofma
 exceptions
+libc_cv_ld_secondary
 gnu89_inline
 libc_cv_ssp
 fno_unit_at_a_time
@@ -6488,8 +6489,10 @@ if { ac_try='${CC-cc} $ASFLAGS -c conftest.s 1>&5'
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; }; then
   libc_cv_asm_weak_directive=yes
+  libc_cv_asm_weak=.weak
 else
   libc_cv_asm_weak_directive=no
+  libc_cv_asm_weak=
 fi
 rm -f conftest*
 fi
@@ -6518,6 +6521,7 @@ EOF
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; }; then
     libc_cv_asm_weakext_directive=yes
+    libc_cv_asm_weak=.weakext
   else
     libc_cv_asm_weakext_directive=no
   fi
@@ -6536,6 +6540,71 @@ elif test $libc_cv_asm_weakext_directive = yes; then
 
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for .secondary assembler directive" >&5
+$as_echo_n "checking for .secondary assembler directive... " >&6; }
+if ${libc_cv_asm_secondary_directive+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat > conftest.s <<EOF
+${libc_cv_dot_text}
+_sym:
+.secondary _sym
+EOF
+test -n "$libc_cv_asm_weak" && cat >> conftest.s <<EOF
+$libc_cv_asm_weak _sym
+EOF
+if ${CC-cc} -c $ASFLAGS -o conftest.o conftest.s 1>&5 2>&5; then
+  if $READELF -s conftest.o | fgrep _sym | fgrep SECOND > /dev/null; then
+    libc_cv_asm_secondary_directive=yes
+  else
+    libc_cv_asm_secondary_directive=no
+  fi
+else
+  libc_cv_asm_secondary_directive=no
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_secondary_directive" >&5
+$as_echo "$libc_cv_asm_secondary_directive" >&6; }
+if test $libc_cv_asm_secondary_directive = yes; then
+  $as_echo "#define HAVE_ASM_SECONDARY_DIRECTIVE 1" >>confdefs.h
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for secondary symbol in shared library" >&5
+$as_echo_n "checking for secondary symbol in shared library... " >&6; }
+if ${libc_cv_ld_secondary+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat > conftest.c <<EOF
+asm (".secondary foo");
+void foo (void) { }
+EOF
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+			    -fPIC -shared -o conftest.so conftest.c
+			    -nostartfiles -nostdlib
+			    1>&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+  then
+    if $READELF -s conftest.so | fgrep foo | fgrep SECOND > /dev/null; then
+      libc_cv_ld_secondary=yes
+    else
+      libc_cv_ld_secondary=no
+    fi
+  else
+    libc_cv_ld_secondary=no
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_secondary" >&5
+$as_echo "$libc_cv_ld_secondary" >&6; }
+else
+  libc_cv_ld_secondary=no
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld --no-whole-archive" >&5
 $as_echo_n "checking for ld --no-whole-archive... " >&6; }
 if ${libc_cv_ld_no_whole_archive+:} false; then :
diff --git a/configure.ac b/configure.ac
index 7e9383a7f0..86632ca6b5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1628,8 +1628,10 @@ foo:
 EOF
 if AC_TRY_COMMAND(${CC-cc} $ASFLAGS -c conftest.s 1>&AS_MESSAGE_LOG_FD); then
   libc_cv_asm_weak_directive=yes
+  libc_cv_asm_weak=.weak
 else
   libc_cv_asm_weak_directive=no
+  libc_cv_asm_weak=
 fi
 rm -f conftest*])
 
@@ -1648,6 +1650,7 @@ baz:
 EOF
   if AC_TRY_COMMAND(${CC-cc} $ASFLAGS -c conftest.s 1>&AS_MESSAGE_LOG_FD); then
     libc_cv_asm_weakext_directive=yes
+    libc_cv_asm_weak=.weakext
   else
     libc_cv_asm_weakext_directive=no
   fi
@@ -1661,6 +1664,53 @@ elif test $libc_cv_asm_weakext_directive = yes; then
   AC_DEFINE(HAVE_ASM_WEAKEXT_DIRECTIVE)
 fi
 
+AC_CACHE_CHECK(for .secondary assembler directive,
+	       libc_cv_asm_secondary_directive, [dnl
+cat > conftest.s <<EOF
+${libc_cv_dot_text}
+_sym:
+.secondary _sym
+EOF
+test -n "$libc_cv_asm_weak" && cat >> conftest.s <<EOF
+$libc_cv_asm_weak _sym
+EOF
+if ${CC-cc} -c $ASFLAGS -o conftest.o conftest.s 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
+  if $READELF -s conftest.o | fgrep _sym | fgrep SECOND > /dev/null; then
+    libc_cv_asm_secondary_directive=yes
+  else
+    libc_cv_asm_secondary_directive=no
+  fi
+else
+  libc_cv_asm_secondary_directive=no
+fi
+rm -f conftest*])
+if test $libc_cv_asm_secondary_directive = yes; then
+  AC_DEFINE(HAVE_ASM_SECONDARY_DIRECTIVE)
+  AC_CACHE_CHECK(for secondary symbol in shared library,
+		 libc_cv_ld_secondary, [dnl
+cat > conftest.c <<EOF
+asm (".secondary foo");
+void foo (void) { }
+EOF
+  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+			    -fPIC -shared -o conftest.so conftest.c
+			    -nostartfiles -nostdlib
+			    1>&AS_MESSAGE_LOG_FD])
+  then
+    if $READELF -s conftest.so | fgrep foo | fgrep SECOND > /dev/null; then
+      libc_cv_ld_secondary=yes
+    else
+      libc_cv_ld_secondary=no
+    fi
+  else
+    libc_cv_ld_secondary=no
+  fi
+  rm -f conftest*])
+else
+  libc_cv_ld_secondary=no
+fi
+AC_SUBST(libc_cv_ld_secondary)
+
 AC_CACHE_CHECK(for ld --no-whole-archive, libc_cv_ld_no_whole_archive, [dnl
 cat > conftest.c <<\EOF
 _start () {}
diff --git a/elf/Makefile b/elf/Makefile
index 4ceeaf89be..31029c1e77 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -269,6 +269,12 @@ modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
 endif
 endif
 
+ifeq (yes,$(have-secondary))
+tests += tst-secondary1 tst-secondary2 tst-secondary3
+modules-names += tst-secondarymod tst-secondary1mod tst-secondary2mod \
+		 tst-secondary3mod
+endif
+
 ifeq (yes,$(build-shared))
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out
@@ -1144,6 +1150,17 @@ $(objpfx)ifuncmain5static: $(addprefix $(objpfx),ifuncdep5.o)
 $(objpfx)ifuncmain5staticpic: $(addprefix $(objpfx),ifuncdep5pic.o)
 $(objpfx)ifuncmain5picstatic: $(addprefix $(objpfx),ifuncdep5pic.o)
 
+LDFLAGS-tst-secondarymod.so = -Wl,-z,secondary
+
+$(objpfx)tst-secondary1: $(objpfx)tst-secondarymod.so \
+			 $(objpfx)tst-secondary1mod.so
+
+$(objpfx)tst-secondary2: $(objpfx)tst-secondarymod.so \
+			 $(objpfx)tst-secondary2mod.so
+
+$(objpfx)tst-secondary3: $(objpfx)tst-secondarymod.so \
+			 $(objpfx)tst-secondary3mod.so
+
 $(objpfx)tst-unique1: $(libdl)
 $(objpfx)tst-unique1.out: $(objpfx)tst-unique1mod1.so \
 			  $(objpfx)tst-unique1mod2.so
diff --git a/elf/dl-addr.c b/elf/dl-addr.c
index a025652c08..b4dd8887f5 100644
--- a/elf/dl-addr.c
+++ b/elf/dl-addr.c
@@ -87,7 +87,8 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
 
       for (; (void *) symtab < (void *) symtabend; ++symtab)
 	if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
-	     || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
+	     || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK
+	     || ELFW(ST_BIND) (symtab->st_info) == STB_SECONDARY)
 	    && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
 	    && (symtab->st_shndx != SHN_UNDEF
 		|| symtab->st_value != 0)
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 11cb44b451..7e35723aab 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -518,10 +518,15 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
 
 	  switch (ELFW(ST_BIND) (sym->st_info))
 	    {
+	    case STB_SECONDARY:
+	      /* Secondary definition.  Use this value if we don't find
+		 another.  */
+	      goto dynamic_weak;
 	    case STB_WEAK:
 	      /* Weak definition.  Use this value if we don't find another.  */
 	      if (__glibc_unlikely (GLRO(dl_dynamic_weak)))
 		{
+dynamic_weak:
 		  if (! result->s)
 		    {
 		      result->s = sym;
@@ -857,7 +862,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
 
   if (__glibc_unlikely (current_value.s == NULL))
     {
-      if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+      if ((*ref == NULL
+	   || (ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK
+	       && ELFW(ST_BIND) ((*ref)->st_info) != STB_SECONDARY))
 	  && skip_map == NULL
 	  && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
 	{
diff --git a/elf/elf.h b/elf/elf.h
index fbadda4377..4cc607480b 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -472,7 +472,8 @@ typedef struct
 #define STB_LOCAL	0		/* Local symbol */
 #define STB_GLOBAL	1		/* Global symbol */
 #define STB_WEAK	2		/* Weak symbol */
-#define	STB_NUM		3		/* Number of defined types.  */
+#define STB_SECONDARY	3		/* Secondary symbol */
+#define	STB_NUM		4		/* Number of defined types.  */
 #define STB_LOOS	10		/* Start of OS-specific */
 #define STB_GNU_UNIQUE	10		/* Unique symbol.  */
 #define STB_HIOS	12		/* End of OS-specific */
diff --git a/elf/sprof.c b/elf/sprof.c
index ec3fde3848..9ed60956cd 100644
--- a/elf/sprof.c
+++ b/elf/sprof.c
@@ -1082,7 +1082,8 @@ read_symbols (struct shobj *shobj)
 	    newsym->name = &shobj->strtab[sym->st_name];
 	    newsym->addr = sym->st_value;
 	    newsym->size = sym->st_size;
-	    newsym->weak = ELFW(ST_BIND) (sym->st_info) == STB_WEAK;
+	    newsym->weak = (ELFW(ST_BIND) (sym->st_info) == STB_SECONDARY
+			    || ELFW(ST_BIND) (sym->st_info) == STB_WEAK);
 	    newsym->hidden = (ELFW(ST_VISIBILITY) (sym->st_other)
 			      != STV_DEFAULT);
 	    newsym->ticks = 0;
@@ -1140,7 +1141,8 @@ read_symbols (struct shobj *shobj)
 	      newsym->name = &strtab[symtab->st_name];
 	      newsym->addr = symtab->st_value;
 	      newsym->size = symtab->st_size;
-	      newsym->weak = ELFW(ST_BIND) (symtab->st_info) == STB_WEAK;
+	      newsym->weak = (ELFW(ST_BIND) (symtab->st_info) == STB_SECONDARY
+			      || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK);
 	      newsym->hidden = (ELFW(ST_VISIBILITY) (symtab->st_other)
 				!= STV_DEFAULT);
 	      newsym->ticks = 0;
diff --git a/elf/tst-secondary.h b/elf/tst-secondary.h
new file mode 100644
index 0000000000..0487e25c60
--- /dev/null
+++ b/elf/tst-secondary.h
@@ -0,0 +1,3 @@
+#define GLOBAL		1
+#define WEAK		2
+#define SECONDARY	3
diff --git a/elf/tst-secondary1.c b/elf/tst-secondary1.c
new file mode 100644
index 0000000000..f4d6edd722
--- /dev/null
+++ b/elf/tst-secondary1.c
@@ -0,0 +1,13 @@
+/* Verify that secdonary function is called.  */
+
+#include "tst-secondary.h"
+
+extern int bar (void);
+extern void foo (void);
+
+int
+main (void)
+{
+  foo ();
+  return bar () != SECONDARY;
+}
diff --git a/elf/tst-secondary1mod.c b/elf/tst-secondary1mod.c
new file mode 100644
index 0000000000..cd0130cacd
--- /dev/null
+++ b/elf/tst-secondary1mod.c
@@ -0,0 +1,4 @@
+void
+foo (void)
+{
+}
diff --git a/elf/tst-secondary2.c b/elf/tst-secondary2.c
new file mode 100644
index 0000000000..3f221cb172
--- /dev/null
+++ b/elf/tst-secondary2.c
@@ -0,0 +1,13 @@
+/* Verify that global function is called.  */
+
+#include "tst-secondary.h"
+
+extern int bar (void);
+extern void foo (void);
+
+int
+main (void)
+{
+  foo ();
+  return bar () != GLOBAL;
+}
diff --git a/elf/tst-secondary2mod.c b/elf/tst-secondary2mod.c
new file mode 100644
index 0000000000..f9407a9b1c
--- /dev/null
+++ b/elf/tst-secondary2mod.c
@@ -0,0 +1,12 @@
+#include "tst-secondary.h"
+
+int
+bar (void)
+{
+  return GLOBAL;
+}
+
+void
+foo (void)
+{
+}
diff --git a/elf/tst-secondary3.c b/elf/tst-secondary3.c
new file mode 100644
index 0000000000..b55baea6d6
--- /dev/null
+++ b/elf/tst-secondary3.c
@@ -0,0 +1,13 @@
+/* Verify that weak function is called.  */
+
+#include "tst-secondary.h"
+
+extern int bar (void);
+extern void foo (void);
+
+int
+main (void)
+{
+  foo ();
+  return bar () != WEAK;
+}
diff --git a/elf/tst-secondary3mod.c b/elf/tst-secondary3mod.c
new file mode 100644
index 0000000000..edfb25bbb2
--- /dev/null
+++ b/elf/tst-secondary3mod.c
@@ -0,0 +1,13 @@
+#include "tst-secondary.h"
+
+int
+__attribute__ ((weak))
+bar (void)
+{
+  return WEAK;
+}
+
+void
+foo (void)
+{
+}
diff --git a/elf/tst-secondarymod.c b/elf/tst-secondarymod.c
new file mode 100644
index 0000000000..5363e99654
--- /dev/null
+++ b/elf/tst-secondarymod.c
@@ -0,0 +1,9 @@
+#include "tst-secondary.h"
+
+asm (".secondary bar");
+
+int
+bar (void)
+{
+  return SECONDARY;
+}