From 22e5bbd0deadcbd767864bd714e890b70e1fe1df Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 10 Apr 2019 17:10:36 -0400 Subject: [PATCH] overhaul i386 syscall mechanism not to depend on external asm source this is the first part of a series of patches intended to make __syscall fully self-contained in the object file produced using syscall.h, which will make it possible for crt1 code to perform syscalls. the (confusingly named) i386 __vsyscall mechanism, which this commit removes, was introduced before the presence of a valid thread pointer was mandatory; back then the thread pointer was setup lazily only if threads were used. the intent was to be able to perform syscalls using the kernel's fast entry point in the VDSO, which can use the sysenter (Intel) or syscall (AMD) instruction instead of int $128, but without inlining an access to the __syscall global at the point of each syscall, which would incur a significant size cost from PIC setup everywhere. the mechanism also shuffled registers/calling convention around to avoid spills of call-saved registers, and to avoid allocating ebx or ebp via asm constraints, since there are plenty of broken-but-supported compiler versions which are incapable of allocating ebx with -fPIC or ebp with -fno-omit-frame-pointer. the new mechanism preserves the properties of avoiding spills and avoiding allocation of ebx/ebp in constraints, but does it inline, using some fairly simple register shuffling, and uses a field of the thread structure rather than global data for the vdso-provided syscall code address. for now, the external __syscall function is refactored not to use the old __vsyscall so it can be kept, but the intent is to remove it too. --- arch/i386/syscall_arch.h | 29 ++++++++---- ldso/dynlink.c | 3 ++ src/env/__init_tls.c | 2 + src/env/__libc_start_main.c | 2 +- src/internal/defsysinfo.c | 3 ++ src/internal/i386/defsysinfo.s | 9 ++++ src/internal/i386/syscall.s | 81 +++++----------------------------- src/internal/libc.c | 1 - src/thread/pthread_create.c | 1 + 9 files changed, 51 insertions(+), 80 deletions(-) create mode 100644 src/internal/defsysinfo.c create mode 100644 src/internal/i386/defsysinfo.s diff --git a/arch/i386/syscall_arch.h b/arch/i386/syscall_arch.h index 4c9d874a..8fe35424 100644 --- a/arch/i386/syscall_arch.h +++ b/arch/i386/syscall_arch.h @@ -3,52 +3,63 @@ ((union { long long ll; long l[2]; }){ .ll = x }).l[1] #define __SYSCALL_LL_O(x) __SYSCALL_LL_E((x)) +#if SYSCALL_NO_TLS +#define SYSCALL_INSNS "int $128" +#else +#define SYSCALL_INSNS "call *%%gs:16" +#endif + +#define SYSCALL_INSNS_12 "xchg %%ebx,%%edx ; " SYSCALL_INSNS " ; xchg %%ebx,%%edx" +#define SYSCALL_INSNS_34 "xchg %%ebx,%%edi ; " SYSCALL_INSNS " ; xchg %%ebx,%%edi" + static inline long __syscall0(long n) { unsigned long __ret; - __asm__ __volatile__ (".hidden __vsyscall ; call __vsyscall" : "=a"(__ret) : "a"(n) : "memory"); + __asm__ __volatile__ (SYSCALL_INSNS : "=a"(__ret) : "a"(n) : "memory"); return __ret; } static inline long __syscall1(long n, long a1) { unsigned long __ret; - __asm__ __volatile__ (".hidden __vsyscall ; call __vsyscall" : "=a"(__ret) : "a"(n), "d"(a1) : "memory"); + __asm__ __volatile__ (SYSCALL_INSNS_12 : "=a"(__ret) : "a"(n), "d"(a1) : "memory"); return __ret; } static inline long __syscall2(long n, long a1, long a2) { unsigned long __ret; - __asm__ __volatile__ (".hidden __vsyscall ; call __vsyscall" : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2) : "memory"); + __asm__ __volatile__ (SYSCALL_INSNS_12 : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2) : "memory"); return __ret; } static inline long __syscall3(long n, long a1, long a2, long a3) { unsigned long __ret; - __asm__ __volatile__ (".hidden __vsyscall ; call __vsyscall" : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2), "D"(a3) : "memory"); + __asm__ __volatile__ (SYSCALL_INSNS_34 : "=a"(__ret) : "a"(n), "D"(a1), "c"(a2), "d"(a3) : "memory"); return __ret; } static inline long __syscall4(long n, long a1, long a2, long a3, long a4) { unsigned long __ret; - __asm__ __volatile__ (".hidden __vsyscall ; call __vsyscall" : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2), "D"(a3), "S"(a4) : "memory"); + __asm__ __volatile__ (SYSCALL_INSNS_34 : "=a"(__ret) : "a"(n), "D"(a1), "c"(a2), "d"(a3), "S"(a4) : "memory"); return __ret; } static inline long __syscall5(long n, long a1, long a2, long a3, long a4, long a5) { - unsigned long __ret; - __asm__ __volatile__ ("push %6 ; .hidden __vsyscall ; call __vsyscall ; add $4,%%esp" : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2), "D"(a3), "S"(a4), "g"(a5) : "memory"); + unsigned long __ret, __tmp; + __asm__ __volatile__ ("mov %%ebx,%1 ; mov %3,%%ebx ; " SYSCALL_INSNS " ; mov %1,%%ebx" + : "=a"(__ret), "=m"(__tmp) : "a"(n), "g"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); return __ret; } static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) { - unsigned long __ret; - __asm__ __volatile__ ("push %6 ; .hidden __vsyscall6 ; call __vsyscall6 ; add $4,%%esp" : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2), "D"(a3), "S"(a4), "g"(0+(long[]){a5, a6}) : "memory"); + unsigned long __ret, __tmp1, __tmp2; + __asm__ __volatile__ ("mov %%ebx,%1 ; mov %%ebp,%2 ; mov %4,%%ebx ; mov %9,%%ebp ; " SYSCALL_INSNS " ; mov %2,%%ebp ; mov %1,%%ebx" + : "=a"(__ret), "=m"(__tmp1), "=m"(__tmp2) : "a"(n), "g"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "g"(a6) : "memory"); return __ret; } diff --git a/ldso/dynlink.c b/ldso/dynlink.c index 7cb66db9..42a5470d 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -1,4 +1,5 @@ #define _GNU_SOURCE +#define SYSCALL_NO_TLS 1 #include #include #include @@ -1685,6 +1686,8 @@ _Noreturn void __dls3(size_t *sp) libc.auxv = auxv = (void *)(argv+i+1); decode_vec(auxv, aux, AUX_CNT); __hwcap = aux[AT_HWCAP]; + search_vec(auxv, &__sysinfo, AT_SYSINFO); + __pthread_self()->sysinfo = __sysinfo; libc.page_size = aux[AT_PAGESZ]; libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID] || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]); diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c index f1874f2a..5f12500c 100644 --- a/src/env/__init_tls.c +++ b/src/env/__init_tls.c @@ -1,3 +1,4 @@ +#define SYSCALL_NO_TLS 1 #include #include #include @@ -21,6 +22,7 @@ int __init_tp(void *p) td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock); td->locale = &libc.global_locale; td->robust_list.head = &td->robust_list.head; + td->sysinfo = __sysinfo; td->next = td->prev = td; return 0; } diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c index 7c95f822..8fbe5262 100644 --- a/src/env/__libc_start_main.c +++ b/src/env/__libc_start_main.c @@ -28,7 +28,7 @@ void __init_libc(char **envp, char *pn) libc.auxv = auxv = (void *)(envp+i+1); for (i=0; auxv[i]; i+=2) if (auxv[i]robust_list.head = &new->robust_list.head; new->CANARY = self->CANARY; + new->sysinfo = self->sysinfo; /* Setup argument structure for the new thread on its stack. * It's safe to access from the caller only until the thread -- 2.25.1