diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp
index 4e73f89e3fd9..c713a1c1e08d 100644
--- a/src/coreclr/nativeaot/Bootstrap/main.cpp
+++ b/src/coreclr/nativeaot/Bootstrap/main.cpp
@@ -94,7 +94,6 @@ static char& __unbox_z = __stop___unbox;
#endif // _MSC_VER
extern "C" bool RhInitialize();
-extern "C" void RhSetRuntimeInitializationCallback(int (*fPtr)());
extern "C" bool RhRegisterOSModule(void * pModule,
void * pvManagedCodeStartRange, uint32_t cbManagedCodeRange,
@@ -169,10 +168,28 @@ extern "C" int __managed__Main(int argc, char* argv[]);
#else
#define NATIVEAOT_ENTRYPOINT __managed__Startup
extern "C" void __managed__Startup();
+// _initialize is a function generated by the WASI SDK libc that calls the LLVM synthesized __wasm_call_ctors function for reactor components:
+// https://github.com/WebAssembly/wasi-libc/blob/9f51a7102085ec6a6ced5778f0864c9af9f50000/libc-bottom-half/crt/crt1-reactor.c#L7-L27
+// We define and call it for NATIVEAOT_DLL and TARGET_WASI to call all the global c++ static constructors. This ensures the runtime is initialized
+// when calling into WebAssembly Component Model components
+#if defined(NATIVEAOT_DLL) && defined(TARGET_WASI)
+extern "C" void _initialize();
+
+// CustomNativeMain programs are built using the same libbootstrapperdll as NATIVEAOT_DLL but wasi-libc will not provide an _initialize implementation,
+// so create a dummy one here and make it weak to allow wasi-libc to provide the real implementation for WASI reactor components.
+__attribute__((weak)) void _initialize()
+{
+}
+
+#endif // TARGET_WASI
#endif // !NATIVEAOT_DLL
static int InitializeRuntime()
{
+#if defined(NATIVEAOT_DLL) && defined(TARGET_WASI)
+ _initialize();
+#endif
+
if (!RhInitialize())
return -1;
@@ -200,6 +217,12 @@ static int InitializeRuntime()
return 0;
}
+#ifdef NATIVEAOT_DLL
+int (*g_RuntimeInitializationCallback)() = &InitializeRuntime;
+#else
+int (*g_RuntimeInitializationCallback)() = nullptr;
+#endif
+
#ifndef NATIVEAOT_DLL
#ifdef ENSURE_PRIMARY_STACK_SIZE
@@ -229,20 +252,3 @@ int main(int argc, char* argv[])
return __managed__Main(argc, argv);
}
#endif // !NATIVEAOT_DLL
-
-#ifdef NATIVEAOT_DLL
-static struct InitializeRuntimePointerHelper
-{
- InitializeRuntimePointerHelper()
- {
- RhSetRuntimeInitializationCallback(&InitializeRuntime);
- }
-} initializeRuntimePointerHelper;
-
-extern "C" void* NativeAOT_StaticInitialization();
-
-void* NativeAOT_StaticInitialization()
-{
- return &initializeRuntimePointerHelper;
-}
-#endif // NATIVEAOT_DLL
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets
index f88b9a2e0ac9..29d97fa8866c 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets
@@ -142,7 +142,6 @@ The .NET Foundation licenses this file to you under the MIT license.
-
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets
index 9512bf826c40..8c912da082d9 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets
@@ -87,7 +87,6 @@ The .NET Foundation licenses this file to you under the MIT license.
-
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
index 1f4bdbc95e52..389f7cef6408 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -508,7 +508,6 @@ The .NET Foundation licenses this file to you under the MIT license.
-
@@ -523,7 +522,7 @@ The .NET Foundation licenses this file to you under the MIT license.
-
+
diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp
index 4b0ed2f9c0f5..f0e925ce5853 100644
--- a/src/coreclr/nativeaot/Runtime/thread.cpp
+++ b/src/coreclr/nativeaot/Runtime/thread.cpp
@@ -33,7 +33,7 @@ EXTERN_C NATIVEAOT_API void* REDHAWK_CALLCONV RhpHandleAlloc(void* pObject, int
EXTERN_C NATIVEAOT_API void REDHAWK_CALLCONV RhHandleSet(void* handle, void* pObject);
EXTERN_C NATIVEAOT_API void REDHAWK_CALLCONV RhHandleFree(void* handle);
-static int (*g_RuntimeInitializationCallback)();
+extern int (*g_RuntimeInitializationCallback)();
static Thread* g_RuntimeInitializingThread;
#endif //!DACCESS_COMPILE
@@ -1173,11 +1173,6 @@ FORCEINLINE bool Thread::InlineTryFastReversePInvoke(ReversePInvokeFrame * pFram
return true;
}
-EXTERN_C void RhSetRuntimeInitializationCallback(int (*fPtr)())
-{
- g_RuntimeInitializationCallback = fPtr;
-}
-
void Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame)
{
if (!IsStateSet(TSF_Attached))