From dffee606cfbb1b388c0f44e222b6ab484e08d7cd Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 15 Nov 2023 20:56:58 -0800 Subject: [PATCH] Run host compiler to create dlopen helper --- Makefile | 6 +- libc/dlopen/.dlopen.aarch64.glibc.elf | Bin 6008 -> 0 bytes libc/dlopen/.dlopen.x86_64.freebsd.elf | Bin 5824 -> 0 bytes libc/dlopen/.dlopen.x86_64.glibc.elf | Bin 6064 -> 0 bytes libc/dlopen/.dlopen.x86_64.musl.elf | Bin 5808 -> 0 bytes libc/dlopen/dlopen.c | 436 +++++++++++++++++-------- libc/dlopen/dlopen.mk | 12 +- libc/dlopen/misc/helper.c | 10 - 8 files changed, 310 insertions(+), 154 deletions(-) delete mode 100755 libc/dlopen/.dlopen.aarch64.glibc.elf delete mode 100755 libc/dlopen/.dlopen.x86_64.freebsd.elf delete mode 100755 libc/dlopen/.dlopen.x86_64.glibc.elf delete mode 100755 libc/dlopen/.dlopen.x86_64.musl.elf delete mode 100644 libc/dlopen/misc/helper.c diff --git a/Makefile b/Makefile index 602a08272..e1c8ff522 100644 --- a/Makefile +++ b/Makefile @@ -184,7 +184,6 @@ include libc/calls/calls.mk #─┐ include libc/irq/irq.mk # ├──SYSTEMS RUNTIME include third_party/nsync/nsync.mk # │ You can issue system calls include libc/runtime/runtime.mk # │ -include libc/dlopen/dlopen.mk # │ include third_party/double-conversion/dc.mk # │ include libc/crt/crt.mk # │ include third_party/dlmalloc/dlmalloc.mk #─┘ @@ -192,8 +191,9 @@ include libc/mem/mem.mk #─┐ include third_party/gdtoa/gdtoa.mk # ├──DYNAMIC RUNTIME include third_party/nsync/mem/mem.mk # │ You can now use stdio include libc/proc/proc.mk # │ You can now use threads -include libc/thread/thread.mk # │ You can now use processes -include tool/hello/hello.mk # │ You can finally call malloc() +include libc/dlopen/dlopen.mk # │ You can now use processes +include libc/thread/thread.mk # │ You can finally call malloc() +include tool/hello/hello.mk # │ include third_party/zlib/zlib.mk # │ include libc/stdio/stdio.mk # │ include libc/time/time.mk # │ diff --git a/libc/dlopen/.dlopen.aarch64.glibc.elf b/libc/dlopen/.dlopen.aarch64.glibc.elf deleted file mode 100755 index 33e28454db135cb76e632eb28157867416ebb0f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6008 zcmeHLU2I&%6`tL7o6v;Blpq3ucw%GiT<`oSAzcziZFk@mS0-CCrP)N|%I8S}Xc4qlPhQ(`PQh^D491 zd>?cha$2jSxTH-J*Q#CuD0Y4Ekci?I)g#hF!S89^O3=P8WQismjeUx*`!5aa_g@;e zNPJ8Em{+8oh+3*xu`&>h1PQaw9A!g} zMZ#QxPA_gzq#rsuEN)(fKMp=gB?o1@bUHGN-6*Wo{#~o^FM&@YN7Dl!oGsX@-igvm z?ccBp{~Gutax~orVx@LWzFY``YG6DsH|l!_OBKIddZYjm3n1s!>V8o7hW%0ninSxd zcvcS=M97t^wSw`p)u0Y#=;aQ1x#A)3pkFFqL=27iLEcDfvV3keD=(_dp4|hxyd9~Y z+YF00_Zn~a;JseH5EO<=wR#~Kymwc*S}6?r*|K;zG+eEyhhC_a>7hv9X-7~_Ug&Ggm-2U+=MX` zm%Wl{v@iT(G8ykUBf8AC?lkJ+ci1{B{{?cVBmWKZfFr*NIqS%8Lw?ec&pGp-X8TdJA{RSdFe>w-h ztk35%4Ieg(iP-Z7?@{cc`rC|oz4QFz@AR*K;`iIm_aA!|`cJ}-f%BP0*4oBfwlc2e zu~+Px`D~qOAhygLIFY_R9W%F}-3jyWOanM;`@lT?7QW9TC(Zc211HSwpRG$bmd8%p zb;db*AL9wz4c8*qVQfp{XL9F|J+%Kqv-wxxJa7=$)oeDgX3c)!qrfR3)}c8EoCQj1 z55dG9*=O2Dx5l=t@35SlvyY;kUa9Y2vsLtNL_P(sTR0@)(#Y?E+qiQOpjjnH9CkpBLFd~~_ld7jd7sMfkS@VjWO@>eVJ{&0=TtpCr2W>u)E zcv!(ZK~gsc&&E?)&$IqxZHH%@>>o+ENnezB78iNGY3;n?CPkjLSE@Xt9g`nb$LM#T zP882v_Pm~PimmU_FLAte zZ={~yvnZ~HnO(bnn(VqiJ5s5SBzt;Ny{Yc)JtJ1^d2GjyRCn)>l{O|-E7s~k-Orj- zse)_yVUwy<>xI-%Wh9jyDdB=&$}81BuzP#mA2PPC=+}xSl|NFE4+)F)Agp<~5Y$T5 z%0+^Qx}Z?@MNvzK%XR6pglD}liYGo-N+wk(dItl4xZoA@u%Q%cdVUc2M?y`O(V#zE z%AvO^+Q|EL-=wm&nn~rV!^4G2eYH9II=t*BS=wBWeOe%Lf3r=-3(A+HAWMh#(fV;M$LBL&PK%6{GfYUjG++hW$@zfyns7IKzF)X74~j=79F6v_LHCfF(Rg zY@t2(|J};do^g!GxCJ$vqVu;Gti%M`GY$|LU+6#eh!4VEVhm-*8RC6mxAwjyI`m&@ z^BWXoPHE4$M`YY%|Fq}$Wf6+~0J0>;Q6l56*h}n<+CK(P=0wA9>wgK)ANB(ko1*Xk z2w2xX8oy@Ljv#k2H$4TxwP#!+J{@^sY1bI#-$m?sPPQg`*vKoQ|2+4L;uO+U2(2gWiEpCDwda2eekgRcEW-lrNWY7MaO}TJ q&#^9bFsdI}PUfGm6|NiEO|<`sOQKAB7umO~`YY{!!6hAg(*Fksy>tBl diff --git a/libc/dlopen/.dlopen.x86_64.freebsd.elf b/libc/dlopen/.dlopen.x86_64.freebsd.elf deleted file mode 100755 index 49ae72332b6caafb7475b39c1deb77d17b22f3aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5824 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\n\ +#include \n\ +#include \n\ +int main(int argc, char *argv[]) {\n\ + char *ep;\n\ + long addr;\n\ + if (argc != 2) {\n\ + fprintf(stderr, \"%s: not intended to be run directly\\n\", argv[0]);\n\ + return 1;\n\ + }\n\ + addr = strtol(argv[1], &ep, 10);\n\ + if (*ep) {\n\ + fprintf(stderr, \"%s: invalid function address\\n\", argv[0]);\n\ + return 2;\n\ + }\n\ + return ((int (*)(void *))addr)((void *[]){\n\ + dlopen,\n\ + dlsym,\n\ + dlclose,\n\ + dlerror,\n\ + });\n\ +}\n" + struct Loaded { char *base; char *entry; @@ -103,25 +128,51 @@ long __sysv2nt14(); static _Thread_local char dlerror_buf[128]; +static const char *get_tmp_dir(void) { + const char *tmpdir; + if (!(tmpdir = getenv("TMPDIR")) || !*tmpdir) { + if (!(tmpdir = getenv("HOME")) || !*tmpdir) { + tmpdir = "."; + } + } + return tmpdir; +} + +static int is_file_newer_than(const char *path, const char *other) { + struct stat st1, st2; + if (stat(path, &st1)) { + return -1; + } + if (stat(other, &st2)) { + if (errno == ENOENT) { + return true; + } else { + return -1; + } + } + return timespec_cmp(st1.st_mtim, st2.st_mtim) > 0; +} + // on system five we sadly need this brutal trampoline // todo(jart): add tls trampoline to sigaction() handlers // todo(jart): morph binary to get tls from host c library static long foreign_tramp(long a, long b, long c, long d, long e, long func(long, long, long, long, long)) { long res; - sigset_t mask; - sigset_t block = -1; - struct CosmoTib *tib; - sys_sigprocmask(SIG_SETMASK, &block, &mask); - tib = __get_tls(); + BLOCK_SIGNALS; +#ifdef __x86_64__ + struct CosmoTib *tib = __get_tls(); __set_tls(foreign.tib); +#endif res = func(a, b, c, d, e); +#ifdef __x86_64__ __set_tls(tib); - sys_sigprocmask(SIG_SETMASK, &mask, 0); +#endif + ALLOW_SIGNALS; return res; } -static unsigned get_elf_prot(unsigned x) { +static unsigned elf2prot(unsigned x) { unsigned r = 0; if (x & PF_R) r += PROT_READ; if (x & PF_W) r += PROT_WRITE; @@ -145,55 +196,54 @@ static int get_host_elf_machine(void) { #endif } -static char *elf_map(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdr) { - uintptr_t maxva = 0; - uintptr_t minva = -1; +static char *elf_map(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdr, long pagesz, + char *interp_path, size_t interp_size) { + Elf64_Addr maxva = 0; + Elf64_Addr minva = -1; for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) { if (p->p_type != PT_LOAD) { continue; } if (p->p_vaddr < minva) { - minva = p->p_vaddr; + minva = p->p_vaddr & -pagesz; } if (p->p_vaddr + p->p_memsz > maxva) { maxva = p->p_vaddr + p->p_memsz; } } - minva = minva & -PAGE_SIZE; uint8_t *base = __sys_mmap(0, maxva - minva, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, 0); if (base == MAP_FAILED) { return MAP_FAILED; } - __sys_munmap(base, maxva - minva); - for (Elf64_Phdr *p = phdr; p < &phdr[ehdr->e_phnum]; p++) { + for (Elf64_Phdr *p = phdr; p < phdr + ehdr->e_phnum; p++) { if (p->p_type != PT_LOAD) { + if (p->p_type == PT_INTERP && interp_size && + (p->p_filesz >= interp_size - 1 || + pread(fd, interp_path, p->p_filesz, p->p_offset) != p->p_filesz)) { + return MAP_FAILED; + } continue; } - uintptr_t skew = p->p_vaddr & (PAGE_SIZE - 1); - uint8_t *start = base + p->p_vaddr - skew; - size_t mapsize = skew + p->p_memsz; - uint8_t *m = __sys_mmap(start, mapsize, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, 0); - if (m == MAP_FAILED) { + int prot = elf2prot(p->p_flags); + Elf64_Addr skew = p->p_vaddr & (pagesz - 1); + Elf64_Off off = p->p_offset - skew; + if (__sys_mmap(base + p->p_vaddr - skew, skew + p->p_filesz, prot, + MAP_FIXED | MAP_PRIVATE, fd, off, off) == MAP_FAILED) { return MAP_FAILED; } - ssize_t rr = pread(fd, m + skew, p->p_filesz, p->p_offset); - if (rr != (ssize_t)p->p_filesz) { - return MAP_FAILED; - } - if (sys_mprotect(m, mapsize, get_elf_prot(p->p_flags))) { + Elf64_Addr fend = (p->p_vaddr + p->p_filesz + (pagesz - 1)) & -pagesz; + Elf64_Addr mend = p->p_vaddr + p->p_memsz; + if (mend > fend && __sys_mmap(base + fend, mend - fend, prot, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, + 0, 0) == MAP_FAILED) { return MAP_FAILED; } } return (void *)base; } -static int elf_open(const char *file) { - return open(file, O_RDONLY | O_CLOEXEC); -} - static bool elf_slurp(struct Loaded *l, int fd, const char *file) { if (pread(fd, &l->eh, 64, 0) != 64) { return false; @@ -212,16 +262,18 @@ static bool elf_slurp(struct Loaded *l, int fd, const char *file) { return true; } -static bool elf_load(struct Loaded *l, const char *file) { +static bool elf_load(struct Loaded *l, const char *file, long pagesz, + char *interp_path, size_t interp_size) { int fd; - if ((fd = elf_open(file)) == -1) { + if ((fd = open(file, O_RDONLY | O_CLOEXEC)) == -1) { return false; } if (!elf_slurp(l, fd, file)) { close(fd); return false; } - if ((l->base = elf_map(fd, &l->eh, l->ph)) == MAP_FAILED) { + if ((l->base = elf_map(fd, &l->eh, l->ph, pagesz, interp_path, + interp_size)) == MAP_FAILED) { close(fd); return false; } @@ -230,44 +282,37 @@ static bool elf_load(struct Loaded *l, const char *file) { return true; } -static bool elf_interp(char *buf, size_t bsz, const char *file) { - int fd; - if ((fd = elf_open(file)) == -1) { - return false; - } - struct Loaded l; - if (!elf_slurp(&l, fd, file)) { - close(fd); - return false; - } - for (unsigned i = 0; i < l.eh.e_phnum; i++) { - if (l.ph[i].p_type == PT_INTERP) { - if (l.ph[i].p_filesz >= bsz || - pread(fd, buf, l.ph[i].p_filesz, l.ph[i].p_offset) != - l.ph[i].p_filesz) { - close(fd); - return false; - } - break; - } - } - close(fd); - return true; -} - static long *push_strs(long *sp, char **list, int count) { *--sp = 0; while (count) *--sp = (long)list[--count]; return sp; } -static void elf_exec(const char *file, const char *iinterp, int argc, - char **argv, char **envp) { - struct Loaded prog; - if (!elf_load(&prog, file)) return; +static wontreturn dontinstrument void foreign_helper(void **p) { + foreign.dlopen = p[0]; + foreign.dlsym = p[1]; + foreign.dlclose = p[2]; + foreign.dlerror = p[3]; + longjmp(foreign.jb, 1); +} +static dontinline void elf_exec(const char *file, char **envp) { + + // get microprocessor page size + long pagesz = getauxval(AT_PAGESZ); + + // load executable + struct Loaded prog; + char interp_path[256] = {0}; + if (!elf_load(&prog, file, pagesz, interp_path, sizeof(interp_path))) { + return; + } + + // load platform libc struct Loaded interp; - if (!elf_load(&interp, iinterp)) return; + if (!elf_load(&interp, interp_path, pagesz, 0, 0)) { + return; + } // count environment variables int envc = 0; @@ -283,15 +328,19 @@ static void elf_exec(const char *file, const char *iinterp, int argc, // we need just enough stack memory beneath it for initialization char *map; size_t stksize = 65536; - size_t stkalign = sizeof(char *) * 2; - size_t argsize = (argc + 1 + envc + 1 + auxc * 2 + 1) * sizeof(char *); - size_t mapsize = (stksize + argsize + (PAGE_SIZE - 1)) & -PAGE_SIZE; + size_t stkalign = 8 * 2; + size_t argsize = (1 + 2 + 1 + envc + 1 + auxc * 2 + 1 + 3) * 8; + size_t mapsize = (stksize + argsize + (pagesz - 1)) & -pagesz; size_t skew = (mapsize - argsize) & (stkalign - 1); map = __sys_mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, 0); if (map == MAP_FAILED) return; long *sp = (long *)(map + mapsize - skew); + // push argument string + char *address_argument = (char *)(sp -= 3); + FormatInt64(address_argument, (uintptr_t)foreign_helper); + // push auxiliary values *--sp = 0; unsigned long key, val; @@ -300,18 +349,26 @@ static void elf_exec(const char *file, const char *iinterp, int argc, if (key == AT_PHDR) val = (long)(prog.base + prog.eh.e_phoff); if (key == AT_PHENT) val = prog.eh.e_phentsize; if (key == AT_PHNUM) val = prog.eh.e_phnum; - if (key == AT_PAGESZ) val = PAGE_SIZE; + if (key == AT_PAGESZ) val = pagesz; if (key == AT_BASE) val = (long)interp.base; if (key == AT_FLAGS) val = 0; if (key == AT_ENTRY) val = (long)prog.entry; - if (key == AT_EXECFN) val = (long)argv[0]; + if (key == AT_EXECFN) val = (long)program_invocation_name; *--sp = val; *--sp = key; } - // push main() arguments + // push environment variable pointers sp = push_strs(sp, envp, envc); - sp = push_strs(sp, argv, argc); + envp = (char **)sp; + + // push argument pointers + *--sp = 0; + *--sp = (long)address_argument; + *--sp = (long)program_invocation_name; + char **argv = (char **)sp; + (void)argv; + int argc = 2; *--sp = argc; STRACE("running dlopen importer %p...", interp.entry); @@ -391,26 +448,74 @@ static void *foreign_alloc(size_t n) { return res; } +static uint8_t *movimm(uint8_t p[static 16], int reg, uint64_t val) { +#ifdef __x86_64__ + int rex; + rex = AMD_REXW; + if (reg & 8) { + rex |= AMD_REXB; + } + *p++ = rex; + *p++ = AMD_MOV_IMM | (reg & 7); + p = WRITE64LE(p, val); +#elif defined(__aarch64__) + // ARM immediate moves are encoded as: + // + // ┌64-bit + // │ + // │┌{sign,???,zero,non}-extending + // ││ + // ││ ┌short[4] index + // ││ │ + // ││ MOV │ immediate register + // │├┐┌─┴──┐├┐┌──────┴───────┐┌─┴─┐ + // 0bmxx100101iivvvvvvvvvvvvvvvvrrrrr + // + // Which allows 16 bits to be loaded into a register at a time, with + // tricks for clearing other parts of the register. For example, the + // sign-extending mode will set the higher order shorts to all ones, + // and it expects the immediate to be encoded using ones' complement + uint32_t op; + for (unsigned i = 0; i < 4; ++i) { + op = ARM_MOV_NEX; + op |= i << ARM_IDX_OFF; + op |= reg << ARM_REG_OFF; + op |= (val & 0xffff) << ARM_IMM_OFF; + val >>= 16; + *(uint32_t *)p = op; + p += sizeof(uint32_t); + } +#else +#error "unsupported architecture" +#endif + return p; +} + static void *foreign_thunk_sysv(void *func) { - unsigned char *code; - if (!(code = foreign_alloc(23))) return 0; + uint8_t *code, *p; +#ifdef __x86_64__ // movabs $func,%r9 - code[0] = 0x49; - code[1] = 0xb9; - WRITE64LE(code + 2, (uintptr_t)func); - // movabs $tramp,%r10 - code[10] = 0x49; - code[11] = 0xba; - WRITE64LE(code + 12, (uintptr_t)foreign_tramp); + // movabs $foreign_tramp,%r10 // jmp *%r10 - code[20] = 0x41; - code[21] = 0xff; - code[22] = 0xe2; + if (!(p = code = foreign_alloc(23))) return 0; // 10 + 10 + 3 = 23 + p = movimm(p, 9, (uintptr_t)func); + p = movimm(p, 10, (uintptr_t)foreign_tramp); + *p++ = 0x41; + *p++ = 0xff; + *p++ = 0xe2; +#elif defined(__aarch64__) + if (!(p = code = foreign_alloc(36))) return 0; // 16 + 16 + 4 = 36 + p = movimm(p, 5, (uintptr_t)func); + p = movimm(p, 10, (uintptr_t)foreign_tramp); + *(uint32_t *)p = 0xd63f0140; // blr x10 +#else +#error "unsupported architecture" +#endif return code; } static void *foreign_thunk_nt(void *func) { - unsigned char *code; + uint8_t *code; if (!(code = foreign_alloc(27))) return 0; // push %rbp code[0] = 0x55; @@ -433,52 +538,117 @@ static void *foreign_thunk_nt(void *func) { return code; } -static wontreturn dontinstrument void foreign_helper(void **p) { - foreign.dlopen = foreign_thunk_sysv(p[0]); - foreign.dlsym = foreign_thunk_sysv(p[1]); - foreign.dlclose = foreign_thunk_sysv(p[2]); - foreign.dlerror = foreign_thunk_sysv(p[3]); - longjmp(foreign.jb, 1); +static dontinline bool foreign_compile(char exe[hasatleast PATH_MAX]) { + + // construct path + strlcpy(exe, get_tmp_dir(), PATH_MAX); + strlcat(exe, "/.cosmo/", PATH_MAX); + if (mkdir(exe, 0755) && errno != EEXIST) { + return false; + } + strlcat(exe, "dlopen-helper", PATH_MAX); + + // skip build if helper exists and this program is older + switch (is_file_newer_than(GetProgramExecutableName(), exe)) { + case -1: + return false; + case false: + return true; + case true: + break; + default: + __builtin_unreachable(); + } + + // skip build if helper has same source code + int fd; + char src[PATH_MAX]; + char sauce[sizeof(HELPER)]; + strlcpy(src, exe, PATH_MAX); + strlcat(src, ".c", PATH_MAX); + if ((fd = open(src, O_RDONLY | O_CLOEXEC)) != -1) { + ssize_t got = pread(fd, sauce, sizeof(HELPER), 0); + close(fd); + if (got == sizeof(HELPER) - 1 && + !memcmp(sauce, HELPER, sizeof(HELPER) - 1)) { + return true; + } + } + + // create source file + char tmp[PATH_MAX]; + strlcpy(tmp, src, PATH_MAX); + strlcat(tmp, ".XXXXXX", PATH_MAX); + if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) { + return false; + } + if (write(fd, HELPER, sizeof(HELPER) - 1) != sizeof(HELPER) - 1) { + close(fd); + unlink(tmp); + return false; + } + if (close(fd)) { + unlink(tmp); + return false; + } + if (rename(tmp, src)) { + unlink(tmp); + return false; + } + + // create executable + strlcpy(tmp, exe, PATH_MAX); + strlcat(tmp, ".XXXXXX", PATH_MAX); + if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) { + return false; + } + int pid, ws; + char *args[] = {"cc", "-pie", "-fPIC", src, "-o", tmp, "-ldl", 0}; + errno_t err = posix_spawnp(&pid, args[0], NULL, NULL, args, environ); + if (err) { + unlink(tmp); + errno = err; + return false; + } + while (waitpid(pid, &ws, 0) == -1) { + if (errno != EINTR) { + unlink(tmp); + return false; + } + } + if (ws) { + unlink(tmp); + return false; + } + if (rename(tmp, exe)) { + unlink(tmp); + return false; + } + return true; } static bool foreign_setup(void) { - char interp[256] = {0}; - if (!elf_interp(interp, sizeof(interp), "/usr/bin/env")) { + // geth path of helper executable + char exe[PATH_MAX]; + if (!foreign_compile(exe)) { return false; } - const char *dlopen_helper = 0; + // load helper executable into address space #ifdef __x86_64__ - if (IsFreebsd()) { - dlopen_helper = "/zip/.dlopen.x86_64.freebsd.elf"; - } else if (IsLinux()) { - if (fileexists("/lib64/ld-linux-x86-64.so.2")) { - dlopen_helper = "/zip/.dlopen.x86_64.glibc.elf"; - } else { - dlopen_helper = "/zip/.dlopen.x86_64.musl.elf"; - } - } -#elif defined(__aarch64__) - if (0 && IsLinux()) { // TODO(jart): implement me - dlopen_helper = "/zip/.dlopen.aarch64.glibc.elf"; - } -#endif - if (!dlopen_helper) { - enosys(); - return false; // this platform isn't supported yet - } struct CosmoTib *cosmo_tib = __get_tls(); +#endif if (!setjmp(foreign.jb)) { - elf_exec(dlopen_helper, interp, 2, - (char *[]){ - program_invocation_name, - (char *)foreign_helper, - NULL, - }, - environ); + elf_exec(exe, environ); return false; // if elf_exec() returns, it failed } +#ifdef __x86_64__ foreign.tib = __get_tls(); __set_tls(cosmo_tib); +#endif + foreign.dlopen = foreign_thunk_sysv(foreign.dlopen); + foreign.dlsym = foreign_thunk_sysv(foreign.dlsym); + foreign.dlclose = foreign_thunk_sysv(foreign.dlclose); + foreign.dlerror = foreign_thunk_sysv(foreign.dlerror); foreign.is_supported = true; return true; } @@ -615,6 +785,7 @@ static void *dlopen_silicon(const char *path, int mode) { */ void *cosmo_dlopen(const char *path, int mode) { void *res; + BLOCK_SIGNALS; if (IsWindows()) { res = dlopen_nt(path, mode); } else if (IsXnuSilicon()) { @@ -628,6 +799,7 @@ void *cosmo_dlopen(const char *path, int mode) { } else { res = 0; } + ALLOW_SIGNALS; STRACE("dlopen(%#s, %d) → %p% m", path, mode, res); return res; } @@ -646,7 +818,9 @@ void *cosmo_dlsym(void *handle, const char *name) { if (IsWindows()) { func = dlsym_nt(handle, name); } else if (IsXnuSilicon()) { - func = __syslib->__dlsym(handle, name); + if ((func = __syslib->__dlsym(handle, name))) { + func = foreign_thunk_sysv(func); + } } else if (IsXnu()) { dlerror_set("dlopen() isn't supported on x86-64 MacOS"); func = 0; diff --git a/libc/dlopen/dlopen.mk b/libc/dlopen/dlopen.mk index a44d17246..c69421946 100644 --- a/libc/dlopen/dlopen.mk +++ b/libc/dlopen/dlopen.mk @@ -15,16 +15,9 @@ LIBC_DLOPEN_A_SRCS = \ $(LIBC_DLOPEN_A_SRCS_S) \ $(LIBC_DLOPEN_A_SRCS_C) -LIBC_DLOPEN_DSOS = \ - o/$(MODE)/libc/dlopen/.dlopen.aarch64.glibc.elf.zip.o \ - o/$(MODE)/libc/dlopen/.dlopen.x86_64.freebsd.elf.zip.o \ - o/$(MODE)/libc/dlopen/.dlopen.x86_64.glibc.elf.zip.o \ - o/$(MODE)/libc/dlopen/.dlopen.x86_64.musl.elf.zip.o - LIBC_DLOPEN_A_OBJS = \ $(LIBC_DLOPEN_A_SRCS_S:%.S=o/$(MODE)/%.o) \ - $(LIBC_DLOPEN_A_SRCS_C:%.c=o/$(MODE)/%.o) \ - $(LIBC_DLOPEN_DSOS) + $(LIBC_DLOPEN_A_SRCS_C:%.c=o/$(MODE)/%.o) LIBC_DLOPEN_A_CHECKS = \ $(LIBC_DLOPEN_A).pkg \ @@ -36,6 +29,7 @@ LIBC_DLOPEN_A_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_NEXGEN32E \ LIBC_NT_KERNEL32 \ + LIBC_PROC \ LIBC_RUNTIME \ LIBC_SYSV \ LIBC_SYSV_CALLS \ @@ -58,8 +52,6 @@ $(LIBC_DLOPEN_A_OBJS): private \ -Wframe-larger-than=4096 \ -Walloca-larger-than=4096 -$(LIBC_DLOPEN_DSOS): private ZIPOBJ_FLAGS += -B - LIBC_DLOPEN_LIBS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x))) LIBC_DLOPEN_SRCS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)_SRCS)) LIBC_DLOPEN_HDRS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/dlopen/misc/helper.c b/libc/dlopen/misc/helper.c deleted file mode 100644 index 3aa34fc60..000000000 --- a/libc/dlopen/misc/helper.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -int main(int argc, char *argv[]) { - return ((int (*)(void *))argv[1])((void *[]){ - dlopen, - dlsym, - dlclose, - dlerror, - }); -}