From patchwork Sun Aug 6 22:26:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 21940 Received: (qmail 82633 invoked by alias); 6 Aug 2017 22:26:13 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 80771 invoked by uid 89); 6 Aug 2017 22:26:12 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.7 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS, TBC autolearn=ham version=3.3.2 spammy= X-HELO: mail-pf0-f195.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition:user-agent; bh=xGl5wKHdNs1sZDAvhj9uCD/Uuz4rPTnW5TWN7f3/GfQ=; b=URI9v4KuFEvCtote5X2FAxic76FhjIAdUpgVueT524lRJN9TQgG3hhcW9aLLJ6t/ji EwH2lev66ZXC46w7n9qdcZJSLzh86y6eLxyh7akE07zOBXvLpIWTyq6Q+IrHDxhxUXfB XdNq2NhGjy4pBjGlO6SEfTaE0FQwKGfWwXObP6iBI7hgi8lBlYM+8gDho7QtBTZDXBZ4 qN+WzhNKolr7B7ayIbqCMsW4dqlF/efnpnZiFXfVr8tnDNVkqSzkVHSyBt+mgjN4535V N+ycDzdKbzyceAuGp2Tckenq01ApjOJdRg3b+LJOWA7N++S9or8lLwAOiBt3w+Uw5tVZ b3oQ== X-Gm-Message-State: AIVw112toqgUH8FN6Lvx1g83+qDfprakEjWOpVpsty3+N1gtPbqVyd98 sfAuDIYr+fb96g/6 X-Received: by 10.98.103.137 with SMTP id t9mr9962108pfj.273.1502058367918; Sun, 06 Aug 2017 15:26:07 -0700 (PDT) Date: Sun, 6 Aug 2017 15:26:06 -0700 From: "H.J. Lu" To: GNU C Library Subject: [PATCH] i386: Add _startup_sbrk and _startup_fatal [BZ #21913] Message-ID: <20170806222606.GA13700@gmail.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.8.3 (2017-05-23) On Linux/x86, there are 3 ways to make a system call: 1. call *%gs:SYSINFO_OFFSET. This requires TLS initialization. 2. call *_dl_sysinfo. This requires relocation of _dl_sysinfo. 3. int $0x80. This works everywhere. When an object file is compiled with PIC, #1 is prefered since it is faster than #3 and doesn't require relocation of _dl_sysinfo. For dynamic executables, ld.so initializes TLS. However, for static executables, before TLS is initialized by __libc_setup_tls, #3 should be used for syscalls. This patch adds _startup_sbrk and _startup_fatal to be used in static executables before __libc_setup_tls is called. By default, they are defined to __sbrk and __libc_fatal, respectively. On x86, a special _startup_sbrk is provided and _startup_fatal is turned into ABORT_INSTRUCTION. Any comments? H.J. --- [BZ #21913] * csu/libc-tls.c: Include . (__libc_setup_tls): Call _startup_sbrk instead of __sbrk. Call _startup_fatal instead of __libc_fatal. * elf/dl-tunables.c: Include . (tunables_strdup): Call _startup_sbrk instead of __sbrk. * sysdeps/generic/startup.h: New file. * sysdeps/unix/sysv/linux/i386/startup.h: Likewise. * sysdeps/unix/sysv/linux/i386/startup_sbrk.c: Likewise. * sysdeps/unix/sysv/linux/i386/Makefile (sysdep_routine): Add startup_sbrk if default to PIC. (static-only-routines): Likewise. --- csu/libc-tls.c | 13 +++--- elf/dl-tunables.c | 8 +++- sysdeps/generic/startup.h | 30 +++++++++++++ sysdeps/unix/sysv/linux/i386/Makefile | 4 ++ sysdeps/unix/sysv/linux/i386/startup.h | 38 ++++++++++++++++ sysdeps/unix/sysv/linux/i386/startup_sbrk.c | 67 +++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 sysdeps/generic/startup.h create mode 100644 sysdeps/unix/sysv/linux/i386/startup.h create mode 100644 sysdeps/unix/sysv/linux/i386/startup_sbrk.c diff --git a/csu/libc-tls.c b/csu/libc-tls.c index 3c897bf28b..6f0e698220 100644 --- a/csu/libc-tls.c +++ b/csu/libc-tls.c @@ -16,11 +16,12 @@ License along with the GNU C Library; if not, see . */ +#include +#include +#include #include #include #include -#include -#include #include @@ -142,11 +143,11 @@ __libc_setup_tls (void) _dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign and dl_tls_static_align. */ tcb_offset = roundup (memsz + GL(dl_tls_static_size), max_align); - tlsblock = __sbrk (tcb_offset + TLS_INIT_TCB_SIZE + max_align); + tlsblock = _startup_sbrk (tcb_offset + TLS_INIT_TCB_SIZE + max_align); #elif TLS_DTV_AT_TP tcb_offset = roundup (TLS_INIT_TCB_SIZE, align ?: 1); - tlsblock = __sbrk (tcb_offset + memsz + max_align - + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); + tlsblock = _startup_sbrk (tcb_offset + memsz + max_align + + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); tlsblock += TLS_PRE_TCB_SIZE; #else /* In case a model with a different layout for the TCB and DTV @@ -193,7 +194,7 @@ __libc_setup_tls (void) # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" #endif if (__builtin_expect (lossage != NULL, 0)) - __libc_fatal (lossage); + _startup_fatal (lossage); /* Update the executable's link map with enough information to make the TLS routines happy. */ diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c index 231fb8ca93..23c89b2c03 100644 --- a/elf/dl-tunables.c +++ b/elf/dl-tunables.c @@ -18,9 +18,11 @@ License along with the GNU C Library; if not, see . */ +#include +#include +#include #include #include -#include #include #include #include @@ -42,7 +44,9 @@ tunables_strdup (const char *in) size_t i = 0; while (in[i++] != '\0'); - char *out = __sbrk (i); + + /* Can't use __sbrk before __libc_setup_tls is called. */ + char *out = _startup_sbrk (i); /* FIXME: In reality if the allocation fails, __sbrk will crash attempting to set the thread-local errno since the TCB has not yet been set up. This diff --git a/sysdeps/generic/startup.h b/sysdeps/generic/startup.h new file mode 100644 index 0000000000..aa63b31181 --- /dev/null +++ b/sysdeps/generic/startup.h @@ -0,0 +1,30 @@ +/* Generic definitions of functions used by static libc main startup. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +static inline void * +_startup_sbrk (intptr_t __delta) +{ + return __sbrk (__delta); +} + +__attribute__ ((__noreturn__)) +static inline void +_startup_fatal (const char *__message) +{ + __libc_fatal (__message); +} diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile index 4080b8c966..cefa1511f6 100644 --- a/sysdeps/unix/sysv/linux/i386/Makefile +++ b/sysdeps/unix/sysv/linux/i386/Makefile @@ -31,6 +31,10 @@ sysdep_routines += divdi3 shared-only-routines += divdi3 CPPFLAGS-divdi3.c = -Din_divdi3_c endif +ifneq (,$(pic-default)) +sysdep_routines += startup_sbrk +static-only-routines += startup_sbrk +endif endif ifeq ($(subdir),nptl) diff --git a/sysdeps/unix/sysv/linux/i386/startup.h b/sysdeps/unix/sysv/linux/i386/startup.h new file mode 100644 index 0000000000..ccfba45153 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/startup.h @@ -0,0 +1,38 @@ +/* Linux/i386 definitions of functions used by static libc main startup. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#if defined PIC && !defined SHARED +# include + +/* Can't use "call *%gs:SYSINFO_OFFSET" during statup in static PIE. */ +# define I386_USE_SYSENTER 0 + +extern void * _startup_sbrk (intptr_t) attribute_hidden; + +__attribute__ ((__noreturn__)) +static inline void +_startup_fatal (const char *__message __attribute__ ((unused))) +{ + /* This is only called very early during startup in static PIE. + FIXME: How can it be improved? */ + ABORT_INSTRUCTION; + __builtin_unreachable (); +} +#else +# include_next +#endif diff --git a/sysdeps/unix/sysv/linux/i386/startup_sbrk.c b/sysdeps/unix/sysv/linux/i386/startup_sbrk.c new file mode 100644 index 0000000000..8239938ddf --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/startup_sbrk.c @@ -0,0 +1,67 @@ +/* Linux/i386 definitions of _startup_sbrk. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +/* Defined in brk.c. */ +extern void *__curbrk attribute_hidden; + +static int +startup_brk (void *addr) +{ + INTERNAL_SYSCALL_DECL (err); + void *newbrk = (void *) INTERNAL_SYSCALL_CALL (brk, err, addr); + __curbrk = newbrk; + if (newbrk < addr) + _startup_fatal (NULL); + return 0; +} + +/* Extend the process's data space by INCREMENT. If INCREMENT is negative, + shrink data space by - INCREMENT. Return start of new space allocated, + or call _startup_fatal for errors. */ + +void * +_startup_sbrk (intptr_t increment) +{ + void *oldbrk; + + /* Update __curbrk from the kernel's brk value. That way two separate + instances of __brk and __sbrk can share the heap, returning + interleaved pieces of it. */ + if (__curbrk == NULL) + if (startup_brk (0) < 0) /* Initialize the break. */ + _startup_fatal (NULL); + + if (increment == 0) + return __curbrk; + + oldbrk = __curbrk; + if (increment > 0 + ? ((uintptr_t) oldbrk + (uintptr_t) increment < (uintptr_t) oldbrk) + : ((uintptr_t) oldbrk < (uintptr_t) -increment)) + _startup_fatal (NULL); + + if (startup_brk (oldbrk + increment) < 0) + _startup_fatal (NULL); + + return oldbrk; +}