diff --git a/build.py b/build.py index ccbc9bee2..678a1fece 100755 --- a/build.py +++ b/build.py @@ -241,6 +241,7 @@ def clean_elf(): def run_ndk_build(flags): os.chdir("native") flags = "NDK_PROJECT_PATH=. NDK_APPLICATION_MK=src/Application.mk " + flags + cpu_count = 1 proc = system(f"{ndk_build} {flags} -j{cpu_count}") if proc.returncode != 0: error("Build binary failed!") diff --git a/native/src/crt0/Android.mk b/native/src/crt0/Android.mk index a3e4dd843..c64dba259 100644 --- a/native/src/crt0/Android.mk +++ b/native/src/crt0/Android.mk @@ -6,7 +6,7 @@ LOCAL_MODULE := crt0 # Manually link the compiler runtime library LOCAL_compiler_rt := $(shell $(TARGET_CC) -target $(LLVM_TRIPLE)$(TARGET_PLATFORM_LEVEL) --print-libgcc-file-name) -LOCAL_EXPORT_LDFLAGS := -static -nostartfiles -nodefaultlibs $(LOCAL_compiler_rt) +LOCAL_EXPORT_LDFLAGS := -static -nostartfiles -nodefaultlibs $(LOCAL_compiler_rt) -Wl,--error-limit=0 LOCAL_SRC_FILES := \ malloc.c \ diff --git a/native/src/crt0/malloc.c b/native/src/crt0/malloc.c index 14ff4c256..14d766157 100644 --- a/native/src/crt0/malloc.c +++ b/native/src/crt0/malloc.c @@ -5,5 +5,12 @@ #define HAVE_MORECORE 0 #define NO_MALLINFO 1 #define NO_MALLOC_STATS 1 +#define LACKS_TIME_H 1 +#define malloc_getpagesize 4096 + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-but-set-variable" #include "dlmalloc/malloc.c" + +#pragma clang diagnostic pop diff --git a/native/src/crt0/syscall.c b/native/src/crt0/syscall.c index 2d020fb62..2b8bafd84 100644 --- a/native/src/crt0/syscall.c +++ b/native/src/crt0/syscall.c @@ -2,19 +2,202 @@ #include "linux_syscall_support.h" +// Some missing declarations +static inline _syscall3(int, faccessat, int, f, const char *, p, int, m) +_syscall2(int, umount2, const char *, t, int, f) +_syscall4(int, renameat, int, o, const char *, op, int, n, const char *, np) +_syscall1(mode_t, umask, mode_t, mask) +_syscall1(int, chroot, const char *, path) +_syscall2(int, nanosleep, const struct kernel_timespec *, req, struct kernel_timespec *, rem) +_syscall5(int, mount, const char *, s, const char *, t, + const char *, fs, unsigned long, f, const void *, d) +_syscall3(int, symlinkat, const char *, t, int, fd, const char *, l) +_syscall3(int, mkdirat, int, dirfd, const char *, pathname, mode_t, mode) +_syscall4(ssize_t, sendfile, int, out_fd, int, in_fd, off_t *, offset, size_t, count) +_syscall5(int, linkat, int, o, const char *, op, int, n, const char *, np, int, f) +_syscall4(int, mknodat, int, dirfd, const char *, pathname, mode_t, mode, dev_t, dev) +_syscall2(int, fchmod, int, fd, mode_t, mode) +_syscall4(int, fchmodat, int, dirfd, const char *, pathname, mode_t, mode, int, flags) +_syscall5(int, fchownat, int, dirfd, const char *, p, uid_t, owner, gid_t, group, int, flags) +_syscall3(ssize_t, readv, int, fd, const struct kernel_iovec*, v, size_t, c) + +#define SYMBOL_ALIAS(from, to) \ +__asm__(".global " #from " \n " #from " = " #to) + #define EXPORT_SYMBOL(name) \ -__asm__(".global " #name " \n " #name " = sys_" #name) +SYMBOL_ALIAS(name, sys_##name) EXPORT_SYMBOL(_exit); EXPORT_SYMBOL(open); +EXPORT_SYMBOL(openat); EXPORT_SYMBOL(close); EXPORT_SYMBOL(read); +EXPORT_SYMBOL(symlink); EXPORT_SYMBOL(write); EXPORT_SYMBOL(writev); EXPORT_SYMBOL(unlink); EXPORT_SYMBOL(mmap); +EXPORT_SYMBOL(munmap); +EXPORT_SYMBOL(mremap); EXPORT_SYMBOL(readlink); EXPORT_SYMBOL(unlinkat); EXPORT_SYMBOL(getpid); EXPORT_SYMBOL(chdir); EXPORT_SYMBOL(umount2); +EXPORT_SYMBOL(readlinkat); +EXPORT_SYMBOL(renameat); +EXPORT_SYMBOL(umask); +EXPORT_SYMBOL(chroot); +EXPORT_SYMBOL(mount); +EXPORT_SYMBOL(symlinkat); +EXPORT_SYMBOL(stat); +EXPORT_SYMBOL(lstat); +EXPORT_SYMBOL(statfs); +EXPORT_SYMBOL(mkdirat); +EXPORT_SYMBOL(ioctl); +EXPORT_SYMBOL(fork); +EXPORT_SYMBOL(sendfile); +EXPORT_SYMBOL(ftruncate); +EXPORT_SYMBOL(linkat); +EXPORT_SYMBOL(mknodat); +EXPORT_SYMBOL(fchmod); +EXPORT_SYMBOL(fchmodat); +EXPORT_SYMBOL(fchownat); +EXPORT_SYMBOL(readv); +EXPORT_SYMBOL(lseek); + +SYMBOL_ALIAS(exit, _exit); + +#if defined(__LP64__) + +EXPORT_SYMBOL(fstat); +EXPORT_SYMBOL(newfstatat); +SYMBOL_ALIAS(fstatat, newfstatat); + +#else + +EXPORT_SYMBOL(fstat64); +EXPORT_SYMBOL(fstatat64); +SYMBOL_ALIAS(fstat, fstat64); +SYMBOL_ALIAS(fstatat, fstatat64); + +#endif + +int fchown(int fd, uid_t owner, gid_t group) { + return fchownat(fd, "", owner, group, AT_EMPTY_PATH); +} + +int lchown(const char* path, uid_t uid, gid_t gid) { + return fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW); +} + +int chown(const char* path, uid_t uid, gid_t gid) { + return fchownat(AT_FDCWD, path, uid, gid, 0); +} + +int chmod(const char* path, mode_t mode) { + return sys_fchmodat(AT_FDCWD, path, mode, 0); +} + +int mkfifoat(int fd, const char* path, mode_t mode) { + return sys_mknodat(fd, path, (mode & ~S_IFMT) | S_IFIFO, 0); +} + +int mkfifo(const char* path, mode_t mode) { + return mkfifoat(AT_FDCWD, path, mode); +} + +int mknod(const char* path, mode_t mode, dev_t dev) { + return sys_mknodat(AT_FDCWD, path, mode, dev); +} + +int link(const char *oldpath, const char *newpath) { + return sys_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0); +} + +int rmdir(const char *path) { + return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); +} + +int mkdir(const char *pathname, mode_t mode) { + return sys_mkdirat(AT_FDCWD, pathname, mode); +} + +int symlink(const char *target, const char *linkpath) { + return sys_symlinkat(target, AT_FDCWD, linkpath); +} + +int rename(const char *oldpath, const char *newpath) { + return sys_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath); +} + +int access(const char* path, int mode) { + return faccessat(AT_FDCWD, path, mode, 0); +} + +int remove(const char *path) { + int r = sys_unlinkat(AT_FDCWD, path, 0); + if (r < 0 && errno == EISDIR) { + r = sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); + } + return r; +} + +// Source: bionic/libc/bionic/abort.cpp +void abort() { + // Don't block SIGABRT to give any signal handler a chance; we ignore + // any errors -- X311J doesn't allow abort to return anyway. + struct kernel_sigset_t mask; + sys_sigfillset(&mask); + sys_sigdelset(&mask, SIGABRT); + + sys_sigprocmask(SIG_SETMASK, &mask, NULL); + sys_raise(SIGABRT); + + // If SIGABRT is ignored or it's caught and the handler returns, + // remove the SIGABRT signal handler and raise SIGABRT again. + struct kernel_sigaction sa = { .sa_handler_ = SIG_DFL, .sa_flags = SA_RESTART }; + sys_sigaction(SIGABRT, &sa, NULL); + + sys_sigprocmask(SIG_SETMASK, &mask, NULL); + sys_raise(SIGABRT); + + // If we get this far, just exit. + _exit(127); +} + +// Source: bionic/libc/bionic/usleep.cpp +int usleep(useconds_t us) { + struct kernel_timespec ts; + ts.tv_sec = us / 1000000; + ts.tv_nsec = (us % 1000000) * 1000; + return sys_nanosleep(&ts, NULL); +} + +// Source: bionic/libc/bionic/faccessat.cpp +int faccessat(int dirfd, const char *pathname, int mode, int flags) { + // "The mode specifies the accessibility check(s) to be performed, + // and is either the value F_OK, or a mask consisting of the + // bitwise OR of one or more of R_OK, W_OK, and X_OK." + if ((mode != F_OK) && ((mode & ~(R_OK | W_OK | X_OK)) != 0) && + ((mode & (R_OK | W_OK | X_OK)) == 0)) { + errno = EINVAL; + return -1; + } + + if (flags != 0) { + // We deliberately don't support AT_SYMLINK_NOFOLLOW, a glibc + // only feature which is error prone and dangerous. + // More details at http://permalink.gmane.org/gmane.linux.lib.musl.general/6952 + // + // AT_EACCESS isn't supported either. Android doesn't have setuid + // programs, and never runs code with euid!=uid. + // + // We could use faccessat2(2) from Linux 5.8, but since we don't want the + // first feature and don't need the second, we just reject such requests. + errno = EINVAL; + return -1; + } + + return sys_faccessat(dirfd, pathname, mode); +}