Skip to content

Commit 0e49bed

Browse files
committed
Support 40 cosmo_dlopen() function parameters
Our dynamic linking implementation is now able to support functions with dozens of parameters. In addition to having extra integral arguments you can now pass vector registers using intrinsic types. Lastly, you can now return multiple values, which is useful for functions returning structs.
1 parent a3deef7 commit 0e49bed

File tree

6 files changed

+550
-135
lines changed

6 files changed

+550
-135
lines changed

libc/dlopen/BUILD.mk

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ LIBC_DLOPEN = $(LIBC_DLOPEN_A_DEPS) $(LIBC_DLOPEN_A)
88
LIBC_DLOPEN_A = o/$(MODE)/libc/dlopen/dlopen.a
99
LIBC_DLOPEN_A_FILES := $(wildcard libc/dlopen/*)
1010
LIBC_DLOPEN_A_HDRS = $(filter %.h,$(LIBC_DLOPEN_A_FILES))
11-
LIBC_DLOPEN_A_SRCS = $(filter %.c,$(LIBC_DLOPEN_A_FILES))
12-
LIBC_DLOPEN_A_OBJS = $(LIBC_DLOPEN_A_SRCS:%.c=o/$(MODE)/%.o)
11+
LIBC_DLOPEN_A_SRCS_C = $(filter %.c,$(LIBC_DLOPEN_A_FILES))
12+
LIBC_DLOPEN_A_SRCS_S = $(filter %.S,$(LIBC_DLOPEN_A_FILES))
13+
LIBC_DLOPEN_A_SRCS = $(LIBC_DLOPEN_A_SRCS_C) $(LIBC_DLOPEN_A_SRCS_S)
14+
15+
LIBC_DLOPEN_A_OBJS = \
16+
$(LIBC_DLOPEN_A_SRCS_C:%.c=o/$(MODE)/%.o) \
17+
$(LIBC_DLOPEN_A_SRCS_S:%.S=o/$(MODE)/%.o)
1318

1419
LIBC_DLOPEN_A_CHECKS = \
1520
$(LIBC_DLOPEN_A).pkg \
@@ -45,6 +50,10 @@ $(LIBC_DLOPEN_A_OBJS): private \
4550
-Wframe-larger-than=4096 \
4651
-Walloca-larger-than=4096
4752

53+
# these assembly files are safe to build on aarch64
54+
o/$(MODE)/libc/dlopen/foreign_tramp.o: libc/dlopen/foreign_tramp.S
55+
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
56+
4857
LIBC_DLOPEN_LIBS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)))
4958
LIBC_DLOPEN_SRCS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)_SRCS))
5059
LIBC_DLOPEN_HDRS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)_HDRS))

libc/dlopen/dlopen.c

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ struct Loaded {
116116
Elf64_Phdr ph[25];
117117
};
118118

119-
static struct {
119+
struct {
120120
atomic_uint once;
121121
bool is_supported;
122122
struct CosmoTib *tib;
@@ -125,9 +125,10 @@ static struct {
125125
int (*dlclose)(void *);
126126
char *(*dlerror)(void);
127127
jmp_buf jb;
128-
} foreign;
128+
} __foreign;
129129

130130
long __sysv2nt14();
131+
long foreign_tramp();
131132

132133
static _Thread_local char dlerror_buf[128];
133134

@@ -156,28 +157,6 @@ static int is_file_newer_than(const char *path, const char *other) {
156157
return timespec_cmp(st1.st_mtim, st2.st_mtim) > 0;
157158
}
158159

159-
// on system five we sadly need this brutal trampoline
160-
// todo(jart): add tls trampoline to sigaction() handlers
161-
// todo(jart): morph binary to get tls from host c library
162-
static long foreign_tramp(long a, long b, long c, long d, long e,
163-
long func(long, long, long, long, long, double,
164-
double, double, double, double, double),
165-
double A, double B, double C, double D, double E,
166-
double F) {
167-
long res;
168-
BLOCK_SIGNALS;
169-
#ifdef __x86_64__
170-
struct CosmoTib *tib = __get_tls();
171-
__set_tls(foreign.tib);
172-
#endif
173-
res = func(a, b, c, d, e, A, B, C, D, E, F);
174-
#ifdef __x86_64__
175-
__set_tls(tib);
176-
#endif
177-
ALLOW_SIGNALS;
178-
return res;
179-
}
180-
181160
static unsigned elf2prot(unsigned x) {
182161
unsigned r = 0;
183162
if (x & PF_R) r += PROT_READ;
@@ -308,11 +287,11 @@ static long *push_strs(long *sp, char **list, int count) {
308287
}
309288

310289
static wontreturn dontinstrument void foreign_helper(void **p) {
311-
foreign.dlopen = p[0];
312-
foreign.dlsym = p[1];
313-
foreign.dlclose = p[2];
314-
foreign.dlerror = p[3];
315-
longjmp(foreign.jb, 1);
290+
__foreign.dlopen = p[0];
291+
__foreign.dlsym = p[1];
292+
__foreign.dlclose = p[2];
293+
__foreign.dlerror = p[3];
294+
longjmp(__foreign.jb, 1);
316295
}
317296

318297
static dontinline void elf_exec(const char *file, char **envp) {
@@ -515,19 +494,19 @@ static uint8_t *movimm(uint8_t p[static 16], int reg, uint64_t val) {
515494
static void *foreign_thunk_sysv(void *func) {
516495
uint8_t *code, *p;
517496
#ifdef __x86_64__
518-
// movabs $func,%r9
497+
// movabs $func,%rax
519498
// movabs $foreign_tramp,%r10
520499
// jmp *%r10
521500
if (!(p = code = foreign_alloc(23))) return 0; // 10 + 10 + 3 = 23
522-
p = movimm(p, 9, (uintptr_t)func);
501+
p = movimm(p, 0, (uintptr_t)func);
523502
p = movimm(p, 10, (uintptr_t)foreign_tramp);
524503
*p++ = 0x41;
525504
*p++ = 0xff;
526505
*p++ = 0xe2;
527506
#elif defined(__aarch64__)
528507
__jit_begin();
529508
if ((p = code = foreign_alloc(36))) {
530-
p = movimm(p, 5, (uintptr_t)func);
509+
p = movimm(p, 8, (uintptr_t)func);
531510
p = movimm(p, 10, (uintptr_t)foreign_tramp);
532511
*(uint32_t *)p = 0xd61f0140; // br x10
533512
__clear_cache(code, p + 4);
@@ -671,19 +650,19 @@ static bool foreign_setup(void) {
671650
#ifdef __x86_64__
672651
struct CosmoTib *cosmo_tib = __get_tls();
673652
#endif
674-
if (!setjmp(foreign.jb)) {
653+
if (!setjmp(__foreign.jb)) {
675654
elf_exec(exe, environ);
676655
return false; // if elf_exec() returns, it failed
677656
}
678657
#ifdef __x86_64__
679-
foreign.tib = __get_tls();
658+
__foreign.tib = __get_tls();
680659
__set_tls(cosmo_tib);
681660
#endif
682-
foreign.dlopen = foreign_thunk_sysv(foreign.dlopen);
683-
foreign.dlsym = foreign_thunk_sysv(foreign.dlsym);
684-
foreign.dlclose = foreign_thunk_sysv(foreign.dlclose);
685-
foreign.dlerror = foreign_thunk_sysv(foreign.dlerror);
686-
foreign.is_supported = true;
661+
__foreign.dlopen = foreign_thunk_sysv(__foreign.dlopen);
662+
__foreign.dlsym = foreign_thunk_sysv(__foreign.dlsym);
663+
__foreign.dlclose = foreign_thunk_sysv(__foreign.dlclose);
664+
__foreign.dlerror = foreign_thunk_sysv(__foreign.dlerror);
665+
__foreign.is_supported = true;
687666
return true;
688667
}
689668

@@ -693,8 +672,8 @@ static void foreign_once(void) {
693672

694673
static bool foreign_init(void) {
695674
bool res;
696-
cosmo_once(&foreign.once, foreign_once);
697-
if (!(res = foreign.is_supported)) {
675+
cosmo_once(&__foreign.once, foreign_once);
676+
if (!(res = __foreign.is_supported)) {
698677
dlerror_set("dlopen() isn't supported on this platform");
699678
}
700679
return res;
@@ -824,7 +803,7 @@ void *cosmo_dlopen(const char *path, int mode) {
824803
dlerror_set("dlopen() isn't supported on OpenBSD yet");
825804
res = 0;
826805
} else if (foreign_init()) {
827-
res = foreign.dlopen(path, mode);
806+
res = __foreign.dlopen(path, mode);
828807
} else {
829808
res = 0;
830809
}
@@ -854,7 +833,7 @@ void *cosmo_dlsym(void *handle, const char *name) {
854833
dlerror_set("dlopen() isn't supported on x86-64 MacOS");
855834
func = 0;
856835
} else if (foreign_init()) {
857-
if ((func = foreign.dlsym(handle, name))) {
836+
if ((func = __foreign.dlsym(handle, name))) {
858837
func = foreign_thunk_sysv(func);
859838
}
860839
} else {
@@ -880,7 +859,7 @@ int cosmo_dlclose(void *handle) {
880859
dlerror_set("dlopen() isn't supported on x86-64 MacOS");
881860
res = -1;
882861
} else if (foreign_init()) {
883-
res = foreign.dlclose(handle);
862+
res = __foreign.dlclose(handle);
884863
} else {
885864
res = -1;
886865
}
@@ -898,7 +877,7 @@ char *cosmo_dlerror(void) {
898877
} else if (IsWindows() || IsXnu()) {
899878
res = dlerror_buf;
900879
} else if (foreign_init()) {
901-
res = foreign.dlerror();
880+
res = __foreign.dlerror();
902881
res = dlerror_set(res);
903882
} else {
904883
res = dlerror_buf;

0 commit comments

Comments
 (0)