Movatterモバイル変換
[0]ホーム
This is the mail archive of thelibc-alpha@sourceware.orgmailing list for theglibc project.
[PATCH] i386: Add _startup_sbrk and _startup_fatal [BZ #21913]
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>
- Date: Sun, 6 Aug 2017 15:26:06 -0700
- Subject: [PATCH] i386: Add _startup_sbrk and _startup_fatal [BZ #21913]
- Authentication-results: sourceware.org; auth=none
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 isfaster than #3 and doesn't require relocation of _dl_sysinfo. Fordynamic executables, ld.so initializes TLS. However, for staticexecutables, before TLS is initialized by __libc_setup_tls, #3 shouldbe used for syscalls. This patch adds _startup_sbrk and _startup_fatalto be used in static executables before __libc_setup_tls is called. Bydefault, they are defined to __sbrk and __libc_fatal, respectively. Onx86, a special _startup_sbrk is provided and _startup_fatal is turnedinto ABORT_INSTRUCTION.Any comments?H.J.---[BZ #21913]* csu/libc-tls.c: Include <startup.h>.(__libc_setup_tls): Call _startup_sbrk instead of __sbrk. Call_startup_fatal instead of __libc_fatal.* elf/dl-tunables.c: Include <startup.h>.(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): Addstartup_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.cdiff --git a/csu/libc-tls.c b/csu/libc-tls.cindex 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 <http://www.gnu.org/licenses/>. */ +#include <unistd.h>+#include <stdio.h>+#include <startup.h> #include <errno.h> #include <ldsodefs.h> #include <tls.h>-#include <unistd.h>-#include <stdio.h> #include <sys/param.h> @@ -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.cindex 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 <http://www.gnu.org/licenses/>. */ +#include <unistd.h>+#include <stdio.h>+#include <startup.h> #include <stdint.h> #include <stdbool.h>-#include <unistd.h> #include <stdlib.h> #include <sysdep.h> #include <fcntl.h>@@ -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. Thisdiff --git a/sysdeps/generic/startup.h b/sysdeps/generic/startup.hnew file mode 100644index 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+ <http://www.gnu.org/licenses/>. */++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/Makefileindex 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.hnew file mode 100644index 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+ <http://www.gnu.org/licenses/>. */++#if defined PIC && !defined SHARED+# include <abort-instr.h>++/* 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 <startup.h>+#endifdiff --git a/sysdeps/unix/sysv/linux/i386/startup_sbrk.c b/sysdeps/unix/sysv/linux/i386/startup_sbrk.cnew file mode 100644index 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+ <http://www.gnu.org/licenses/>. */++#include <unistd.h>+#include <startup.h>+#include <errno.h>+#include <sysdep.h>++/* 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;+}-- 2.13.3
[8]ページ先頭