From 7c307c072818133880a6a74bc21efff83aa419b2 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 13 Oct 2022 18:06:00 -0700 Subject: [PATCH 1/5] Support threads in the new crt1-command.c ctor check. Use an atomic compare-and-swap for checking whether constructors have been run, when threads are enabled. --- libc-bottom-half/crt/crt1-command.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libc-bottom-half/crt/crt1-command.c b/libc-bottom-half/crt/crt1-command.c index 6e2bcd942..6c9e7deab 100644 --- a/libc-bottom-half/crt/crt1-command.c +++ b/libc-bottom-half/crt/crt1-command.c @@ -3,17 +3,22 @@ extern void __wasm_call_ctors(void); extern int __main_void(void); extern void __wasm_call_dtors(void); -// Commands should only be called once per instance. This simple check ensures -// that the `_start` function isn't started more than once. -static volatile int started = 0; - __attribute__((export_name("_start"))) void _start(void) { - // Don't allow the program to be called multiple times. + // Commands should only be called once per instance. This simple check + // ensures that the `_start` function isn't started more than once. +#ifdef _REENTRANT + static volatile _Atomic int started = 0; + if (__sync_val_compare_and_swap(&started, 0, 1) != 0) { + __builtin_trap(); + } +#else + static volatile int started = 0; if (started != 0) { __builtin_trap(); } started = 1; +#endif // The linker synthesizes this to call constructors. __wasm_call_ctors(); From e3a04a84a9d4a3d561e537a73c8790cfd4395ad2 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 13 Oct 2022 18:35:04 -0700 Subject: [PATCH 2/5] Fix the type of `started`. --- libc-bottom-half/crt/crt1-command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc-bottom-half/crt/crt1-command.c b/libc-bottom-half/crt/crt1-command.c index 6c9e7deab..fd7833a07 100644 --- a/libc-bottom-half/crt/crt1-command.c +++ b/libc-bottom-half/crt/crt1-command.c @@ -8,7 +8,7 @@ void _start(void) { // Commands should only be called once per instance. This simple check // ensures that the `_start` function isn't started more than once. #ifdef _REENTRANT - static volatile _Atomic int started = 0; + static volatile int started = 0; if (__sync_val_compare_and_swap(&started, 0, 1) != 0) { __builtin_trap(); } From 15c74f9a62ae472678bb4db95aec5b11fe208096 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 14 Oct 2022 08:49:23 -0700 Subject: [PATCH 3/5] Factor out common code. --- libc-bottom-half/crt/crt1-command.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libc-bottom-half/crt/crt1-command.c b/libc-bottom-half/crt/crt1-command.c index fd7833a07..edc874880 100644 --- a/libc-bottom-half/crt/crt1-command.c +++ b/libc-bottom-half/crt/crt1-command.c @@ -7,13 +7,12 @@ __attribute__((export_name("_start"))) void _start(void) { // Commands should only be called once per instance. This simple check // ensures that the `_start` function isn't started more than once. -#ifdef _REENTRANT static volatile int started = 0; +#ifdef _REENTRANT if (__sync_val_compare_and_swap(&started, 0, 1) != 0) { __builtin_trap(); } #else - static volatile int started = 0; if (started != 0) { __builtin_trap(); } From cec75b47062ded266cb2405970b74c6af56586d5 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 14 Oct 2022 14:07:55 -0700 Subject: [PATCH 4/5] Use instead of __sync_ intrinsics. --- libc-bottom-half/crt/crt1-command.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libc-bottom-half/crt/crt1-command.c b/libc-bottom-half/crt/crt1-command.c index edc874880..4ea267b96 100644 --- a/libc-bottom-half/crt/crt1-command.c +++ b/libc-bottom-half/crt/crt1-command.c @@ -1,3 +1,6 @@ +#ifdef _REENTRANT +#include +#endif #include extern void __wasm_call_ctors(void); extern int __main_void(void); @@ -7,12 +10,14 @@ __attribute__((export_name("_start"))) void _start(void) { // Commands should only be called once per instance. This simple check // ensures that the `_start` function isn't started more than once. - static volatile int started = 0; #ifdef _REENTRANT - if (__sync_val_compare_and_swap(&started, 0, 1) != 0) { + static volatile _Atomic int started = 0; + int expected = 0; + if (!atomic_compare_exchange_strong(&started, &expected, 1)) { __builtin_trap(); } #else + static volatile int started = 0; if (started != 0) { __builtin_trap(); } From 69200f807e5729dad64f82b5c0e3eacd298a872e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 14 Oct 2022 14:50:28 -0700 Subject: [PATCH 5/5] Add a comment about `volatile`. --- libc-bottom-half/crt/crt1-command.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libc-bottom-half/crt/crt1-command.c b/libc-bottom-half/crt/crt1-command.c index 4ea267b96..48be79f7e 100644 --- a/libc-bottom-half/crt/crt1-command.c +++ b/libc-bottom-half/crt/crt1-command.c @@ -10,6 +10,11 @@ __attribute__((export_name("_start"))) void _start(void) { // Commands should only be called once per instance. This simple check // ensures that the `_start` function isn't started more than once. + // + // We use `volatile` here to prevent the store to `started` from being + // sunk past any subsequent code, and to prevent any compiler from + // optimizing based on the knowledge that `_start` is the program + // entrypoint. #ifdef _REENTRANT static volatile _Atomic int started = 0; int expected = 0;