From 725521cc7eae536cc9542e832afba665d69545ea Mon Sep 17 00:00:00 2001 From: Joel Severin Date: Wed, 27 Mar 2024 22:13:53 +0100 Subject: [PATCH] NOMERGE: Hacks to get Linux/Wasm to compile (minimal and incorrect) --- arch/wasm/arch.mak | 1 + arch/wasm/atomic_arch.h | 15 + arch/wasm/bits/alltypes.h.in | 17 ++ arch/wasm/bits/fenv.h | 10 + arch/wasm/bits/float.h | 15 + arch/wasm/bits/ipcstat.h | 1 + arch/wasm/bits/msg.h | 18 ++ arch/wasm/bits/posix.h | 2 + arch/wasm/bits/ptrace.h | 2 + arch/wasm/bits/reg.h | 3 + arch/wasm/bits/sem.h | 13 + arch/wasm/bits/setjmp.h | 1 + arch/wasm/bits/shm.h | 31 +++ arch/wasm/bits/signal.h | 85 ++++++ arch/wasm/bits/stat.h | 25 ++ arch/wasm/bits/stdint.h | 20 ++ arch/wasm/bits/syscall.h.in | 305 +++++++++++++++++++++ arch/wasm/bits/user.h | 8 + arch/wasm/crt_arch.h | 40 +++ arch/wasm/kstat.h | 21 ++ arch/wasm/pthread_arch.h | 15 + arch/wasm/reloc.h | 13 + arch/wasm/syscall_arch.h | 12 + configure | 13 +- include/elf.h | 56 ++++ include/unistd.h | 5 +- src/internal/pthread_impl.h | 9 +- src/internal/syscall.h | 55 ++-- src/linux/clone.c | 21 +- src/linux/reboot.c | 2 +- src/misc/syscall.c | 56 +++- src/misc/syscalls.c | 0 src/misc/wasm/syscalls.s | 123 +++++++++ src/network/accept.c | 2 +- src/network/accept4.c | 2 +- src/network/bind.c | 2 +- src/network/connect.c | 2 +- src/network/getpeername.c | 2 +- src/network/getsockname.c | 2 +- src/network/getsockopt.c | 6 +- src/network/listen.c | 2 +- src/network/recvmsg.c | 2 +- src/network/sendmsg.c | 2 +- src/network/setsockopt.c | 6 +- src/network/shutdown.c | 2 +- src/network/socket.c | 5 +- src/network/socketpair.c | 5 +- src/process/posix_spawn.c | 3 +- src/process/vfork.c | 12 +- src/setjmp/longjmp.c | 19 ++ src/setjmp/wasm/longjmp.S | 13 + src/setjmp/wasm/setjmp.S | 5 + src/signal/wasm/restore.s | 98 +++++++ src/signal/wasm/sigsetjmp.S | 5 + src/thread/__syscall_cp.c | 18 -- src/thread/__timedwait.c | 6 +- src/thread/__wait.c | 4 +- src/thread/pthread_barrier_wait.c | 4 +- src/thread/pthread_cancel.c | 108 ++++++-- src/thread/pthread_cond_timedwait.c | 4 +- src/thread/pthread_mutex_timedlock.c | 6 +- src/thread/pthread_mutex_trylock.c | 2 +- src/thread/pthread_mutex_unlock.c | 2 +- src/thread/pthread_mutexattr_setprotocol.c | 2 +- src/thread/wasm/__set_thread_area.c | 9 + src/thread/wasm/clone.s | 149 ++++++++++ src/unistd/access.c | 2 +- src/unistd/faccessat.c | 2 +- 68 files changed, 1387 insertions(+), 141 deletions(-) create mode 100644 arch/wasm/arch.mak create mode 100644 arch/wasm/atomic_arch.h create mode 100644 arch/wasm/bits/alltypes.h.in create mode 100644 arch/wasm/bits/fenv.h create mode 100644 arch/wasm/bits/float.h create mode 100644 arch/wasm/bits/ipcstat.h create mode 100644 arch/wasm/bits/msg.h create mode 100644 arch/wasm/bits/posix.h create mode 100644 arch/wasm/bits/ptrace.h create mode 100644 arch/wasm/bits/reg.h create mode 100644 arch/wasm/bits/sem.h create mode 100644 arch/wasm/bits/setjmp.h create mode 100644 arch/wasm/bits/shm.h create mode 100644 arch/wasm/bits/signal.h create mode 100644 arch/wasm/bits/stat.h create mode 100644 arch/wasm/bits/stdint.h create mode 100644 arch/wasm/bits/syscall.h.in create mode 100644 arch/wasm/bits/user.h create mode 100644 arch/wasm/crt_arch.h create mode 100644 arch/wasm/kstat.h create mode 100644 arch/wasm/pthread_arch.h create mode 100644 arch/wasm/reloc.h create mode 100644 arch/wasm/syscall_arch.h create mode 100644 src/misc/syscalls.c create mode 100644 src/misc/wasm/syscalls.s create mode 100644 src/setjmp/wasm/longjmp.S create mode 100644 src/setjmp/wasm/setjmp.S create mode 100644 src/signal/wasm/restore.s create mode 100644 src/signal/wasm/sigsetjmp.S create mode 100644 src/thread/wasm/__set_thread_area.c create mode 100644 src/thread/wasm/clone.s diff --git a/arch/wasm/arch.mak b/arch/wasm/arch.mak new file mode 100644 index 0000000..aa4d05c --- /dev/null +++ b/arch/wasm/arch.mak @@ -0,0 +1 @@ +COMPAT_SRC_DIRS = compat/time32 diff --git a/arch/wasm/atomic_arch.h b/arch/wasm/atomic_arch.h new file mode 100644 index 0000000..95e840e --- /dev/null +++ b/arch/wasm/atomic_arch.h @@ -0,0 +1,15 @@ +#define a_cas a_cas +static inline int a_cas(volatile int *p, int t, int s) +{ + __atomic_compare_exchange_n(p, &t, s, (_Bool)0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return t; +} + +extern void __wasm_abort(); + +#define a_crash a_crash +static inline void a_crash() +{ + __wasm_abort(); + __builtin_unreachable(); +} diff --git a/arch/wasm/bits/alltypes.h.in b/arch/wasm/bits/alltypes.h.in new file mode 100644 index 0000000..4b9c346 --- /dev/null +++ b/arch/wasm/bits/alltypes.h.in @@ -0,0 +1,17 @@ +#define _REDIR_TIME64 1 +#define _Addr long +#define _Int64 long long +#define _Reg int + +#define __BYTE_ORDER 1234 + +#define __LONG_MAX 0x7fffffffL + +#ifndef __cplusplus +TYPEDEF int wchar_t; +#endif + +TYPEDEF float float_t; +TYPEDEF double double_t; + +TYPEDEF struct { long long __ll; long double __ld; } max_align_t; diff --git a/arch/wasm/bits/fenv.h b/arch/wasm/bits/fenv.h new file mode 100644 index 0000000..edbdea2 --- /dev/null +++ b/arch/wasm/bits/fenv.h @@ -0,0 +1,10 @@ +#define FE_ALL_EXCEPT 0 +#define FE_TONEAREST 0 + +typedef unsigned long fexcept_t; + +typedef struct { + unsigned long __cw; +} fenv_t; + +#define FE_DFL_ENV ((const fenv_t *) -1) diff --git a/arch/wasm/bits/float.h b/arch/wasm/bits/float.h new file mode 100644 index 0000000..97ba282 --- /dev/null +++ b/arch/wasm/bits/float.h @@ -0,0 +1,15 @@ + +#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L +#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L +#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L +#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L + +#define LDBL_MANT_DIG 113 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 33 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 36 diff --git a/arch/wasm/bits/ipcstat.h b/arch/wasm/bits/ipcstat.h new file mode 100644 index 0000000..4f4fcb0 --- /dev/null +++ b/arch/wasm/bits/ipcstat.h @@ -0,0 +1 @@ +#define IPC_STAT 0x102 diff --git a/arch/wasm/bits/msg.h b/arch/wasm/bits/msg.h new file mode 100644 index 0000000..7bbbb2b --- /dev/null +++ b/arch/wasm/bits/msg.h @@ -0,0 +1,18 @@ +struct msqid_ds { + struct ipc_perm msg_perm; + unsigned long __msg_stime_lo; + unsigned long __msg_stime_hi; + unsigned long __msg_rtime_lo; + unsigned long __msg_rtime_hi; + unsigned long __msg_ctime_lo; + unsigned long __msg_ctime_hi; + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; +}; diff --git a/arch/wasm/bits/posix.h b/arch/wasm/bits/posix.h new file mode 100644 index 0000000..30a3871 --- /dev/null +++ b/arch/wasm/bits/posix.h @@ -0,0 +1,2 @@ +#define _POSIX_V6_ILP32_OFFBIG 1 +#define _POSIX_V7_ILP32_OFFBIG 1 diff --git a/arch/wasm/bits/ptrace.h b/arch/wasm/bits/ptrace.h new file mode 100644 index 0000000..da93e7a --- /dev/null +++ b/arch/wasm/bits/ptrace.h @@ -0,0 +1,2 @@ +#define PTRACE_GET_THREAD_AREA 25 +#define PTRACE_SINGLEBLOCK 33 diff --git a/arch/wasm/bits/reg.h b/arch/wasm/bits/reg.h new file mode 100644 index 0000000..0c7bffc --- /dev/null +++ b/arch/wasm/bits/reg.h @@ -0,0 +1,3 @@ +#undef __WORDSIZE +#define __WORDSIZE 32 +/* FIXME */ diff --git a/arch/wasm/bits/sem.h b/arch/wasm/bits/sem.h new file mode 100644 index 0000000..6566154 --- /dev/null +++ b/arch/wasm/bits/sem.h @@ -0,0 +1,13 @@ +struct semid_ds { + struct ipc_perm sem_perm; + unsigned long __sem_otime_lo; + unsigned long __sem_otime_hi; + unsigned long __sem_ctime_lo; + unsigned long __sem_ctime_hi; + unsigned short sem_nsems; + char __sem_nsems_pad[sizeof(long)-sizeof(short)]; + long __unused3; + long __unused4; + time_t sem_otime; + time_t sem_ctime; +}; diff --git a/arch/wasm/bits/setjmp.h b/arch/wasm/bits/setjmp.h new file mode 100644 index 0000000..55e3a95 --- /dev/null +++ b/arch/wasm/bits/setjmp.h @@ -0,0 +1 @@ +typedef unsigned long long __jmp_buf[32]; diff --git a/arch/wasm/bits/shm.h b/arch/wasm/bits/shm.h new file mode 100644 index 0000000..725fb46 --- /dev/null +++ b/arch/wasm/bits/shm.h @@ -0,0 +1,31 @@ +#define SHMLBA 4096 + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + unsigned long __shm_atime_lo; + unsigned long __shm_atime_hi; + unsigned long __shm_dtime_lo; + unsigned long __shm_dtime_hi; + unsigned long __shm_ctime_lo; + unsigned long __shm_ctime_hi; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __pad1; + unsigned long __pad2; + unsigned long __pad3; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; +}; + +struct shminfo { + unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4]; +}; + +struct shm_info { + int __used_ids; + unsigned long shm_tot, shm_rss, shm_swp; + unsigned long __swap_attempts, __swap_successes; +}; diff --git a/arch/wasm/bits/signal.h b/arch/wasm/bits/signal.h new file mode 100644 index 0000000..ab24d3d --- /dev/null +++ b/arch/wasm/bits/signal.h @@ -0,0 +1,85 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ + || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef unsigned long greg_t, gregset_t[2]; +typedef struct sigcontext { + unsigned long stack_pointer; + unsigned long tls; +} mcontext_t; +#else +typedef struct { + unsigned long __regs[2]; +} mcontext_t; +#endif + +#if defined(_GNU_SOURCE) +#define REG_SP 0 +#define REG_TP 1 +#endif + +struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + struct __ucontext *uc_link; + sigset_t uc_sigmask; + stack_t uc_stack; + mcontext_t uc_mcontext; +} ucontext_t; + +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +#endif + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS + +#define _NSIG 65 diff --git a/arch/wasm/bits/stat.h b/arch/wasm/bits/stat.h new file mode 100644 index 0000000..8a4d509 --- /dev/null +++ b/arch/wasm/bits/stat.h @@ -0,0 +1,25 @@ +/* copied from kernel definition, but with padding replaced + * by the corresponding correctly-sized userspace types. */ + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + long long __st_rdev_padding; + off_t st_size; + blksize_t st_blksize; + int __st_blksize_padding; + blkcnt_t st_blocks; + struct { + long tv_sec; + long tv_nsec; + } __st_atim32, __st_mtim32, __st_ctim32; + unsigned __unused[2]; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; +}; diff --git a/arch/wasm/bits/stdint.h b/arch/wasm/bits/stdint.h new file mode 100644 index 0000000..d1b2712 --- /dev/null +++ b/arch/wasm/bits/stdint.h @@ -0,0 +1,20 @@ +typedef int32_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast16_t; +typedef uint32_t uint_fast32_t; + +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN + +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX + +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX +#define SIZE_MAX UINT32_MAX diff --git a/arch/wasm/bits/syscall.h.in b/arch/wasm/bits/syscall.h.in new file mode 100644 index 0000000..5227a60 --- /dev/null +++ b/arch/wasm/bits/syscall.h.in @@ -0,0 +1,305 @@ +#define __NR_io_setup 0 +#define __NR_io_destroy 1 +#define __NR_io_submit 2 +#define __NR_io_cancel 3 +#define __NR_setxattr 5 +#define __NR_lsetxattr 6 +#define __NR_fsetxattr 7 +#define __NR_getxattr 8 +#define __NR_lgetxattr 9 +#define __NR_fgetxattr 10 +#define __NR_listxattr 11 +#define __NR_llistxattr 12 +#define __NR_flistxattr 13 +#define __NR_removexattr 14 +#define __NR_lremovexattr 15 +#define __NR_fremovexattr 16 +#define __NR_getcwd 17 +#define __NR_lookup_dcookie 18 +#define __NR_eventfd2 19 +#define __NR_epoll_create1 20 +#define __NR_epoll_ctl 21 +#define __NR_epoll_pwait 22 +#define __NR_dup 23 +#define __NR_dup3 24 +#define __NR_fcntl 25 +#define __NR_inotify_init1 26 +#define __NR_inotify_add_watch 27 +#define __NR_inotify_rm_watch 28 +#define __NR_ioctl 29 +#define __NR_ioprio_set 30 +#define __NR_ioprio_get 31 +#define __NR_flock 32 +#define __NR_mknodat 33 +#define __NR_mkdirat 34 +#define __NR_unlinkat 35 +#define __NR_symlinkat 36 +#define __NR_linkat 37 +#define __NR_umount2 39 +#define __NR_mount 40 +#define __NR_pivot_root 41 +#define __NR_nfsservctl 42 +#define __NR_statfs64 43 +#define __NR_fstatfs64 44 +#define __NR_truncate 45 +#define __NR_ftruncate 46 +#define __NR_fallocate 47 +#define __NR_faccessat 48 +#define __NR_chdir 49 +#define __NR_fchdir 50 +#define __NR_chroot 51 +#define __NR_fchmod 52 +#define __NR_fchmodat 53 +#define __NR_fchownat 54 +#define __NR_fchown 55 +#define __NR_openat 56 +#define __NR_close 57 +#define __NR_vhangup 58 +#define __NR_pipe2 59 +#define __NR_quotactl 60 +#define __NR_getdents64 61 +#define __NR_lseek 62 +#define __NR_read 63 +#define __NR_write 64 +#define __NR_readv 65 +#define __NR_writev 66 +#define __NR_pread64 67 +#define __NR_pwrite64 68 +#define __NR_preadv 69 +#define __NR_pwritev 70 +#define __NR_sendfile 71 +#define __NR_signalfd4 74 +#define __NR_vmsplice 75 +#define __NR_splice 76 +#define __NR_tee 77 +#define __NR_readlinkat 78 +#define __NR_fstat 80 +#define __NR_sync 81 +#define __NR_fsync 82 +#define __NR_fdatasync 83 +#define __NR_sync_file_range 84 +#define __NR_timerfd_create 85 +#define __NR_acct 89 +#define __NR_capget 90 +#define __NR_capset 91 +#define __NR_personality 92 +#define __NR_exit 93 +#define __NR_exit_group 94 +#define __NR_waitid 95 +#define __NR_set_tid_address 96 +#define __NR_unshare 97 +#define __NR_set_robust_list 99 +#define __NR_get_robust_list 100 +#define __NR_getitimer 102 +#define __NR_setitimer 103 +#define __NR_kexec_load 104 +#define __NR_init_module 105 +#define __NR_delete_module 106 +#define __NR_timer_create 107 +#define __NR_timer_getoverrun 109 +#define __NR_timer_delete 111 +#define __NR_syslog 116 +#define __NR_ptrace 117 +#define __NR_sched_setparam 118 +#define __NR_sched_setscheduler 119 +#define __NR_sched_getscheduler 120 +#define __NR_sched_getparam 121 +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#define __NR_sched_yield 124 +#define __NR_sched_get_priority_max 125 +#define __NR_sched_get_priority_min 126 +#define __NR_restart_syscall 128 +#define __NR_kill 129 +#define __NR_tkill 130 +#define __NR_tgkill 131 +#define __NR_sigaltstack 132 +#define __NR_rt_sigsuspend 133 +#define __NR_rt_sigaction 134 +#define __NR_rt_sigprocmask 135 +#define __NR_rt_sigpending 136 +#define __NR_rt_sigqueueinfo 138 +#define __NR_rt_sigreturn 139 +#define __NR_setpriority 140 +#define __NR_getpriority 141 +#define __NR_reboot 142 +#define __NR_setregid 143 +#define __NR_setgid 144 +#define __NR_setreuid 145 +#define __NR_setuid 146 +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#define __NR_setfsuid 151 +#define __NR_setfsgid 152 +#define __NR_times 153 +#define __NR_setpgid 154 +#define __NR_getpgid 155 +#define __NR_getsid 156 +#define __NR_setsid 157 +#define __NR_getgroups 158 +#define __NR_setgroups 159 +#define __NR_uname 160 +#define __NR_sethostname 161 +#define __NR_setdomainname 162 +#define __NR_getrusage 165 +#define __NR_umask 166 +#define __NR_prctl 167 +#define __NR_getcpu 168 +#define __NR_getpid 172 +#define __NR_getppid 173 +#define __NR_getuid 174 +#define __NR_geteuid 175 +#define __NR_getgid 176 +#define __NR_getegid 177 +#define __NR_gettid 178 +#define __NR_sysinfo 179 +#define __NR_mq_open 180 +#define __NR_mq_unlink 181 +#define __NR_mq_notify 184 +#define __NR_mq_getsetattr 185 +#define __NR_msgget 186 +#define __NR_msgctl 187 +#define __NR_msgrcv 188 +#define __NR_msgsnd 189 +#define __NR_semget 190 +#define __NR_semctl 191 +#define __NR_semop 193 +#define __NR_shmget 194 +#define __NR_shmctl 195 +#define __NR_shmat 196 +#define __NR_shmdt 197 +#define __NR_socket 198 +#define __NR_socketpair 199 +#define __NR_bind 200 +#define __NR_listen 201 +#define __NR_accept 202 +#define __NR_connect 203 +#define __NR_getsockname 204 +#define __NR_getpeername 205 +#define __NR_sendto 206 +#define __NR_recvfrom 207 +#define __NR_setsockopt 208 +#define __NR_getsockopt 209 +#define __NR_shutdown 210 +#define __NR_sendmsg 211 +#define __NR_recvmsg 212 +#define __NR_readahead 213 +#define __NR_brk 214 +#define __NR_munmap 215 +#define __NR_mremap 216 +#define __NR_add_key 217 +#define __NR_request_key 218 +#define __NR_keyctl 219 +#define __NR_clone 220 +#define __NR_execve 221 +#define __NR_mmap2 222 +#define __NR_fadvise64 223 +#define __NR_rt_tgsigqueueinfo 240 +#define __NR_perf_event_open 241 +#define __NR_accept4 242 +#define __NR_arch_specific_syscall 244 +#define __NR_prlimit64 261 +#define __NR_fanotify_init 262 +#define __NR_fanotify_mark 263 +#define __NR_name_to_handle_at 264 +#define __NR_open_by_handle_at 265 +#define __NR_syncfs 267 +#define __NR_setns 268 +#define __NR_sendmmsg 269 +#define __NR_process_vm_readv 270 +#define __NR_process_vm_writev 271 +#define __NR_kcmp 272 +#define __NR_finit_module 273 +#define __NR_sched_setattr 274 +#define __NR_sched_getattr 275 +#define __NR_renameat2 276 +#define __NR_seccomp 277 +#define __NR_getrandom 278 +#define __NR_memfd_create 279 +#define __NR_bpf 280 +#define __NR_execveat 281 +#define __NR_userfaultfd 282 +#define __NR_membarrier 283 +#define __NR_mlock2 284 +#define __NR_copy_file_range 285 +#define __NR_preadv2 286 +#define __NR_pwritev2 287 +#define __NR_pkey_mprotect 288 +#define __NR_pkey_alloc 289 +#define __NR_pkey_free 290 +#define __NR_statx 291 +#define __NR_rseq 293 +#define __NR_kexec_file_load 294 +#define __NR_clock_gettime64 403 +#define __NR_clock_settime64 404 +#define __NR_clock_adjtime64 405 +#define __NR_clock_getres_time64 406 +#define __NR_clock_nanosleep_time64 407 +#define __NR_timer_gettime64 408 +#define __NR_timer_settime64 409 +#define __NR_timerfd_gettime64 410 +#define __NR_timerfd_settime64 411 +#define __NR_utimensat_time64 412 +#define __NR_pselect6_time64 413 +#define __NR_ppoll_time64 414 +#define __NR_io_pgetevents_time64 416 +#define __NR_recvmmsg_time64 417 +#define __NR_mq_timedsend_time64 418 +#define __NR_mq_timedreceive_time64 419 +#define __NR_semtimedop_time64 420 +#define __NR_rt_sigtimedwait_time64 421 +#define __NR_futex_time64 422 +#define __NR_sched_rr_get_interval_time64 423 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_cachestat 451 +#define __NR_fchmodat2 452 + +/* These ones are NOT supported but required by musl - will return -ENOSYS. */ +#define __NR_nanosleep 101 +#define __NR_settimeofday 170 +#define __NR_swapon 224 +#define __NR_swapoff 225 +#define __NR_mprotect 226 +#define __NR_msync 227 +#define __NR_mlock 228 +#define __NR_munlock 229 +#define __NR_mlockall 230 +#define __NR_munlockall 231 +#define __NR_mincore 232 +#define __NR_madvise 233 +#define __NR_remap_file_pages 234 +#define __NR_mbind 235 +#define __NR_get_mempolicy 236 +#define __NR_set_mempolicy 237 +#define __NR_migrate_pages 238 +#define __NR_move_pages 239 + +/* Required by musl to select the correct prototype. Notice the double __. */ +#define SYS__llseek __NR_lseek diff --git a/arch/wasm/bits/user.h b/arch/wasm/bits/user.h new file mode 100644 index 0000000..7954679 --- /dev/null +++ b/arch/wasm/bits/user.h @@ -0,0 +1,8 @@ +struct user_regs_struct { + unsigned long stack_pointer; + unsigned long tls; +}; + +typedef unsigned long elf_greg_t; +typedef struct user_regs_struct elf_gregset_t; +#define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t)) diff --git a/arch/wasm/crt_arch.h b/arch/wasm/crt_arch.h new file mode 100644 index 0000000..fe3ce01 --- /dev/null +++ b/arch/wasm/crt_arch.h @@ -0,0 +1,40 @@ +/* + * We provide a prototype for main here (it's declared without prototype in crt1.c etc.). The reason + * we have to do this is to avoid an issue with LLVM wrapping and renaming it __original_main, which + * will fail when programs later on provide a real main with correct prototype and link it. + * + * Oh, and then it comes along and renames it __main_argc_argv because it has parameters, so we have + * to alias that as well and main will now be called __main_argc_argv. This cannot be a direct alias + * as it is not defined yet, so we just call it... + * + * To add salt to the injury, musl insists to call the 3-argument version with envp which is non- + * standard. What a wonderful mess... We need to clean this up someday, maybe auto-detect somehow. + */ +int __main_argc_argv(int argc, char *argv[]); +int main(int argc, char *argv[], char *envp[]) +{ + (void)envp; + return __main_argc_argv(argc, argv); +} + +/* + * This must really be written in assembly (to capture the stack pointer properly), but we know that + * the initial stack pointer is page aligned, so we can cheat a bit and align it to the next page... + * The problem is that LLVM does not seem to work when functions are defined with inline asm (in C). + * TODO: fix this hack by refactoring musl and moving things into a .S file. + */ +#ifndef SHARED +void _start(void) +{ + void _start_c(/* no prototype on purpose */); + int dummy; + _start_c(((unsigned long)(void*)&dummy + 4095UL) & ~4095UL); +} +#else +void _dlstart(void) +{ + void _dlstart_c(/* no prototype on purpose */); + int dummy; + _dlstart_c(((unsigned long)(void*)&dummy + 4095UL) & ~4095UL); +} +#endif diff --git a/arch/wasm/kstat.h b/arch/wasm/kstat.h new file mode 100644 index 0000000..c144957 --- /dev/null +++ b/arch/wasm/kstat.h @@ -0,0 +1,21 @@ +struct kstat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + long long __st_rdev_padding; + off_t st_size; + blksize_t st_blksize; + int __st_blksize_padding; + blkcnt_t st_blocks; + long st_atime_sec; + long st_atime_nsec; + long st_mtime_sec; + long st_mtime_nsec; + long st_ctime_sec; + long st_ctime_nsec; + unsigned __unused[2]; +}; diff --git a/arch/wasm/pthread_arch.h b/arch/wasm/pthread_arch.h new file mode 100644 index 0000000..0625bd1 --- /dev/null +++ b/arch/wasm/pthread_arch.h @@ -0,0 +1,15 @@ +#include + +/* + * Wasm (as compiled with LLVM) handles TLS data directly, instead of the + * indirect approach used for ELF targets (where musl manages all TLS). There is + * still a pthread TLS area to keep track of, and musl manages that by these + * functions. In other words, __musl_tp will point to a struct pthread. + */ + +extern _Thread_local uintptr_t __musl_tp; + +static inline uintptr_t __get_tp(void) +{ + return __musl_tp; +} diff --git a/arch/wasm/reloc.h b/arch/wasm/reloc.h new file mode 100644 index 0000000..833a2f5 --- /dev/null +++ b/arch/wasm/reloc.h @@ -0,0 +1,13 @@ +#define LDSO_ARCH "wasm" + +#define TPOFF_K 0 + +#define REL_SYMBOLIC R_WASM_64 +#define REL_PLT R_WASM_JUMP_SLOT +#define REL_RELATIVE R_WASM_RELATIVE +#define REL_COPY R_WASM_COPY +#define REL_DTPMOD R_WASM_TLS_DTPMOD64 +#define REL_DTPOFF R_WASM_TLS_DTPREL64 +#define REL_TPOFF R_WASM_TLS_TPREL64 + +#define CRTJMP(pc,sp) abort() diff --git a/arch/wasm/syscall_arch.h b/arch/wasm/syscall_arch.h new file mode 100644 index 0000000..1e06877 --- /dev/null +++ b/arch/wasm/syscall_arch.h @@ -0,0 +1,12 @@ +#define __SYSCALL_LL_E(x) \ +((union { long long ll; long l[2]; }){ .ll = x }).l[0], \ +((union { long long ll; long l[2]; }){ .ll = x }).l[1] +#define __SYSCALL_LL_O(x) __SYSCALL_LL_E((x)) + +extern long __syscall0(long n); +extern long __syscall1(long n, long a); +extern long __syscall2(long n, long a, long b); +extern long __syscall3(long n, long a, long b, long c); +extern long __syscall4(long n, long a, long b, long c, long d); +extern long __syscall5(long n, long a, long b, long c, long d, long e); +extern long __syscall6(long n, long a, long b, long c, long d, long e, long f); diff --git a/configure b/configure index bc9fbe4..b44705b 100755 --- a/configure +++ b/configure @@ -340,6 +340,7 @@ riscv64*) ARCH=riscv64 ;; riscv32*) ARCH=riscv32 ;; sh[1-9bel-]*|sh|superh*) ARCH=sh ;; s390x*) ARCH=s390x ;; +wasm*) ARCH=wasm ;; unknown) fail "$0: unable to detect target arch; try $0 --target=..." ;; *) fail "$0: unknown or unsupported target \"$target\"" ;; esac @@ -586,33 +587,33 @@ fi # Reduce space lost to padding for alignment purposes by sorting data # objects according to their alignment reqirements. This approximates # optimal packing. -tryldflag LDFLAGS_AUTO -Wl,--sort-section,alignment -tryldflag LDFLAGS_AUTO -Wl,--sort-common +#tryldflag LDFLAGS_AUTO -Wl,--sort-section,alignment +#tryldflag LDFLAGS_AUTO -Wl,--sort-common # When linking shared library, drop dummy weak definitions that were # replaced by strong definitions from other translation units. tryldflag LDFLAGS_AUTO -Wl,--gc-sections # Some patched GCC builds have these defaults messed up... -tryldflag LDFLAGS_AUTO -Wl,--hash-style=both +#tryldflag LDFLAGS_AUTO -Wl,--hash-style=both # Prevent linking if there are undefined symbols; if any exist, # libc.so will crash at runtime during relocation processing. # The common way this can happen is failure to link the compiler # runtime library; implementation error is also a possibility. -tryldflag LDFLAGS_AUTO -Wl,--no-undefined +#tryldflag LDFLAGS_AUTO -Wl,--no-undefined # Avoid exporting symbols from compiler runtime libraries. They # should be hidden anyway, but some toolchains including old gcc # versions built without shared library support and pcc are broken. -tryldflag LDFLAGS_AUTO -Wl,--exclude-libs=ALL +#tryldflag LDFLAGS_AUTO -Wl,--exclude-libs=ALL # Public data symbols must be interposable to allow for copy # relocations, but otherwise we want to bind symbols at libc link # time to eliminate startup relocations and PLT overhead. Use # --dynamic-list rather than -Bsymbolic-functions for greater # control over what symbols are left unbound. -tryldflag LDFLAGS_AUTO -Wl,--dynamic-list="$srcdir/dynamic.list" +#tryldflag LDFLAGS_AUTO -Wl,--dynamic-list="$srcdir/dynamic.list" # Find compiler runtime library test -z "$LIBCC" && tryldflag LIBCC -lgcc && tryldflag LIBCC -lgcc_eh diff --git a/include/elf.h b/include/elf.h index 3d5e13e..3620e8b 100644 --- a/include/elf.h +++ b/include/elf.h @@ -3310,6 +3310,62 @@ enum #define R_RISCV_TLSDESC_ADD_LO12 64 #define R_RISCV_TLSDESC_CALL 65 +#define R_WASM_NONE 0 +#define R_WASM_32 1 +#define R_WASM_64 2 +#define R_WASM_RELATIVE 3 +#define R_WASM_COPY 4 +#define R_WASM_JUMP_SLOT 5 +#define R_WASM_TLS_DTPMOD32 6 +#define R_WASM_TLS_DTPMOD64 7 +#define R_WASM_TLS_DTPREL32 8 +#define R_WASM_TLS_DTPREL64 9 +#define R_WASM_TLS_TPREL32 10 +#define R_WASM_TLS_TPREL64 11 + +#define R_WASM_BRANCH 16 +#define R_WASM_JAL 17 +#define R_WASM_CALL 18 +#define R_WASM_CALL_PLT 19 +#define R_WASM_GOT_HI20 20 +#define R_WASM_TLS_GOT_HI20 21 +#define R_WASM_TLS_GD_HI20 22 +#define R_WASM_PCREL_HI20 23 +#define R_WASM_PCREL_LO12_I 24 +#define R_WASM_PCREL_LO12_S 25 +#define R_WASM_HI20 26 +#define R_WASM_LO12_I 27 +#define R_WASM_LO12_S 28 +#define R_WASM_TPREL_HI20 29 +#define R_WASM_TPREL_LO12_I 30 +#define R_WASM_TPREL_LO12_S 31 +#define R_WASM_TPREL_ADD 32 +#define R_WASM_ADD8 33 +#define R_WASM_ADD16 34 +#define R_WASM_ADD32 35 +#define R_WASM_ADD64 36 +#define R_WASM_SUB8 37 +#define R_WASM_SUB16 38 +#define R_WASM_SUB32 39 +#define R_WASM_SUB64 40 +#define R_WASM_GNU_VTINHERIT 41 +#define R_WASM_GNU_VTENTRY 42 +#define R_WASM_ALIGN 43 +#define R_WASM_RVC_BRANCH 44 +#define R_WASM_RVC_JUMP 45 +#define R_WASM_LUI 46 +#define R_WASM_GPREL_I 47 +#define R_WASM_GPREL_S 48 +#define R_WASM_TPREL_I 49 +#define R_WASM_TPREL_S 50 +#define R_WASM_RELAX 51 +#define R_WASM_SUB6 52 +#define R_WASM_SET6 53 +#define R_WASM_SET8 54 +#define R_WASM_SET16 55 +#define R_WASM_SET32 56 +#define R_WASM_32_PCREL 57 + #define EF_LARCH_ABI_MODIFIER_MASK 0x07 #define EF_LARCH_ABI_SOFT_FLOAT 0x01 #define EF_LARCH_ABI_SINGLE_FLOAT 0x02 diff --git a/include/unistd.h b/include/unistd.h index 5bc7f79..ca939bd 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -177,7 +177,10 @@ void setusershell(void); void endusershell(void); char *getusershell(void); int acct(const char *); -long syscall(long, ...); +#define __syscall_nargs_x(a,b,c,d,e,f,g,h,n,...) n +#define __syscall_nargs(...) __syscall_nargs_x(__VA_ARGS__,7,6,5,4,3,2,1,0,) +long syscall(long, long, ...); +#define syscall(...) syscall(__syscall_nargs(__VA_ARGS__), __VA_ARGS__) int execvpe(const char *, char *const [], char *const []); int issetugid(void); int getentropy(void *, size_t); diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index de2b9d8..e2ac283 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -158,6 +158,7 @@ extern hidden void *__pthread_tsd_main[]; extern hidden volatile int __eintr_valid_flag; hidden int __clone(int (*)(void *), void *, int, void *, ...); +hidden int _Clone(int (*)(void *), void *, int, void *, pid_t *, void *, pid_t *); hidden int __set_thread_area(void *); hidden int __libc_sigaction(int, const struct sigaction *, struct sigaction *); hidden void __unmapself(void *, size_t); @@ -169,14 +170,14 @@ static inline void __wake(volatile void *addr, int cnt, int priv) { if (priv) priv = FUTEX_PRIVATE; if (cnt<0) cnt = INT_MAX; - __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || - __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); + __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt, 0, 0, 0) != -ENOSYS || + __syscall(SYS_futex, addr, FUTEX_WAKE, cnt, 0, 0, 0); } static inline void __futexwait(volatile void *addr, int val, int priv) { if (priv) priv = FUTEX_PRIVATE; - __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || - __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); + __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0, 0, 0) != -ENOSYS || + __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0, 0, 0); } hidden void __acquire_ptc(void); diff --git a/src/internal/syscall.h b/src/internal/syscall.h index 33d981f..590b6cb 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -23,9 +23,14 @@ typedef long syscall_arg_t; #endif -hidden long __syscall_ret(unsigned long), - __syscall_cp(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, - syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_ret(unsigned long); +hidden long __syscall_cp_c0(syscall_arg_t); +hidden long __syscall_cp_c1(syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c2(syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c3(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c4(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c5(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c6(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); #define __syscall1(n,a) __syscall1(n,__scc(a)) #define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b)) @@ -44,36 +49,22 @@ hidden long __syscall_ret(unsigned long), #define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) #define syscall(...) __syscall_ret(__syscall(__VA_ARGS__)) -#define socketcall(nm,a,b,c,d,e,f) __syscall_ret(__socketcall(nm,a,b,c,d,e,f)) -#define socketcall_cp(nm,a,b,c,d,e,f) __syscall_ret(__socketcall_cp(nm,a,b,c,d,e,f)) +#define socketcall(...) __syscall_ret(__socketcall(__VA_ARGS__)) +#define socketcall_cp(...) __syscall_ret(__socketcall_cp(__VA_ARGS__)) -#define __syscall_cp0(n) (__syscall_cp)(n,0,0,0,0,0,0) -#define __syscall_cp1(n,a) (__syscall_cp)(n,__scc(a),0,0,0,0,0) -#define __syscall_cp2(n,a,b) (__syscall_cp)(n,__scc(a),__scc(b),0,0,0,0) -#define __syscall_cp3(n,a,b,c) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),0,0,0) -#define __syscall_cp4(n,a,b,c,d) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),0,0) -#define __syscall_cp5(n,a,b,c,d,e) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),0) -#define __syscall_cp6(n,a,b,c,d,e,f) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#define __syscall_cp0(n) __syscall_cp_c0(n) +#define __syscall_cp1(n,a) __syscall_cp_c1(n,__scc(a)) +#define __syscall_cp2(n,a,b) __syscall_cp_c2(n,__scc(a),__scc(b)) +#define __syscall_cp3(n,a,b,c) __syscall_cp_c3(n,__scc(a),__scc(b),__scc(c)) +#define __syscall_cp4(n,a,b,c,d) __syscall_cp_c4(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall_cp5(n,a,b,c,d,e) __syscall_cp_c5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall_cp6(n,a,b,c,d,e,f) __syscall_cp_c6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) #define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__) #define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__)) -static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, syscall_arg_t b, syscall_arg_t c, syscall_arg_t d, syscall_arg_t e, syscall_arg_t f) -{ - long r; - if (cp) r = __syscall_cp(sys, a, b, c, d, e, f); - else r = __syscall(sys, a, b, c, d, e, f); - if (r != -ENOSYS) return r; -#ifdef SYS_socketcall - if (cp) r = __syscall_cp(SYS_socketcall, sock, ((long[6]){a, b, c, d, e, f})); - else r = __syscall(SYS_socketcall, sock, ((long[6]){a, b, c, d, e, f})); -#endif - return r; -} -#define __socketcall(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 0, \ - __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) -#define __socketcall_cp(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 1, \ - __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) +#define __socketcall(nm, ...) __syscall(SYS_##nm, __VA_ARGS__) +#define __socketcall_cp(nm, ...) __syscall_cp(SYS_##nm, __VA_ARGS__) /* fixup legacy 16-bit junk */ @@ -374,14 +365,14 @@ static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, #endif #ifdef SYS_open -#define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE) +#define __sys_open2(x,pn,fl) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, 0) #define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo) -#define __sys_open_cp2(x,pn,fl) __syscall_cp2(SYS_open, pn, (fl)|O_LARGEFILE) +#define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_open, pn, (fl)|O_LARGEFILE, 0) #define __sys_open_cp3(x,pn,fl,mo) __syscall_cp3(SYS_open, pn, (fl)|O_LARGEFILE, mo) #else -#define __sys_open2(x,pn,fl) __syscall3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE) +#define __sys_open2(x,pn,fl) __syscall4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, 0) #define __sys_open3(x,pn,fl,mo) __syscall4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo) -#define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE) +#define __sys_open_cp2(x,pn,fl) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, 0) #define __sys_open_cp3(x,pn,fl,mo) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo) #endif diff --git a/src/linux/clone.c b/src/linux/clone.c index 257c1ce..e3e8aa0 100644 --- a/src/linux/clone.c +++ b/src/linux/clone.c @@ -31,7 +31,7 @@ int clone(int (*func)(void *), void *stack, int flags, void *arg, ...) /* Flags that produce an invalid thread/TLS state are disallowed. */ int badflags = CLONE_THREAD | CLONE_SETTLS | CLONE_CHILD_CLEARTID; - if ((flags & badflags) || !stack) + if ((flags & badflags) || (!stack && !(flags & CLONE_VFORK))) return __syscall_ret(-EINVAL); va_start(ap, arg); @@ -63,3 +63,22 @@ int clone(int (*func)(void *), void *stack, int flags, void *arg, ...) __restore_sigs(&csa.sigmask); return __syscall_ret(ret); } + +int __clone(int (*fn)(void *), void *stack, int flags, void *arg, ...) +{ + /* Avoid calling assembler functions with va_args (fails on Wasm). */ + va_list ap; + pid_t *ptid = 0, *ctid = 0; + void *tls = 0; + + va_start(ap, arg); + if (flags & (CLONE_PIDFD | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID)) + ptid = va_arg(ap, pid_t *); + if (flags & CLONE_CHILD_SETTID) { + tls = va_arg(ap, void *); + ctid = va_arg(ap, pid_t *); + } + va_end(ap); + + return _Clone(fn, stack, flags, arg, ptid, tls, ctid); +} diff --git a/src/linux/reboot.c b/src/linux/reboot.c index 7f12af7..f131745 100644 --- a/src/linux/reboot.c +++ b/src/linux/reboot.c @@ -3,5 +3,5 @@ int reboot(int type) { - return syscall(SYS_reboot, 0xfee1dead, 672274793, type); + return syscall(SYS_reboot, 0xfee1dead, 672274793, type, 0); } diff --git a/src/misc/syscall.c b/src/misc/syscall.c index 6f3ef65..471a9b2 100644 --- a/src/misc/syscall.c +++ b/src/misc/syscall.c @@ -5,17 +5,57 @@ #undef syscall -long syscall(long n, ...) +long syscall(long count, long n, ...) { va_list ap; syscall_arg_t a,b,c,d,e,f; va_start(ap, n); - a=va_arg(ap, syscall_arg_t); - b=va_arg(ap, syscall_arg_t); - c=va_arg(ap, syscall_arg_t); - d=va_arg(ap, syscall_arg_t); - e=va_arg(ap, syscall_arg_t); - f=va_arg(ap, syscall_arg_t); + switch (count) { + case 0: + va_end(ap); + return __syscall_ret(__syscall(n)); + case 1: + a = va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n, a)); + case 2: + a = va_arg(ap, syscall_arg_t); + b = va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n, a, b)); + case 3: + a = va_arg(ap, syscall_arg_t); + b = va_arg(ap, syscall_arg_t); + c = va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n, a, b, c)); + case 4: + a = va_arg(ap, syscall_arg_t); + b = va_arg(ap, syscall_arg_t); + c = va_arg(ap, syscall_arg_t); + d = va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n, a, b, c, d)); + case 5: + a = va_arg(ap, syscall_arg_t); + b = va_arg(ap, syscall_arg_t); + c = va_arg(ap, syscall_arg_t); + d = va_arg(ap, syscall_arg_t); + e = va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n, a, b, c, d, e)); + case 6: + a = va_arg(ap, syscall_arg_t); + b = va_arg(ap, syscall_arg_t); + c = va_arg(ap, syscall_arg_t); + d = va_arg(ap, syscall_arg_t); + e = va_arg(ap, syscall_arg_t); + f = va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n, a, b, c, d, e, f)); + default: + break; + } va_end(ap); - return __syscall_ret(__syscall(n,a,b,c,d,e,f)); + return -ENOSYS; } diff --git a/src/misc/syscalls.c b/src/misc/syscalls.c new file mode 100644 index 0000000..e69de29 diff --git a/src/misc/wasm/syscalls.s b/src/misc/wasm/syscalls.s new file mode 100644 index 0000000..70e5069 --- /dev/null +++ b/src/misc/wasm/syscalls.s @@ -0,0 +1,123 @@ +.globaltype __stack_pointer, i32 +.globaltype __tls_base, i32 +.functype __wasm_syscall_0(i32, i32, i32) -> (i32) +.functype __wasm_syscall_1(i32, i32, i32, i32) -> (i32) +.functype __wasm_syscall_2(i32, i32, i32, i32, i32) -> (i32) +.functype __wasm_syscall_3(i32, i32, i32, i32, i32, i32) -> (i32) +.functype __wasm_syscall_4(i32, i32, i32, i32, i32, i32, i32) -> (i32) +.functype __wasm_syscall_5(i32, i32, i32, i32, i32, i32, i32, i32) -> (i32) +.functype __wasm_syscall_6(i32, i32, i32, i32, i32, i32, i32, i32, i32) -> (i32) + +#define haxx + +.macro __SYSCALL_HEAD + global.get __stack_pointer + global.get __tls_base + local.get 0 +.endm + +.macro __SYSCALL_FOOT + /* + * The kernel never changes __stack_pointer or __tls_base during most + * syscalls. The ones where it does (clone, signals, exec) are handled + * separately and don't go via this function, making it safe to ignore. + */ +.endm + +.globl __syscall0 +.hidden __syscall0 +__syscall0: + .functype __syscall0(i32) -> (i32) + + __SYSCALL_HEAD + call __wasm_syscall_0 + __SYSCALL_FOOT + + end_function + +.globl __syscall1 +.hidden __syscall1 +__syscall1: + .functype __syscall1(i32, i32) -> (i32) + + __SYSCALL_HEAD + local.get 1 + call __wasm_syscall_1 + __SYSCALL_FOOT + + end_function + +.globl __syscall2 +.hidden __syscall2 +__syscall2: + .functype __syscall2(i32, i32, i32) -> (i32) + + __SYSCALL_HEAD + local.get 1 + local.get 2 + call __wasm_syscall_2 + __SYSCALL_FOOT + + end_function + +.globl __syscall3 +.hidden __syscall3 +__syscall3: + .functype __syscall3(i32, i32, i32, i32) -> (i32) + + __SYSCALL_HEAD + local.get 1 + local.get 2 + local.get 3 + call __wasm_syscall_3 + __SYSCALL_FOOT + + end_function + +.globl __syscall4 +.hidden __syscall4 +__syscall4: + .functype __syscall4(i32, i32, i32, i32, i32) -> (i32) + + __SYSCALL_HEAD + local.get 1 + local.get 2 + local.get 3 + local.get 4 + call __wasm_syscall_4 + __SYSCALL_FOOT + + end_function + +.globl __syscall5 +.hidden __syscall5 +__syscall5: + .functype __syscall5(i32, i32, i32, i32, i32, i32) -> (i32) + + __SYSCALL_HEAD + local.get 1 + local.get 2 + local.get 3 + local.get 4 + local.get 5 + call __wasm_syscall_5 + __SYSCALL_FOOT + + end_function + +.globl __syscall6 +.hidden __syscall6 +__syscall6: + .functype __syscall6(i32, i32, i32, i32, i32, i32, i32) -> (i32) + + __SYSCALL_HEAD + local.get 1 + local.get 2 + local.get 3 + local.get 4 + local.get 5 + local.get 6 + call __wasm_syscall_6 + __SYSCALL_FOOT + + end_function diff --git a/src/network/accept.c b/src/network/accept.c index a92406f..5fa901a 100644 --- a/src/network/accept.c +++ b/src/network/accept.c @@ -3,5 +3,5 @@ int accept(int fd, struct sockaddr *restrict addr, socklen_t *restrict len) { - return socketcall_cp(accept, fd, addr, len, 0, 0, 0); + return socketcall_cp(accept, fd, addr, len); } diff --git a/src/network/accept4.c b/src/network/accept4.c index 765a38e..91575d1 100644 --- a/src/network/accept4.c +++ b/src/network/accept4.c @@ -7,7 +7,7 @@ int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int flg) { if (!flg) return accept(fd, addr, len); - int ret = socketcall_cp(accept4, fd, addr, len, flg, 0, 0); + int ret = socketcall_cp(accept4, fd, addr, len, flg); if (ret>=0 || (errno != ENOSYS && errno != EINVAL)) return ret; if (flg & ~(SOCK_CLOEXEC|SOCK_NONBLOCK)) { errno = EINVAL; diff --git a/src/network/bind.c b/src/network/bind.c index 07bb669..0ff11d9 100644 --- a/src/network/bind.c +++ b/src/network/bind.c @@ -3,5 +3,5 @@ int bind(int fd, const struct sockaddr *addr, socklen_t len) { - return socketcall(bind, fd, addr, len, 0, 0, 0); + return socketcall(bind, fd, addr, len); } diff --git a/src/network/connect.c b/src/network/connect.c index 289127b..ace2add 100644 --- a/src/network/connect.c +++ b/src/network/connect.c @@ -3,5 +3,5 @@ int connect(int fd, const struct sockaddr *addr, socklen_t len) { - return socketcall_cp(connect, fd, addr, len, 0, 0, 0); + return socketcall_cp(connect, fd, addr, len); } diff --git a/src/network/getpeername.c b/src/network/getpeername.c index 6567b45..fc366a3 100644 --- a/src/network/getpeername.c +++ b/src/network/getpeername.c @@ -3,5 +3,5 @@ int getpeername(int fd, struct sockaddr *restrict addr, socklen_t *restrict len) { - return socketcall(getpeername, fd, addr, len, 0, 0, 0); + return socketcall(getpeername, fd, addr, len); } diff --git a/src/network/getsockname.c b/src/network/getsockname.c index 7885fc1..2a4d3eb 100644 --- a/src/network/getsockname.c +++ b/src/network/getsockname.c @@ -3,5 +3,5 @@ int getsockname(int fd, struct sockaddr *restrict addr, socklen_t *restrict len) { - return socketcall(getsockname, fd, addr, len, 0, 0, 0); + return socketcall(getsockname, fd, addr, len); } diff --git a/src/network/getsockopt.c b/src/network/getsockopt.c index d3640d9..aaf0b7c 100644 --- a/src/network/getsockopt.c +++ b/src/network/getsockopt.c @@ -8,7 +8,7 @@ int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t long tv32[2]; struct timeval *tv; - int r = __socketcall(getsockopt, fd, level, optname, optval, optlen, 0); + int r = __socketcall(getsockopt, fd, level, optname, optval, optlen); if (r==-ENOPROTOOPT) switch (level) { case SOL_SOCKET: @@ -20,7 +20,7 @@ int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD; if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD; r = __socketcall(getsockopt, fd, level, optname, - tv32, (socklen_t[]){sizeof tv32}, 0); + tv32, (socklen_t[]){sizeof tv32}); if (r<0) break; tv = optval; tv->tv_sec = tv32[0]; @@ -33,7 +33,7 @@ int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD; if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD; r = __socketcall(getsockopt, fd, level, - optname, optval, optlen, 0); + optname, optval, optlen); break; } } diff --git a/src/network/listen.c b/src/network/listen.c index f84ad03..87eec05 100644 --- a/src/network/listen.c +++ b/src/network/listen.c @@ -3,5 +3,5 @@ int listen(int fd, int backlog) { - return socketcall(listen, fd, backlog, 0, 0, 0, 0); + return socketcall(listen, fd, backlog); } diff --git a/src/network/recvmsg.c b/src/network/recvmsg.c index 0364162..8f9b81d 100644 --- a/src/network/recvmsg.c +++ b/src/network/recvmsg.c @@ -59,7 +59,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) msg = &h; } #endif - r = socketcall_cp(recvmsg, fd, msg, flags, 0, 0, 0); + r = socketcall_cp(recvmsg, fd, msg, flags); if (r >= 0) __convert_scm_timestamps(msg, orig_controllen); #if LONG_MAX > INT_MAX if (orig) *orig = h; diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c index acdfdf2..611186d 100644 --- a/src/network/sendmsg.c +++ b/src/network/sendmsg.c @@ -28,5 +28,5 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) } } #endif - return socketcall_cp(sendmsg, fd, msg, flags, 0, 0, 0); + return socketcall_cp(sendmsg, fd, msg, flags); } diff --git a/src/network/setsockopt.c b/src/network/setsockopt.c index 612a194..d97ce57 100644 --- a/src/network/setsockopt.c +++ b/src/network/setsockopt.c @@ -12,7 +12,7 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt time_t s; suseconds_t us; - int r = __socketcall(setsockopt, fd, level, optname, optval, optlen, 0); + int r = __socketcall(setsockopt, fd, level, optname, optval, optlen); if (r==-ENOPROTOOPT) switch (level) { case SOL_SOCKET: @@ -30,7 +30,7 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD; r = __socketcall(setsockopt, fd, level, optname, - ((long[]){s, CLAMP(us)}), 2*sizeof(long), 0); + ((long[]){s, CLAMP(us)}), 2*sizeof(long)); break; case SO_TIMESTAMP: case SO_TIMESTAMPNS: @@ -38,7 +38,7 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD; if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD; r = __socketcall(setsockopt, fd, level, - optname, optval, optlen, 0); + optname, optval, optlen); break; } } diff --git a/src/network/shutdown.c b/src/network/shutdown.c index 10ca21a..fa51bfc 100644 --- a/src/network/shutdown.c +++ b/src/network/shutdown.c @@ -3,5 +3,5 @@ int shutdown(int fd, int how) { - return socketcall(shutdown, fd, how, 0, 0, 0, 0); + return socketcall(shutdown, fd, how); } diff --git a/src/network/socket.c b/src/network/socket.c index afa1a7f..d2beb31 100644 --- a/src/network/socket.c +++ b/src/network/socket.c @@ -5,12 +5,11 @@ int socket(int domain, int type, int protocol) { - int s = __socketcall(socket, domain, type, protocol, 0, 0, 0); + int s = __socketcall(socket, domain, type, protocol); if ((s==-EINVAL || s==-EPROTONOSUPPORT) && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { s = __socketcall(socket, domain, - type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), - protocol, 0, 0, 0); + type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), protocol); if (s < 0) return __syscall_ret(s); if (type & SOCK_CLOEXEC) __syscall(SYS_fcntl, s, F_SETFD, FD_CLOEXEC); diff --git a/src/network/socketpair.c b/src/network/socketpair.c index f348962..28603ed 100644 --- a/src/network/socketpair.c +++ b/src/network/socketpair.c @@ -5,12 +5,11 @@ int socketpair(int domain, int type, int protocol, int fd[2]) { - int r = socketcall(socketpair, domain, type, protocol, fd, 0, 0); + int r = socketcall(socketpair, domain, type, protocol, fd); if (r<0 && (errno==EINVAL || errno==EPROTONOSUPPORT) && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { r = socketcall(socketpair, domain, - type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), - protocol, fd, 0, 0); + type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), protocol, fd); if (r < 0) return r; if (type & SOCK_CLOEXEC) { __syscall(SYS_fcntl, fd[0], F_SETFD, FD_CLOEXEC); diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c index 8294598..668694d 100644 --- a/src/process/posix_spawn.c +++ b/src/process/posix_spawn.c @@ -175,12 +175,13 @@ int posix_spawn(pid_t *restrict res, const char *restrict path, char stack[1024+PATH_MAX]; int ec=0, cs; struct args args; + const posix_spawnattr_t dummy = {0}; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); args.path = path; args.fa = fa; - args.attr = attr ? attr : &(const posix_spawnattr_t){0}; + args.attr = attr ? attr : &dummy; args.argv = argv; args.envp = envp; pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask); diff --git a/src/process/vfork.c b/src/process/vfork.c index d430c13..0b16b9d 100644 --- a/src/process/vfork.c +++ b/src/process/vfork.c @@ -1,14 +1,12 @@ #define _GNU_SOURCE -#include +#include +#include #include #include "syscall.h" pid_t vfork(void) { - /* vfork syscall cannot be made from C code */ -#ifdef SYS_fork - return syscall(SYS_fork); -#else - return syscall(SYS_clone, SIGCHLD, 0); -#endif + fprintf(stderr, + "vfork() is not implemented yet, use clone() instead!\n"); + abort(); } diff --git a/src/setjmp/longjmp.c b/src/setjmp/longjmp.c index e69de29..d03b171 100644 --- a/src/setjmp/longjmp.c +++ b/src/setjmp/longjmp.c @@ -0,0 +1,19 @@ + +#include +#include + +/* + * setjmp/sigsetjmp/longjmp is currently not supported (but it can be, + * LLVM has support for it with some fixup logic needed). Since some + * programs use setjmp but only longjmp when for example an error occurs, + * we can allow setjmp/sigsetjmp (by doing nothing). When it actually + * wants to longjmp we have to abort, let's just hope that never happens. + */ +_Noreturn void longjmp(jmp_buf env, int status); +{ + (void)env; + (void)status; + + fprintf(stderr, "longjmp() is not implemented yet!\n"); + abort(); +} diff --git a/src/setjmp/wasm/longjmp.S b/src/setjmp/wasm/longjmp.S new file mode 100644 index 0000000..192b0b3 --- /dev/null +++ b/src/setjmp/wasm/longjmp.S @@ -0,0 +1,13 @@ +.functype abort() -> () + +.globl longjmp +longjmp: + .functype longjmp(i32, i32) -> () + # setjmp/sigsetjmp/longjmp is currently not supported (but it can be, + # LLVM has support for it with some fixup logic needed). Since some + # programs use setjmp but only longjmp when for example an error occurs, + # we can allow setjmp/sigsetjmp (by doing nothing). When it actually + # wants to longjmp we have to abort, let's just hope that never happens. + call abort + + end_function diff --git a/src/setjmp/wasm/setjmp.S b/src/setjmp/wasm/setjmp.S new file mode 100644 index 0000000..50b8983 --- /dev/null +++ b/src/setjmp/wasm/setjmp.S @@ -0,0 +1,5 @@ +.globl setjmp +setjmp: + .functype setjmp(i32) -> () + # We allow this, but do nothing. longjmp() is forbidden though. + end_function diff --git a/src/signal/wasm/restore.s b/src/signal/wasm/restore.s new file mode 100644 index 0000000..f14b43c --- /dev/null +++ b/src/signal/wasm/restore.s @@ -0,0 +1,98 @@ +.globaltype __stack_pointer, i32 +.globaltype __tls_base, i32 +.functype __wasm_syscall_0(i32, i32, i32) -> (i32) + +.globl __restore_rt +.hidden __restore_rt +__restore_rt: + .functype __restore_rt() -> () + + global.get __stack_pointer + global.get __tls_base + i32.const 139 # SYS_rt_sigreturn + call __wasm_syscall_0 + unreachable + + end_function + +.globl __restore +.hidden __restore +__restore: + .functype __restore() -> () + + call __restore_rt + + end_function + +/* TODO: Move this to a better place... */ +.globl __libc_handle_signal +__libc_handle_signal: + .functype __libc_handle_signal() -> () + /* 0: sig_param */ + /* 1: info_param */ + /* 2: uc_param */ + /* 3: sa_handler */ + .local i32, i32, i32, i32 + + /* sig_param */ + global.get __stack_pointer + i32.load 0 + /* + * LLVM complains for some reason if we leave this on the Wasm stack. We + * put it in a local instead and then everything works, somehow... + */ + local.set 0 + + /* info_param */ + global.get __stack_pointer + i32.const 4 + i32.add + i32.load 0 + local.set 1 + + /* uc_param */ + global.get __stack_pointer + i32.const 8 + i32.add + i32.load 0 + local.set 2 + + /* sa_handler */ + global.get __stack_pointer + i32.const 12 + i32.add + i32.load 0 + local.set 3 + + /* (__stack_pointer is already 16-byte aligned by the kernel.) */ + + /* !SA_SIGINFO */ + block + local.get 1 + br_if 0 + + local.get 0 /* sig_param */ + local.get 3 /* sa_handler cast to handler */ + /* handler(sig) */ + call_indirect (i32) -> () + end_block + + /* SA_SIGINFO */ + block + local.get 1 + i32.eqz + br_if 0 + + local.get 0 /* sig _param*/ + local.get 1 /* info_param */ + local.get 2 /* uc_param */ + local.get 3 /* sa_handler cast to sigaction */ + /* sigaction(sig_param, info_param, uc_param) */ + call_indirect (i32, i32, i32) -> () + end_block + + /* Unless the handler itself calls SYS_rt_sigreturn we have to do it. */ + call __restore_rt + unreachable + + end_function diff --git a/src/signal/wasm/sigsetjmp.S b/src/signal/wasm/sigsetjmp.S new file mode 100644 index 0000000..83dd15d --- /dev/null +++ b/src/signal/wasm/sigsetjmp.S @@ -0,0 +1,5 @@ +.globl sigsetjmp +sigsetjmp: + .functype sigsetjmp(i32, i32) -> () + # We allow this, but do nothing. longjmp() is forbidden though. + end_function diff --git a/src/thread/__syscall_cp.c b/src/thread/__syscall_cp.c index 42a0167..f33c5d0 100644 --- a/src/thread/__syscall_cp.c +++ b/src/thread/__syscall_cp.c @@ -1,20 +1,2 @@ #include "pthread_impl.h" #include "syscall.h" - -hidden long __syscall_cp_c(); - -static long sccp(syscall_arg_t nr, - syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, - syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) -{ - return __syscall(nr, u, v, w, x, y, z); -} - -weak_alias(sccp, __syscall_cp_c); - -long (__syscall_cp)(syscall_arg_t nr, - syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, - syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) -{ - return __syscall_cp_c(nr, u, v, w, x, y, z); -} diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c index 666093b..ffa12cc 100644 --- a/src/thread/__timedwait.c +++ b/src/thread/__timedwait.c @@ -17,13 +17,13 @@ static int __futex4_cp(volatile void *addr, int op, int val, const struct timesp r = -ENOSYS; if (SYS_futex == SYS_futex_time64 || !IS32BIT(s)) r = __syscall_cp(SYS_futex_time64, addr, op, val, - to ? ((long long[]){s, ns}) : 0); + to ? ((long long[]){s, ns}) : 0, 0, 0); if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r; to = to ? (void *)(long[]){CLAMP(s), ns} : 0; #endif - r = __syscall_cp(SYS_futex, addr, op, val, to); + r = __syscall_cp(SYS_futex, addr, op, val, to, 0, 0); if (r != -ENOSYS) return r; - return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, to); + return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, to, 0, 0); } static volatile int dummy = 0; diff --git a/src/thread/__wait.c b/src/thread/__wait.c index dc33c1a..847de07 100644 --- a/src/thread/__wait.c +++ b/src/thread/__wait.c @@ -10,8 +10,8 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) } if (waiters) a_inc(waiters); while (*addr==val) { - __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS - || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); + __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0, 0, 0) != -ENOSYS + || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0, 0, 0); } if (waiters) a_dec(waiters); } diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c index cc2a8bb..e2fa679 100644 --- a/src/thread/pthread_barrier_wait.c +++ b/src/thread/pthread_barrier_wait.c @@ -84,8 +84,8 @@ int pthread_barrier_wait(pthread_barrier_t *b) a_spin(); a_inc(&inst->finished); while (inst->finished == 1) - __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS - || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0); + __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0,0,0) != -ENOSYS + || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0,0,0); return PTHREAD_BARRIER_SERIAL_THREAD; } diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c index 139a6fc..4ba7b8e 100644 --- a/src/thread/pthread_cancel.c +++ b/src/thread/pthread_cancel.c @@ -3,9 +3,7 @@ #include "pthread_impl.h" #include "syscall.h" -hidden long __cancel(), __syscall_cp_asm(), __syscall_cp_c(); - -long __cancel() +hidden long __cancel() { pthread_t self = __pthread_self(); if (self->canceldisable == PTHREAD_CANCEL_ENABLE || self->cancelasync) @@ -14,27 +12,85 @@ long __cancel() return -ECANCELED; } -long __syscall_cp_asm(volatile void *, syscall_arg_t, - syscall_arg_t, syscall_arg_t, syscall_arg_t, - syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_asm0(volatile void *, syscall_arg_t); +hidden long __syscall_cp_asm1(volatile void *, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_asm2(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_asm3(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_asm4(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_asm5(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_asm6(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); + +long __syscall_cp_asm0(volatile void *, syscall_arg_t) { abort(); /* TODO */ } +long __syscall_cp_asm1(volatile void *, syscall_arg_t, syscall_arg_t) { abort(); /* TODO */ } +long __syscall_cp_asm2(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t) { abort(); /* TODO */ } +long __syscall_cp_asm3(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t) { abort(); /* TODO */ } +long __syscall_cp_asm4(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t) { abort(); /* TODO */ } +long __syscall_cp_asm5(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t) { abort(); /* TODO */ } +long __syscall_cp_asm6(volatile void *, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t) { abort(); /* TODO */ } + +hidden long __syscall_cp_c0(syscall_arg_t); +hidden long __syscall_cp_c1(syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c2(syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c3(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c4(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c5(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); +hidden long __syscall_cp_c6(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); + +/* It's a TODO to handle this... */ +/* +#define SYSCALL_CP_C(num, ...) do {\ + pthread_t self; \ + long r; \ + int st; \ + \ + if ((st=(self=__pthread_self())->canceldisable) \ + && (st==PTHREAD_CANCEL_DISABLE || nr==SYS_close)) \ + return __syscall(__VA_ARGS__); \ + \ + r = __syscall_cp_asm##num(&self->cancel, __VA_ARGS__); \ + if (r==-EINTR && nr!=SYS_close && self->cancel && \ + self->canceldisable != PTHREAD_CANCEL_DISABLE) \ + r = __cancel(); \ + return r; \ + } while(0) +*/ +#define SYSCALL_CP_C(num, ...) do {\ + return __syscall(__VA_ARGS__); \ + } while(0) + +long __syscall_cp_c0(syscall_arg_t nr) +{ + SYSCALL_CP_C(0, nr); +} + +long __syscall_cp_c1(syscall_arg_t nr, syscall_arg_t u) +{ + SYSCALL_CP_C(1, nr, u); +} + +long __syscall_cp_c2(syscall_arg_t nr, syscall_arg_t u, syscall_arg_t v) +{ + SYSCALL_CP_C(2, nr, u, v); +} -long __syscall_cp_c(syscall_arg_t nr, - syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, - syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +long __syscall_cp_c3(syscall_arg_t nr, syscall_arg_t u, syscall_arg_t v, syscall_arg_t w) { - pthread_t self; - long r; - int st; - - if ((st=(self=__pthread_self())->canceldisable) - && (st==PTHREAD_CANCEL_DISABLE || nr==SYS_close)) - return __syscall(nr, u, v, w, x, y, z); - - r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); - if (r==-EINTR && nr!=SYS_close && self->cancel && - self->canceldisable != PTHREAD_CANCEL_DISABLE) - r = __cancel(); - return r; + SYSCALL_CP_C(3, nr, u, v, w); +} + +long __syscall_cp_c4(syscall_arg_t nr, syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, syscall_arg_t x) +{ + SYSCALL_CP_C(4, nr, u, v, w, x); +} + +long __syscall_cp_c5(syscall_arg_t nr, syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, syscall_arg_t x, syscall_arg_t y) +{ + SYSCALL_CP_C(5, nr, u, v, w, x, y); +} + +long __syscall_cp_c6(syscall_arg_t nr, syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + SYSCALL_CP_C(6, nr, u, v, w, x, y, z); } static void _sigaddset(sigset_t *set, int sig) @@ -49,7 +105,7 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx) { pthread_t self = __pthread_self(); ucontext_t *uc = ctx; - uintptr_t pc = uc->uc_mcontext.MC_PC; + uintptr_t pc; a_barrier(); if (!self->cancel || self->canceldisable == PTHREAD_CANCEL_DISABLE) return; @@ -61,6 +117,8 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx) __cancel(); } +#ifdef MC_PC + pc = uc->uc_mcontext.MC_PC; if (pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) { uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel; #ifdef CANCEL_GOT @@ -68,6 +126,10 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx) #endif return; } +#else + /* TODO: handle this. */ + abort(); +#endif __syscall(SYS_tkill, self->tid, SIGCANCEL); } diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c index 6b76145..fc6793e 100644 --- a/src/thread/pthread_cond_timedwait.c +++ b/src/thread/pthread_cond_timedwait.c @@ -49,8 +49,8 @@ static inline void unlock_requeue(volatile int *l, volatile int *r, int w) { a_store(l, 0); if (w) __wake(l, 1, 1); - else __syscall(SYS_futex, l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS - || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r); + else __syscall(SYS_futex, l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r, 0) != -ENOSYS + || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r, 0); } enum { diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c index 9279fc5..9615429 100644 --- a/src/thread/pthread_mutex_timedlock.c +++ b/src/thread/pthread_mutex_timedlock.c @@ -11,11 +11,11 @@ static int __futex4(volatile void *addr, int op, int val, const struct timespec int r = -ENOSYS; if (SYS_futex == SYS_futex_time64 || !IS32BIT(s)) r = __syscall(SYS_futex_time64, addr, op, val, - to ? ((long long[]){s, ns}) : 0); + to ? ((long long[]){s, ns}) : 0, 0, 0); if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r; to = to ? (void *)(long[]){CLAMP(s), ns} : 0; #endif - return __syscall(SYS_futex, addr, op, val, to); + return __syscall(SYS_futex, addr, op, val, to, 0, 0); } static int pthread_mutex_timedlock_pi(pthread_mutex_t *restrict m, const struct timespec *restrict at) @@ -36,7 +36,7 @@ static int pthread_mutex_timedlock_pi(pthread_mutex_t *restrict m, const struct /* Catch spurious success for non-robust mutexes. */ if (!(type&4) && ((m->_m_lock & 0x40000000) || m->_m_waiters)) { a_store(&m->_m_waiters, -1); - __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); + __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv, 0, 0, 0, 0); self->robust_list.pending = 0; break; } diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c index a24e7c5..fc6dc8d 100644 --- a/src/thread/pthread_mutex_trylock.c +++ b/src/thread/pthread_mutex_trylock.c @@ -43,7 +43,7 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m) success: if ((type&8) && m->_m_waiters) { int priv = (type & 128) ^ 128; - __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); + __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv, 0, 0, 0, 0); self->robust_list.pending = 0; return (type&4) ? ENOTRECOVERABLE : EBUSY; } diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c index b66423e..69f1a9c 100644 --- a/src/thread/pthread_mutex_unlock.c +++ b/src/thread/pthread_mutex_unlock.c @@ -33,7 +33,7 @@ int __pthread_mutex_unlock(pthread_mutex_t *m) if (type&8) { if (old<0 || a_cas(&m->_m_lock, old, new)!=old) { if (new) a_store(&m->_m_waiters, -1); - __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); + __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv, 0, 0, 0, 0); } cont = 0; waiters = 0; diff --git a/src/thread/pthread_mutexattr_setprotocol.c b/src/thread/pthread_mutexattr_setprotocol.c index 8b80c1c..b98cbc2 100644 --- a/src/thread/pthread_mutexattr_setprotocol.c +++ b/src/thread/pthread_mutexattr_setprotocol.c @@ -14,7 +14,7 @@ int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int protocol) r = check_pi_result; if (r < 0) { volatile int lk = 0; - r = -__syscall(SYS_futex, &lk, FUTEX_LOCK_PI, 0, 0); + r = -__syscall(SYS_futex, &lk, FUTEX_LOCK_PI, 0, 0, 0, 0); a_store(&check_pi_result, r); } if (r) return r; diff --git a/src/thread/wasm/__set_thread_area.c b/src/thread/wasm/__set_thread_area.c new file mode 100644 index 0000000..f703c34 --- /dev/null +++ b/src/thread/wasm/__set_thread_area.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +_Thread_local uintptr_t __musl_tp = 0U; + +int __set_thread_area(void *p) +{ + __musl_tp = (uintptr_t)p; + return 0; +} diff --git a/src/thread/wasm/clone.s b/src/thread/wasm/clone.s new file mode 100644 index 0000000..4aa3a7e --- /dev/null +++ b/src/thread/wasm/clone.s @@ -0,0 +1,149 @@ +.globaltype __stack_pointer, i32 +.globaltype __tls_base, i32 +.functype __wasm_syscall_1(i32, i32, i32, i32) -> (i32) +.functype __wasm_syscall_5(i32, i32, i32, i32, i32, i32, i32, i32) -> (i32) + +.globl __get_tls_base +__get_tls_base: + .functype __get_tls_base() -> (i32) + global.get __tls_base + end_function + +# The runtime expects to be able to set __tls_base as part of it's clone setup. +.globl __set_tls_base +__set_tls_base: + .functype __set_tls_base(i32) -> () + local.get 0 + global.set __tls_base + end_function + +# This function gets called by the host once it detects a clone happening. +.globl __libc_clone_callback +__libc_clone_callback: + .functype __libc_clone_callback() -> (i32) + + i32.const 0 # sp (no care) + i32.const 0 # tp (no care) + i32.const 93 # SYS_exit (will be used at the end of this function) + + # Extract arg + global.get __stack_pointer + i32.const 4 + i32.add + i32.load 0 + + # Extract fn + global.get __stack_pointer + i32.load 0 + + # Deallocate fn+arg+alignemnt + global.get __stack_pointer + i32.const 16 + i32.add + global.set __stack_pointer + + # Call fn(arg) + call_indirect (i32) -> (i32) + + # syscall(SYS_exit, the return value from the callback) + call __wasm_syscall_1 + end_function + +.globl _Clone +_Clone: + # int _Clone(fn, stack, flags, arg, ptid, tls, ctid); + # 0 1 2 3 4 5 6 + .functype _Clone(i32, i32, i32, i32, i32, i32, i32) -> (i32) + .local i32 /* 7: child_stack */ + + # We save fn+arg on the stack. There are two distincs cases for stack: + # * stack is NULL: the kernel will in this special case copy the value + # of __stack_pointer to the new task. This means we should fill in fn + # and arg on our stack. This also implies that the caller uses + # CLONE_VFORK which pauses the calling task (or it does not care about + # the stack being corrupted in the caller, which is a very odd case). + # * stack is not NULL: the kernel will in this case set the stack + # pointer of the new task to the value of the stack argument. + # + # In either case we don't really need to "allocate" space on these + # stacks, but we do it anyway, should the syscall wrappers change in the + # future to call C code. In that case we also need to align the stack. + + # If stack was NULL, store into __stack_pointer instead. The kernel will + # in this special case copy the value of the stack pointer to the new + # task in the clone syscall. (Allocating space on these stacks is not + # strictly necessary but a nice thing if the syscall function changes + # to a C function in the future - in that case we should also align the + # stack to 16 bytes.) To be consistent, also allocate on non-NULL stack. + block + local.get 1 + br_if 0 # if (stack != NULL): break to block 0; + # else if (stack == NULL): + + global.get __stack_pointer + i32.const 16 + i32.sub + local.tee 7 + global.set __stack_pointer + end_block + + block + local.get 1 + i32.eqz + br_if 0 # if (stack == NULL): break to block 0; + # else if (stack != NULL): + + local.get 1 + i32.const 16 + i32.sub + local.tee 7 + local.set 1 + end_block + + /* + * At this point: + * local 1 contains the decremented stack address or NULL. + * local 7 contains the decremented stack address (never NULL). + * i.e. we don't pass the decremented __stack_pointer if stack == NULL. + */ + + # Store fn at the lowest address. + local.get 7 + local.get 0 + i32.store 0 + + # Store arg at the next-lowest address. + local.get 7 + i32.const 4 + i32.add + local.get 3 + i32.store 0 + + # syscall(SYS_clone, clone_flags, newsp, parent_tidptr, child_tidptr, tls) + global.get __stack_pointer # our sp (used when newsp is NULL) + global.get __tls_base # our tp (used when CLONE_SETTLS is not set) + i32.const 220 # SYS_clone + local.get 2 # clone_flags + local.get 1 # newsp (maybe NULL) + local.get 4 # ptid + local.get 6 # ctid + local.get 5 # tls + call __wasm_syscall_5 + + # On Wasm, we don't end up returning twice - instead wasm_clone_callback + # is called and we can extract fn and arg from __stack_pointer. This + # means that we for sure currently are in the parent when returning. + + block + local.get 1 + br_if 0 # if (stack != NULL): break to block 0; + # else if(stack == NULL): + + global.get __stack_pointer + i32.const 16 + i32.add + global.set __stack_pointer + end_block + + # (Pass on return value from the above syscall to the caller.) + end_function diff --git a/src/unistd/access.c b/src/unistd/access.c index d6eed68..449f9b4 100644 --- a/src/unistd/access.c +++ b/src/unistd/access.c @@ -7,6 +7,6 @@ int access(const char *filename, int amode) #ifdef SYS_access return syscall(SYS_access, filename, amode); #else - return syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0); + return syscall(SYS_faccessat2, AT_FDCWD, filename, amode, 0); #endif } diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c index 43052dd..56d650c 100644 --- a/src/unistd/faccessat.c +++ b/src/unistd/faccessat.c @@ -18,7 +18,7 @@ static int checker(void *p) if (__syscall(SYS_setregid, __syscall(SYS_getegid), -1) || __syscall(SYS_setreuid, __syscall(SYS_geteuid), -1)) __syscall(SYS_exit, 1); - ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0); + ret = __syscall(SYS_faccessat2, c->fd, c->filename, c->amode, 0); __syscall(SYS_write, c->p, &ret, sizeof ret); return 0; } -- 2.25.1