From cd4213365120a6b73bcb49e3e4bc83cb36a6c55f Mon Sep 17 00:00:00 2001 From: HAMIDx9 Date: Tue, 8 Aug 2017 06:59:45 +0000 Subject: [PATCH] Add arm64 build support --- script/cibuild | 10 + script/cibuild-electron-linux-arm64 | 5 + script/create-dist.py | 2 + toolchain.gypi | 19 +- .../third_party/lss/linux_syscall_support.h | 1175 ++++++++++++++--- 5 files changed, 1029 insertions(+), 182 deletions(-) create mode 100755 script/cibuild-electron-linux-arm64 diff --git a/script/cibuild b/script/cibuild index edd1b0a06d..7186a5726d 100755 --- a/script/cibuild +++ b/script/cibuild @@ -34,6 +34,14 @@ LINUX_DEPS_ARM = [ 'gcc-4.8-multilib-arm-linux-gnueabihf', ] +LINUX_DEPS_ARM64 = [ + 'binutils-aarch64-linux-gnu', + 'libc6-dev-arm64-cross', + 'linux-libc-dev-arm64-cross', + 'g++-4.8-aarch64-linux-gnu', + 'gcc-4.8-aarch64-linux-gnu', + 'gcc-aarch64-linux-gnu', +] def main(): os.environ['CI'] = '1' @@ -56,6 +64,8 @@ def main(): deps = LINUX_DEPS if target_arch == 'arm': deps += LINUX_DEPS_ARM + elif target_arch == 'arm64': + deps += LINUX_DEPS_ARM64 else: deps += LINUX_DEPS_NO_ARM execute(['sudo', 'apt-get', 'install'] + deps) diff --git a/script/cibuild-electron-linux-arm64 b/script/cibuild-electron-linux-arm64 new file mode 100755 index 0000000000..a08c2de150 --- /dev/null +++ b/script/cibuild-electron-linux-arm64 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +export TARGET_ARCH=arm64 + +script/cibuild-linux diff --git a/script/create-dist.py b/script/create-dist.py index dc689ac338..69c778187f 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -208,6 +208,8 @@ def strip_binaries(): def strip_binary(binary_path): if get_target_arch() == 'arm': strip = 'arm-linux-gnueabihf-strip' + elif get_target_arch() == 'arm64': + strip = 'aarch64-linux-gnu-strip' else: strip = 'strip' execute([strip, binary_path]) diff --git a/toolchain.gypi b/toolchain.gypi index f00016651c..3c8e69235c 100644 --- a/toolchain.gypi +++ b/toolchain.gypi @@ -140,7 +140,7 @@ }], # Setup sysroot environment. - ['OS=="linux" and target_arch in ["arm", "ia32", "x64"]', { + ['OS=="linux" and target_arch in ["arm", "ia32", "x64", "arm64"]', { 'target_defaults': { 'target_conditions': [ ['_toolset=="target"', { @@ -259,6 +259,23 @@ ], }], ], + }], # target_arch=="arm64" and _toolset=="target" + ['target_arch=="arm64" and _toolset=="target"', { + 'conditions': [ + ['clang==0', { + 'cflags_cc': [ + '-Wno-abi', + ], + }], + ['clang==1 and arm_arch!=""', { + 'cflags': [ + '-target aarch64-linux-gnu', + ], + 'ldflags': [ + '-target aarch64-linux-gnu', + ], + }], + ], }], # target_arch=="arm" and _toolset=="target" ], }, diff --git a/vendor/third_party/lss/linux_syscall_support.h b/vendor/third_party/lss/linux_syscall_support.h index d04901dbd6..cb3fac22ad 100644 --- a/vendor/third_party/lss/linux_syscall_support.h +++ b/vendor/third_party/lss/linux_syscall_support.h @@ -82,11 +82,13 @@ #ifndef SYS_LINUX_SYSCALL_SUPPORT_H #define SYS_LINUX_SYSCALL_SUPPORT_H -/* We currently only support x86-32, x86-64, ARM, MIPS, and PPC on Linux. +/* We currently only support x86-32, x86-64, ARM, MIPS, PPC, s390 and s390x + * on Linux. * Porting to other related platforms should not be difficult. */ #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ - defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__)) \ + defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \ + defined(__aarch64__) || defined(__s390__)) \ && (defined(__linux) || defined(__ANDROID__)) #ifndef SYS_CPLUSPLUS @@ -100,6 +102,7 @@ extern "C" { #include #include +#include #include #include #include @@ -116,9 +119,16 @@ extern "C" { #ifdef __mips__ /* Include definitions of the ABI currently in use. */ +#ifdef __ANDROID__ +/* Android doesn't have sgidefs.h, but does have asm/sgidefs.h, + * which has the definitions we need. + */ +#include +#else #include #endif #endif +#endif /* The Android NDK's #defines these macros as aliases * to their non-64 counterparts. To avoid naming conflict, remove them. */ @@ -172,12 +182,17 @@ struct kernel_dirent64 { }; /* include/linux/dirent.h */ +#if defined(__aarch64__) +// aarch64 only defines dirent64, just uses that for dirent too. +#define kernel_dirent kernel_dirent64 +#else struct kernel_dirent { long d_ino; long d_off; unsigned short d_reclen; char d_name[256]; }; +#endif /* include/linux/uio.h */ struct kernel_iovec { @@ -242,7 +257,7 @@ struct kernel_rusage { }; #if defined(__i386__) || defined(__ARM_EABI__) || defined(__ARM_ARCH_3__) \ - || defined(__PPC__) + || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) /* include/asm-{arm,i386,mips,ppc}/signal.h */ struct kernel_old_sigaction { @@ -256,6 +271,8 @@ struct kernel_old_sigaction { } __attribute__((packed,aligned(4))); #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) #define kernel_old_sigaction kernel_sigaction +#elif defined(__aarch64__) + // No kernel_old_sigaction defined for arm64. #endif /* Some kernel functions (e.g. sigaction() in 2.6.23) require that the @@ -273,7 +290,7 @@ struct kernel_old_sigaction { #define KERNEL_NSIG 64 #endif -/* include/asm-{arm,i386,mips,x86_64}/signal.h */ +/* include/asm-{arm,aarch64,i386,mips,x86_64}/signal.h */ struct kernel_sigset_t { unsigned long sig[(KERNEL_NSIG + 8*sizeof(unsigned long) - 1)/ (8*sizeof(unsigned long))]; @@ -305,7 +322,7 @@ struct kernel_sockaddr { char sa_data[14]; }; -/* include/asm-{arm,i386,mips,ppc}/stat.h */ +/* include/asm-{arm,aarch64,i386,mips,ppc,s390}/stat.h */ #ifdef __mips__ #if _MIPS_SIM == _MIPS_SIM_ABI64 struct kernel_stat { @@ -378,7 +395,7 @@ struct kernel_stat64 { }; #endif -/* include/asm-{arm,i386,mips,x86_64,ppc}/stat.h */ +/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/stat.h */ #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) struct kernel_stat { /* The kernel headers suggest that st_dev and st_rdev should be 32bit @@ -426,7 +443,7 @@ struct kernel_stat { uint64_t st_mtime_nsec_; uint64_t st_ctime_; uint64_t st_ctime_nsec_; - int64_t __unused[3]; + int64_t __unused4[3]; }; #elif defined(__PPC__) struct kernel_stat { @@ -472,9 +489,76 @@ struct kernel_stat { int st_blocks; int st_pad4[14]; }; +#elif defined(__aarch64__) +struct kernel_stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long st_rdev; + unsigned long __pad1; + long st_size; + int st_blksize; + int __pad2; + long st_blocks; + long st_atime_; + unsigned long st_atime_nsec_; + long st_mtime_; + unsigned long st_mtime_nsec_; + long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned int __unused4; + unsigned int __unused5; +}; +#elif defined(__s390x__) +struct kernel_stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned long st_nlink; + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad1; + unsigned long st_rdev; + unsigned long st_size; + unsigned long st_atime_; + unsigned long st_atime_nsec_; + unsigned long st_mtime_; + unsigned long st_mtime_nsec_; + unsigned long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long st_blksize; + long st_blocks; + unsigned long __unused[3]; +}; +#elif defined(__s390__) +struct kernel_stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime_; + unsigned long st_atime_nsec_; + unsigned long st_mtime_; + unsigned long st_mtime_nsec_; + unsigned long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long __unused4; + unsigned long __unused5; +}; #endif -/* include/asm-{arm,i386,mips,x86_64,ppc}/statfs.h */ +/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/statfs.h */ #ifdef __mips__ #if _MIPS_SIM != _MIPS_SIM_ABI64 struct kernel_statfs64 { @@ -492,6 +576,22 @@ struct kernel_statfs64 { unsigned long f_spare[6]; }; #endif +#elif defined(__s390__) +/* See also arch/s390/include/asm/compat.h */ +struct kernel_statfs64 { + unsigned int f_type; + unsigned int f_bsize; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_bavail; + unsigned long long f_files; + unsigned long long f_ffree; + struct { int val[2]; } f_fsid; + unsigned int f_namelen; + unsigned int f_frsize; + unsigned int f_flags; + unsigned int f_spare[4]; +}; #elif !defined(__x86_64__) struct kernel_statfs64 { unsigned long f_type; @@ -508,7 +608,7 @@ struct kernel_statfs64 { }; #endif -/* include/asm-{arm,i386,mips,x86_64,ppc,generic}/statfs.h */ +/* include/asm-{arm,i386,mips,x86_64,ppc,generic,s390}/statfs.h */ #ifdef __mips__ struct kernel_statfs { long f_type; @@ -540,6 +640,21 @@ struct kernel_statfs { uint64_t f_frsize; uint64_t f_spare[5]; }; +#elif defined(__s390__) +struct kernel_statfs { + unsigned int f_type; + unsigned int f_bsize; + unsigned long f_blocks; + unsigned long f_bfree; + unsigned long f_bavail; + unsigned long f_files; + unsigned long f_ffree; + struct { int val[2]; } f_fsid; + unsigned int f_namelen; + unsigned int f_frsize; + unsigned int f_flags; + unsigned int f_spare[4]; +}; #else struct kernel_statfs { unsigned long f_type; @@ -559,7 +674,7 @@ struct kernel_statfs { /* Definitions missing from the standard header files */ #ifndef O_DIRECTORY -#if defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) +#if defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || defined(__aarch64__) #define O_DIRECTORY 0040000 #else #define O_DIRECTORY 0200000 @@ -612,11 +727,12 @@ struct kernel_statfs { #endif #ifndef MAKE_PROCESS_CPUCLOCK #define MAKE_PROCESS_CPUCLOCK(pid, clock) \ - ((~(int)(pid) << 3) | (int)(clock)) + ((int)(~(unsigned)(pid) << 3) | (int)(clock)) #endif #ifndef MAKE_THREAD_CPUCLOCK #define MAKE_THREAD_CPUCLOCK(tid, clock) \ - ((~(int)(tid) << 3) | (int)((clock) | CPUCLOCK_PERTHREAD_MASK)) + ((int)(~(unsigned)(tid) << 3) | \ + (int)((clock) | CPUCLOCK_PERTHREAD_MASK)) #endif #ifndef FUTEX_WAIT @@ -912,7 +1028,103 @@ struct kernel_statfs { #ifndef __NR_getcpu #define __NR_getcpu (__NR_SYSCALL_BASE + 345) #endif -/* End of ARM 3/EABI definitions */ +/* End of ARM 3/EABI definitions */ +#elif defined(__aarch64__) +#ifndef __NR_setxattr +#define __NR_setxattr 5 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 6 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 8 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 9 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 11 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 12 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 30 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 31 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 35 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 47 +#endif +#ifndef __NR_openat +#define __NR_openat 56 +#endif +#ifndef __NR_quotactl +#define __NR_quotactl 60 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 61 +#endif +#ifndef __NR_getdents +#define __NR_getdents __NR_getdents64 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 67 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 68 +#endif +#ifndef __NR_ppoll +#define __NR_ppoll 73 +#endif +#ifndef __NR_readlinkat +#define __NR_readlinkat 78 +#endif +#ifndef __NR_newfstatat +#define __NR_newfstatat 79 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 96 +#endif +#ifndef __NR_futex +#define __NR_futex 98 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 113 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 114 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#endif +#ifndef __NR_tkill +#define __NR_tkill 130 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#endif +#ifndef __NR_gettid +#define __NR_gettid 178 +#endif +#ifndef __NR_readahead +#define __NR_readahead 213 +#endif +#ifndef __NR_fadvise64 +#define __NR_fadvise64 223 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 239 +#endif +/* End of aarch64 definitions */ #elif defined(__x86_64__) #ifndef __NR_pread64 #define __NR_pread64 17 @@ -1369,6 +1581,189 @@ struct kernel_statfs { #define __NR_getcpu 302 #endif /* End of powerpc defininitions */ +#elif defined(__s390__) +#ifndef __NR_quotactl +#define __NR_quotactl 131 +#endif +#ifndef __NR_rt_sigreturn +#define __NR_rt_sigreturn 173 +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigaction 174 +#endif +#ifndef __NR_rt_sigprocmask +#define __NR_rt_sigprocmask 175 +#endif +#ifndef __NR_rt_sigpending +#define __NR_rt_sigpending 176 +#endif +#ifndef __NR_rt_sigsuspend +#define __NR_rt_sigsuspend 179 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 180 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 181 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 220 +#endif +#ifndef __NR_readahead +#define __NR_readahead 222 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 224 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 225 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 227 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 228 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 230 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 231 +#endif +#ifndef __NR_gettid +#define __NR_gettid 236 +#endif +#ifndef __NR_tkill +#define __NR_tkill 237 +#endif +#ifndef __NR_futex +#define __NR_futex 238 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 239 +#endif +#ifndef __NR_sched_getaffinity +#define __NR_sched_getaffinity 240 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 252 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 260 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 261 +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 265 +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 266 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 282 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 283 +#endif +#ifndef __NR_openat +#define __NR_openat 288 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 294 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 310 +#endif +#ifndef __NR_getcpu +#define __NR_getcpu 311 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 314 +#endif +/* Some syscalls are named/numbered differently between s390 and s390x. */ +#ifdef __s390x__ +# ifndef __NR_getrlimit +# define __NR_getrlimit 191 +# endif +# ifndef __NR_setresuid +# define __NR_setresuid 208 +# endif +# ifndef __NR_getresuid +# define __NR_getresuid 209 +# endif +# ifndef __NR_setresgid +# define __NR_setresgid 210 +# endif +# ifndef __NR_getresgid +# define __NR_getresgid 211 +# endif +# ifndef __NR_setfsuid +# define __NR_setfsuid 215 +# endif +# ifndef __NR_setfsgid +# define __NR_setfsgid 216 +# endif +# ifndef __NR_fadvise64 +# define __NR_fadvise64 253 +# endif +# ifndef __NR_newfstatat +# define __NR_newfstatat 293 +# endif +#else /* __s390x__ */ +# ifndef __NR_getrlimit +# define __NR_getrlimit 76 +# endif +# ifndef __NR_setfsuid +# define __NR_setfsuid 138 +# endif +# ifndef __NR_setfsgid +# define __NR_setfsgid 139 +# endif +# ifndef __NR_setresuid +# define __NR_setresuid 164 +# endif +# ifndef __NR_getresuid +# define __NR_getresuid 165 +# endif +# ifndef __NR_setresgid +# define __NR_setresgid 170 +# endif +# ifndef __NR_getresgid +# define __NR_getresgid 171 +# endif +# ifndef __NR_ugetrlimit +# define __NR_ugetrlimit 191 +# endif +# ifndef __NR_mmap2 +# define __NR_mmap2 192 +# endif +# ifndef __NR_setresuid32 +# define __NR_setresuid32 208 +# endif +# ifndef __NR_getresuid32 +# define __NR_getresuid32 209 +# endif +# ifndef __NR_setresgid32 +# define __NR_setresgid32 210 +# endif +# ifndef __NR_getresgid32 +# define __NR_getresgid32 211 +# endif +# ifndef __NR_setfsuid32 +# define __NR_setfsuid32 215 +# endif +# ifndef __NR_setfsgid32 +# define __NR_setfsgid32 216 +# endif +# ifndef __NR_fadvise64_64 +# define __NR_fadvise64_64 264 +# endif +# ifndef __NR_fstatat64 +# define __NR_fstatat64 293 +# endif +#endif /* __s390__ */ +/* End of s390/s390x definitions */ #endif @@ -1432,7 +1827,7 @@ struct kernel_statfs { #undef LSS_RETURN #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ - || defined(__ARM_EABI__)) + || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__)) /* Failing system calls return a negative result in the range of * -1..-4095. These are "errno" values with the sign inverted. */ @@ -1485,29 +1880,30 @@ struct kernel_statfs { void (**entrypoint)(void); asm volatile(".bss\n" ".align 8\n" - ".globl "SYS_SYSCALL_ENTRYPOINT"\n" - ".common "SYS_SYSCALL_ENTRYPOINT",8,8\n" + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" ".previous\n" /* This logically does 'lea "SYS_SYSCALL_ENTRYPOINT", %0' */ "call 0f\n" "0:pop %0\n" "add $_GLOBAL_OFFSET_TABLE_+[.-0b], %0\n" - "mov "SYS_SYSCALL_ENTRYPOINT"@GOT(%0), %0\n" + "mov " SYS_SYSCALL_ENTRYPOINT "@GOT(%0), %0\n" : "=r"(entrypoint)); return entrypoint; } #define LSS_ENTRYPOINT ".bss\n" \ ".align 8\n" \ - ".globl "SYS_SYSCALL_ENTRYPOINT"\n" \ - ".common "SYS_SYSCALL_ENTRYPOINT",8,8\n" \ + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ ".previous\n" \ /* Check the SYS_SYSCALL_ENTRYPOINT vector */ \ "push %%eax\n" \ "call 10000f\n" \ "10000:pop %%eax\n" \ "add $_GLOBAL_OFFSET_TABLE_+[.-10000b], %%eax\n" \ - "mov "SYS_SYSCALL_ENTRYPOINT"@GOT(%%eax), %%eax\n"\ + "mov " SYS_SYSCALL_ENTRYPOINT \ + "@GOT(%%eax), %%eax\n" \ "mov 0(%%eax), %%eax\n" \ "test %%eax, %%eax\n" \ "jz 10002f\n" \ @@ -1700,32 +2096,6 @@ struct kernel_statfs { LSS_RETURN(int, __res); } - #define __NR__fadvise64_64 __NR_fadvise64_64 - LSS_INLINE _syscall6(int, _fadvise64_64, int, fd, - unsigned, offset_lo, unsigned, offset_hi, - unsigned, len_lo, unsigned, len_hi, - int, advice) - - LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, - loff_t len, int advice) { - return LSS_NAME(_fadvise64_64)(fd, - (unsigned)offset, (unsigned)(offset >>32), - (unsigned)len, (unsigned)(len >> 32), - advice); - } - - #define __NR__fallocate __NR_fallocate - LSS_INLINE _syscall6(int, _fallocate, int, fd, - int, mode, - unsigned, offset_lo, unsigned, offset_hi, - unsigned, len_lo, unsigned, len_hi) - - LSS_INLINE int LSS_NAME(fallocate)(int fd, int mode, - loff_t offset, loff_t len) { - union { loff_t off; unsigned w[2]; } o = { offset }, l = { len }; - return LSS_NAME(_fallocate)(fd, mode, o.w[0], o.w[1], l.w[0], l.w[1]); - } - LSS_INLINE _syscall1(int, set_thread_area, void *, u) LSS_INLINE _syscall1(int, get_thread_area, void *, u) @@ -1779,10 +2149,10 @@ struct kernel_statfs { void (**entrypoint)(void); asm volatile(".bss\n" ".align 8\n" - ".globl "SYS_SYSCALL_ENTRYPOINT"\n" - ".common "SYS_SYSCALL_ENTRYPOINT",8,8\n" + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" ".previous\n" - "mov "SYS_SYSCALL_ENTRYPOINT"@GOTPCREL(%%rip), %0\n" + "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %0\n" : "=r"(entrypoint)); return entrypoint; } @@ -1790,10 +2160,10 @@ struct kernel_statfs { #define LSS_ENTRYPOINT \ ".bss\n" \ ".align 8\n" \ - ".globl "SYS_SYSCALL_ENTRYPOINT"\n" \ - ".common "SYS_SYSCALL_ENTRYPOINT",8,8\n" \ + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ ".previous\n" \ - "mov "SYS_SYSCALL_ENTRYPOINT"@GOTPCREL(%%rip), %%rcx\n" \ + "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %%rcx\n" \ "mov 0(%%rcx), %%rcx\n" \ "test %%rcx, %%rcx\n" \ "jz 10001f\n" \ @@ -2013,13 +2383,6 @@ struct kernel_statfs { } LSS_INLINE _syscall2(int, arch_prctl, int, c, void *, a) - /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ - LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, loff_t len, - int advice) { - LSS_BODY(4, int, fadvise64, LSS_SYSCALL_ARG(fd), (uint64_t)(offset), - (uint64_t)(len), LSS_SYSCALL_ARG(advice)); - } - LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { /* On x86-64, the kernel does not know how to return from * a signal handler. Instead, it relies on user space to provide a @@ -2232,86 +2595,188 @@ struct kernel_statfs { int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { long __res; + if (fn == NULL || child_stack == NULL) { + __res = -EINVAL; + LSS_RETURN(int, __res); + } + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + { + uintptr_t* cstack = (uintptr_t*)child_stack - 2; + cstack[0] = (uintptr_t)fn; + cstack[1] = (uintptr_t)arg; + child_stack = cstack; + } { register int __flags __asm__("r0") = flags; register void *__stack __asm__("r1") = child_stack; register void *__ptid __asm__("r2") = parent_tidptr; register void *__tls __asm__("r3") = newtls; register int *__ctid __asm__("r4") = child_tidptr; - __asm__ __volatile__(/* if (fn == NULL || child_stack == NULL) - * return -EINVAL; - */ -#ifdef __thumb2__ - "push {r7}\n" -#endif - "cmp %2,#0\n" - "it ne\n" - "cmpne %3,#0\n" - "it eq\n" - "moveq %0,%1\n" - "beq 1f\n" + __asm__ __volatile__( +#ifdef __thumb2__ + "push {r7}\n" +#endif + /* %r0 = syscall(%r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = newtls, + * %r4 = child_tidptr) + */ + "mov r7, %6\n" + "swi 0x0\n" - /* Push "arg" and "fn" onto the stack that will be + /* if (%r0 != 0) + * return %r0; + */ + "cmp r0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ldr r0,[sp, #4]\n" + + "ldr lr,[sp]\n" + "blx lr\n" + + /* Call _exit(%r0). + */ + "mov r7, %7\n" + "swi 0x0\n" + /* Unreachable */ + "bkpt #0\n" + "1:\n" +#ifdef __thumb2__ + "pop {r7}\n" +#endif + "movs %0,r0\n" + : "=r"(__res) + : "r"(__stack), "r"(__flags), "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "cc", "lr", "memory" +#ifndef __thumb2__ + , "r7" +#endif + ); + } + LSS_RETURN(int, __res); + } + #elif defined(__aarch64__) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(r,a) register int64_t __r##r __asm__("x"#r) = (int64_t)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register int64_t __res_x0 __asm__("x0"); \ + int64_t __res; \ + __asm__ __volatile__ ("mov x8, %1\n" \ + "svc 0x0\n" \ + : "=r"(__res_x0) \ + : "i"(__NR_##name) , ## args \ + : "x8", "memory"); \ + __res = __res_x0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + int64_t __res; + { + register uint64_t __flags __asm__("x0") = flags; + register void *__stack __asm__("x1") = child_stack; + register void *__ptid __asm__("x2") = parent_tidptr; + register void *__tls __asm__("x3") = newtls; + register int *__ctid __asm__("x4") = child_tidptr; + __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be * used by the child. */ - "str %5,[%3,#-4]!\n" - "str %2,[%3,#-4]!\n" + "stp %1, %4, [%2, #-16]!\n" - /* %r0 = syscall(%r0 = flags, - * %r1 = child_stack, - * %r2 = parent_tidptr, - * %r3 = newtls, - * %r4 = child_tidptr) + /* %x0 = syscall(%x0 = flags, + * %x1 = child_stack, + * %x2 = parent_tidptr, + * %x3 = newtls, + * %x4 = child_tidptr) */ - "mov r7, %9\n" - "swi 0x0\n" + "mov x8, %8\n" + "svc 0x0\n" /* if (%r0 != 0) * return %r0; */ - "movs %0,r0\n" - "bne 1f\n" + "mov %0, x0\n" + "cbnz x0, 1f\n" /* In the child, now. Call "fn(arg)". */ - "ldr r0,[sp, #4]\n" - - /* When compiling for Thumb-2 the "MOV LR,PC" here - * won't work because it loads PC+4 into LR, - * whereas the LDR is a 4-byte instruction. - * This results in the child thread always - * crashing with an "Illegal Instruction" when it - * returned into the middle of the LDR instruction - * The instruction sequence used instead was - * recommended by - * "https://wiki.edubuntu.org/ARM/Thumb2PortingHowto#Quick_Reference". - */ - #ifdef __thumb2__ - "ldr r7,[sp]\n" - "blx r7\n" - #else - "mov lr,pc\n" - "ldr pc,[sp]\n" - #endif + "ldp x1, x0, [sp], #16\n" + "blr x1\n" /* Call _exit(%r0). */ - "mov r7, %10\n" - "swi 0x0\n" + "mov x8, %9\n" + "svc 0x0\n" "1:\n" -#ifdef __thumb2__ - "pop {r7}" -#endif : "=r" (__res) - : "i"(-EINVAL), - "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit) -#ifdef __thumb2__ - : "cc", "lr", "memory"); -#else - : "cc", "r7", "lr", "memory"); -#endif + : "cc", "x8", "memory"); } LSS_RETURN(int, __res); } @@ -2320,14 +2785,22 @@ struct kernel_statfs { #define LSS_REG(r,a) register unsigned long __r##r __asm__("$"#r) = \ (unsigned long)(a) #undef LSS_BODY + #undef LSS_SYSCALL_CLOBBERS + #if _MIPS_SIM == _MIPS_SIM_ABI32 + #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", \ + "$11", "$12", "$13", "$14", "$15", \ + "$24", "$25", "hi", "lo", "memory" + #else + #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", \ + "$13", "$14", "$15", "$24", "$25", \ + "hi", "lo", "memory" + #endif #define LSS_BODY(type,name,r7,...) \ register unsigned long __v0 __asm__("$2") = __NR_##name; \ __asm__ __volatile__ ("syscall\n" \ - : "+r"(__v0), r7 (__r7) \ + : "=r"(__v0), r7 (__r7) \ : "0"(__v0), ##__VA_ARGS__ \ - : "$8", "$9", "$10", "$11", "$12", \ - "$13", "$14", "$15", "$24", "$25", \ - "memory"); \ + : LSS_SYSCALL_CLOBBERS); \ LSS_RETURN(type, __v0, __r7) #undef _syscall0 #define _syscall0(type, name) \ @@ -2441,7 +2914,7 @@ struct kernel_statfs { LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { - register unsigned long __v0 __asm__("$2"); + register unsigned long __v0 __asm__("$2") = -EINVAL; register unsigned long __r7 __asm__("$7") = (unsigned long)newtls; { register int __flags __asm__("$4") = flags; @@ -2460,25 +2933,24 @@ struct kernel_statfs { /* if (fn == NULL || child_stack == NULL) * return -EINVAL; */ - "li %0,%2\n" + "beqz %4,1f\n" "beqz %5,1f\n" - "beqz %6,1f\n" /* Push "arg" and "fn" onto the stack that will be * used by the child. */ #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 - "subu %6,32\n" - "sw %5,0(%6)\n" - "sw %8,4(%6)\n" + "subu %5,32\n" + "sw %4,0(%5)\n" + "sw %7,4(%5)\n" #elif _MIPS_SIM == _MIPS_SIM_NABI32 - "sub %6,32\n" - "sw %5,0(%6)\n" - "sw %8,8(%6)\n" + "sub %5,32\n" + "sw %4,0(%5)\n" + "sw %7,8(%5)\n" #else - "dsubu %6,32\n" - "sd %5,0(%6)\n" - "sd %8,8(%6)\n" + "dsubu %5,32\n" + "sd %4,0(%5)\n" + "sd %7,8(%5)\n" #endif /* $7 = syscall($4 = flags, @@ -2487,7 +2959,7 @@ struct kernel_statfs { * $7 = newtls, * $8 = child_tidptr) */ - "li $2,%3\n" + "li $2,%2\n" "syscall\n" /* if ($7 != 0) @@ -2513,7 +2985,7 @@ struct kernel_statfs { /* Call _exit($2) */ "move $4,$2\n" - "li $2,%4\n" + "li $2,%3\n" "syscall\n" "1:\n" @@ -2525,9 +2997,9 @@ struct kernel_statfs { "daddu $29,16\n" #endif : "+r" (__v0), "+r" (__r7) - : "i"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit), - "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), - "r"(__ptid), "r"(__r7), "r"(__ctid) + : "i"(__NR_clone), "i"(__NR_exit), "r"(fn), + "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__ctid) : "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25", "memory"); } @@ -2716,6 +3188,138 @@ struct kernel_statfs { } LSS_RETURN(int, __ret, __err); } + #elif defined(__s390__) + #undef LSS_REG + #define LSS_REG(r, a) register unsigned long __r##r __asm__("r"#r) = (unsigned long) a + #undef LSS_BODY + #define LSS_BODY(type, name, args...) \ + register unsigned long __nr __asm__("r1") \ + = (unsigned long)(__NR_##name); \ + register long __res_r2 __asm__("r2"); \ + long __res; \ + __asm__ __volatile__ \ + ("svc 0\n\t" \ + : "=d"(__res_r2) \ + : "d"(__nr), ## args \ + : "memory"); \ + __res = __res_r2; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(2, arg1); \ + LSS_BODY(type, name, "0"(__r2)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4)); \ + } + #undef _syscall4 + #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ + type4 arg4) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_REG(5, arg4); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5)); \ + } + #undef _syscall5 + #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ + type4 arg4, type5 arg5) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_REG(5, arg4); LSS_REG(6, arg5); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5), "d"(__r6)); \ + } + #undef _syscall6 + #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5, type6, arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ + type4 arg4, type5 arg5, type6 arg6) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_REG(5, arg4); LSS_REG(6, arg5); LSS_REG(7, arg6); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5), "d"(__r6), "d"(__r7)); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __ret; + { + register int (*__fn)(void *) __asm__ ("r1") = fn; + register void *__cstack __asm__ ("r2") = child_stack; + register int __flags __asm__ ("r3") = flags; + register void *__arg __asm__ ("r0") = arg; + register int *__ptidptr __asm__ ("r4") = parent_tidptr; + register void *__newtls __asm__ ("r6") = newtls; + register int *__ctidptr __asm__ ("r5") = child_tidptr; + __asm__ __volatile__ ( + #ifndef __s390x__ + /* arg already in r0 */ + "ltr %4, %4\n\t" /* check fn, which is already in r1 */ + "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ + "ltr %5, %5\n\t" /* check child_stack, which is already in r2 */ + "jz 1f\n\t" /* NULL stack pointer, return -EINVAL */ + /* flags already in r3 */ + /* parent_tidptr already in r4 */ + /* child_tidptr already in r5 */ + /* newtls already in r6 */ + "svc %2\n\t" /* invoke clone syscall */ + "ltr %0,%%r2\n\t" /* load return code into __ret and test */ + "jnz 1f\n\t" /* return to parent if non-zero */ + /* start child thread */ + "lr %%r2, %7\n\t" /* set first parameter to void *arg */ + "ahi %%r15, -96\n\t" /* make room on the stack for the save area */ + "xc 0(4,%%r15), 0(%%r15)\n\t" + "basr %%r14, %4\n\t" /* jump to fn */ + "svc %3\n" /* invoke exit syscall */ + "1:\n" + #else + /* arg already in r0 */ + "ltgr %4, %4\n\t" /* check fn, which is already in r1 */ + "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ + "ltgr %5, %5\n\t" /* check child_stack, which is already in r2 */ + "jz 1f\n\t" /* NULL stack pointer, return -EINVAL */ + /* flags already in r3 */ + /* parent_tidptr already in r4 */ + /* child_tidptr already in r5 */ + /* newtls already in r6 */ + "svc %2\n\t" /* invoke clone syscall */ + "ltgr %0, %%r2\n\t" /* load return code into __ret and test */ + "jnz 1f\n\t" /* return to parent if non-zero */ + /* start child thread */ + "lgr %%r2, %7\n\t" /* set first parameter to void *arg */ + "aghi %%r15, -160\n\t" /* make room on the stack for the save area */ + "xc 0(8,%%r15), 0(%%r15)\n\t" + "basr %%r14, %4\n\t" /* jump to fn */ + "svc %3\n" /* invoke exit syscall */ + "1:\n" + #endif + : "=r" (__ret) + : "0" (-EINVAL), "i" (__NR_clone), "i" (__NR_exit), + "d" (__fn), "d" (__cstack), "d" (__flags), "d" (__arg), + "d" (__ptidptr), "d" (__newtls), "d" (__ctidptr) + : "cc", "r14", "memory" + ); + } + LSS_RETURN(int, __ret); + } #endif #define __NR__exit __NR_exit #define __NR__gettid __NR_gettid @@ -2728,15 +3332,21 @@ struct kernel_statfs { LSS_INLINE _syscall2(int, clock_gettime, int, c, struct kernel_timespec*, t) LSS_INLINE _syscall1(int, dup, int, f) - LSS_INLINE _syscall2(int, dup2, int, s, - int, d) + #if !defined(__aarch64__) + // The dup2 syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall2(int, dup2, int, s, + int, d) + #endif LSS_INLINE _syscall3(int, execve, const char*, f, const char*const*,a,const char*const*, e) LSS_INLINE _syscall1(int, _exit, int, e) LSS_INLINE _syscall1(int, exit_group, int, e) LSS_INLINE _syscall3(int, fcntl, int, f, int, c, long, a) - LSS_INLINE _syscall0(pid_t, fork) + #if !defined(__aarch64__) + // The fork syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall0(pid_t, fork) + #endif LSS_INLINE _syscall2(int, fstat, int, f, struct kernel_stat*, b) LSS_INLINE _syscall2(int, fstatfs, int, f, @@ -2754,12 +3364,15 @@ struct kernel_statfs { int, o, int, v, struct kernel_timespec*, t) LSS_INLINE _syscall3(int, getdents, int, f, - struct kernel_dirent*, d, int, c) + struct kernel_dirent*, d, int, c) LSS_INLINE _syscall3(int, getdents64, int, f, struct kernel_dirent64*, d, int, c) LSS_INLINE _syscall0(gid_t, getegid) LSS_INLINE _syscall0(uid_t, geteuid) - LSS_INLINE _syscall0(pid_t, getpgrp) + #if !defined(__aarch64__) + // The getgprp syscall has been deprecated on aarch64. + LSS_INLINE _syscall0(pid_t, getpgrp) + #endif LSS_INLINE _syscall0(pid_t, getpid) LSS_INLINE _syscall0(pid_t, getppid) LSS_INLINE _syscall2(int, getpriority, int, a, @@ -2818,10 +3431,14 @@ struct kernel_statfs { LSS_INLINE _syscall5(void*, _mremap, void*, o, size_t, os, size_t, ns, unsigned long, f, void *, a) - LSS_INLINE _syscall3(int, open, const char*, p, - int, f, int, m) - LSS_INLINE _syscall3(int, poll, struct kernel_pollfd*, u, - unsigned int, n, int, t) + #if !defined(__aarch64__) + // The open and poll syscalls have been deprecated on aarch64. We polyfill + // them below. + LSS_INLINE _syscall3(int, open, const char*, p, + int, f, int, m) + LSS_INLINE _syscall3(int, poll, struct kernel_pollfd*, u, + unsigned int, n, int, t) + #endif LSS_INLINE _syscall5(int, prctl, int, option, unsigned long, arg2, unsigned long, arg3, @@ -2836,8 +3453,11 @@ struct kernel_statfs { #endif LSS_INLINE _syscall3(ssize_t, read, int, f, void *, b, size_t, c) - LSS_INLINE _syscall3(int, readlink, const char*, p, - char*, b, size_t, s) + #if !defined(__aarch64__) + // The readlink syscall has been deprecated on aarch64. We polyfill below. + LSS_INLINE _syscall3(int, readlink, const char*, p, + char*, b, size_t, s) + #endif LSS_INLINE _syscall4(int, rt_sigaction, int, s, const struct kernel_sigaction*, a, struct kernel_sigaction*, o, size_t, c) @@ -2872,17 +3492,23 @@ struct kernel_statfs { LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s, const stack_t*, o) #if defined(__NR_sigreturn) - LSS_INLINE _syscall1(int, sigreturn, unsigned long, u) + LSS_INLINE _syscall1(int, sigreturn, unsigned long, u) + #endif + #if !defined(__aarch64__) + // The stat syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall2(int, stat, const char*, f, + struct kernel_stat*, b) #endif - LSS_INLINE _syscall2(int, stat, const char*, f, - struct kernel_stat*, b) LSS_INLINE _syscall2(int, statfs, const char*, f, struct kernel_statfs*, b) LSS_INLINE _syscall3(int, tgkill, pid_t, p, pid_t, t, int, s) LSS_INLINE _syscall2(int, tkill, pid_t, p, int, s) - LSS_INLINE _syscall1(int, unlink, const char*, f) + #if !defined(__aarch64__) + // The unlink syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall1(int, unlink, const char*, f) + #endif LSS_INLINE _syscall3(ssize_t, write, int, f, const void *, b, size_t, c) LSS_INLINE _syscall3(ssize_t, writev, int, f, @@ -2908,14 +3534,77 @@ struct kernel_statfs { LSS_INLINE _syscall4(int, socketpair, int, d, int, t, int, p, int*, s) #endif - #if defined(__x86_64__) + #if defined(__NR_fadvise64) + #if defined(__x86_64__) + /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, loff_t len, + int advice) { + LSS_BODY(4, int, fadvise64, LSS_SYSCALL_ARG(fd), (uint64_t)(offset), + (uint64_t)(len), LSS_SYSCALL_ARG(advice)); + } + #else + LSS_INLINE _syscall4(int, fadvise64, + int, fd, loff_t, offset, loff_t, len, int, advice) + #endif + #elif defined(__i386__) + #define __NR__fadvise64_64 __NR_fadvise64_64 + LSS_INLINE _syscall6(int, _fadvise64_64, int, fd, + unsigned, offset_lo, unsigned, offset_hi, + unsigned, len_lo, unsigned, len_hi, + int, advice) + + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, + loff_t len, int advice) { + return LSS_NAME(_fadvise64_64)(fd, + (unsigned)offset, (unsigned)(offset >>32), + (unsigned)len, (unsigned)(len >> 32), + advice); + } + + #elif defined(__s390__) && !defined(__s390x__) + #define __NR__fadvise64_64 __NR_fadvise64_64 + struct kernel_fadvise64_64_args { + int fd; + long long offset; + long long len; + int advice; + }; + + LSS_INLINE _syscall1(int, _fadvise64_64, + struct kernel_fadvise64_64_args *args) + + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, + loff_t len, int advice) { + struct kernel_fadvise64_64_args args = { fd, offset, len, advice }; + return LSS_NAME(_fadvise64_64)(&args); + } + #endif + #if defined(__NR_fallocate) + #if defined(__x86_64__) /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ LSS_INLINE int LSS_NAME(fallocate)(int f, int mode, loff_t offset, loff_t len) { LSS_BODY(4, int, fallocate, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(mode), (uint64_t)(offset), (uint64_t)(len)); } + #elif defined(__i386__) || (defined(__s390__) && !defined(__s390x__)) + #define __NR__fallocate __NR_fallocate + LSS_INLINE _syscall6(int, _fallocate, int, fd, + int, mode, + unsigned, offset_lo, unsigned, offset_hi, + unsigned, len_lo, unsigned, len_hi) + LSS_INLINE int LSS_NAME(fallocate)(int fd, int mode, + loff_t offset, loff_t len) { + union { loff_t off; unsigned w[2]; } o = { offset }, l = { len }; + return LSS_NAME(_fallocate)(fd, mode, o.w[0], o.w[1], l.w[0], l.w[1]); + } + #else + LSS_INLINE _syscall4(int, fallocate, + int, f, int, mode, loff_t, offset, loff_t, len) + #endif + #endif + #if defined(__x86_64__) || defined(__s390x__) LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, gid_t *egid, gid_t *sgid) { @@ -2927,15 +3616,6 @@ struct kernel_statfs { uid_t *suid) { return LSS_NAME(getresuid)(ruid, euid, suid); } - - /* Need to make sure __off64_t isn't truncated to 32-bits under x32. */ - LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, - __off64_t o) { - LSS_BODY(6, void*, mmap, LSS_SYSCALL_ARG(s), LSS_SYSCALL_ARG(l), - LSS_SYSCALL_ARG(p), LSS_SYSCALL_ARG(f), - LSS_SYSCALL_ARG(d), (uint64_t)(o)); - } - LSS_INLINE _syscall4(int, newfstatat, int, d, const char *, p, struct kernel_stat*, b, int, f) @@ -2959,6 +3639,7 @@ struct kernel_statfs { LSS_INLINE int LSS_NAME(sigaction)(int signum, const struct kernel_sigaction *act, struct kernel_sigaction *oldact) { + #if defined(__x86_64__) /* On x86_64, the kernel requires us to always set our own * SA_RESTORER in order to be able to return from a signal handler. * This function must have a "magic" signature that the "gdb" @@ -2970,10 +3651,10 @@ struct kernel_statfs { a.sa_restorer = LSS_NAME(restore_rt)(); return LSS_NAME(rt_sigaction)(signum, &a, oldact, (KERNEL_NSIG+7)/8); - } else { + } else + #endif return LSS_NAME(rt_sigaction)(signum, act, oldact, (KERNEL_NSIG+7)/8); - } } LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { @@ -2991,8 +3672,9 @@ struct kernel_statfs { } #endif #if defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ - defined(__ARM_EABI__) || \ - (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) + defined(__ARM_EABI__) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) || \ + defined(__s390__) LSS_INLINE _syscall4(pid_t, wait4, pid_t, p, int*, s, int, o, struct kernel_rusage*, r) @@ -3001,11 +3683,14 @@ struct kernel_statfs { return LSS_NAME(wait4)(pid, status, options, 0); } #endif - #if defined(__i386__) || defined(__x86_64__) + #if defined(__NR_openat) LSS_INLINE _syscall4(int, openat, int, d, const char *, p, int, f, int, m) + #endif + #if defined(__NR_unlinkat) LSS_INLINE _syscall3(int, unlinkat, int, d, const char *, p, int, f) #endif - #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) + #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + (defined(__s390__) && !defined(__s390x__)) #define __NR__getresgid32 __NR_getresgid32 #define __NR__getresuid32 __NR_getresuid32 #define __NR__setfsgid32 __NR_setfsgid32 @@ -3159,9 +3844,11 @@ struct kernel_statfs { (1UL << ((signum - 1) % (8*sizeof(set->sig[0]))))); } } - #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ - defined(__ARM_EABI__) || \ - (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || defined(__PPC__) + #if defined(__i386__) || \ + defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + defined(__PPC__) || \ + (defined(__s390__) && !defined(__s390x__)) #define __NR__sigaction __NR_sigaction #define __NR__sigpending __NR_sigpending #define __NR__sigprocmask __NR_sigprocmask @@ -3172,13 +3859,23 @@ struct kernel_statfs { LSS_INLINE _syscall5(int, _llseek, uint, fd, unsigned long, hi, unsigned long, lo, loff_t *, res, uint, wh) -#if !defined(__ARM_EABI__) - LSS_INLINE _syscall1(void*, mmap, void*, a) -#endif - LSS_INLINE _syscall6(void*, mmap2, void*, s, +#if defined(__s390__) && !defined(__s390x__) + /* On s390, mmap2() arguments are passed in memory. */ + LSS_INLINE void* LSS_NAME(_mmap2)(void *s, size_t l, int p, int f, int d, + off_t o) { + unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, + (unsigned long) p, (unsigned long) f, + (unsigned long) d, (unsigned long) o }; + LSS_REG(2, buf); + LSS_BODY(void*, mmap2, "0"(__r2)); + } +#else + #define __NR__mmap2 __NR_mmap2 + LSS_INLINE _syscall6(void*, _mmap2, void*, s, size_t, l, int, p, int, f, int, d, - off_t, o) + off_t, o) +#endif LSS_INLINE _syscall3(int, _sigaction, int, s, const struct kernel_old_sigaction*, a, struct kernel_old_sigaction*, o) @@ -3300,6 +3997,43 @@ struct kernel_statfs { return rc; } #endif + #if defined(__i386__) || \ + defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + defined(__PPC__) || \ + (defined(__s390__) && !defined(__s390x__)) + /* On these architectures, implement mmap() with mmap2(). */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + if (o % 4096) { + LSS_ERRNO = EINVAL; + return (void *) -1; + } + return LSS_NAME(_mmap2)(s, l, p, f, d, (o / 4096)); + } + #elif defined(__s390x__) + /* On s390x, mmap() arguments are passed in memory. */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, + (unsigned long) p, (unsigned long) f, + (unsigned long) d, (unsigned long) o }; + LSS_REG(2, buf); + LSS_BODY(void*, mmap, "0"(__r2)); + } + #elif defined(__x86_64__) + /* Need to make sure __off64_t isn't truncated to 32-bits under x32. */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + LSS_BODY(6, void*, mmap, LSS_SYSCALL_ARG(s), LSS_SYSCALL_ARG(l), + LSS_SYSCALL_ARG(p), LSS_SYSCALL_ARG(f), + LSS_SYSCALL_ARG(d), (uint64_t)(o)); + } + #else + /* Remaining 64-bit architectures. */ + LSS_INLINE _syscall6(void*, mmap, void*, addr, size_t, length, int, prot, + int, flags, int, fd, int64_t, offset) + #endif #if defined(__PPC__) #undef LSS_SC_LOADARGS_0 #define LSS_SC_LOADARGS_0(dummy...) @@ -3389,7 +4123,7 @@ struct kernel_statfs { LSS_SC_BODY(4, int, 8, d, type, protocol, sv); } #endif - #if defined(__ARM_EABI__) + #if defined(__ARM_EABI__) || defined (__aarch64__) LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg, int, flags) LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*, @@ -3403,7 +4137,8 @@ struct kernel_statfs { int*, sv) #endif #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ - (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + defined(__s390__) #define __NR__socketcall __NR_socketcall LSS_INLINE _syscall2(int, _socketcall, int, c, va_list, a) @@ -3447,7 +4182,7 @@ struct kernel_statfs { return LSS_NAME(socketcall)(8, d, type, protocol, sv); } #endif - #if defined(__i386__) || defined(__PPC__) + #if defined(__NR_fstatat64) LSS_INLINE _syscall4(int, fstatat64, int, d, const char *, p, struct kernel_stat64 *, b, int, f) @@ -3466,7 +4201,7 @@ struct kernel_statfs { register unsigned long __v1 __asm__("$3"); register unsigned long __r7 __asm__("$7"); __asm__ __volatile__ ("syscall\n" - : "+r"(__v0), "=r"(__v1), "=r" (__r7) + : "=r"(__v0), "=r"(__v1), "=r" (__r7) : "0"(__v0) : "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25", "memory"); @@ -3480,13 +4215,15 @@ struct kernel_statfs { return 0; } } - #else + #elif !defined(__aarch64__) + // The unlink syscall has been deprecated on aarch64. We polyfill it below. LSS_INLINE _syscall1(int, pipe, int *, p) #endif /* TODO(csilvers): see if ppc can/should support this as well */ #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ - defined(__ARM_EABI__) || \ - (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) + defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) || \ + (defined(__s390__) && !defined(__s390x__)) #define __NR__statfs64 __NR_statfs64 #define __NR__fstatfs64 __NR_fstatfs64 LSS_INLINE _syscall3(int, _statfs64, const char*, p, @@ -3658,6 +4395,82 @@ struct kernel_statfs { #endif #endif +#if defined(__aarch64__) + LSS_INLINE _syscall3(int, dup3, int, s, int, d, int, f) + LSS_INLINE _syscall4(int, newfstatat, int, dirfd, const char *, pathname, + struct kernel_stat *, buf, int, flags) + LSS_INLINE _syscall2(int, pipe2, int *, pipefd, int, flags) + LSS_INLINE _syscall5(int, ppoll, struct kernel_pollfd *, u, + unsigned int, n, const struct kernel_timespec *, t, + const struct kernel_sigset_t *, sigmask, size_t, s) + LSS_INLINE _syscall4(int, readlinkat, int, d, const char *, p, char *, b, + size_t, s) +#endif + +/* + * Polyfills for deprecated syscalls. + */ + +#if defined(__aarch64__) + LSS_INLINE int LSS_NAME(dup2)(int s, int d) { + return LSS_NAME(dup3)(s, d, 0); + } + + LSS_INLINE int LSS_NAME(open)(const char *pathname, int flags, int mode) { + return LSS_NAME(openat)(AT_FDCWD, pathname, flags, mode); + } + + LSS_INLINE int LSS_NAME(unlink)(const char *pathname) { + return LSS_NAME(unlinkat)(AT_FDCWD, pathname, 0); + } + + LSS_INLINE int LSS_NAME(readlink)(const char *pathname, char *buffer, + size_t size) { + return LSS_NAME(readlinkat)(AT_FDCWD, pathname, buffer, size); + } + + LSS_INLINE pid_t LSS_NAME(pipe)(int *pipefd) { + return LSS_NAME(pipe2)(pipefd, 0); + } + + LSS_INLINE int LSS_NAME(poll)(struct kernel_pollfd *fds, unsigned int nfds, + int timeout) { + struct kernel_timespec timeout_ts; + struct kernel_timespec *timeout_ts_p = NULL; + + if (timeout >= 0) { + timeout_ts.tv_sec = timeout / 1000; + timeout_ts.tv_nsec = (timeout % 1000) * 1000000; + timeout_ts_p = &timeout_ts; + } + return LSS_NAME(ppoll)(fds, nfds, timeout_ts_p, NULL, 0); + } + + LSS_INLINE int LSS_NAME(stat)(const char *pathname, + struct kernel_stat *buf) { + return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); + } + + LSS_INLINE pid_t LSS_NAME(fork)(void) { + // No fork syscall on aarch64 - implement by means of the clone syscall. + // Note that this does not reset glibc's cached view of the PID/TID, so + // some glibc interfaces might go wrong in the forked subprocess. + int flags = SIGCHLD; + void *child_stack = NULL; + void *parent_tidptr = NULL; + void *newtls = NULL; + void *child_tidptr = NULL; + + LSS_REG(0, flags); + LSS_REG(1, child_stack); + LSS_REG(2, parent_tidptr); + LSS_REG(3, newtls); + LSS_REG(4, child_tidptr); + LSS_BODY(pid_t, clone, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), + "r"(__r4)); + } +#endif + #ifdef __ANDROID__ /* These restore the original values of these macros saved by the * corresponding #pragma push_macro near the top of this file. */