diff --git mlibc-clean/abis/linux/in.h mlibc-workdir/abis/linux/in.h index 87bc25f..d7370d0 100644 --- mlibc-clean/abis/linux/in.h +++ mlibc-workdir/abis/linux/in.h @@ -109,6 +109,9 @@ struct group_source_req { #define IPPORT_RESERVED 1024 +#define IP_MULTICAST_TTL 33 +#define IPV6_MULTICAST_HOPS 18 + #define IPPROTO_IP 0 #define IPPROTO_HOPOPTS 0 #define IPPROTO_ICMP 1 diff --git mlibc-clean/meson.build mlibc-workdir/meson.build index bb8928f..969145b 100644 --- mlibc-clean/meson.build +++ mlibc-workdir/meson.build @@ -256,6 +256,15 @@ elif host_machine.system() == 'dripos' rtld_include_dirs += include_directories('sysdeps/dripos/include') libc_include_dirs += include_directories('sysdeps/dripos/include') subdir('sysdeps/dripos') +elif host_machine.system() == 'astral' + disable_crypt_option = true + disable_iconv_option = true + disable_intl_option = true + rtld_include_dirs += include_directories('sysdeps/astral/include') + libc_include_dirs += include_directories('sysdeps/astral/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/astral') else error('No sysdeps defined for OS: ' + host_machine.system()) endif diff --git mlibc-clean/options/ansi/generic/environment.cpp mlibc-workdir/options/ansi/generic/environment.cpp index 5625592..36b42ee 100644 --- mlibc-clean/options/ansi/generic/environment.cpp +++ mlibc-workdir/options/ansi/generic/environment.cpp @@ -111,8 +111,10 @@ namespace mlibc { int putenv(char *string) { frg::string_view view{string}; size_t s = view.find_first('='); - if(s == size_t(-1)) - __ensure(!"Environment strings need to contain an equals sign"); + if(s == size_t(-1)) { + unsetenv(string); + return 0; + } update_vector(); assign_variable(view.sub_string(0, s), string, true); diff --git mlibc-clean/options/ansi/generic/string-stubs.cpp mlibc-workdir/options/ansi/generic/string-stubs.cpp index 8defd0e..d6cb65b 100644 --- mlibc-clean/options/ansi/generic/string-stubs.cpp +++ mlibc-workdir/options/ansi/generic/string-stubs.cpp @@ -406,7 +406,6 @@ char *strerror(int e) { case ENOPROTOOPT: s = "Protocol not available (ENOPROTOOPT)"; break; case ENOTEMPTY: s = "Directory not empty (ENOTEMPTY)"; break; case ENOTRECOVERABLE: s = "Sate not recoverable (ENOTRECOVERABLE)"; break; - case ENOTSUP: s = "Operation not supported (ENOTSUP)"; break; case ENOTTY: s = "Inappropriate ioctl for device (ENOTTY)"; break; case EOVERFLOW: s = "Value too large for defined datatype (EOVERFLOW)"; break; #if EOPNOTSUPP != ENOTSUP diff --git mlibc-clean/options/crypt/generic/crypt-stubs.cpp mlibc-workdir/options/crypt/generic/crypt-stubs.cpp index 65e0d23..95b060c 100644 --- mlibc-clean/options/crypt/generic/crypt-stubs.cpp +++ mlibc-workdir/options/crypt/generic/crypt-stubs.cpp @@ -1,7 +1,8 @@ #include #include +#include -char *crypt(const char *, const char *) { +char *crypt(const char *passwd, const char *) { __ensure(!"Not implemented"); __builtin_unreachable(); } diff --git mlibc-clean/options/glibc/generic/execinfo.cpp mlibc-workdir/options/glibc/generic/execinfo.cpp index 3474615..e034881 100644 --- mlibc-clean/options/glibc/generic/execinfo.cpp +++ mlibc-workdir/options/glibc/generic/execinfo.cpp @@ -1,9 +1,10 @@ #include #include +#include int backtrace(void **, int) { - __ensure(!"Not implemented"); - __builtin_unreachable(); + mlibc::infoLogger() << "libc: backtrace() is not implemented!\n" << frg::endlog; + return 0; } char **backtrace_symbols(void *const *, int) { diff --git mlibc-clean/options/posix/generic/dlfcn-stubs.cpp mlibc-workdir/options/posix/generic/dlfcn-stubs.cpp index fc34a3b..b1a95a9 100644 --- mlibc-clean/options/posix/generic/dlfcn-stubs.cpp +++ mlibc-workdir/options/posix/generic/dlfcn-stubs.cpp @@ -1,4 +1,4 @@ - +#define _GNU_SOURCE #include #include diff --git mlibc-clean/options/posix/generic/unistd-stubs.cpp mlibc-workdir/options/posix/generic/unistd-stubs.cpp index 444ad22..0f1b125 100644 --- mlibc-clean/options/posix/generic/unistd-stubs.cpp +++ mlibc-workdir/options/posix/generic/unistd-stubs.cpp @@ -484,8 +484,9 @@ int lockf(int fd, int op, off_t size) { } int nice(int) { - __ensure(!"Not implemented"); - __builtin_unreachable(); + return EPERM; + //__ensure(!"Not implemented"); + //__builtin_unreachable(); } long pathconf(const char *, int name) { @@ -1297,6 +1298,7 @@ void encrypt(char[64], int) { } #endif +#if 0 #if __MLIBC_BSD_OPTION void *sbrk(intptr_t increment) { if(increment) { @@ -1313,3 +1315,4 @@ void *sbrk(intptr_t increment) { return out; } #endif +#endif diff --git mlibc-clean/options/rtld/generic/main.cpp mlibc-workdir/options/rtld/generic/main.cpp index 0f5f1a3..c66ef93 100644 --- mlibc-clean/options/rtld/generic/main.cpp +++ mlibc-workdir/options/rtld/generic/main.cpp @@ -17,6 +17,8 @@ #include "elf.hpp" #include "linker.hpp" +#define _GNU_SOURCE + #if __MLIBC_POSIX_OPTION #include #endif diff --git mlibc-workdir/sysdeps/astral/crt-x86_64/crt0.S mlibc-workdir/sysdeps/astral/crt-x86_64/crt0.S new file mode 100644 index 0000000..0a0a4a0 --- /dev/null +++ mlibc-workdir/sysdeps/astral/crt-x86_64/crt0.S @@ -0,0 +1,7 @@ + +.section .text +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + diff --git mlibc-workdir/sysdeps/astral/generic/astral.cpp mlibc-workdir/sysdeps/astral/generic/astral.cpp new file mode 100644 index 0000000..f1edacc --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/astral.cpp @@ -0,0 +1,17 @@ +#include +#include + +#define ARCH_CTL_GSBASE 0 +#define ARCH_CTL_FSBASE 1 + +#ifndef MLIBC_BUILDING_RTLD + +int syscall_archctl(int func, void *arg) { + long ret; + long error = syscall(SYSCALL_ARCHCTL, &ret, func, (uint64_t)arg); + if (error) + errno = error; + return error ? -1 : ret; +} + +#endif diff --git mlibc-workdir/sysdeps/astral/generic/entry.cpp mlibc-workdir/sysdeps/astral/generic/entry.cpp new file mode 100644 index 0000000..e5b087a --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/entry.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} + diff --git mlibc-workdir/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp new file mode 100644 index 0000000..b73c420 --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp @@ -0,0 +1,1007 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MLIBC_BUILDING_RTLD +// (s)brk is emulated in the libc rather than being +// an actual system call. +#define SBRK_BUFFER_SIZE (1024 * 1024 * 16) +static void *sbrkbuffer; +static off_t sbrkoffset; + +extern "C" void *sbrk(intptr_t increment) { + // allocate the buffer if its the first time sbrk is called + if (sbrkbuffer == NULL) { + int e = mlibc::sys_vm_map(NULL, SBRK_BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0, &sbrkbuffer); + if (e) { + errno = e; + return NULL; + } + } + + if (increment == 0) + return sbrkbuffer; + + off_t newoffset = sbrkoffset + increment; + if (newoffset < 0) { + // offset goes below what we allocated, this is bad + errno = EINVAL; + return NULL; + } + + if (newoffset >= SBRK_BUFFER_SIZE) { + // new offset goes past what was allocated + errno = ENOMEM; + return NULL; + } + + void *ret = (void *)((uintptr_t)sbrkbuffer + increment); + sbrkoffset = newoffset; + return ret; +} +#endif + +namespace mlibc { + int sys_getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + // TODO unstub + mlibc::infoLogger() << "getsockopt: " << fd << " " << layer << " " << number << frg::endlog; + return 0; + } + + int sys_setgroups(size_t size, const gid_t *list) { + // TODO unstub + return 0; + } + + int sys_getgroups(size_t size, gid_t *list, int *ret) { + // TODO unstub + *ret = 0; + return 0; + } + + int sys_tgkill(int pid, int tid, int sig) { + long ret; + return syscall(SYSCALL_KILLTHREAD, &ret, pid, tid, sig); + } + + int sys_sigpending(sigset_t *set) { + long ret; + return syscall(SYSCALL_SIGPENDING, &ret, (uint64_t)set); + } + + int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal) { + long ret; + long err = syscall(SYSCALL_SIGTIMEDWAIT, &ret, (uint64_t)set, (uint64_t)info, (uint64_t)timeout); + *out_signal = ret; + return err; + } + + int sys_sigsuspend(const sigset_t *set) { + long ret; + return syscall(SYSCALL_SIGSUSPEND, &ret, (uint64_t)set); + } + + int sys_vm_protect(void *pointer, size_t size, int prot) { + long ret; + return syscall(SYSCALL_MPROTECT, &ret, (uint64_t)pointer, size, prot); + } + + int sys_setuid(uid_t id) { + long ret; + return syscall(SYSCALL_SETUID, &ret, id); + } + + int sys_setgid(gid_t id) { + long ret; + return syscall(SYSCALL_SETGID, &ret, id); + } + + int sys_seteuid(uid_t id) { + long ret; + return syscall(SYSCALL_SETEUID, &ret, id); + } + + int sys_setegid(gid_t id) { + long ret; + return syscall(SYSCALL_SETEGID, &ret, id); + } + + uid_t sys_getuid() { + uid_t r, e, s; + sys_getresuid(&r, &e, &s); + + return r; + } + + uid_t sys_geteuid() { + uid_t r, e, s; + sys_getresuid(&r, &e, &s); + + return e; + } + + gid_t sys_getgid() { + gid_t r, e, s; + sys_getresgid(&r, &e, &s); + + return r; + } + + gid_t sys_getegid() { + gid_t r, e, s; + sys_getresgid(&r, &e, &s); + + return e; + } + + int sys_setresuid(uid_t _ruid, uid_t _euid, uid_t _suid) { + long ret; + return syscall(SYSCALL_SETRESUID, &ret, _ruid, _euid, _suid); + } + + int sys_setresgid(gid_t _rgid, gid_t _egid, gid_t _sgid) { + long ret; + return syscall(SYSCALL_SETRESGID, &ret, _rgid, _egid, _sgid); + } + + int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + long ret; + return syscall(SYSCALL_GETRESUID, &ret, (uint64_t)ruid, (uint64_t)euid, (uint64_t)suid); + } + + int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + long ret; + return syscall(SYSCALL_GETRESGID, &ret, (uint64_t)rgid, (uint64_t)egid, (uint64_t)sgid); + } + + int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + long ret; + return syscall(SYSCALL_MKNODAT, &ret, dirfd, (uint64_t)path, mode, dev); + } + + int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { + return sys_mknodat(dirfd, path, S_IFIFO | mode, 0); + } + + int sys_rmdir(const char *path) { + return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); + } + + int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + long readc; + long error = syscall(SYSCALL_PREAD, &readc, fd, (uint64_t)buf, n, off); + *bytes_read = readc; + return error; + } + + int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + long writec; + long error = syscall(SYSCALL_PWRITE, &writec, fd, (uint64_t)buf, n, off); + *bytes_written = writec; + return error; + } + + #ifndef MLIBC_BUILDING_RTLD + + typedef struct { + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[1024]; + } dent_t; + + // TODO at least cache the results and invalidade on a chdir + int sys_getcwd(char *buffer, size_t size) { + // cwd implemented in userspace + // + // note: not thread safe if the other threads chroot + + char path[PATH_MAX]; + int curroffset = PATH_MAX - 1; + path[curroffset] = '\0'; + + + struct stat rootdir; // we will use dev and inode to find files and determine when the root dir has been hit + if (fstatat(-1, "/", &rootdir, 0)) + return errno; + + int dirfd = open(".", O_RDONLY); + if (dirfd < 0) + return errno; + + struct stat dirstat; + + if (fstat(dirfd, &dirstat)) { + close(dirfd); + return errno; + } + + if (dirstat.st_dev == rootdir.st_dev && dirstat.st_ino == rootdir.st_ino) { + // cwd is root dir + close(dirfd); + if (size < 2) + return ERANGE; + + buffer[0] = '/'; + buffer[1] = '\0'; + return 0; + } + + struct stat upstat; + do { + if (fstat(dirfd, &dirstat)) { + close(dirfd); + return errno; + } + + int upfd = openat(dirfd, "..", O_RDONLY); + + if (fstat(upfd, &upstat)) { + close(upfd); + close(dirfd); + return errno; + } + + close(dirfd); + + dent_t dent; + size_t readcount; + while (sys_read_entries(upfd, &dent, sizeof(dent), &readcount) == 0) { + if (readcount == 0) + break; + + if (strcmp(".", dent.d_name) == 0 || strcmp("..", dent.d_name) == 0) + continue; + + int tmp = openat(upfd, dent.d_name, O_RDONLY); + // could have been deleted, continue + if (tmp < 0) + continue; + + struct stat dentstat; + if (fstat(tmp, &dentstat)) { + close(tmp); + return errno; + } + + close(tmp); + + if (dentstat.st_dev == dirstat.st_dev && dentstat.st_ino == dirstat.st_ino) + break; + } + + // didn't find the directory + if (readcount == 0) { + close(upfd); + return ENOENT; + } + + dirfd = upfd; + + // add it to the path to be returned + size_t namelen = strlen(dent.d_name); + curroffset -= namelen + 1; // + 1 as we add the leading '/' as well + // passed the start of the buffer + if (curroffset <= 1) { + close (dirfd); + return ENAMETOOLONG; + } + + memcpy(&path[curroffset + 1], dent.d_name, namelen); + path[curroffset] = '/'; + } while (upstat.st_dev != rootdir.st_dev || upstat.st_ino != rootdir.st_ino); + + close(dirfd); + + if (size < PATH_MAX - curroffset) + return ERANGE; + + strcpy(buffer, &path[curroffset]); + + mlibc::infoLogger() << "mlibc: sys_getcwd returning value " << buffer << frg::endlog; + return 0; + } + + #endif + + int sys_pause() { + long ret; + return syscall(SYSCALL_PAUSE, &ret); + } + + int sys_chroot(const char *path) { + long ret; + return syscall(SYSCALL_CHROOT, &ret, (uint64_t)path); + } + + int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + long ret; + int len = max_addr_length; + long error = syscall(SYSCALL_GETPEERNAME, &ret, fd, (uint64_t)addr_ptr, (uint64_t)&len); + *actual_length = len; + return error; + } + + int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + long ret; + int len = max_addr_length; + long error = syscall(SYSCALL_GETSOCKNAME, &ret, fd, (uint64_t)addr_ptr, (uint64_t)&len); + *actual_length = len; + return error; + } + + int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + long ret = 0; + long err = syscall(SYSCALL_SOCKETPAIR, &ret, domain, type_and_flags, proto); + if (err) + return err; + + fds[0] = ret & 0xffffffff; + fds[1] = (ret >> 32) & 0xffffffff; + return err; + } + + int sys_getitimer(int which, struct itimerval *curr_value) { + long ret; + return syscall(SYSCALL_GETITIMER, &ret, which, (uint64_t)curr_value); + } + + int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + long ret; + return syscall(SYSCALL_SETITIMER, &ret, which, (uint64_t)new_value, (uint64_t)old_value); + } + + #ifndef MLIBC_BUILDING_RTLD + #define TTY_IOCTL_NAME 0x771101141113l + #define TTY_NAME_MAX 32 + #define TTY_PREFIX "/dev/" + + + int sys_ttyname(int fd, char * buffer, size_t size) { + size_t prefixlen = strlen(TTY_PREFIX); + if (size < TTY_NAME_MAX + prefixlen) { + mlibc::panicLogger() << "ttyname size too small" << frg::endlog; + __builtin_unreachable(); + } + + strcpy(buffer, TTY_PREFIX); + + int res; + return sys_ioctl(fd, TTY_IOCTL_NAME, (void *)(buffer + prefixlen), &res); + } + #endif + + int sys_fsync(int fd) { + long ret; + return syscall(SYSCALL_FSYNC, &ret, fd); + } + + int sys_fdatasync(int fd) { + // TODO proper datasync syscall + return sys_fsync(fd); + } + + + pid_t sys_getppid() { + long ret; + syscall(SYSCALL_GETPPID, &ret); + return ret; + } + + int sys_getsid(pid_t pid, pid_t *pgid) { + long ret; + long error = syscall(SYSCALL_GETSID, &ret, pid); + *pgid = ret; + return error; + } + + int sys_getpgid(pid_t pid, pid_t *pgid) { + long ret; + long error = syscall(SYSCALL_GETPGID, &ret, pid); + *pgid = ret; + return error; + } + + int sys_gethostname(char *buffer, size_t bufsize) { + long ret; + return syscall(SYSCALL_HOSTNAME, &ret, NULL, 0, (uint64_t)buffer, bufsize); + } + + int sys_sethostname(const char *buffer, size_t bufsize) { + long ret; + return syscall(SYSCALL_HOSTNAME, &ret, (uint64_t)buffer, bufsize, NULL, 0), NULL, 0; + } + + int sys_uname(struct utsname *buf) { + long ret; + return syscall(SYSCALL_UNAME, &ret, (uint64_t)buf); + } + + void sys_sync() { + long ret; + syscall(SYSCALL_SYNC, &ret); + } + + #ifndef MLIBC_BUILDING_RTLD + int sys_getentropy(void *buffer, size_t length) { + int fd; + int error = sys_open("/dev/urandom", O_RDONLY, 0, &fd); + if (error) + mlibc::panicLogger() << "/dev/urandom open error " << strerror(error) << frg::endlog; + + ssize_t bytes; + error = sys_read(fd, buffer, length, &bytes); + if (error) { + mlibc::infoLogger() << "/dev/urandom read error " << strerror(error) << frg::endlog; + return error; + } + + sys_close(fd); + return 0; + } + #endif + + int sys_kill(int pid, int signal) { + long ret; + return syscall(SYSCALL_KILL, &ret, pid, signal); + } + + int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + long ret; + return syscall(SYSCALL_SIGPROCMASK, &ret, how, (uint64_t)set, (uint64_t)retrieve); + } + + int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + long ret; + return syscall(SYSCALL_SIGALTSTACK, &ret, (uint64_t)ss, (uint64_t)oss); + } + + #ifndef MLIBC_BUILDING_RTLD + extern "C" void __mlibc_restorer(); + + int sys_sigaction(int sig, const struct sigaction *__restrict act, + struct sigaction *__restrict oldact) { + long ret; + + struct sigaction newact; + if (act) + memcpy(&newact, act, sizeof(struct sigaction)); + + if (act && (newact.sa_flags & SA_RESTORER) == 0) { + newact.sa_restorer = __mlibc_restorer; + newact.sa_flags |= SA_RESTORER; + } + + return syscall(SYSCALL_SIGACTION, &ret, sig, act ? (uint64_t)&newact : 0, (uint64_t)oldact); + } + + int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + int tmp; + if (int e = sys_ioctl(fd, TIOCGPTN, &index, &tmp); e) + return e; + + if ((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + + return 0; + } + #endif + + int sys_setpgid(pid_t pid, pid_t pgid) { + long ret; + return syscall(SYSCALL_SETPGID, &ret, pid, pgid); + } + + int sys_setsid(pid_t *out) { + long ret; + long error = syscall(SYSCALL_SETSID, &ret); + *out = ret; + return error; + } + + int sys_futex_tid() { + long ret; + syscall(SYSCALL_GETTID, &ret); + return ret; + } + + #ifndef MLIBC_BUILDING_RTLD + + [[noreturn]] void sys_thread_exit() { + syscall(SYSCALL_THREADEXIT, nullptr); + } + + extern "C" void __mlibc_thread_entry(); + + int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + long ret; + long err = syscall(SYSCALL_NEWTHREAD, &ret, (uintptr_t)__mlibc_thread_entry, (uintptr_t)stack); + *pid_out = ret; + return err; + } + + #endif + + int sys_listen(int fd, int backlog) { + long ret; + return syscall(SYSCALL_LISTEN, &ret, fd, backlog); + } + + int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + long ret; + long error = syscall(SYSCALL_ACCEPT, &ret, fd, (uint64_t)addr_ptr, (uint64_t)addr_length, flags); + *newfd = ret; + return error; + } + + int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + long ret; + return syscall(SYSCALL_CONNECT, &ret, fd, (uint64_t)addr_ptr, addr_length); + } + + int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length) { + long ret; + long err = syscall(SYSCALL_RECVMSG, &ret, fd, (uint64_t)hdr, flags); + *length = ret; + return err; + } + + int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + long ret; + return syscall(SYSCALL_SETSOCKOPT, &ret, fd, layer, number, (uint64_t)buffer, size); + } + + int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + long ret; + long err = syscall(SYSCALL_SENDMSG, &ret, fd, (uint64_t)hdr, flags); + *length = ret; + return err; + } + + int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + long ret; + return syscall(SYSCALL_BIND, &ret, fd, (uint64_t)addr_ptr, addr_length); + } + + int sys_socket(int family, int type, int protocol, int *fd) { + long ret; + long err = syscall(SYSCALL_SOCKET, &ret, family, type, protocol); + *fd = ret; + return err; + } + + int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + long ret; + return syscall(SYSCALL_RENAMEAT, &ret, olddirfd, (uint64_t)old_path, newdirfd, (uint64_t)new_path); + } + + int sys_rename(const char *path, const char *new_path) { + return sys_renameat(AT_FDCWD, path, AT_FDCWD, new_path); + } + + int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + long ret; + return syscall(SYSCALL_UTIMENSAT, &ret, dirfd, (uint64_t)pathname, (uint64_t)times, flags); + } + + int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { + long ret; + return syscall(SYSCALL_FCHOWNAT, &ret, dirfd, (uint64_t)pathname, owner, group, flags); + } + + int sys_mount(const char *source, const char *target, const char *fstype, unsigned long flags, const void *data) { + long ret; + return syscall(SYSCALL_MOUNT, &ret, (uint64_t)source, (uint64_t)target, (uint64_t)fstype, flags, (uint64_t)data); + } + + int sys_ftruncate(int fd, size_t size) { + long ret; + return syscall(SYSCALL_FTRUNCATE, &ret, fd, size); + } + + int sys_sleep(time_t *secs, long *nanos) { + struct timespec ts; + ts.tv_sec = *secs; + ts.tv_nsec = *nanos; + long ret; + long err = syscall(SYSCALL_NANOSLEEP, &ret, (uintptr_t)&ts, (uintptr_t)&ts); + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + return err; + } + + int sys_tcgetattr(int fd, struct termios *attr){ + int res; + return sys_ioctl(fd, TCGETS, (void *)attr, &res); + } + + int sys_tcsetattr(int fd, int act, const struct termios *attr){ + int res; + return sys_ioctl(fd, TCSETS, (void *)attr, &res); + } + + int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + long ret; + long error = syscall(SYSCALL_POLL, &ret, (uint64_t)fds, count, timeout); + *num_events = ret; + return error; + } + + int sys_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + long ret; + long error = syscall(SYSCALL_PPOLL, &ret, (uint64_t)fds, nfds, (uint64_t)timeout, (uint64_t)sigmask); + *num_events = ret; + return error; + } + +#ifndef MLIBC_BUILDING_RTLD + int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + pollfd *fds = (pollfd *)malloc(num_fds * sizeof(pollfd)); + + if(fds == NULL) + return ENOMEM; + + int actualcount = 0; + + for (int fd = 0; fd < num_fds; ++fd) { + short events = 0; + if (read_set && FD_ISSET(fd, read_set)) { + events |= POLLIN; + } + + if (write_set && FD_ISSET(fd, write_set)) { + events |= POLLOUT; + } + + if (except_set && FD_ISSET(fd, except_set)) { + events |= POLLPRI; + } + + if (events) { + fds[actualcount].fd = fd; + fds[actualcount].events = events; + fds[actualcount].revents = 0; + actualcount++; + } + } + + int num; + int err = sys_ppoll(fds, actualcount, timeout, sigmask, &num); + + if (err) { + free(fds); + return err; + } + + #define READ_SET_POLLSTUFF (POLLIN | POLLHUP | POLLERR) + #define WRITE_SET_POLLSTUFF (POLLOUT | POLLERR) + #define EXCEPT_SET_POLLSTUFF (POLLPRI) + + int returncount = 0; + for (int fd = 0; fd < actualcount; ++fd) { + int events = fds[fd].events; + if ((events & POLLIN) && (fds[fd].revents & READ_SET_POLLSTUFF) == 0) { + FD_CLR(fds[fd].fd, read_set); + events &= ~POLLIN; + } + + if ((events & POLLOUT) && (fds[fd].revents & WRITE_SET_POLLSTUFF) == 0) { + FD_CLR(fds[fd].fd, write_set); + events &= ~POLLOUT; + } + + if ((events & POLLPRI) && (fds[fd].revents & EXCEPT_SET_POLLSTUFF) == 0) { + FD_CLR(fds[fd].fd, except_set); + events &= ~POLLPRI; + } + + if (events) + returncount++; + } + *num_events = returncount; + free(fds); + return 0; + } +#endif + + int sys_umask(mode_t mode, mode_t *old) { + long ret; + long error = syscall(SYSCALL_UMASK, &ret, mode); + *old = ret; + return error; + } + + int sys_fchmod(int fd, mode_t mode) { + long ret; + return syscall(SYSCALL_FCHMOD, &ret, fd, mode); + } + + int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + long ret; + return syscall(SYSCALL_FCHMODAT, &ret, fd, (uint64_t)pathname, mode, flags); + } + + int sys_chmod(const char *pathname, mode_t mode) { + return sys_fchmodat(AT_FDCWD, pathname, mode, 0); + } + + int sys_readlinkat(int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length) { + long ret; + long error = syscall(SYSCALL_READLINKAT, &ret, dirfd, (uint64_t)path, (uint64_t)buffer, max_size); + *length = ret; + return error; + } + + int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length) { + return sys_readlinkat(AT_FDCWD, path, buffer, max_size, length); + } + + static int dolink(int oldfd, const char *oldpath, int newfd, const char *newpath, int flags, int type) { + long ret; + return syscall(SYSCALL_LINKAT, &ret, oldfd, (uint64_t)oldpath, newfd, (uint64_t)newpath, flags, type); + } + + int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + return dolink(olddirfd, old_path, newdirfd, new_path, flags, 0); + } + + int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); + } + + int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + return dolink(AT_FDCWD, target_path, dirfd, link_path, 0, 1); + } + + int sys_symlink(const char *target_path, const char *link_path) { + return sys_symlinkat(target_path, AT_FDCWD, link_path); + } + + int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + long ret; + return syscall(SYSCALL_MKDIRAT, &ret, dirfd, (uint64_t)path, mode); + } + + int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); + } + + int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + long ret; + long err = syscall(SYSCALL_IOCTL, &ret, fd, request, (uint64_t)arg); + *result = ret; + return err; + } + + int sys_unlinkat(int fd, const char *path, int flags) { + long ret; + return syscall(SYSCALL_UNLINKAT, &ret, fd, (uint64_t)path, flags); + } + + int sys_faccessat(int dirfd, const char *pathname, int mode, int flags){ + long ret; + return syscall(SYSCALL_FACCESSAT, &ret, dirfd, (uint64_t)pathname, mode, flags); + } + + int sys_access(const char *path, int mode){ + return sys_faccessat(AT_FDCWD, path, mode, 0); + } + + int sys_pipe(int *fds, int flags) { + long ret = 0; + long err = syscall(SYSCALL_PIPE2, &ret, flags); + if (err) + return err; + + fds[0] = ret & 0xffffffff; + fds[1] = (ret >> 32) & 0xffffffff; + return err; + } + + int sys_chdir(const char *path) { + long ret; + return syscall(SYSCALL_CHDIR, &ret, (uint64_t)path); + } + + int sys_fchdir(int fd) { + long ret; + return syscall(SYSCALL_FCHDIR, &ret, fd); + } + + int sys_fcntl(int fd, int request, va_list args, int *result) { + long arg = va_arg(args, uint64_t); + long ret; + long err = syscall(SYSCALL_FCNTL, &ret, fd, request, arg); + *result = ret; + return err; + } + + int sys_dup(int fd, int flags, int *newfd) { + long ret; + long err = syscall(SYSCALL_DUP, &ret, fd); + *newfd = ret; + return err; + } + + int sys_dup2(int fd, int flags, int newfd) { + long ret; + return syscall(SYSCALL_DUP2, &ret, fd, newfd); + } + + int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read) { + long ret; + long err = syscall(SYSCALL_GETDENTS, &ret, handle, (uint64_t)buffer, max_size); + if (err) + return err; + *bytes_read = ret; + return err; + } + + int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + long ret; + long err = syscall(SYSCALL_WAITPID, &ret, pid, (uint64_t)status, flags); + *ret_pid = ret; + return err; + } + + int sys_execve(const char *path, char *const argv[], char *const envp[]) { + long ret; + return syscall(SYSCALL_EXECVE, &ret, (uint64_t)path, (uint64_t)argv, (uint64_t)envp); + } + + int sys_fork(pid_t *pid) { + long ret = 0; + long error = syscall(SYSCALL_FORK, &ret); + *pid = ret; + return error; + } + + int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + long ret; + switch (fsfdt) { + case fsfd_target::path: + return syscall(SYSCALL_FSTATAT, &ret, AT_FDCWD, (uint64_t)path, (uint64_t)statbuf, flags); + case fsfd_target::fd: + return syscall(SYSCALL_FSTAT, &ret, fd, (uint64_t)statbuf); + case fsfd_target::fd_path: + return syscall(SYSCALL_FSTATAT, &ret, fd, (uint64_t)path, (uint64_t)statbuf, flags); + default: + mlibc::infoLogger() << "mlibc: stat: Unknown fsfd_target: " << (int)fsfdt << frg::endlog; + return ENOSYS; + } + } + + pid_t sys_getpid() { + long ret; + syscall(SYSCALL_GETPID, &ret); + return ret; + } + + void sys_libc_log(const char *message) { + long ret; + syscall(SYSCALL_PRINT, &ret, (uint64_t)message); + } + + [[noreturn]] void sys_libc_panic() { + sys_libc_log("mlibc: panic"); + sys_exit(1); + } + + [[noreturn]] void sys_exit(int status) { + syscall(SYSCALL_EXIT, NULL, status); + __builtin_unreachable(); + } + + int sys_tcb_set(void *pointer) { + long r; + return syscall(SYSCALL_ARCHCTL, &r, ARCH_CTL_FSBASE, (uint64_t)pointer); + } + + #define FUTEX_WAIT 0 + #define FUTEX_WAKE 1 + + int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + long ret; + return syscall(SYSCALL_FUTEX, &ret, (uint64_t)pointer, FUTEX_WAIT, expected, (uint64_t)time); + } + + int sys_futex_wake(int *pointer) { + long ret; + return syscall(SYSCALL_FUTEX, &ret, (uint64_t)pointer, FUTEX_WAKE, INT_MAX, NULL); + } + + int sys_anon_allocate(size_t size, void **pointer) { + size += 4096 - (size % 4096); + return sys_vm_map(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0, pointer); + } + int sys_anon_free(void *pointer, size_t size) { + size += 4096 - (size % 4096); + return sys_vm_unmap(pointer, size); + } + + int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + long ret; + long err = syscall(SYSCALL_OPENAT, &ret, dirfd, (uint64_t)path, flags, mode); + if (err) + return err; + *fd = ret; + return 0; + } + + int sys_open(const char *pathname, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, pathname, flags, mode, fd); + }; + + int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_DIRECTORY, 0, handle); + } + + int sys_read(int fd, void *buff, size_t count, ssize_t *bytes_read) { + long readc; + long error = syscall(SYSCALL_READ, &readc, fd, (uint64_t)buff, count); + *bytes_read = readc; + return error; + } + + int sys_write(int fd, const void *buff, size_t count, ssize_t *bytes_written) { + long writec; + long error = syscall(SYSCALL_WRITE, &writec, fd, (uint64_t)buff, count); + *bytes_written = writec; + return error; + } + + int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + long ret = 0; + long error = syscall(SYSCALL_SEEK, &ret, fd, offset, whence); + *new_offset = ret; + return error; + } + + int sys_close(int fd) { + long r; + return syscall(SYSCALL_CLOSE, &r, fd); + } + + int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + long ret; + long err = syscall(SYSCALL_MMAP, &ret, (uint64_t)hint, size, prot, flags, fd, offset); + *window = (void *)ret; + return err; + } + + int sys_vm_unmap(void *pointer, size_t size) { + long ret; + return syscall(SYSCALL_MUNMAP, &ret, (uintptr_t)pointer, size); + } + + int sys_isatty(int fd) { + long ret; + return syscall(SYSCALL_ISATTY, &ret, fd); + } + + int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec ts; + long ret; + int err = syscall(SYSCALL_CLOCKGET, &ret, clock, (uint64_t)&ts); + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + return err; + } + +} // namespace mlibc diff --git mlibc-workdir/sysdeps/astral/include/astral/archctl.h mlibc-workdir/sysdeps/astral/include/astral/archctl.h new file mode 100644 index 0000000..990eca0 --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/archctl.h @@ -0,0 +1,11 @@ +#ifndef _ASTRAL_SYSCALL_ARCHCTL_INCLUDE +#define _ASTRAL_SYSCALL_ARCHCTL_INCLUDE + +#include + +#define ARCH_CTL_GSBASE 0 +#define ARCH_CTL_FSBASE 1 + +int arch_ctl(int func, void *arg); + +#endif diff --git mlibc-workdir/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h new file mode 100644 index 0000000..4d603e8 --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h @@ -0,0 +1,115 @@ +#ifndef _SYSCALL_H_INCLUDE +#define _SYSCALL_H_INCLUDE + +#define SYSCALL_PRINT 0 +#define SYSCALL_MMAP 1 +#define SYSCALL_OPENAT 2 +#define SYSCALL_READ 3 +#define SYSCALL_SEEK 4 +#define SYSCALL_CLOSE 5 +#define SYSCALL_ARCHCTL 6 +#define SYSCALL_WRITE 7 +#define SYSCALL_GETPID 8 +#define SYSCALL_FSTAT 9 +#define SYSCALL_FSTATAT 10 +#define SYSCALL_FORK 11 +#define SYSCALL_EXECVE 12 +#define SYSCALL_EXIT 13 +#define SYSCALL_WAITPID 14 +#define SYSCALL_MUNMAP 15 +#define SYSCALL_GETDENTS 16 +#define SYSCALL_DUP 17 +#define SYSCALL_DUP2 18 +#define SYSCALL_DUP3 19 +#define SYSCALL_FCNTL 20 +#define SYSCALL_CHDIR 21 +#define SYSCALL_PIPE2 22 +#define SYSCALL_ISATTY 23 +#define SYSCALL_FACCESSAT 24 +#define SYSCALL_UNLINKAT 25 +#define SYSCALL_IOCTL 26 +#define SYSCALL_MKDIRAT 27 +#define SYSCALL_CLOCKGET 28 +#define SYSCALL_LINKAT 29 +#define SYSCALL_READLINKAT 30 +#define SYSCALL_FCHMOD 31 +#define SYSCALL_FCHMODAT 32 +#define SYSCALL_UMASK 33 +#define SYSCALL_POLL 34 +#define SYSCALL_NANOSLEEP 35 +#define SYSCALL_FTRUNCATE 36 +#define SYSCALL_MOUNT 37 +#define SYSCALL_FCHOWNAT 38 +#define SYSCALL_UTIMENSAT 39 +#define SYSCALL_RENAMEAT 40 +#define SYSCALL_SOCKET 41 +#define SYSCALL_BIND 42 +#define SYSCALL_SENDMSG 43 +#define SYSCALL_SETSOCKOPT 44 +#define SYSCALL_RECVMSG 45 +#define SYSCALL_LISTEN 46 +#define SYSCALL_CONNECT 47 +#define SYSCALL_ACCEPT 48 +#define SYSCALL_NEWTHREAD 49 +#define SYSCALL_THREADEXIT 50 +#define SYSCALL_FUTEX 51 +#define SYSCALL_GETTID 52 +#define SYSCALL_GETPPID 53 +#define SYSCALL_GETPGID 54 +#define SYSCALL_GETSID 55 +#define SYSCALL_SETSID 56 +#define SYSCALL_SETPGID 57 +#define SYSCALL_SIGACTION 58 +#define SYSCALL_SIGALTSTACK 59 +#define SYSCALL_SIGPROCMASK 60 +#define SYSCALL_KILL 61 +#define SYSCALL_SIGRETURN 62 +#define SYSCALL_UNAME 63 +#define SYSCALL_HOSTNAME 64 +#define SYSCALL_SYNC 65 +#define SYSCALL_FSYNC 66 +#define SYSCALL_FCHDIR 67 +#define SYSCALL_SETITIMER 68 +#define SYSCALL_GETITIMER 69 +#define SYSCALL_SOCKETPAIR 70 +#define SYSCALL_GETSOCKNAME 71 +#define SYSCALL_GETPEERNAME 72 +#define SYSCALL_CHROOT 73 +#define SYSCALL_PAUSE 74 +#define SYSCALL_PPOLL 75 +#define SYSCALL_PREAD 76 +#define SYSCALL_PWRITE 77 +#define SYSCALL_MKNODAT 78 +#define SYSCALL_GETRESUID 79 +#define SYSCALL_GETRESGID 80 +#define SYSCALL_SETRESUID 81 +#define SYSCALL_SETRESGID 82 +#define SYSCALL_MPROTECT 83 +#define SYSCALL_SETUID 84 +#define SYSCALL_SETEUID 85 +#define SYSCALL_SETGID 86 +#define SYSCALL_SETEGID 87 +#define SYSCALL_SIGSUSPEND 88 +#define SYSCALL_SIGTIMEDWAIT 89 +#define SYSCALL_SIGPENDING 90 +#define SYSCALL_KILLTHREAD 91 + +#include +#include + +static long syscall(long func, long* ret, uint64_t p1 = 0, uint64_t p2 = 0, uint64_t p3 = 0, uint64_t p4 = 0, uint64_t p5 = 0, uint64_t p6 = 0) { + volatile long err; + + register uint64_t r4 asm("r10") = p4; + register uint64_t r5 asm("r8") = p5; + register uint64_t r6 asm("r9") = p6; + + asm volatile("syscall" + : "=a"(*ret), "=d"(err) + : "a"(func), "D"(p1), "S"(p2), "d"(p3), "r"(r4), + "r"(r5), "r"(r6) + : "memory", "rcx", "r11"); + return err; +} + +#endif diff --git mlibc-workdir/sysdeps/astral/meson.build mlibc-workdir/sysdeps/astral/meson.build new file mode 100644 index 0000000..f7c5b72 --- /dev/null +++ mlibc-workdir/sysdeps/astral/meson.build @@ -0,0 +1,76 @@ + +rtld_sources += files( + 'generic/generic.cpp', + 'generic/astral.cpp', +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/astral.cpp', + 'generic/generic.cpp', + 'threading/x86_64-thread.cpp', + 'threading/x86_64-thread-entry.S', + 'signal/x86_64-restorer.S', +) + +if not no_headers + install_headers( + 'include/abi-bits/access.h', + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/vt.h', + subdir: 'abi-bits' + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) +endif diff --git mlibc-workdir/sysdeps/astral/signal/x86_64-restorer.S mlibc-workdir/sysdeps/astral/signal/x86_64-restorer.S new file mode 100644 index 0000000..dd33a36 --- /dev/null +++ mlibc-workdir/sysdeps/astral/signal/x86_64-restorer.S @@ -0,0 +1,6 @@ +.section .text +.global __mlibc_restorer +__mlibc_restorer: + sub $8, %rsp + mov $62, %rax + syscall diff --git mlibc-workdir/sysdeps/astral/threading/x86_64-thread-entry.S mlibc-workdir/sysdeps/astral/threading/x86_64-thread-entry.S new file mode 100644 index 0000000..4cb3ae0 --- /dev/null +++ mlibc-workdir/sysdeps/astral/threading/x86_64-thread-entry.S @@ -0,0 +1,7 @@ + .section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline diff --git mlibc-workdir/sysdeps/astral/threading/x86_64-thread.cpp mlibc-workdir/sysdeps/astral/threading/x86_64-thread.cpp new file mode 100644 index 0000000..3b893f0 --- /dev/null +++ mlibc-workdir/sysdeps/astral/threading/x86_64-thread.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + if (mlibc::sys_tcb_set(tcb)) { + __ensure(!"failed to set tcb for new thread"); + } + + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x400000 + +namespace mlibc { + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } + +}