From patchwork Wed Mar 21 01:05:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zack Weinberg X-Patchwork-Id: 26394 Received: (qmail 40898 invoked by alias); 21 Mar 2018 01:05:58 -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 40555 invoked by uid 89); 21 Mar 2018 01:05:58 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, KAM_STOCKGEN, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=jargon, bne, 5428, 5913 X-HELO: mailbackend.panix.com From: Zack Weinberg To: libc-alpha@sourceware.org Subject: [RFC PATCH] Introduce pt-compat-stubs and use it to replace pt-vfork. (Architecture maintainer feedback wanted.) Date: Tue, 20 Mar 2018 21:05:51 -0400 Message-Id: <20180321010551.9611-1-zackw@panix.com> MIME-Version: 1.0 I am looking into the possibility of eliminating all of the duplicate function definitions from libpthread, replacing them with properly-tagged weak compatibility symbols that just call the definition in libc. Because one of the duplicated functions is vfork, the calls to libc absolutely must reuse the stack frame (a "sibcall" in GCC internals jargon), and on several important targets, GCC does not implement sibcalls, or only implements them for intra-module calls. But we only need to implement a single special case, sibcalling a function with exactly the same signature, from immediately after the caller's own entry point; so doing it by hand in assembly language is not a crazy notion. I believe I have managed to turn the trick for all currently-supported targets *except* powerpc64, where I cannot find a way around a linker sanity check. The object file contains 0000000000000000 <.__pstub_vfork>: 0: 48 00 00 00 b 0 <.__pstub_vfork> 0: R_PPC64_REL24 __libc_vfork 4: 60 00 00 00 nop and the linker throws this error: nptl/libpthread_pic.a(pt-compat-stubs.os): In function `__pstub_vfork': .../pt-compat-stubs.S:56:(.text+0x0): call to `__libc_vfork@@GLIBC_PRIVATE' lacks nop, can't restore toc; recompile with -fPIC You can see that there *is* a nop after the call. GNU ld lumps several different circumstances into this error message, one of which is just that R_PPC64_REL24 to a symbol outside the current module has been applied to a plain branch (as opposed to branch-and-link) instruction. *Normally* this would be unsafe, but in this specific case, I believe it would work fine: __pstub_vfork is never called from within libpthread, so __libc_vfork will ultimately return to a TOC-restoration shim within __pstub_vfork's own caller. There's some code in bfd/elf64-ppc.c that makes it sound like there might be a way to bypass the sanity check, if (stub_entry->stub_type == ppc_stub_plt_call && !htab->opd_abi && htab->params->plt_localentry0 != 0 && is_elfv2_localentry0 (&h->elf)) { /* The function doesn't use or change r2. */ can_plt_call = TRUE; } but I can't figure out how to make that condition be true. Any help would be appreciated. Anyhow, I thought I'd get some feedback on the changes to the other architectures as well, before I go any further. This patch just converts the existing vfork stub, so that review can focus on the new sysdep.h SIBCALL macros. * sysdeps/generic/pt-compat-stubs.S: New file. * nptl/pt-vfork.c, sysdeps/unix/sysv/linux/aarch64/pt-vfork.c * sysdeps/unix/sysv/linux/m68k/pt-vfork.c * sysdeps/unix/sysv/linux/tile/pt-vfork.c Remove file. * nptl/Makefile (libpthread-routines): Remove pt-vfork, add pt-compat-stubs. (libpthread-shared-only-routines): Add pt-compat-stubs. * posix/vfork.c: Define __libc_vfork as well as __vfork and vfork. * sysdeps/generic/sysdep.h (SIBCALL): New macro to perform sibling calls; the generic definition errors out if used. * sysdeps/aarch64/sysdep.h, sysdeps/arm/sysdep.h * sysdeps/hppa/sysdep.h, sysdeps/ia64/sysdep.h * sysdeps/m68k/sysdep.h, sysdeps/microblaze/sysdep.h * sysdeps/nios2/sysdep.h, sysdeps/powerpc/powerpc32/sysdep.h * sysdeps/powerpc/powerpc64/sysdep.h, sysdeps/s390/s390-32/sysdep.h * sysdeps/s390/s390-64/sysdep.h, sysdeps/tile/sysdep.h * sysdeps/unix/alpha/sysdep.h, sysdeps/unix/mips/mips32/sysdep.h * sysdeps/unix/mips/mips64/n32/sysdep.h * sysdeps/unix/mips/mips64/n64/sysdep.h * sysdeps/unix/sysv/linux/riscv/sysdep.h * sysdeps/x86/sysdep.h Provide appropriate architecture-specific definition of SIBCALL. --- nptl/Makefile | 5 ++- nptl/pt-vfork.c | 65 ------------------------------ posix/vfork.c | 6 +-- sysdeps/aarch64/sysdep.h | 9 +++++ sysdeps/arm/sysdep.h | 9 +++++ sysdeps/generic/pt-compat-stubs.S | 64 +++++++++++++++++++++++++++++ sysdeps/generic/sysdep.h | 13 +++++- sysdeps/hppa/sysdep.h | 10 +++++ sysdeps/ia64/sysdep.h | 9 +++++ sysdeps/m68k/sysdep.h | 9 +++++ sysdeps/microblaze/sysdep.h | 9 +++++ sysdeps/nios2/sysdep.h | 23 ++++++++++- sysdeps/powerpc/powerpc32/sysdep.h | 8 ++++ sysdeps/powerpc/powerpc64/sysdep.h | 9 +++++ sysdeps/s390/s390-32/sysdep.h | 9 +++++ sysdeps/s390/s390-64/sysdep.h | 9 +++++ sysdeps/sh/sysdep.h | 14 +++++++ sysdeps/sparc/sysdep.h | 9 +++++ sysdeps/tile/sysdep.h | 9 +++++ sysdeps/unix/alpha/sysdep.h | 10 +++++ sysdeps/unix/mips/mips32/sysdep.h | 25 ++++++++++++ sysdeps/unix/mips/mips64/n32/sysdep.h | 31 ++++++++++++++ sysdeps/unix/mips/mips64/n64/sysdep.h | 23 +++++++++++ sysdeps/unix/sysv/linux/aarch64/pt-vfork.c | 54 ------------------------- sysdeps/unix/sysv/linux/m68k/pt-vfork.c | 1 - sysdeps/unix/sysv/linux/riscv/sysdep.h | 9 +++++ sysdeps/unix/sysv/linux/tile/pt-vfork.c | 1 - sysdeps/x86/sysdep.h | 9 +++++ 28 files changed, 333 insertions(+), 128 deletions(-) delete mode 100644 nptl/pt-vfork.c create mode 100644 sysdeps/generic/pt-compat-stubs.S delete mode 100644 sysdeps/unix/sysv/linux/aarch64/pt-vfork.c delete mode 100644 sysdeps/unix/sysv/linux/m68k/pt-vfork.c delete mode 100644 sysdeps/unix/sysv/linux/tile/pt-vfork.c diff --git a/nptl/Makefile b/nptl/Makefile index 94be92c789..18fbdfbee7 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -120,9 +120,10 @@ libpthread-routines = nptl-init vars events version pt-interp \ cancellation \ lowlevellock \ lll_timedlock_wait lll_timedwait_tid \ - pt-fork pt-vfork \ + pt-fork \ $(pthread-compat-wrappers) \ pt-raise pt-system \ + pt-compat-stubs \ flockfile ftrylockfile funlockfile \ sigaction \ herrno res pt-allocrtsig \ @@ -146,7 +147,7 @@ libpthread-routines = nptl-init vars events version pt-interp \ # pthread_setresgid libpthread-shared-only-routines = version pt-interp pt-allocrtsig \ - unwind-forcedunwind + pt-compat-stubs unwind-forcedunwind # Since cancellation handling is in large parts handled using exceptions # we have to compile some files with exception handling enabled, some diff --git a/nptl/pt-vfork.c b/nptl/pt-vfork.c deleted file mode 100644 index 2f890d3f30..0000000000 --- a/nptl/pt-vfork.c +++ /dev/null @@ -1,65 +0,0 @@ -/* vfork ABI-compatibility entry points for libpthread. - Copyright (C) 2014-2018 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 - -/* libpthread used to have its own vfork implementation that differed - from libc's only in having a pointless micro-optimization. There - is no longer any use to having a separate copy in libpthread, but - the historical ABI requires it. For static linking, there is no - need to provide anything here--the libc version will be linked in. - For shared library ABI compatibility, there must be __vfork and - vfork symbols in libpthread.so; so we define them using IFUNC to - redirect to the libc function. */ - -/* Note! If the architecture doesn't support IFUNC, then we need an - alternate target-specific mechanism to implement this. So we just - assume IFUNC here and require that the target override this file - if necessary. - - If the architecture can assume all supported versions of gcc will - produce a tail-call to __libc_vfork, consider including the version - in sysdeps/unix/sysv/linux/aarch64/pt-vfork.c. */ - -#if !HAVE_IFUNC -# error "must write pt-vfork for this machine or get IFUNC support" -#endif - -#if (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ - || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)) - -extern __typeof (vfork) __libc_vfork; /* Defined in libc. */ - -# undef INIT_ARCH -# define INIT_ARCH() -# define DEFINE_VFORK(name) libc_ifunc (name, &__libc_vfork) - -#endif - -#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) -extern __typeof(vfork) vfork_ifunc; -DEFINE_VFORK (vfork_ifunc) -compat_symbol (libpthread, vfork_ifunc, vfork, GLIBC_2_0); -#endif - -#if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) -extern __typeof(vfork) __vfork_ifunc; -DEFINE_VFORK (__vfork_ifunc) -compat_symbol (libpthread, __vfork_ifunc, __vfork, GLIBC_2_1_2); -#endif diff --git a/posix/vfork.c b/posix/vfork.c index d4e76ad21e..07cfca1885 100644 --- a/posix/vfork.c +++ b/posix/vfork.c @@ -21,10 +21,10 @@ /* If we don't have vfork, fork is close enough. */ __pid_t -__vfork (void) +__libc_vfork (void) { return __fork (); } +strong_alias (__libc_vfork, __vfork) libc_hidden_def (__vfork) - -weak_alias (__vfork, vfork) +weak_alias (__libc_vfork, vfork) diff --git a/sysdeps/aarch64/sysdep.h b/sysdeps/aarch64/sysdep.h index 5b30709436..a790e3b4ea 100644 --- a/sysdeps/aarch64/sysdep.h +++ b/sysdeps/aarch64/sysdep.h @@ -151,6 +151,15 @@ movk PTR_REG (R), #:abs_g0_nc:NAME; #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + b JUMPTARGET(dest) + /* Since C identifiers are not normally prefixed with an underscore on this system, the asm identifier `syscall_error' intrudes on the C name space. Make sure we use an innocuous name. */ diff --git a/sysdeps/arm/sysdep.h b/sysdeps/arm/sysdep.h index 21673feea2..b3a233bff5 100644 --- a/sysdeps/arm/sysdep.h +++ b/sysdeps/arm/sysdep.h @@ -121,6 +121,15 @@ #define CALL_MCOUNT /* Do nothing. */ #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + b PLTJMP(dest) + /* Since C identifiers are not normally prefixed with an underscore on this system, the asm identifier `syscall_error' intrudes on the C name space. Make sure we use an innocuous name. */ diff --git a/sysdeps/generic/pt-compat-stubs.S b/sysdeps/generic/pt-compat-stubs.S new file mode 100644 index 0000000000..9edf765c8c --- /dev/null +++ b/sysdeps/generic/pt-compat-stubs.S @@ -0,0 +1,64 @@ +/* Compatibility stubs for functions formerly exposed by libpthread. + Copyright (C) 2018 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 + . */ + +/* The functions defined by this file used to have two different + definitions, one in libc.so and one in libpthread.so. Nowadays, + only the version in libc is necessary, but libpthread must continue + to expose these symbols for compatibility's sake. The stubs just + jump to the definition in libc. + + This file is written in heavily macro-ized assembly language + because one of the stubs that it needs to define is vfork, and the + implementation of vfork must not touch the stack. Having done the + work to handle that, we may as well reuse the mechanism for all of + the stubs. */ + +#include +#include + + compat_text_section + +#define define_stub(name) \ + define_stub_1(__pstub_##name, __libc_##name) +#define define_stub_1(pstub_name, libc_name) \ + ENTRY(pstub_name) ASM_LINE_SEP \ + SIBCALL(libc_name) ASM_LINE_SEP \ + END(pstub_name) + +#define compat_stub(base, sym, ver) \ + compat_stub_1(base, sym, ver, __COUNTER__) +#define compat_stub_1(base, sym, ver, tag) \ + compat_stub_2(base, sym, ver, tag) +#define compat_stub_2(base, sym, ver, tag) \ + compat_stub_3(__pstub_##base, __pstub_##base##_##tag, sym, ver) +#define compat_stub_3(base, nonce, sym, ver) \ + weak_alias(base, nonce) ASM_LINE_SEP \ + compat_symbol(libpthread, nonce, sym, ver) + +#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ + || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) + + define_stub(vfork) +# if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) + compat_stub(vfork, vfork, GLIBC_2_0) +# endif +# if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) + compat_stub(vfork, __vfork, GLIBC_2_1_2) +# endif + +#endif diff --git a/sysdeps/generic/sysdep.h b/sysdeps/generic/sysdep.h index 934d4da839..59e8ec237a 100644 --- a/sysdeps/generic/sysdep.h +++ b/sysdeps/generic/sysdep.h @@ -33,9 +33,20 @@ # ifndef JUMPTARGET # define JUMPTARGET(sym) sym # endif + +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +# ifndef SIBCALL +# define SIBCALL(dest) \ + .error "Missing definition of SIBCALL" +# endif #endif -/* Makros to generate eh_frame unwind information. */ + +/* Macros to generate eh_frame unwind information. */ #ifdef __ASSEMBLER__ # define cfi_startproc .cfi_startproc # define cfi_endproc .cfi_endproc diff --git a/sysdeps/hppa/sysdep.h b/sysdeps/hppa/sysdep.h index 4b139228a1..12cfe51dc3 100644 --- a/sysdeps/hppa/sysdep.h +++ b/sysdeps/hppa/sysdep.h @@ -62,6 +62,16 @@ #define PSEUDO_END(name) \ END (name) + +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + b JUMPTARGET(dest) + #undef JUMPTARGET #define JUMPTARGET(name) name #define SYSCALL_PIC_SETUP /* Nothing. */ diff --git a/sysdeps/ia64/sysdep.h b/sysdeps/ia64/sysdep.h index 6066ebd1d3..ba0e4a5ed2 100644 --- a/sysdeps/ia64/sysdep.h +++ b/sysdeps/ia64/sysdep.h @@ -59,4 +59,13 @@ #undef END #define END(sym) .endp C_SYMBOL_NAME(sym) +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + .mib; nop 0; nop 0; br.sptk.many C_SYMBOL_NAME(dest);; + #endif /* ASSEMBLER */ diff --git a/sysdeps/m68k/sysdep.h b/sysdeps/m68k/sysdep.h index 0ecb3eae9f..ae085ed9f1 100644 --- a/sysdeps/m68k/sysdep.h +++ b/sysdeps/m68k/sysdep.h @@ -71,4 +71,13 @@ # define JUMPTARGET(name) name # endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + jbra JUMPTARGET(dest) + #endif /* __ASSEMBLER__ */ diff --git a/sysdeps/microblaze/sysdep.h b/sysdeps/microblaze/sysdep.h index 86cd827a09..091986d221 100644 --- a/sysdeps/microblaze/sysdep.h +++ b/sysdeps/microblaze/sysdep.h @@ -70,6 +70,15 @@ # define PSEUDO_END(name) \ END (name) +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + brid JUMPTARGET(dest); nop + # undef JUMPTARGET # ifdef PIC # define JUMPTARGET(name) name##@PLTPC diff --git a/sysdeps/nios2/sysdep.h b/sysdeps/nios2/sysdep.h index 38ea9456af..97a3e2eb24 100644 --- a/sysdeps/nios2/sysdep.h +++ b/sysdeps/nios2/sysdep.h @@ -62,4 +62,25 @@ # define CALL_MCOUNT /* Do nothing. */ #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#ifdef __PIC__ +#define SIBCALL(dest) \ + nextpc r2; \ +1: \ + movhi r3, %hiadj(_gp_got - 1b); \ + addi r3, r3, %lo(_gp_got - 1b); \ + addi r2, r2, r3; \ + ldw r2, %call(dest)(r2); \ + jmp r2 +#else +#define SIBCALL(dest) \ + jmpi dest +#endif + + #endif /* __ASSEMBLER__ */ diff --git a/sysdeps/powerpc/powerpc32/sysdep.h b/sysdeps/powerpc/powerpc32/sysdep.h index 5f1294ead3..da67bf0e91 100644 --- a/sysdeps/powerpc/powerpc32/sysdep.h +++ b/sysdeps/powerpc/powerpc32/sysdep.h @@ -90,6 +90,14 @@ GOT_LABEL: ; \ cfi_endproc; \ ASM_SIZE_DIRECTIVE(name) +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#define SIBCALL(dest) \ + b JUMPTARGET(dest) + #if !IS_IN(rtld) && !defined(__SPE__) # define ABORT_TRANSACTION_IMPL \ cmpwi 2,0; \ diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h index 2df1d9b6e6..10b778b244 100644 --- a/sysdeps/powerpc/powerpc64/sysdep.h +++ b/sysdeps/powerpc/powerpc64/sysdep.h @@ -359,6 +359,15 @@ LT_LABELSUFFIX(name,_name_end): ; \ #define PSEUDO_END_ERRVAL(name) \ END (name) +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#define SIBCALL(dest) \ + b JUMPTARGET(dest); \ + ori r0, r0, 0 + #else /* !__ASSEMBLER__ */ #if _CALL_ELF != 2 diff --git a/sysdeps/s390/s390-32/sysdep.h b/sysdeps/s390/s390-32/sysdep.h index 7e2763fe92..6ba1496735 100644 --- a/sysdeps/s390/s390-32/sysdep.h +++ b/sysdeps/s390/s390-32/sysdep.h @@ -59,6 +59,15 @@ #define CALL_MCOUNT /* Do nothing. */ #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + jg JUMPTARGET(dest) + /* Since C identifiers are not normally prefixed with an underscore on this system, the asm identifier `syscall_error' intrudes on the C name space. Make sure we use an innocuous name. */ diff --git a/sysdeps/s390/s390-64/sysdep.h b/sysdeps/s390/s390-64/sysdep.h index a573e08e92..67f8f09542 100644 --- a/sysdeps/s390/s390-64/sysdep.h +++ b/sysdeps/s390/s390-64/sysdep.h @@ -57,6 +57,15 @@ #define CALL_MCOUNT /* Do nothing. */ #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + jg JUMPTARGET(dest) + /* Since C identifiers are not normally prefixed with an underscore on this system, the asm identifier `syscall_error' intrudes on the C name space. Make sure we use an innocuous name. */ diff --git a/sysdeps/sh/sysdep.h b/sysdeps/sh/sysdep.h index 37889fb0cc..63eab89001 100644 --- a/sysdeps/sh/sysdep.h +++ b/sysdeps/sh/sysdep.h @@ -66,6 +66,20 @@ #define CALL_MCOUNT /* Do nothing. */ #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + mov.l 1f, r1; \ + braf r1; \ + nop; \ +0: .align 2; \ +1: .long dest@PLT+(.-0b) + + /* Since C identifiers are not normally prefixed with an underscore on this system, the asm identifier `syscall_error' intrudes on the C name space. Make sure we use an innocuous name. */ diff --git a/sysdeps/sparc/sysdep.h b/sysdeps/sparc/sysdep.h index 487852c7ec..130d782b11 100644 --- a/sysdeps/sparc/sysdep.h +++ b/sysdeps/sparc/sysdep.h @@ -79,4 +79,13 @@ C_LABEL(name) \ #undef LOC #define LOC(name) .L##name +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + jmp dest + #endif /* __ASSEMBLER__ */ diff --git a/sysdeps/tile/sysdep.h b/sysdeps/tile/sysdep.h index bb82d3ca6c..aee9893233 100644 --- a/sysdeps/tile/sysdep.h +++ b/sysdeps/tile/sysdep.h @@ -56,6 +56,15 @@ #define CALL_MCOUNT /* Do nothing. */ #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + j plt(dest) + /* Local label name for asm code. */ #define L(name) .L##name diff --git a/sysdeps/unix/alpha/sysdep.h b/sysdeps/unix/alpha/sysdep.h index 104aa8e48b..263117f805 100644 --- a/sysdeps/unix/alpha/sysdep.h +++ b/sysdeps/unix/alpha/sysdep.h @@ -148,6 +148,16 @@ __LABEL(name) \ #undef PSEUDO_END_ERRVAL #define PSEUDO_END_ERRVAL(sym) END(sym) +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#define SIBCALL(dest) \ + ldgp gp, 0(pv); \ + lda pv, dest; \ + jmp (pv), dest + #define ret_ERRVAL ret #define r0 v0 diff --git a/sysdeps/unix/mips/mips32/sysdep.h b/sysdeps/unix/mips/mips32/sysdep.h index 825d007489..a45eba7430 100644 --- a/sysdeps/unix/mips/mips32/sysdep.h +++ b/sysdeps/unix/mips/mips32/sysdep.h @@ -54,3 +54,28 @@ L(syse1): bne a3, zero, 99b; \ L(syse1): #endif + +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#ifdef __PIC__ +#define SIBCALL(dest) \ + .set nomips16; \ + .set noreorder; \ + .cpload $25; \ + .set nomacro; \ + lw $25, %call16(dest)($28); \ + nop; \ + .reloc 1f, R_MIPS_JALR, dest; \ +1: jr $25; \ + nop +#else +#define SIBCALL(dest) \ + .set nomips16; \ + .set noreorder; \ + .set nomacro; \ + j dest; \ + nop +#endif diff --git a/sysdeps/unix/mips/mips64/n32/sysdep.h b/sysdeps/unix/mips/mips64/n32/sysdep.h index 78c1eca872..caae9a4b4d 100644 --- a/sysdeps/unix/mips/mips64/n32/sysdep.h +++ b/sysdeps/unix/mips/mips64/n32/sysdep.h @@ -61,4 +61,35 @@ L(syse1): L(syse1): #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#ifdef __PIC__ +/* There's no PLT on MIPS/n32, we are expected to load the address by + hand, but the usual gp register on MIPS ($28) is call-saved so we + can't use it. Use $at ($1) instead. */ +#define SIBCALL(dest) \ + .set nomips16; \ + .set noreorder; \ + .set nomacro; \ + .set noat; \ +0: lui $1, %hi(%neg(%gp_rel(0b))); \ + addiu $1, $1, %lo(%neg(%gp_rel(0b))); \ + addu $1, $1, $25; \ + lw $1, %call16(dest)($1); \ + nop; \ + .reloc 1f, R_MIPS_JALR, dest; \ +1: jr $25; \ + nop +#else +#define SIBCALL(dest) \ + .set nomips16; \ + .set noreorder; \ + .set nomacro; \ + j dest; \ + nop #endif + +#endif /* __ASSEMBLER__ */ diff --git a/sysdeps/unix/mips/mips64/n64/sysdep.h b/sysdeps/unix/mips/mips64/n64/sysdep.h index a559917e64..167f330020 100644 --- a/sysdeps/unix/mips/mips64/n64/sysdep.h +++ b/sysdeps/unix/mips/mips64/n64/sysdep.h @@ -61,4 +61,27 @@ L(syse1): L(syse1): #endif +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#define SIBCALL(dest) \ +/* There's no PLT on MIPS/n64, we are expected to load the address by + hand, but the usual gp register on MIPS ($28) is call-saved so we + can't use it. Use $at ($1) instead. */ +#define SIBCALL(dest) \ + .set nomips16; \ + .set noreorder; \ + .set nomacro; \ + .set noat; \ +0: lui $1, %hi(%neg(%gp_rel(0b))); \ + daddiu $1, $1, %lo(%neg(%gp_rel(0b))); \ + daddu $1, $1, $25; \ + ld $1, %call16(dest)($1); \ + nop; \ + .reloc 1f, R_MIPS_JALR, dest; \ +1: jr $25; \ + nop + #endif diff --git a/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c b/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c deleted file mode 100644 index 2b277f25ec..0000000000 --- a/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c +++ /dev/null @@ -1,54 +0,0 @@ -/* vfork ABI-compatibility entry points for libpthread. - Copyright (C) 2014-2018 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 - -/* libpthread used to have its own vfork implementation that differed - from libc's only in having a pointless micro-optimization. There - is no longer any use to having a separate copy in libpthread, but - the historical ABI requires it. For static linking, there is no - need to provide anything here--the libc version will be linked in. - For shared library ABI compatibility, there must be __vfork and - vfork symbols in libpthread.so. */ - -#if HAVE_IFUNC -# include -#elif (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \ - || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)) - -/* Thankfully, on AArch64 we can rely on the compiler generating - a tail call here. */ - -extern void __libc_vfork (void); - -void -vfork_compat (void) -{ - __libc_vfork (); -} - -# if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) -compat_symbol (libpthread, vfork_compat, vfork, GLIBC_2_0); -# endif - -# if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20) -strong_alias (vfork_compat, vfork_compat2) -compat_symbol (libpthread, vfork_compat2, __vfork, GLIBC_2_1_2); -# endif - -#endif diff --git a/sysdeps/unix/sysv/linux/m68k/pt-vfork.c b/sysdeps/unix/sysv/linux/m68k/pt-vfork.c deleted file mode 100644 index 5fbc6526aa..0000000000 --- a/sysdeps/unix/sysv/linux/m68k/pt-vfork.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.h b/sysdeps/unix/sysv/linux/riscv/sysdep.h index 5470ea3d2a..0a2c2f8696 100644 --- a/sysdeps/unix/sysv/linux/riscv/sysdep.h +++ b/sysdeps/unix/sysv/linux/riscv/sysdep.h @@ -107,6 +107,15 @@ # undef ret_ERRVAL # define ret_ERRVAL ret +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + tail JUMPTARGET(dest) + #endif /* __ASSEMBLER__ */ /* In order to get __set_errno() definition in INLINE_SYSCALL. */ diff --git a/sysdeps/unix/sysv/linux/tile/pt-vfork.c b/sysdeps/unix/sysv/linux/tile/pt-vfork.c deleted file mode 100644 index 5fbc6526aa..0000000000 --- a/sysdeps/unix/sysv/linux/tile/pt-vfork.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h index afcb7cfd76..6baf03de94 100644 --- a/sysdeps/x86/sysdep.h +++ b/sysdeps/x86/sysdep.h @@ -46,6 +46,15 @@ #define ENTRY_CHK(name) ENTRY (name) #define END_CHK(name) END (name) +/* Make a "sibling call" to DEST -- that is, transfer control to DEST + as-if it had been the function called by the caller of this function. + DEST is likely to be defined in a different shared object. Only + ever used immediately after ENTRY. Must not touch the stack at + all, and must preserve all argument and call-saved registers. */ +#undef SIBCALL +#define SIBCALL(dest) \ + jmp JUMPTARGET(dest) + /* Since C identifiers are not normally prefixed with an underscore on this system, the asm identifier `syscall_error' intrudes on the C name space. Make sure we use an innocuous name. */