tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Reducing ld.elf_so relocations and size
Hi all,
attached patch in combination with the environment handling patch I send
earlier addresses two issues with ld.elf_so:
(1) It has too many runtime relocations because the integrated libc
doesn't exploit the fact that the non-local references are still hidden.
E.g. on AMD64, both data access and function calls can be done relative
to the instruction pointer without using the GOT. This improves code
size and startup time. The changes around errlist reduce the number of
runtime relocations for one for every errno value and give around 3KB on
AMD64.
(2) It (almost) allows to drop the special visibility hacks in
ld.elf_so. Look at the output of 'readelf -s ld.elf_so' and the long
list of GLOBAL symbols with DEFAULT visiblity. After the patch, only 3
symbols are still visible that shouldn't be (__bss_start, _edata, _end)
and they come from the ld script used. It should be fixed to make them
hidden or protected, but that's a separate discussion.
The patch is currently missing the !x86 machine/asm.h changes and some
other minor changes to avoid some GOT references. Some platforms might
need additional helper code as well, but that's easy to identify.
The patch also doesn't contain a build time assertion for the symbol
list of ld.elf_so yet.
There are some further changes to consider like making __cerror a hidden
lymbol, taking it out of the public namespace. It would allow taking the
shorter code sequence for the shared library build as well.
I know that the global define trick is not the most beautiful approach,
but I haven't found an idea that involves less code changes and still
gives the benefits of (1). More importantly, I would strongly prefer to
only have to source code as optimisation, not to make it work. I also
don't want to duplicate the logic from libc to decide where a specific
source file lives and if the C version or the MD assembler should be
used. Ideas are welcome.
Joerg
Index: include/dlfcn.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/include/dlfcn.h,v
retrieving revision 1.21
diff -u -p -r1.21 dlfcn.h
--- include/dlfcn.h 7 Jan 2010 07:35:35 -0000 1.21
+++ include/dlfcn.h 5 Dec 2010 04:00:23 -0000
@@ -47,7 +47,7 @@ typedef struct _dl_info {
/*
* User interface to the run-time linker.
*/
-__BEGIN_DECLS
+__BEGIN_PUBLIC
void *dlopen(const char *, int);
int dlclose(void *);
void *dlsym(void * __restrict, const char * __restrict);
@@ -57,7 +57,7 @@ int dlctl(void *, int, void *);
int dlinfo(void *, int, void *);
#endif
__aconst char *dlerror(void);
-__END_DECLS
+__END_PUBLIC
/* Values for dlopen `mode'. */
#define RTLD_LAZY 1
Index: include/link_elf.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/include/link_elf.h,v
retrieving revision 1.10
diff -u -p -r1.10 link_elf.h
--- include/link_elf.h 16 Oct 2010 10:27:06 -0000 1.10
+++ include/link_elf.h 5 Dec 2010 03:59:35 -0000
@@ -43,11 +43,11 @@ struct dl_phdr_info
void *dlpi_tls_data;
};
-__BEGIN_DECLS
+__BEGIN_PUBLIC
int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *),
void *);
-__END_DECLS
+__END_PUBLIC
#endif /* _LINK_ELF_H_ */
Index: lib/libc/Makefile
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/Makefile,v
retrieving revision 1.143
diff -u -p -r1.143 Makefile
--- lib/libc/Makefile 4 Sep 2010 12:17:58 -0000 1.143
+++ lib/libc/Makefile 10 Dec 2010 00:54:54 -0000
@@ -118,6 +118,50 @@ LSRCS := ${LSRCS} ${unwanted_file}
.endif
.endfor
+.SUFFIXES: .hpico
+
+errlist_concat.c: errlist.c
+ ${_MKTARGET_CREATE}
+ ${TOOL_AWK} -f ${LIBCDIR}/gen/errlist.awk < ${.ALLSRC} \
+ > errlist_concat.c.tmp && \
+ mv -f errlist_concat.c.tmp errlist_concat.c
+
+CLEANFILES+= errlist_concat.c
+
+.c.hpico:
+ ${_MKTARGET_COMPILE}
+ ${COMPILE.c} ${COPTS.${.IMPSRC:T}} ${CPUFLAGS.${.IMPSRC:T}}
${CPPFLAGS.${.IMPSRC:T}} ${CSHLIBFLAGS} -fvisibility=hidden -U_REENTRANT
-D__FORCE_HIDDEN_DEFAULT ${.IMPSRC} -o ${.TARGET}
+.if !defined(CFLAGS) || empty(CFLAGS:M*-g*)
+ ${OBJCOPY} -x ${.TARGET}
+.endif
+
+.s.hpico:
+ ${_MKTARGET_COMPILE}
+ ${COMPILE.s} ${CAPICFLAGS} ${COPTS.${.IMPSRC:T}}
${CPUFLAGS.${.IMPSRC:T}} ${CPPFLAGS.${.IMPSRC:T}} -U_REENTRANT
-D__FORCE_HIDDEN_DEFAULT ${.IMPSRC} -o ${.TARGET}
+ ${OBJCOPY} -x ${.TARGET}
+
+.S.hpico:
+ ${_MKTARGET_COMPILE}
+ ${COMPILE.S} ${CAPICFLAGS} ${COPTS.${.IMPSRC:T}}
${CPUFLAGS.${.IMPSRC:T}} ${CPPFLAGS.${.IMPSRC:T}} -U_REENTRANT
-D__FORCE_HIDDEN_DEFAULT ${.IMPSRC} -o ${.TARGET}
+ ${OBJCOPY} -x ${.TARGET}
+
+realall: libc_hidden.a
+
+# Functions called by ld.elf_so and the transitive closure
+HIDDEN_SRCS+= __fstat50 __sigaction_sigtramp __sigaction14_sigtramp \
+ __sigtramp2 __sigprocmask14 __sysctl _errno _exit \
+ _lwp_kill _lwp_self \
+ abort cerror close ctype_ errlist_concat errno geteuid \
+ getuid getegid getgid getprogname \
+ memcpy memcpy_chk memset mmap mprotect munmap open raise \
+ read signal strchr strcmp strcpy strlcpy strlen \
+ strncmp strncpy strrchr strsep sysctl tmp_mmap write
+# Helper functions for 64bit division on some platforms.
+HIDDEN_SRCS+= qdivrem udivdi3
+HIDDEN_OBJS+= ${HIDDEN_SRCS:C,$,.hpico,}
+
+libc_hidden.a:: ${HIDDEN_OBJS} __archivebuild
+
NLS= C.msg Pig.msg ca.msg cs.msg de.msg es.msg fi.msg fr.msg nl.msg \
no.msg pl.msg sk.msg sv.msg
Index: lib/libc/arch/i386/SYS.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/arch/i386/SYS.h,v
retrieving revision 1.23
diff -u -p -r1.23 SYS.h
--- lib/libc/arch/i386/SYS.h 28 Apr 2008 20:22:56 -0000 1.23
+++ lib/libc/arch/i386/SYS.h 9 Dec 2010 22:20:10 -0000
@@ -101,7 +101,7 @@
ENTRY(x); \
SYSTRAP(y)
-#ifdef PIC
+#if defined(PIC) && !defined(__FORCE_HIDDEN_DEFAULT)
#define _SYSCALL_ERR \
PIC_PROLOGUE; \
mov PIC_GOT(CERROR), %ecx; \
Index: lib/libc/arch/i386/sys/cerror.S
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/arch/i386/sys/cerror.S,v
retrieving revision 1.14
diff -u -p -r1.14 cerror.S
--- lib/libc/arch/i386/sys/cerror.S 7 Aug 2003 16:42:08 -0000 1.14
+++ lib/libc/arch/i386/sys/cerror.S 9 Dec 2010 22:21:23 -0000
@@ -45,7 +45,7 @@
_ENTRY(CERROR)
pushl %eax
-#ifdef PIC
+#if defined(PIC) && !defined(__FORCE_HIDDEN_DEFAULT)
PIC_PROLOGUE
call PIC_PLT(_C_LABEL(__errno))
PIC_EPILOGUE
Index: lib/libc/arch/x86_64/SYS.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/arch/x86_64/SYS.h,v
retrieving revision 1.10
diff -u -p -r1.10 SYS.h
--- lib/libc/arch/x86_64/SYS.h 23 Nov 2007 07:36:05 -0000 1.10
+++ lib/libc/arch/x86_64/SYS.h 9 Dec 2010 03:12:16 -0000
@@ -49,7 +49,7 @@
ENTRY(x); \
SYSTRAP(y)
-#ifdef PIC
+#if defined(PIC) && !defined(__FORCE_HIDDEN_DEFAULT)
#define _SYSCALL_ERR \
mov PIC_GOT(CERROR), %rcx; \
jmp *%rcx
Index: lib/libc/arch/x86_64/sys/cerror.S
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/arch/x86_64/sys/cerror.S,v
retrieving revision 1.3
diff -u -p -r1.3 cerror.S
--- lib/libc/arch/x86_64/sys/cerror.S 7 Aug 2003 16:42:37 -0000 1.3
+++ lib/libc/arch/x86_64/sys/cerror.S 9 Dec 2010 02:56:56 -0000
@@ -42,12 +42,15 @@
#include "SYS.h"
.globl _C_LABEL(__errno)
+#if defined(__FORCE_HIDDEN_DEFAULT)
+ .hidden _C_LABEL(__errno)
+#endif
_ENTRY(CERROR)
pushq %r12
movl %eax,%edi
movl %eax,%r12d
-#ifdef PIC
+#if defined(PIC) && !defined(__FORCE_HIDDEN_DEFAULT)
call PIC_PLT(_C_LABEL(__errno))
#else
call _C_LABEL(__errno)
Index: lib/libc/gen/errlist.awk
===================================================================
RCS file: lib/libc/gen/errlist.awk
diff -N lib/libc/gen/errlist.awk
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/gen/errlist.awk 9 Dec 2010 04:19:54 -0000
@@ -0,0 +1,23 @@
+BEGIN {
+ offset = 0
+ i = 0
+ print "const char concat_errlist[] = {"
+}
+
+/EL\(\(".*"\)\)/ {
+ offsets[i++] = offset
+ match($0, /EL\(\(".*"\)\)/)
+ printf "\t%s \"\\0\"\n", substr($0, RSTART + 4, RLENGTH - 6)
+ offset = offset + RLENGTH - 8 + 1
+}
+END {
+ print "};"
+ print "const int concat_nerr = " i ";"
+ print "const unsigned short concat_offset[" (i + 1) "] = {"
+ offsets[i++] = offset
+ for (j = 0; j < i; j++) {
+ printf "\t%d,\n", offsets[j]
+ }
+ print "};"
+ if (offset > 65535) exit(1)
+}
Index: libexec/ld.elf_so/Makefile
===================================================================
RCS file: /home/joerg/repo/netbsd/src/libexec/ld.elf_so/Makefile,v
retrieving revision 1.99
diff -u -p -r1.99 Makefile
--- libexec/ld.elf_so/Makefile 5 Dec 2010 00:56:06 -0000 1.99
+++ libexec/ld.elf_so/Makefile 5 Dec 2010 03:58:12 -0000
@@ -1,4 +1,4 @@
-# $NetBSD: src/libexec/ld.elf_so/Makefile,v 1.99 2010-12-05 00:56:06
joerg Exp $
+# $NetBSD: Makefile,v 1.99 2010/12/05 00:56:06 joerg Exp $
#
# NOTE: when changing ld.so, ensure that ldd still compiles.
#
@@ -38,9 +38,10 @@ M= ${.CURDIR}/arch/${ARCHSUBDIR}
(${MACHINE_ARCH} == "vax")) && \
${MKPIC} != "no"
-LDFLAGS+= -shared -symbolic -nostartfiles
+LDFLAGS+= -shared -symbolic -nostdlib -nostartfiles
LDFLAGS+= -Wl,-static
CFLAGS+= -fvisibility=hidden
+CPPFLAGS+= -D__FORCE_HIDDEN_DEFAULT
# Adds SRCS, CPPFLAGS, LDFLAGS, etc. Must go first so MD startup source
# is first.
@@ -58,7 +59,7 @@ PROG= ld.elf_so
CLIBOBJ!= cd ${NETBSDSRCDIR}/lib/libc && ${PRINTOBJDIR}
-SRCS+= rtld.c reloc.c symbol.c xenv.c xmalloc.c xprintf.c debug.c \
+SRCS+= rtld.c reloc.c symbol.c xmalloc.c xprintf.c debug.c \
map_object.c load.c search.c headers.c paths.c expand.c
.if ${USE_FORT} == "yes"
@@ -90,16 +91,17 @@ CPPFLAGS+= -DRTLD_DEFAULT_LIBRARY_PATH=\
COPTS.rtld.c+= -Wno-stack-protector
COPTS.symbol.c+=-Wno-stack-protector
-LDADD+= -L${CLIBOBJ} -L${DESTDIR}${LIBDIR}
+LDADD+= -L${CLIBOBJ} -L${DESTDIR}${LIBDIR} -lc_hidden
-Wl,-z,defs
+DPADD+= ${CLIBOBJ}/libc_hidden.a
.if ${MKPICLIB} != "no"
-LDADD+= -lc_pic
+#LDADD+= -lc_pic
.if ${MKPICINSTALL} != "no"
-DPADD+= ${LIBC_PIC}
+#DPADD+= ${LIBC_PIC}
.endif
-DPADD+= ${CLIBOBJ}/libc_pic.a
+#DPADD+= ${CLIBOBJ}/libc_pic.a
.else
-LDADD+= -lc
-DPADD+= ${CLIBOBJ}/libc.a
+#LDADD+= -lc
+#DPADD+= ${CLIBOBJ}/libc.a
.endif
STRIPFLAG=
Index: libexec/ld.elf_so/xprintf.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/libexec/ld.elf_so/xprintf.c,v
retrieving revision 1.20
diff -u -p -r1.20 xprintf.c
--- libexec/ld.elf_so/xprintf.c 19 May 2009 20:44:52 -0000 1.20
+++ libexec/ld.elf_so/xprintf.c 9 Dec 2010 04:26:54 -0000
@@ -243,16 +243,20 @@ xsnprintf(char *buf, size_t buflen, cons
va_end(ap);
}
+extern const char concat_errlist[];
+extern const int concat_nerr;
+extern const unsigned short concat_offset[];
+
const char *
xstrerror(int error)
{
- if (error >= sys_nerr || error < 0) {
+ if (error >= concat_nerr || error < 0) {
static char buf[128];
xsnprintf(buf, sizeof(buf), "Unknown error: %d", error);
return buf;
}
- return sys_errlist[error];
+ return concat_errlist + concat_offset[error];
}
void
Index: sys/arch/amd64/include/asm.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/arch/amd64/include/asm.h,v
retrieving revision 1.13
diff -u -p -r1.13 asm.h
--- sys/arch/amd64/include/asm.h 26 Oct 2008 00:08:15 -0000 1.13
+++ sys/arch/amd64/include/asm.h 9 Dec 2010 04:29:47 -0000
@@ -69,8 +69,14 @@
# endif
#endif
+#if defined(__FORCE_HIDDEN_DEFAULT)
+#define _ENTRY(x) \
+ .text; _ALIGN_TEXT; .globl x; .hidden x; .type x,@function; x:
+#else
#define _ENTRY(x) \
.text; _ALIGN_TEXT; .globl x; .type x,@function; x:
+#endif
+
#define _LABEL(x) \
.globl x; x:
@@ -108,16 +114,30 @@
#define RCSID(x) .pushsection ".ident"; .asciz x; .popsection
+#if defined(__FORCE_HIDDEN_DEFAULT)
+#define WEAK_ALIAS(alias,sym)
\
+ .weak alias; \
+ .hidden alias; \
+ alias = sym
+#else
#define WEAK_ALIAS(alias,sym)
\
.weak alias; \
alias = sym
+#endif
/*
* STRONG_ALIAS: create a strong alias.
*/
+#if defined(__FORCE_HIDDEN_DEFAULT)
#define STRONG_ALIAS(alias,sym)
\
+ .hidden alias; \
.globl alias; \
alias = sym
+#else
+#define STRONG_ALIAS(alias,sym)
\
+ .globl alias; \
+ alias = sym
+#endif
/* XXXfvdl do not use stabs here */
#ifdef __STDC__
Index: sys/arch/i386/include/asm.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/arch/i386/include/asm.h,v
retrieving revision 1.38
diff -u -p -r1.38 asm.h
--- sys/arch/i386/include/asm.h 3 May 2008 05:54:52 -0000 1.38
+++ sys/arch/i386/include/asm.h 9 Dec 2010 22:23:53 -0000
@@ -93,8 +93,13 @@
# endif
#endif
+#if defined(__FORCE_HIDDEN_DEFAULT)
+#define _ENTRY(x) \
+ .text; _ALIGN_TEXT; .globl x; .hidden x; .type x,@function; x:
+#else
#define _ENTRY(x) \
.text; _ALIGN_TEXT; .globl x; .type x,@function; x:
+#endif
#define _LABEL(x) \
.globl x; x:
@@ -192,16 +197,30 @@
#endif
#ifdef __ELF__
+#if defined(__FORCE_HIDDEN_DEFAULT)
+#define WEAK_ALIAS(alias,sym)
\
+ .weak alias; \
+ .hidden alias; \
+ alias = sym
+#else
#define WEAK_ALIAS(alias,sym)
\
.weak alias; \
alias = sym
#endif
+#endif
/*
* STRONG_ALIAS: create a strong alias.
*/
+#if defined(__FORCE_HIDDEN_DEFAULT)
+#define STRONG_ALIAS(alias,sym)
\
+ .hidden alias; \
+ .globl alias; \
+ alias = sym
+#else
#define STRONG_ALIAS(alias,sym)
\
.globl alias; \
alias = sym
+#endif
#ifdef __STDC__
#define WARN_REFERENCES(sym,msg)
\
Index: sys/sys/cdefs.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/cdefs.h,v
retrieving revision 1.80
diff -u -p -r1.80 cdefs.h
--- sys/sys/cdefs.h 7 Aug 2010 21:03:18 -0000 1.80
+++ sys/sys/cdefs.h 9 Dec 2010 04:11:54 -0000
@@ -218,31 +218,39 @@
#define __used __unused
#endif
+#if defined(__cplusplus)
+# define __BEGIN_EXTERN_C extern "C" {
+# define __END_EXTERN_C }
+# define __static_cast(x,y) static_cast<x>(y)
+#else
+# define __BEGIN_EXTERN_C
+# define __END_EXTERN_C
+# define __static_cast(x,y) (x)y
+#endif
+
#if __GNUC_PREREQ__(4, 0)
# define __dso_public __attribute__((__visibility__("default")))
# define __dso_hidden __attribute__((__visibility__("hidden")))
-# define __BEGIN_PUBLIC _Pragma("GCC visibility push(default)")
-# define __END_PUBLIC _Pragma("GCC visibility pop")
-# define __BEGIN_HIDDEN _Pragma("GCC visibility push(hidden)")
-# define __END_HIDDEN _Pragma("GCC visibility pop")
+# define __BEGIN_PUBLIC _Pragma("GCC visibility push(default)")
__BEGIN_EXTERN_C
+# define __END_PUBLIC __END_EXTERN_C _Pragma("GCC visibility pop")
+# define __BEGIN_HIDDEN _Pragma("GCC visibility push(hidden)")
__BEGIN_EXTERN_C
+# define __END_HIDDEN __END_EXTERN_C _Pragma("GCC visibility pop")
#else
# define __dso_public
# define __dso_hidden
-# define __BEGIN_PUBLIC
-# define __END_PUBLIC
-# define __BEGIN_HIDDEN
-# define __END_HIDDEN
+# define __BEGIN_PUBLIC __BEGIN_EXTERN_C
+# define __END_PUBLIC __END_EXTERN_C
+# define __BEGIN_HIDDEN __BEGIN_EXTERN_C
+# define __END_HIDDEN __END_EXTERN_C
#endif
-#if defined(__cplusplus)
-#define __BEGIN_DECLS __BEGIN_PUBLIC extern "C" {
-#define __END_DECLS } __END_PUBLIC
-#define __static_cast(x,y) static_cast<x>(y)
-#else
-#define __BEGIN_DECLS __BEGIN_PUBLIC
-#define __END_DECLS __END_PUBLIC
-#define __static_cast(x,y) (x)y
+#if defined(__FORCE_HIDDEN_DEFAULT)
+#define __BEGIN_DECLS __BEGIN_HIDDEN
+#define __END_DECLS __END_HIDDEN
+#else
+#define __BEGIN_DECLS __BEGIN_PUBLIC
+#define __END_DECLS __END_PUBLIC
#endif
/*
Index: sys/sys/cdefs_elf.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/cdefs_elf.h,v
retrieving revision 1.34
diff -u -p -r1.34 cdefs_elf.h
--- sys/sys/cdefs_elf.h 8 Dec 2010 01:18:55 -0000 1.34
+++ sys/sys/cdefs_elf.h 9 Dec 2010 02:55:07 -0000
@@ -51,13 +51,22 @@
#define __indr_reference(sym,alias) /* nada, since we do weak refs
*/
+#if defined(__FORCE_HIDDEN_DEFAULT)
+#define __hidden_alias_text(sym) ".hidden " sym ";"
+#else
+#define __hidden_alias_text(sym)
+#endif
+
+
#if __STDC__
#define __strong_alias(alias,sym)
\
- __asm(".global " _C_LABEL_STRING(#alias) "\n" \
+ __asm(__hidden_alias_text(_C_LABEL_STRING(#alias)) \
+ ".global " _C_LABEL_STRING(#alias) "\n" \
_C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym));
#define __weak_alias(alias,sym)
\
- __asm(".weak " _C_LABEL_STRING(#alias) "\n" \
+ __asm(__hidden_alias_text(_C_LABEL_STRING(#alias)) \
+ ".weak " _C_LABEL_STRING(#alias) "\n" \
_C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym));
/* Do not use __weak_extern, use __weak_reference instead */
@@ -86,10 +95,10 @@
#ifdef __LEADING_UNDERSCORE
#define __weak_alias(alias,sym) ___weak_alias(_/**/alias,_/**/sym)
#define ___weak_alias(alias,sym)
\
- __asm(".weak alias\nalias = sym");
+ __asm(__hidden_alias_text(alias) ".weak alias\nalias = sym");
#else
#define __weak_alias(alias,sym)
\
- __asm(".weak alias\nalias = sym");
+ __asm(__hidden_alias_text(alias) ".weak alias\nalias = sym");
#endif
#ifdef __LEADING_UNDERSCORE
#define __weak_extern(sym) ___weak_extern(_/**/sym)
Home |
Main Index |
Thread Index |
Old Index