Skip to content

Commit 35fee1d

Browse files
authored
Implement the critical part of wasi_thread_start in asm (#376)
* Implement the critical part of wasi_thread_start in asm It's fragile to set up the critical part of C environment in C. * Specify --target for asm files as well * wasi_thread_start: Move __tls_base initialization to asm as well
1 parent 082a15c commit 35fee1d

4 files changed

Lines changed: 60 additions & 19 deletions

File tree

Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ LIBC_TOP_HALF_MUSL_SOURCES += \
269269
thread/sem_timedwait.c \
270270
thread/sem_trywait.c \
271271
thread/sem_wait.c \
272+
thread/wasm32/wasi_thread_start.s \
272273
)
273274
endif
274275

@@ -287,12 +288,13 @@ LIBC_TOP_HALF_HEADERS_PRIVATE = $(LIBC_TOP_HALF_DIR)/headers/private
287288
LIBC_TOP_HALF_SOURCES = $(LIBC_TOP_HALF_DIR)/sources
288289
LIBC_TOP_HALF_ALL_SOURCES = \
289290
$(LIBC_TOP_HALF_MUSL_SOURCES) \
290-
$(sort $(shell find $(LIBC_TOP_HALF_SOURCES) -name \*.c))
291+
$(sort $(shell find $(LIBC_TOP_HALF_SOURCES) -name \*.[cs]))
291292

292293
# Add any extra flags
293294
CFLAGS = $(EXTRA_CFLAGS)
294295
# Set the target.
295296
CFLAGS += --target=$(TARGET_TRIPLE)
297+
ASMFLAGS += --target=$(TARGET_TRIPLE)
296298
# WebAssembly floating-point match doesn't trap.
297299
# TODO: Add -fno-signaling-nans when the compiler supports it.
298300
CFLAGS += -fno-trapping-math
@@ -339,10 +341,11 @@ CFLAGS += -isystem "$(SYSROOT_INC)"
339341
# These variables describe the locations of various files and directories in
340342
# the build tree.
341343
objs = $(patsubst $(CURDIR)/%.c,$(OBJDIR)/%.o,$(1))
344+
asmobjs = $(patsubst $(CURDIR)/%.s,$(OBJDIR)/%.o,$(1))
342345
DLMALLOC_OBJS = $(call objs,$(DLMALLOC_SOURCES))
343346
EMMALLOC_OBJS = $(call objs,$(EMMALLOC_SOURCES))
344347
LIBC_BOTTOM_HALF_ALL_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_ALL_SOURCES))
345-
LIBC_TOP_HALF_ALL_OBJS = $(call objs,$(LIBC_TOP_HALF_ALL_SOURCES))
348+
LIBC_TOP_HALF_ALL_OBJS = $(call asmobjs,$(call objs,$(LIBC_TOP_HALF_ALL_SOURCES)))
346349
ifeq ($(MALLOC_IMPL),dlmalloc)
347350
LIBC_OBJS += $(DLMALLOC_OBJS)
348351
else ifeq ($(MALLOC_IMPL),emmalloc)
@@ -517,6 +520,10 @@ $(OBJDIR)/%.o: $(CURDIR)/%.c include_dirs
517520
@mkdir -p "$(@D)"
518521
$(CC) $(CFLAGS) -MD -MP -o $@ -c $<
519522

523+
$(OBJDIR)/%.o: $(CURDIR)/%.s include_dirs
524+
@mkdir -p "$(@D)"
525+
$(CC) $(ASMFLAGS) -o $@ -c $<
526+
520527
-include $(shell find $(OBJDIR) -name \*.d)
521528

522529
$(DLMALLOC_OBJS): CFLAGS += \

expected/wasm32-wasi-pthread/defined-symbols.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ __do_cleanup_pop
4646
__do_cleanup_push
4747
__do_des
4848
__do_orphaned_stdio_locks
49+
__dummy_reference
4950
__duplocale
5051
__env_rm_add
5152
__errno_location
@@ -354,6 +355,7 @@ __wasi_sock_recv
354355
__wasi_sock_send
355356
__wasi_sock_shutdown
356357
__wasi_thread_spawn
358+
__wasi_thread_start_C
357359
__wasilibc_access
358360
__wasilibc_cwd
359361
__wasilibc_cwd_lock

libc-top-half/musl/src/thread/pthread_create.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,14 @@ struct start_args {
238238
volatile int control;
239239
unsigned long sig_mask[_NSIG/8/sizeof(long)];
240240
#else
241+
/*
242+
* Note: the offset of the "stack" and "tls_base" members
243+
* in this structure is hardcoded in wasi_thread_start.
244+
*/
245+
void *stack;
246+
void *tls_base;
241247
void *(*start_func)(void *);
242248
void *start_arg;
243-
void *tls_base;
244249
#endif
245250
};
246251

@@ -274,30 +279,25 @@ static int start_c11(void *p)
274279
return 0;
275280
}
276281
#else
277-
__attribute__((export_name("wasi_thread_start")))
278-
void wasi_thread_start(int tid, void *p)
282+
283+
/*
284+
* We want to ensure wasi_thread_start is linked whenever
285+
* pthread_create is used. The following reference is to ensure that.
286+
* Otherwise, the linker doesn't notice the dependency because
287+
* wasi_thread_start is used indirectly via a wasm export.
288+
*/
289+
void wasi_thread_start(int tid, void *p);
290+
hidden void *__dummy_reference = wasi_thread_start;
291+
292+
hidden void __wasi_thread_start_C(int tid, void *p)
279293
{
280-
/*
281-
* Note: it's fragile to implement wasi_thread_start in C.
282-
* On entry, we don't even have C stack (__stack_pointer)
283-
* set up. Be careful when modifying this function.
284-
*/
285294
struct start_args *args = p;
286-
__asm__(".globaltype __tls_base, i32\n"
287-
"local.get %0\n"
288-
"global.set __tls_base\n"
289-
:: "r"(args->tls_base));
290295
pthread_t self = __pthread_self();
291296
// Set the thread ID (TID) on the pthread structure. The TID is stored
292297
// atomically since it is also stored by the parent thread; this way,
293298
// whichever thread (parent or child) reaches this point first can proceed
294299
// without waiting.
295300
atomic_store((atomic_int *) &(self->tid), tid);
296-
// Set the stack pointer.
297-
__asm__(".globaltype __stack_pointer, i32\n"
298-
"local.get %0\n"
299-
"global.set __stack_pointer\n"
300-
:: "r"(self->stack));
301301
// Execute the user's start function.
302302
__pthread_exit(args->start_func(args->start_arg));
303303
}
@@ -501,6 +501,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
501501
/* Correct the stack size */
502502
new->stack_size = stack - stack_limit;
503503

504+
args->stack = new->stack; /* just for convenience of asm trampoline */
504505
args->start_func = entry;
505506
args->start_arg = arg;
506507
args->tls_base = (void*)new_tls_base;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.text
2+
3+
.export_name wasi_thread_start, wasi_thread_start
4+
5+
.globaltype __stack_pointer, i32
6+
.globaltype __tls_base, i32
7+
.functype __wasi_thread_start_C (i32, i32) -> ()
8+
9+
.hidden wasi_thread_start
10+
.globl wasi_thread_start
11+
.type wasi_thread_start,@function
12+
13+
wasi_thread_start:
14+
.functype wasi_thread_start (i32, i32) -> ()
15+
16+
# Set up the minimum C environment.
17+
# Note: offsetof(start_arg, stack) == 0
18+
local.get 1 # start_arg
19+
i32.load 0 # stack
20+
global.set __stack_pointer
21+
22+
local.get 1 # start_arg
23+
i32.load 4 # tls_base
24+
global.set __tls_base
25+
26+
# Make the C function do the rest of work.
27+
local.get 0 # tid
28+
local.get 1 # start_arg
29+
call __wasi_thread_start_C
30+
31+
end_function

0 commit comments

Comments
 (0)