add optional global visibility override
authorRich Felker <dalias@aerifal.cx>
Mon, 20 Apr 2015 02:05:29 +0000 (22:05 -0400)
committerRich Felker <dalias@aerifal.cx>
Mon, 20 Apr 2015 02:05:29 +0000 (22:05 -0400)
this is implemented via the build system and does not affect source
files. the idea is to use protected or hidden visibility to prevent
the compiler from pessimizing function calls within a shared (or
position-independent static) libc in the form of overhead setting up
for a call through the PLT. the ld-time symbol binding via the
-Bsymbolic-functions option already optimized out the PLT itself, but
not the code in the caller needed to support a call through the PLT.
on some archs this overhead can be substantial; on others it's
trivial.

Makefile
configure
src/internal/vis.h [new file with mode: 0644]

index d943988dc1fdc677a500f9f46b208ffc2044eacd..15a30f83f5cde083e111bf2f54482c584dbe2915 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -104,6 +104,8 @@ NOSSP_SRCS = $(wildcard crt/*.c) \
        src/ldso/dlstart.c src/ldso/dynlink.c
 $(NOSSP_SRCS:%.c=%.o) $(NOSSP_SRCS:%.c=%.lo): CFLAGS += $(CFLAGS_NOSSP)
 
+$(CRT_LIBS): CFLAGS += -DCRT
+
 # This incantation ensures that changes to any subarch asm files will
 # force the corresponding object file to be rebuilt, even if the implicit
 # rule below goes indirectly through a .sub file.
index 41a73b46ef7e5d1d43b68c854605d67a6aed0b9c..0e396941ae208212690e00c1f7b3fb9f8dc91e86 100755 (executable)
--- a/configure
+++ b/configure
@@ -27,6 +27,7 @@ Optional features:
   --enable-optimize=...   optimize listed components for speed over size [auto]
   --enable-debug          build with debugging information [disabled]
   --enable-warnings       build with recommended warnings flags [disabled]
+  --enable-visibility     use global visibility options to optimize PIC [auto]
   --enable-gcc-wrapper    build musl-gcc toolchain wrapper [auto]
   --disable-shared        inhibit building shared library [enabled]
   --disable-static        inhibit building static library [enabled]
@@ -79,7 +80,7 @@ fi
 tryflag () {
 printf "checking whether compiler accepts %s... " "$2"
 echo "typedef int x;" > "$tmpc"
-if $CC "$2" -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+if $CC $2 -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
 printf "yes\n"
 eval "$1=\"\${$1} \$2\""
 eval "$1=\${$1# }"
@@ -124,6 +125,7 @@ target=
 optimize=auto
 debug=no
 warnings=no
+visibility=auto
 shared=auto
 static=yes
 wrapper=auto
@@ -148,6 +150,8 @@ case "$arg" in
 --disable-debug|--enable-debug=no) debug=no ;;
 --enable-warnings|--enable-warnings=yes) warnings=yes ;;
 --disable-warnings|--enable-warnings=no) warnings=no ;;
+--enable-visibility|--enable-visibility=yes) visibility=yes ;;
+--disable-visibility|--enable-visibility=no) visibility=no ;;
 --enable-gcc-wrapper|--enable-gcc-wrapper=yes) wrapper=yes ;;
 --disable-gcc-wrapper|--enable-gcc-wrapper=no) wrapper=no ;;
 --enable-*|--disable-*|--with-*|--without-*|--*dir=*|--build=*) ;;
@@ -415,6 +419,31 @@ tryflag CFLAGS_AUTO -Wno-unknown-pragmas
 tryflag CFLAGS_AUTO -Wno-pointer-to-int-cast
 fi
 
+if test "x$visibility" == xauto ; then
+# This test checks toolchain support for several things:
+# - the -include option
+# - the attributes/pragmas used in vis.h
+# - linking code that takes the address of protected symbols
+printf "checking whether global visibility preinclude works... "
+echo 'int (*fp)(void);' > "$tmpc"
+echo 'int foo(void) { }' >> "$tmpc"
+echo 'int bar(void) { fp = foo; return foo(); }' >> "$tmpc"
+if $CC $CFLAGS_C99FSE -I./arch/$ARCH -I src/internal -I./include \
+  $CPPFLAGS $CFLAGS -DSHARED -fPIC -include vis.h \
+  -nostdlib -shared -Wl,-Bsymbolic-functions \
+  -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+visibility=yes
+else
+visibility=no
+fi
+printf "%s\n" "$visibility"
+fi
+
+if test "x$visibility" == xyes ; then
+CFLAGS_AUTO="$CFLAGS_AUTO -include vis.h"
+CFLAGS_AUTO="${CFLAGS_AUTO# }"
+fi
+
 # Some patched GCC builds have these defaults messed up...
 tryldflag LDFLAGS_AUTO -Wl,--hash-style=both
 
diff --git a/src/internal/vis.h b/src/internal/vis.h
new file mode 100644 (file)
index 0000000..bf7a5b2
--- /dev/null
@@ -0,0 +1,40 @@
+/* This file is only used if enabled in the build system, in which case it is
+ * included automatically via command line options. It is not included
+ * explicitly by any source files or other headers. Its purpose is to
+ * override default visibilities to reduce the size and performance costs
+ * of position-independent code. */
+
+#ifndef CRT
+#ifdef SHARED
+
+/* For shared libc.so, all symbols should be protected, but some toolchains
+ * fail to support copy relocations for protected data, so exclude all
+ * exported data symbols. */
+
+__attribute__((__visibility__("default")))
+extern struct _IO_FILE *const stdin, *const stdout, *const stderr;
+
+__attribute__((__visibility__("default")))
+extern int optind, opterr, optopt, optreset, __optreset, getdate_err, h_errno, daylight, __daylight, signgam, __signgam;
+
+__attribute__((__visibility__("default")))
+extern long timezone, __timezone;
+
+__attribute__((__visibility__("default")))
+extern char *optarg, **environ, **__environ, *tzname[2], *__tzname[2], *__progname, *__progname_full;
+
+#pragma GCC visibility push(protected)
+
+#elif defined(__PIC__)
+
+/* If building static libc.a as position-independent code, try to make
+ * everything hidden except possibly-undefined weak references. */
+
+__attribute__((__visibility__("default")))
+extern void (*const __init_array_start)(), (*const __init_array_end)(),
+       (*const __fini_array_start)(), (*const __fini_array_end)();
+
+#pragma GCC visibility push(hidden)
+
+#endif
+#endif