use explicit visibility to optimize a few hot-path function calls
authorRich Felker <dalias@aerifal.cx>
Thu, 25 Oct 2012 19:40:58 +0000 (15:40 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 25 Oct 2012 19:40:58 +0000 (15:40 -0400)
on x86 and some other archs, functions which make function calls which
might go through a PLT incur a significant overhead cost loading the
GOT register prior to making the call. this load is utterly useless in
musl, since all calls are bound at library-creation time using
-Bsymbolic-functions, but the compiler has no way of knowing this, and
attempts to set the default visibility to protected have failed due to
bugs in GCC and binutils.

this commit simply manually assigns hidden/protected visibility, as
appropriate, to a few internal-use-only functions which have many
callers, or which have callers that are hot paths like getc/putc. it
shaves about 5k off the i386 libc.so with -Os. many of the
improvements are in syscall wrappers, where the benefit is just size
and performance improvement is unmeasurable noise amid the syscall
overhead. however, stdio may be measurably faster.

if in the future there are toolchains that can do the same thing
globally without introducing linking bugs, it might be worth
considering removing these workarounds.

src/internal/libc.h
src/internal/stdio_impl.h
src/internal/syscall.h

index 703d9853c06f8148bd596358f823d83153c2b078..5ab4e679906e85c3a77dd6483a43ab733511a7d5 100644 (file)
@@ -46,10 +46,10 @@ extern struct __libc *__libc_loc(void) __attribute__((const));
 
 
 /* Designed to avoid any overhead in non-threaded processes */
-void __lock(volatile int *);
-void __unlock(volatile int *);
-int __lockfile(FILE *);
-void __unlockfile(FILE *);
+void __lock(volatile int *) ATTR_LIBC_VISIBILITY;
+void __unlock(volatile int *) ATTR_LIBC_VISIBILITY;
+int __lockfile(FILE *) ATTR_LIBC_VISIBILITY;
+void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY;
 #define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1))
 #define UNLOCK(x) (libc.threads_minus_1 ? (__unlock(x),1) : ((void)(x),1))
 
index 279e91fdecb975604e25a11bac17d23f84588a6e..80646f8c731398c94a6aaa4ac1beeff569a94aa3 100644 (file)
@@ -74,10 +74,10 @@ size_t __string_read(FILE *, unsigned char *, size_t);
 int __toread(FILE *);
 int __towrite(FILE *);
 
-int __overflow(FILE *, int);
-int __oflow(FILE *);
-int __uflow(FILE *);
-int __underflow(FILE *);
+#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303)
+__attribute__((visibility("protected")))
+#endif
+int __overflow(FILE *, int), __uflow(FILE *);
 
 int __fseeko(FILE *, off_t, int);
 int __fseeko_unlocked(FILE *, off_t, int);
index 50409ef8168db07e6ef458fefb0ec2b553797bbc..7381efea8d4d1e235d69909074645fca50d3e61e 100644 (file)
@@ -1,9 +1,11 @@
 #ifndef _INTERNAL_SYSCALL_H
 #define _INTERNAL_SYSCALL_H
 
-long __syscall_ret(unsigned long);
-long __syscall(long, ...);
-long __syscall_cp(long, long, long, long, long, long, long);
+#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303)
+__attribute__((visibility("protected")))
+#endif
+long __syscall_ret(unsigned long), __syscall(long, ...),
+       __syscall_cp(long, long, long, long, long, long, long);
 
 #include <sys/syscall.h>
 #include "syscall_arch.h"