Rodrigo Mesquita pushed to branch wip/T26166 at Glasgow Haskell Compiler / GHC Commits: edbc124b by Ben Gamari at 2025-10-10T16:12:13+01:00 rts: Avoid static symbol references to ghc-internal This resolves #26166, a bug due to new constraints placed by Apple's linker on undefined references. One source of such references in the RTS is the many symbols referenced in ghc-internal. To mitigate #26166, we make these references dynamic, as described in Note [RTS/ghc-internal interface]. Fixes #26166 Co-authored-by: Rodrigo Mesquita <rodrigo.m.mesquita@gmail.com> - - - - - 29 changed files: - compiler/GHC/HsToCore/Foreign/C.hs - compiler/GHC/Linker/Dynamic.hs - compiler/GHC/Linker/Static.hs - + libraries/ghc-internal/cbits/RtsIface.c - libraries/ghc-internal/ghc-internal.cabal.in - + libraries/ghc-internal/include/RtsIfaceSymbols.h - rts/BuiltinClosures.c - rts/CloneStack.h - rts/Compact.cmm - rts/ContinuationOps.cmm - rts/Exception.cmm - rts/Prelude.h - rts/PrimOps.cmm - rts/RtsAPI.c - rts/RtsStartup.c - rts/RtsSymbols.c - + rts/RtsToHsIface.c - rts/Schedule.c - rts/StgStdThunks.cmm - rts/configure.ac - − rts/external-symbols.list.in - rts/include/Rts.h - rts/include/RtsAPI.h - + rts/include/rts/RtsToHsIface.h - rts/posix/Signals.c - − rts/rts.buildinfo.in - rts/rts.cabal - rts/wasm/JSFFI.c - utils/deriveConstants/Main.hs Changes: ===================================== compiler/GHC/HsToCore/Foreign/C.hs ===================================== @@ -517,8 +517,8 @@ mkFExportCBits dflags c_nm maybe_target arg_htys res_hty is_IO_res_ty cc text "rts_apply" <> parens ( cap <> (if is_IO_res_ty - then text "runIO_closure" - else text "runNonIO_closure") + then text "ghc_hs_iface->runIO_closure" + else text "ghc_hs_iface->runNonIO_closure") <> comma <> expr_to_run ) <+> comma ===================================== compiler/GHC/Linker/Dynamic.hs ===================================== @@ -150,10 +150,6 @@ linkDynLib logger tmpfs dflags0 unit_env o_files dep_packages -- (and should) do without this for all libraries except -- the RTS; all we need to do is to pass the correct -- HSfoo_dyn.dylib files to the link command. - -- This feature requires Mac OS X 10.3 or later; there is - -- a similar feature, -flat_namespace -undefined suppress, - -- which works on earlier versions, but it has other - -- disadvantages. -- -single_module -- Build the dynamic library as a single "module", i.e. no -- dynamic binding nonsense when referring to symbols from ===================================== compiler/GHC/Linker/Static.hs ===================================== @@ -261,6 +261,11 @@ linkBinary' staticLink logger tmpfs dflags unit_env o_files dep_units = do -- See Note [Dynamic linking on macOS]. then [ "-Wl,-dead_strip_dylibs", "-Wl,-headerpad,8000" ] else []) + + -- See Note [RTS/ghc-internal interface] + ++ (if ghcInternalUnitId `elem` map unitId pkgs + then [ "-Wl,-u,init_ghc_hs_iface" ] + else []) )) -- | Linking a static lib will not really link anything. It will merely produce ===================================== libraries/ghc-internal/cbits/RtsIface.c ===================================== @@ -0,0 +1,52 @@ +/* + * (c) The GHC Team, 2025-2026 + * + * RTS/ghc-internal interface + * + * See Note [RTS/ghc-internal interface]. + */ + +#include "Rts.h" + +void init_ghc_hs_iface(void) __attribute__((constructor)); + +// Forward declarations +#define CLOSURE(module, symbol) \ + extern StgClosure ghczminternal_##module##_##symbol; + +#define UNDEF_CLOSURE(module, symbol) + +#define INFO_TBL(module, symbol) \ + extern StgInfoTable ghczminternal_##module##_##symbol; + +#include "RtsIfaceSymbols.h" + +#undef CLOSURE +#undef UNDEF_CLOSURE +#undef INFO_TBL + +// HsIface definition +#define CLOSURE(module, symbol) \ + .symbol = &ghczminternal_##module##_##symbol, + +#define UNDEF_CLOSURE(module, symbol) \ + .symbol = NULL, + +#define INFO_TBL(module, symbol) \ + .symbol = &ghczminternal_##module##_##symbol, + +static const HsIface the_ghc_hs_iface = { +#include "RtsIfaceSymbols.h" +}; + +void init_ghc_hs_iface(void) +{ + /* + * N.B. ghc-internal may be load multiple times, e.g., when the + * RTS linker is in use. For this reason we explicitly refuse to + * override ghc_hs_iface if it has already been initialized. + */ + if (ghc_hs_iface == NULL) { + ghc_hs_iface = &the_ghc_hs_iface; + } +} ===================================== libraries/ghc-internal/ghc-internal.cabal.in ===================================== @@ -43,6 +43,7 @@ extra-source-files: include/winio_structs.h include/WordSize.h include/HsIntegerGmp.h.in + include/RtsIfaceSymbols.h install-sh source-repository head @@ -444,6 +445,7 @@ Library cbits/strerror.c cbits/debug.c cbits/Stack_c.c + cbits/RtsIface.c cmm-sources: cbits/StackCloningDecoding.cmm ===================================== libraries/ghc-internal/include/RtsIfaceSymbols.h ===================================== @@ -0,0 +1,67 @@ +// See Note [RTS/ghc-internal interface]. + +#if defined(mingw32_HOST_OS) +CLOSURE(GHCziInternalziEventziWindows, processRemoteCompletion_closure) +#else +UNDEF_CLOSURE(GHCziInternalziEventziWindows, processRemoteCompletion_closure) +#endif +CLOSURE(GHCziInternalziTopHandler, runIO_closure) +CLOSURE(GHCziInternalziTopHandler, runNonIO_closure) +CLOSURE(GHCziInternalziTuple, Z0T_closure) +CLOSURE(GHCziInternalziTypes, True_closure) +CLOSURE(GHCziInternalziTypes, False_closure) +CLOSURE(GHCziInternalziPack, unpackCString_closure) +CLOSURE(GHCziInternalziWeakziFinalizze, runFinalizzerBatch_closure) +CLOSURE(GHCziInternalziIOziException, stackOverflow_closure) +CLOSURE(GHCziInternalziIOziException, heapOverflow_closure) +CLOSURE(GHCziInternalziIOziException, allocationLimitExceeded_closure) +CLOSURE(GHCziInternalziIOziException, blockedIndefinitelyOnMVar_closure) +CLOSURE(GHCziInternalziIOziException, blockedIndefinitelyOnSTM_closure) +CLOSURE(GHCziInternalziIOziException, cannotCompactFunction_closure) +CLOSURE(GHCziInternalziIOziException, cannotCompactPinned_closure) +CLOSURE(GHCziInternalziIOziException, cannotCompactMutable_closure) +CLOSURE(GHCziInternalziControlziExceptionziBase, nonTermination_closure) +CLOSURE(GHCziInternalziControlziExceptionziBase, nestedAtomically_closure) +CLOSURE(GHCziInternalziControlziExceptionziBase, noMatchingContinuationPrompt_closure) +CLOSURE(GHCziInternalziEventziThread, blockedOnBadFD_closure) +CLOSURE(GHCziInternalziConcziSync, runSparks_closure) +CLOSURE(GHCziInternalziConcziIO, ensureIOManagerIsRunning_closure) +CLOSURE(GHCziInternalziConcziIO, interruptIOManager_closure) +CLOSURE(GHCziInternalziConcziIO, ioManagerCapabilitiesChanged_closure) +CLOSURE(GHCziInternalziConcziSignal, runHandlersPtr_closure) +CLOSURE(GHCziInternalziTopHandler, flushStdHandles_closure) +CLOSURE(GHCziInternalziTopHandler, runMainIO_closure) +INFO_TBL(GHCziInternalziTypes, Czh_con_info) +INFO_TBL(GHCziInternalziTypes, Izh_con_info) +INFO_TBL(GHCziInternalziTypes, Fzh_con_info) +INFO_TBL(GHCziInternalziTypes, Dzh_con_info) +INFO_TBL(GHCziInternalziTypes, Wzh_con_info) +CLOSURE(GHCziInternalziPrimziPanic, absentSumFieldError_closure) +CLOSURE(GHCziInternalziAllocationLimitHandler, runAllocationLimitHandler_closure) +INFO_TBL(GHCziInternalziPtr, Ptr_con_info) +INFO_TBL(GHCziInternalziPtr, FunPtr_con_info) +INFO_TBL(GHCziInternalziInt, I8zh_con_info) +INFO_TBL(GHCziInternalziInt, I16zh_con_info) +INFO_TBL(GHCziInternalziInt, I32zh_con_info) +INFO_TBL(GHCziInternalziInt, I64zh_con_info) +INFO_TBL(GHCziInternalziWord, W8zh_con_info) +INFO_TBL(GHCziInternalziWord, W16zh_con_info) +INFO_TBL(GHCziInternalziWord, W32zh_con_info) +INFO_TBL(GHCziInternalziWord, W64zh_con_info) +INFO_TBL(GHCziInternalziStable, StablePtr_con_info) +CLOSURE(GHCziInternalziStackziCloneStack, StackSnapshot_closure) +CLOSURE(GHCziInternalziExceptionziType, divZZeroException_closure) +CLOSURE(GHCziInternalziExceptionziType, underflowException_closure) +CLOSURE(GHCziInternalziExceptionziType, overflowException_closure) +CLOSURE(GHCziInternalziCString, unpackCStringzh_closure) +INFO_TBL(GHCziInternalziCString, unpackCStringzh_info) +INFO_TBL(GHCziInternalziCString, unpackCStringUtf8zh_info) +#if defined(wasm32_HOST_ARCH) +CLOSURE(GHCziInternalziWasmziPrimziImports, raiseJSException_closure) +CLOSURE(GHCziInternalziWasmziPrim, JSVal_con_info) +CLOSURE(GHCziInternalziWasmziPrim, threadDelay_closure) +#else +UNDEF_CLOSURE(GHCziInternalziWasmziPrimziImports, raiseJSException_closure) +UNDEF_CLOSURE(GHCziInternalziWasmziPrim, JSVal_con_info) +UNDEF_CLOSURE(GHCziInternalziWasmziPrim, threadDelay_closure) +#endif ===================================== rts/BuiltinClosures.c ===================================== @@ -1,5 +1,4 @@ #include "Rts.h" -#include "Prelude.h" #include "BuiltinClosures.h" /* @@ -17,14 +16,14 @@ void initBuiltinClosures(void) { // INTLIKE closures for (int i = MIN_INTLIKE; i <= MAX_INTLIKE; i++) { StgIntCharlikeClosure *c = &stg_INTLIKE_closure[i - MIN_INTLIKE]; - SET_HDR((StgClosure* ) c, Izh_con_info, CCS_SYSTEM_OR_NULL); + SET_HDR((StgClosure* ) c, ghc_hs_iface->Izh_con_info, CCS_SYSTEM_OR_NULL); c->data = i; } // CHARLIKE closures for (int i = MIN_CHARLIKE; i <= MAX_CHARLIKE; i++) { StgIntCharlikeClosure *c = &stg_CHARLIKE_closure[i - MIN_CHARLIKE]; - SET_HDR((StgClosure* ) c, Czh_con_info, CCS_SYSTEM_OR_NULL); + SET_HDR((StgClosure* ) c, ghc_hs_iface->Czh_con_info, CCS_SYSTEM_OR_NULL); c->data = i; } } ===================================== rts/CloneStack.h ===================================== @@ -8,8 +8,7 @@ #pragma once -extern StgClosure ghczminternal_GHCziInternalziStackziCloneStack_StackSnapshot_closure; -#define StackSnapshot_constructor_closure (&(ghczminternal_GHCziInternalziStackziCloneStack_StackSnapshot_closure)) +#define StackSnapshot_constructor_closure ghc_hs_iface->StackSnapshot_closure StgStack* cloneStack(Capability* capability, const StgStack* stack); ===================================== rts/Compact.cmm ===================================== @@ -10,9 +10,6 @@ #include "Cmm.h" #include "sm/ShouldCompact.h" -import CLOSURE ghczminternal_GHCziInternalziIOziException_cannotCompactFunction_closure; -import CLOSURE ghczminternal_GHCziInternalziIOziException_cannotCompactMutable_closure; -import CLOSURE ghczminternal_GHCziInternalziIOziException_cannotCompactPinned_closure; #if !defined(UnregisterisedCompiler) import CLOSURE g0; import CLOSURE large_alloc_lim; @@ -124,7 +121,7 @@ eval: SMALL_MUT_ARR_PTRS_CLEAN, SMALL_MUT_ARR_PTRS_DIRTY, COMPACT_NFDATA: { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_cannotCompactMutable_closure); + jump stg_raisezh(HsIface_cannotCompactMutable_closure(W_[ghc_hs_iface])); } // We shouldn't see any functions, if this data structure was NFData. @@ -139,7 +136,7 @@ eval: BCO, PAP, CONTINUATION: { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_cannotCompactFunction_closure); + jump stg_raisezh(HsIface_cannotCompactFunction_closure(W_[ghc_hs_iface])); } case ARR_WORDS: { @@ -147,7 +144,7 @@ eval: (should) = ccall shouldCompact(compact "ptr", p "ptr"); if (should == SHOULDCOMPACT_IN_CNF) { P_[pp] = p; return(); } if (should == SHOULDCOMPACT_PINNED) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_cannotCompactPinned_closure); + jump stg_raisezh(HsIface_cannotCompactPinned_closure(W_[ghc_hs_iface])); } CHECK_HASH(); ===================================== rts/ContinuationOps.cmm ===================================== @@ -12,7 +12,6 @@ #include "Cmm.h" -import CLOSURE ghczminternal_GHCziInternalziControlziExceptionziBase_noMatchingContinuationPrompt_closure; #if !defined(UnregisterisedCompiler) import CLOSURE ALLOC_RTS_ctr; import CLOSURE ALLOC_RTS_tot; @@ -104,7 +103,7 @@ stg_control0zh_ll // explicit stack // see Note [When capturing the continuation fails] in Continuation.c if (cont == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziControlziExceptionziBase_noMatchingContinuationPrompt_closure); + jump stg_raisezh(HsIface_noMatchingContinuationPrompt_closure(W_[ghc_hs_iface])); } W_ apply_mask_frame; ===================================== rts/Exception.cmm ===================================== @@ -13,10 +13,6 @@ #include "Cmm.h" #include "RaiseAsync.h" -import CLOSURE ghczminternal_GHCziInternalziTypes_True_closure; -import CLOSURE ghczminternal_GHCziInternalziExceptionziType_divZZeroException_closure; -import CLOSURE ghczminternal_GHCziInternalziExceptionziType_underflowException_closure; -import CLOSURE ghczminternal_GHCziInternalziExceptionziType_overflowException_closure; #if !defined(UnregisterisedCompiler) import CLOSURE CATCHF_PUSHED_ctr; import CLOSURE RtsFlags; @@ -539,7 +535,7 @@ retry_pop_stack: Sp(10) = exception; Sp(9) = stg_raise_ret_info; Sp(8) = exception; - Sp(7) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception + Sp(7) = HsIface_True_closure(W_[ghc_hs_iface]); // True <=> an exception Sp(6) = stg_ap_ppv_info; Sp(5) = 0; Sp(4) = stg_ap_n_info; @@ -650,17 +646,17 @@ stg_raiseIOzh (P_ exception) stg_raiseDivZZerozh () { - jump stg_raisezh(ghczminternal_GHCziInternalziExceptionziType_divZZeroException_closure); + jump stg_raisezh(HsIface_divZZeroException_closure(W_[ghc_hs_iface])); } stg_raiseUnderflowzh () { - jump stg_raisezh(ghczminternal_GHCziInternalziExceptionziType_underflowException_closure); + jump stg_raisezh(HsIface_underflowException_closure(W_[ghc_hs_iface])); } stg_raiseOverflowzh () { - jump stg_raisezh(ghczminternal_GHCziInternalziExceptionziType_overflowException_closure); + jump stg_raisezh(HsIface_overflowException_closure(W_[ghc_hs_iface])); } /* The FFI doesn't support variadic C functions so we can't directly expose ===================================== rts/Prelude.h ===================================== @@ -19,126 +19,69 @@ #define PRELUDE_CLOSURE(i) extern StgClosure (i) #endif -/* See Note [Wired-in exceptions are not CAFfy] in GHC.Core.Make. */ -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziPrimziPanic_absentSumFieldError_closure); /* Define canonical names so we can abstract away from the actual * modules these names are defined in. */ -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziTuple_Z0T_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziTypes_True_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziTypes_False_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziPack_unpackCString_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziPack_unpackCStringUtf8_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziWeak_runFinalizzerBatch_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziWeakziFinalizze_runFinalizzerBatch_closure); - #if defined(IN_STG_CODE) extern W_ ZCMain_main_closure[]; #else extern StgClosure ZCMain_main_closure; #endif -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_stackOverflow_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_allocationLimitExceeded_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_blockedIndefinitelyOnMVar_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_blockedIndefinitelyOnSTM_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_cannotCompactFunction_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_cannotCompactPinned_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziIOziException_cannotCompactMutable_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziControlziExceptionziBase_nonTermination_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziControlziExceptionziBase_nestedAtomically_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziEventziThread_blockedOnBadFD_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziExceptionziType_divZZeroException_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziExceptionziType_underflowException_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziExceptionziType_overflowException_closure); - -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziConcziSync_runSparks_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziConcziIO_ensureIOManagerIsRunning_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziConcziIO_interruptIOManager_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziConcziIO_ioManagerCapabilitiesChanged_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziConcziSignal_runHandlersPtr_closure); -#if defined(mingw32_HOST_OS) -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziEventziWindows_processRemoteCompletion_closure); -#endif - -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziTopHandler_flushStdHandles_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziTopHandler_runMainIO_closure); -PRELUDE_CLOSURE(ghczminternal_GHCziInternalziAllocationLimitHandler_runAllocationLimitHandler_closure); - -PRELUDE_INFO(ghczminternal_GHCziInternalziCString_unpackCStringzh_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziTypes_Czh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziTypes_Izh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziTypes_Fzh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziTypes_Dzh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziTypes_Wzh_con_info); - -PRELUDE_INFO(ghczminternal_GHCziInternalziPtr_Ptr_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziPtr_FunPtr_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziInt_I8zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziInt_I16zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziInt_I32zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziInt_I64zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziWord_W8zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziWord_W16zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziWord_W32zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziWord_W64zh_con_info); -PRELUDE_INFO(ghczminternal_GHCziInternalziStable_StablePtr_con_info); - -#define Unit_closure (&(ghczminternal_GHCziInternalziTuple_Z0T_closure)) -#define True_closure (&(ghczminternal_GHCziInternalziTypes_True_closure)) -#define False_closure (&(ghczminternal_GHCziInternalziTypes_False_closure)) -#define unpackCString_closure (&(ghczminternal_GHCziInternalziPack_unpackCString_closure)) -#define runFinalizerBatch_closure (&(ghczminternal_GHCziInternalziWeakziFinalizze_runFinalizzerBatch_closure)) +#define Unit_closure ghc_hs_iface->Z0T_closure +#define True_closure ghc_hs_iface->True_closure +#define False_closure ghc_hs_iface->False_closure +#define unpackCString_closure ghc_hs_iface->unpackCString_closure +#define runFinalizerBatch_closure ghc_hs_iface->runFinalizzerBatch_closure #define mainIO_closure (&ZCMain_main_closure) -#define runSparks_closure (&(ghczminternal_GHCziInternalziConcziSync_runSparks_closure)) -#define ensureIOManagerIsRunning_closure (&(ghczminternal_GHCziInternalziConcziIO_ensureIOManagerIsRunning_closure)) -#define interruptIOManager_closure (&(ghczminternal_GHCziInternalziConcziIO_interruptIOManager_closure)) -#define ioManagerCapabilitiesChanged_closure (&(ghczminternal_GHCziInternalziConcziIO_ioManagerCapabilitiesChanged_closure)) -#define runHandlersPtr_closure (&(ghczminternal_GHCziInternalziConcziSignal_runHandlersPtr_closure)) +#define runSparks_closure ghc_hs_iface->runSparks_closure +#define ensureIOManagerIsRunning_closure ghc_hs_iface->ensureIOManagerIsRunning_closure +#define interruptIOManager_closure ghc_hs_iface->interruptIOManager_closure +#define ioManagerCapabilitiesChanged_closure ghc_hs_iface->ioManagerCapabilitiesChanged_closure +#define runHandlersPtr_closure ghc_hs_iface->runHandlersPtr_closure #if defined(mingw32_HOST_OS) -#define processRemoteCompletion_closure (&(ghczminternal_GHCziInternalziEventziWindows_processRemoteCompletion_closure)) +#define processRemoteCompletion_closure ghc_hs_iface->processRemoteCompletion_closure #endif -#define runAllocationLimitHandler_closure (&(ghczminternal_GHCziInternalziAllocationLimitHandler_runAllocationLimitHandler_closure)) - -#define flushStdHandles_closure (&(ghczminternal_GHCziInternalziTopHandler_flushStdHandles_closure)) -#define runMainIO_closure (&(ghczminternal_GHCziInternalziTopHandler_runMainIO_closure)) - -#define stackOverflow_closure (&(ghczminternal_GHCziInternalziIOziException_stackOverflow_closure)) -#define heapOverflow_closure (&(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure)) -#define allocationLimitExceeded_closure (&(ghczminternal_GHCziInternalziIOziException_allocationLimitExceeded_closure)) -#define blockedIndefinitelyOnMVar_closure (&(ghczminternal_GHCziInternalziIOziException_blockedIndefinitelyOnMVar_closure)) -#define blockedIndefinitelyOnSTM_closure (&(ghczminternal_GHCziInternalziIOziException_blockedIndefinitelyOnSTM_closure)) -#define cannotCompactFunction_closure (&(ghczminternal_GHCziInternalziIOziException_cannotCompactFunction_closure)) -#define cannotCompactPinned_closure (&(ghczminternal_GHCziInternalziIOziException_cannotCompactPinned_closure)) -#define cannotCompactMutable_closure (&(ghczminternal_GHCziInternalziIOziException_cannotCompactMutable_closure)) -#define nonTermination_closure (&(ghczminternal_GHCziInternalziControlziExceptionziBase_nonTermination_closure)) -#define nestedAtomically_closure (&(ghczminternal_GHCziInternalziControlziExceptionziBase_nestedAtomically_closure)) -#define absentSumFieldError_closure (&(ghczminternal_GHCziInternalziPrimziPanic_absentSumFieldError_closure)) -#define underflowException_closure (&(ghczminternal_GHCziInternalziExceptionziType_underflowException_closure)) -#define overflowException_closure (&(ghczminternal_GHCziInternalziExceptionziType_overflowException_closure)) -#define divZeroException_closure (&(ghczminternal_GHCziInternalziExceptionziType_divZZeroException_closure)) - -#define blockedOnBadFD_closure (&(ghczminternal_GHCziInternalziEventziThread_blockedOnBadFD_closure)) - -#define Czh_con_info (&(ghczminternal_GHCziInternalziTypes_Czh_con_info)) -#define Izh_con_info (&(ghczminternal_GHCziInternalziTypes_Izh_con_info)) -#define Fzh_con_info (&(ghczminternal_GHCziInternalziTypes_Fzh_con_info)) -#define Dzh_con_info (&(ghczminternal_GHCziInternalziTypes_Dzh_con_info)) -#define Wzh_con_info (&(ghczminternal_GHCziInternalziTypes_Wzh_con_info)) -#define W8zh_con_info (&(ghczminternal_GHCziInternalziWord_W8zh_con_info)) -#define W16zh_con_info (&(ghczminternal_GHCziInternalziWord_W16zh_con_info)) -#define W32zh_con_info (&(ghczminternal_GHCziInternalziWord_W32zh_con_info)) -#define W64zh_con_info (&(ghczminternal_GHCziInternalziWord_W64zh_con_info)) -#define I8zh_con_info (&(ghczminternal_GHCziInternalziInt_I8zh_con_info)) -#define I16zh_con_info (&(ghczminternal_GHCziInternalziInt_I16zh_con_info)) -#define I32zh_con_info (&(ghczminternal_GHCziInternalziInt_I32zh_con_info)) -#define I64zh_con_info (&(ghczminternal_GHCziInternalziInt_I64zh_con_info)) -#define I64zh_con_info (&(ghczminternal_GHCziInternalziInt_I64zh_con_info)) -#define Ptr_con_info (&(ghczminternal_GHCziInternalziPtr_Ptr_con_info)) -#define FunPtr_con_info (&(ghczminternal_GHCziInternalziPtr_FunPtr_con_info)) -#define StablePtr_static_info (&(ghczminternal_GHCziInternalziStable_StablePtr_static_info)) -#define StablePtr_con_info (&(ghczminternal_GHCziInternalziStable_StablePtr_con_info)) +#define runAllocationLimitHandler_closure ghc_hs_iface->runAllocationLimitHandler_closure + +#define flushStdHandles_closure ghc_hs_iface->flushStdHandles_closure +#define runMainIO_closure ghc_hs_iface->runMainIO_closure + +#define stackOverflow_closure ghc_hs_iface->stackOverflow_closure +#define heapOverflow_closure ghc_hs_iface->heapOverflow_closure +#define allocationLimitExceeded_closure ghc_hs_iface->allocationLimitExceeded_closure +#define blockedIndefinitelyOnMVar_closure ghc_hs_iface->blockedIndefinitelyOnMVar_closure +#define blockedIndefinitelyOnSTM_closure ghc_hs_iface->blockedIndefinitelyOnSTM_closure +#define cannotCompactFunction_closure ghc_hs_iface->cannotCompactFunction_closure +#define cannotCompactPinned_closure ghc_hs_iface->cannotCompactPinned_closure +#define cannotCompactMutable_closure ghc_hs_iface->cannotCompactMutable_closure +#define nonTermination_closure ghc_hs_iface->nonTermination_closure +#define nestedAtomically_closure ghc_hs_iface->nestedAtomically_closure +#define absentSumFieldError_closure ghc_hs_iface->absentSumFieldError_closure +#define underflowException_closure ghc_hs_iface->underflowException_closure +#define overflowException_closure ghc_hs_iface->overflowException_closure +#define divZeroException_closure ghc_hs_iface->divZZeroException_closure + +#define blockedOnBadFD_closure ghc_hs_iface->blockedOnBadFD_closure + +#define Czh_con_info ghc_hs_iface->Czh_con_info +#define Izh_con_info ghc_hs_iface->Izh_con_info +#define Fzh_con_info ghc_hs_iface->Fzh_con_info +#define Dzh_con_info ghc_hs_iface->Dzh_con_info +#define Wzh_con_info ghc_hs_iface->Wzh_con_info +#define W8zh_con_info ghc_hs_iface->W8zh_con_info +#define W16zh_con_info ghc_hs_iface->W16zh_con_info +#define W32zh_con_info ghc_hs_iface->W32zh_con_info +#define W64zh_con_info ghc_hs_iface->W64zh_con_info +#define I8zh_con_info ghc_hs_iface->I8zh_con_info +#define I16zh_con_info ghc_hs_iface->I16zh_con_info +#define I32zh_con_info ghc_hs_iface->I32zh_con_info +#define I64zh_con_info ghc_hs_iface->I64zh_con_info +#define I64zh_con_info ghc_hs_iface->I64zh_con_info +#define Ptr_con_info ghc_hs_iface->Ptr_con_info +#define FunPtr_con_info ghc_hs_iface->FunPtr_con_info +#define StablePtr_static_info ghc_hs_iface->StablePtr_static_info +#define StablePtr_con_info ghc_hs_iface->StablePtr_con_info ===================================== rts/PrimOps.cmm ===================================== @@ -25,12 +25,8 @@ #include "MachDeps.h" #include "SMPClosureOps.h" -import CLOSURE ghczminternal_GHCziInternalziControlziExceptionziBase_nestedAtomically_closure; -import CLOSURE ghczminternal_GHCziInternalziIOziException_heapOverflow_closure; -import CLOSURE ghczminternal_GHCziInternalziIOziException_blockedIndefinitelyOnMVar_closure; import AcquireSRWLockExclusive; import ReleaseSRWLockExclusive; -import CLOSURE ghczminternal_GHCziInternalziTypes_False_closure; #if defined(PROFILING) import CLOSURE CCS_MAIN; #endif @@ -118,7 +114,7 @@ stg_newByteArrayzh ( W_ n ) ("ptr" p) = ccall allocateArrBytes(MyCapability() "ptr", n, CCCS); if (p == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } return (p); } @@ -135,7 +131,7 @@ stg_newPinnedByteArrayzh ( W_ n ) ("ptr" p) = ccall allocateArrBytesPinned(MyCapability() "ptr", n, BA_ALIGN, CCCS); if (p == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } return (p); } @@ -149,7 +145,7 @@ stg_newAlignedPinnedByteArrayzh ( W_ n, W_ alignment ) ("ptr" p) = ccall allocateArrBytesPinned(MyCapability() "ptr", n, alignment, CCCS); if (p == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } return (p); } @@ -364,7 +360,7 @@ stg_newArrayzh ( W_ n /* words */, gcptr init ) ("ptr" arr) = ccall allocateMutArrPtrs(MyCapability() "ptr", n, CCCS); if (arr == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } // Initialise all elements of the array with the value init @@ -474,7 +470,7 @@ stg_newSmallArrayzh ( W_ n /* words */, gcptr init ) ("ptr" arr) = ccall allocateSmallMutArrPtrs(MyCapability() "ptr", n, CCCS); if (arr == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } // Initialise all elements of the array with the value init @@ -1090,7 +1086,7 @@ stg_listThreadszh () ("ptr" arr) = ccall listThreads(MyCapability() "ptr"); if (arr == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } return (arr); @@ -1360,7 +1356,7 @@ stg_atomicallyzh (P_ stm) /* Nested transactions are not allowed; raise an exception */ if (old_trec != NO_TREC) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziControlziExceptionziBase_nestedAtomically_closure); + jump stg_raisezh(HsIface_nestedAtomically_closure(W_[ghc_hs_iface])); } code = stm; @@ -2231,7 +2227,7 @@ stg_unpackClosurezh ( P_ closure ) dat_arr_sz = SIZEOF_StgArrBytes + WDS(len); ("ptr" dat_arr) = ccall allocateMightFail(MyCapability() "ptr", BYTES_TO_WDS(dat_arr_sz)); if (dat_arr == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } TICK_ALLOC_PRIM(SIZEOF_StgArrBytes, WDS(len), 0); @@ -2251,7 +2247,7 @@ for: ("ptr" ptrArray) = foreign "C" heap_view_closurePtrs(MyCapability() "ptr", clos "ptr"); if (ptrArray == NULL) (likely: False) { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } return (info, dat_arr, ptrArray); @@ -2286,7 +2282,7 @@ stg_waitReadzh ( W_ fd ) if (ok != 0::CBool) (likely: True) { jump stg_block_noregs(); } else { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } } @@ -2299,7 +2295,7 @@ stg_waitWritezh ( W_ fd ) if (ok != 0::CBool) (likely: True) { jump stg_block_noregs(); } else { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } } @@ -2323,7 +2319,7 @@ stg_delayzh ( W_ us_delay ) jump stg_block_noregs(); #endif } else { - jump stg_raisezh(ghczminternal_GHCziInternalziIOziException_heapOverflow_closure); + jump stg_raisezh(HsIface_heapOverflow_closure(W_[ghc_hs_iface])); } } @@ -2518,13 +2514,13 @@ stg_getSparkzh () W_ spark; #if !defined(THREADED_RTS) - return (0,ghczminternal_GHCziInternalziTypes_False_closure); + return (0,HsIface_False_closure(W_[ghc_hs_iface])); #else ("ptr" spark) = ccall findSpark(MyCapability() "ptr"); if (spark != 0) { return (1,spark); } else { - return (0,ghczminternal_GHCziInternalziTypes_False_closure); + return (0,HsIface_False_closure(W_[ghc_hs_iface])); } #endif } ===================================== rts/RtsAPI.c ===================================== @@ -509,7 +509,7 @@ void rts_evalStableIOMain(/* inout */ Capability **cap, SchedulerStatus stat; p = (StgClosure *)deRefStablePtr(s); - w = rts_apply(*cap, &ghczminternal_GHCziInternalziTopHandler_runMainIO_closure, p); + w = rts_apply(*cap, runMainIO_closure, p); tso = createStrictIOThread(*cap, RtsFlags.GcFlags.initialStkSize, w); // async exceptions are always blocked by default in the created // thread. See #1048. @@ -961,7 +961,7 @@ void rts_done (void) void hs_try_putmvar (/* in */ int capability, /* in */ HsStablePtr mvar) { - hs_try_putmvar_with_value(capability, mvar, TAG_CLOSURE(1, Unit_closure)); + hs_try_putmvar_with_value(capability, mvar, TAG_CLOSURE(1, ghc_hs_iface->Z0T_closure)); } void hs_try_putmvar_with_value (/* in */ int capability, ===================================== rts/RtsStartup.c ===================================== @@ -183,8 +183,8 @@ static void initBuiltinGcRoots(void) * these closures `Id`s of these can be safely marked as non-CAFFY * in the compiler. */ - getStablePtr((StgPtr)runIO_closure); - getStablePtr((StgPtr)runNonIO_closure); + getStablePtr((StgPtr)ghc_hs_iface->runIO_closure); + getStablePtr((StgPtr)ghc_hs_iface->runNonIO_closure); getStablePtr((StgPtr)flushStdHandles_closure); getStablePtr((StgPtr)runFinalizerBatch_closure); @@ -263,6 +263,11 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config) setlocale(LC_CTYPE,""); + if (ghc_hs_iface == NULL) { + errorBelch("hs_init_ghc: ghc_hs_iface is uninitialized"); + stg_exit(1); + } + /* Initialise the stats department, phase 0 */ initStats0(); ===================================== rts/RtsSymbols.c ===================================== @@ -464,6 +464,7 @@ extern char **environ; RTS_PROF_SYMBOLS \ RTS_LIBDW_SYMBOLS \ SymI_HasProto(StgReturn) \ + SymI_HasDataProto(ghc_hs_iface) \ SymI_HasDataProto(stg_gc_noregs) \ SymI_HasDataProto(stg_ret_v_info) \ SymI_HasDataProto(stg_ret_p_info) \ ===================================== rts/RtsToHsIface.c ===================================== @@ -0,0 +1,59 @@ +/* + * (c) The GHC Team, 2025-2026 + * + * RTS/ghc-internal interface + * + * + * Note [RTS/ghc-internal interface] + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The runtime system depends upon a variety of symbols defined by Haskell + * modules living in `ghc-internal`. To avoid cyclic dependencies between + * ghc-internal and the RTS, these symbols are referenced indirectly via the + * the `HsIface` structure (specifically `ghc_hs_iface`): + * + * struct HsIface { + * StgClosure *runIO; // GHC.Internal.TopHandler.runIO + * StgClosure *Z0T; // GHC.Internal.Tuple.() + * // etc. + * }; + * + * `ghc_hs_iface` is initialized during program loading via the + * `init_ghc_hs_iface` constructor in `ghc-interface` + * + * const struct HsIface the_hs_iface = { + * .runIO = &ghczminternal_GHCziInternalziTopHandler_runIO_closure, + * .Z0T = &ghczminternal_GHCziInternalziTuple_Z0T_closure, + * // etc. + * }; + * + * void __attribute__((constructor)) init_ghc_hs_iface() { + * ghc_hs_iface = &the_hs_iface; + * } + * + * This effectively breaks the RTS's link-time dependency, replacing it with a + * run-time dependency at the cost of an indirection. It also has the pleasant + * side-effect of making the interface between the RTS and `ghc-internal` + * explicit. + * + * Note that the ((constructor)) symbol is explicitly included in the final + * binary via the linker flag `-uinit_ghc_hs_iface`, when an executable is + * linked against ghc-internal by GHC. + * + * `-uinit_ghc_hs_iface` ensures that the `init_ghc_hs_iface` symbol is + * included in the final link, even when we link against `ghc-internal.a` + * (since, otherwise, only objects members which provide undefined symbols + * needed by the executable are included in the final object). + * + * When `ghc-internal` is a dynamic dependency of an executable, the + * constructor will run when the shared object for `ghc-internal` is loaded. + * When the executable is statically linked against `ghc-internal`, the + * constructor will be run when the program is loaded (since the constructor + * symbol was forcibly included as described in the paragraph above). + */ + +#include "Rts.h" + +// This captures the symbols provided by ghc-internal which +// are needed by the RTS. +const HsIface *ghc_hs_iface = NULL; ===================================== rts/Schedule.c ===================================== @@ -1053,7 +1053,7 @@ scheduleProcessInbox (Capability **pcap USED_IF_THREADS) while (p != NULL) { pnext = p->link; performTryPutMVar(cap, (StgMVar*)deRefStablePtr(p->mvar), - Unit_closure); + ghc_hs_iface->Z0T_closure); freeStablePtr(p->mvar); stgFree(p); p = pnext; ===================================== rts/StgStdThunks.cmm ===================================== @@ -13,8 +13,6 @@ #include "Cmm.h" #include "Updates.h" -import CLOSURE ghczminternal_GHCziInternalziCString_unpackCStringzh_info; -import CLOSURE ghczminternal_GHCziInternalziCString_unpackCStringUtf8zh_info; #if !defined(UnregisterisedCompiler) import CLOSURE STK_CHK_ctr; import CLOSURE stg_bh_upd_frame_info; @@ -348,7 +346,7 @@ stg_do_unpack_cstring(P_ node, P_ newCAF_ret) { W_ str; str = StgThunk_payload(node, 2); push (UPDATE_FRAME_FIELDS(,,stg_bh_upd_frame_info, CCCS, 0, newCAF_ret)) { - jump %ENTRY_CODE(ghczminternal_GHCziInternalziCString_unpackCStringzh_info)(node, str); + jump %ENTRY_CODE(HsIface_unpackCStringzh_info(W_[ghc_hs_iface]))(node, str); } } @@ -372,7 +370,7 @@ stg_do_unpack_cstring_utf8(P_ node, P_ newCAF_ret) { W_ str; str = StgThunk_payload(node, 2); push (UPDATE_FRAME_FIELDS(,,stg_bh_upd_frame_info, CCCS, 0, newCAF_ret)) { - jump %ENTRY_CODE(ghczminternal_GHCziInternalziCString_unpackCStringUtf8zh_info)(node, str); + jump %ENTRY_CODE(HsIface_unpackCStringUtf8zh_info(W_[ghc_hs_iface]))(node, str); } } ===================================== rts/configure.ac ===================================== @@ -487,44 +487,3 @@ cat ghcautoconf.h.autoconf | sed \ >> include/ghcautoconf.h echo "#endif /* __GHCAUTOCONF_H__ */" >> include/ghcautoconf.h ] - -dnl ###################################################################### -dnl Generate external symbol flags (-Wl,-u...) -dnl ###################################################################### - -dnl See Note [Undefined symbols in the RTS] - -[ -symbolExtraDefs='' -if [ "$CABAL_FLAG_find_ptr" = 1 ]; then - symbolExtraDefs+=' -DFIND_PTR' -fi - -cat $srcdir/external-symbols.list.in \ - | "$CC" $symbolExtraDefs -E -P -traditional -Iinclude - -o - \ - | sed -e '/^ *$/d' \ - > external-symbols.list \ - || exit 1 - -if [ "$CABAL_FLAG_leading_underscore" = 1 ]; then - sedExpr='s/^(.*)$/ "-Wl,-u,_\1"/' -else - sedExpr='s/^(.*)$/ "-Wl,-u,\1"/' -fi -sed -E -e "${sedExpr}" external-symbols.list > external-symbols.flags -unset sedExpr -rm -f external-symbols.list -] - -dnl ###################################################################### -dnl Generate build-info -dnl ###################################################################### - -[ -cat $srcdir/rts.buildinfo.in \ - | "$CC" -E -P -traditional - -o - \ - | sed -e '/^ *$/d' \ - > rts.buildinfo \ - || exit 1 -rm -f external-symbols.flags -] ===================================== rts/external-symbols.list.in deleted ===================================== @@ -1,102 +0,0 @@ -#include "ghcautoconf.h" - -#if 0 -See Note [Undefined symbols in the RTS] -#endif - -#if mingw32_HOST_OS -ghczminternal_GHCziInternalziEventziWindows_processRemoteCompletion_closure -#endif - -#if FIND_PTR -findPtr -#endif - -ghczminternal_GHCziInternalziTopHandler_runIO_closure -ghczminternal_GHCziInternalziTopHandler_runNonIO_closure -ghczminternal_GHCziInternalziTuple_Z0T_closure -ghczminternal_GHCziInternalziTypes_True_closure -ghczminternal_GHCziInternalziTypes_False_closure -ghczminternal_GHCziInternalziPack_unpackCString_closure -ghczminternal_GHCziInternalziWeakziFinalizze_runFinalizzerBatch_closure -ghczminternal_GHCziInternalziIOziException_stackOverflow_closure -ghczminternal_GHCziInternalziIOziException_heapOverflow_closure -ghczminternal_GHCziInternalziIOziException_allocationLimitExceeded_closure -ghczminternal_GHCziInternalziIOziException_blockedIndefinitelyOnMVar_closure -ghczminternal_GHCziInternalziIOziException_blockedIndefinitelyOnSTM_closure -ghczminternal_GHCziInternalziIOziException_cannotCompactFunction_closure -ghczminternal_GHCziInternalziIOziException_cannotCompactPinned_closure -ghczminternal_GHCziInternalziIOziException_cannotCompactMutable_closure -ghczminternal_GHCziInternalziControlziExceptionziBase_nonTermination_closure -ghczminternal_GHCziInternalziControlziExceptionziBase_nestedAtomically_closure -ghczminternal_GHCziInternalziEventziThread_blockedOnBadFD_closure -ghczminternal_GHCziInternalziConcziSync_runSparks_closure -ghczminternal_GHCziInternalziConcziIO_ensureIOManagerIsRunning_closure -ghczminternal_GHCziInternalziConcziIO_interruptIOManager_closure -ghczminternal_GHCziInternalziConcziIO_ioManagerCapabilitiesChanged_closure -ghczminternal_GHCziInternalziConcziSignal_runHandlersPtr_closure -ghczminternal_GHCziInternalziTopHandler_flushStdHandles_closure -ghczminternal_GHCziInternalziTopHandler_runMainIO_closure -ghczminternal_GHCziInternalziTypes_Czh_con_info -ghczminternal_GHCziInternalziTypes_Izh_con_info -ghczminternal_GHCziInternalziTypes_Fzh_con_info -ghczminternal_GHCziInternalziTypes_Dzh_con_info -ghczminternal_GHCziInternalziTypes_Wzh_con_info -ghczminternal_GHCziInternalziAllocationLimitHandler_runAllocationLimitHandler_closure -ghczminternal_GHCziInternalziPtr_Ptr_con_info -ghczminternal_GHCziInternalziPtr_FunPtr_con_info -ghczminternal_GHCziInternalziInt_I8zh_con_info -ghczminternal_GHCziInternalziInt_I16zh_con_info -ghczminternal_GHCziInternalziInt_I32zh_con_info -ghczminternal_GHCziInternalziInt_I64zh_con_info -ghczminternal_GHCziInternalziWord_W8zh_con_info -ghczminternal_GHCziInternalziWord_W16zh_con_info -ghczminternal_GHCziInternalziWord_W32zh_con_info -ghczminternal_GHCziInternalziWord_W64zh_con_info -ghczminternal_GHCziInternalziStable_StablePtr_con_info -ghczminternal_GHCziInternalziStackziCloneStack_StackSnapshot_closure - -#if 0 -N.B. These symbols are defined in ghc-internal and may be referenced by the -unregisterised code-generator when compiling RTS Cmm sources. -#endif -hs_atomic_add8 -hs_atomic_add16 -hs_atomic_add32 -hs_atomic_add64 -hs_atomic_sub8 -hs_atomic_sub16 -hs_atomic_sub32 -hs_atomic_sub64 -hs_atomic_and8 -hs_atomic_and16 -hs_atomic_and32 -hs_atomic_and64 -hs_atomic_nand8 -hs_atomic_nand16 -hs_atomic_nand32 -hs_atomic_nand64 -hs_atomic_or8 -hs_atomic_or16 -hs_atomic_or32 -hs_atomic_or64 -hs_atomic_xor8 -hs_atomic_xor16 -hs_atomic_xor32 -hs_atomic_xor64 -hs_cmpxchg8 -hs_cmpxchg16 -hs_cmpxchg32 -hs_cmpxchg64 -hs_xchg8 -hs_xchg16 -hs_xchg32 -hs_xchg64 -hs_atomicread8 -hs_atomicread16 -hs_atomicread32 -hs_atomicread64 -hs_atomicwrite8 -hs_atomicwrite16 -hs_atomicwrite32 -hs_atomicwrite64 ===================================== rts/include/Rts.h ===================================== @@ -229,6 +229,7 @@ void _warnFail(const char *filename, unsigned int linenum); #include "rts/storage/ClosureTypes.h" #include "rts/storage/TSO.h" #include "stg/MiscClosures.h" /* InfoTables, closures etc. defined in the RTS */ + #include "rts/storage/Block.h" #include "rts/storage/ClosureMacros.h" #include "rts/storage/MBlock.h" ===================================== rts/include/RtsAPI.h ===================================== @@ -18,6 +18,7 @@ extern "C" { #include "HsFFI.h" #include "rts/Time.h" #include "rts/Types.h" +#include "rts/RtsToHsIface.h" /* * Running the scheduler @@ -584,11 +585,6 @@ void rts_done (void); // Note that RtsAPI.h is also included by foreign export stubs in // the base package itself. // -extern StgClosure ghczminternal_GHCziInternalziTopHandler_runIO_closure; -extern StgClosure ghczminternal_GHCziInternalziTopHandler_runNonIO_closure; - -#define runIO_closure (&(ghczminternal_GHCziInternalziTopHandler_runIO_closure)) -#define runNonIO_closure (&(ghczminternal_GHCziInternalziTopHandler_runNonIO_closure)) /* ------------------------------------------------------------------------ */ ===================================== rts/include/rts/RtsToHsIface.h ===================================== @@ -0,0 +1,67 @@ +/* + * (c) The GHC Team, 2025-2026 + * + * RTS/ghc-internal interface + * + * See Note [RTS/ghc-internal interface]. + */ + +typedef struct { + StgClosure *processRemoteCompletion_closure; // GHC.Internal.Event.Windows.processRemoteCompletion_closure + StgClosure *runIO_closure; // GHC.Internal.TopHandler.runIO_closure + StgClosure *runNonIO_closure; // GHC.Internal.TopHandler.runNonIO_closure + StgClosure *Z0T_closure; // GHC.Internal.Tuple.Z0T_closure + StgClosure *True_closure; // GHC.Internal.Types.True_closure + StgClosure *False_closure; // GHC.Internal.Types.False_closure + StgClosure *unpackCString_closure; // GHC.Internal.Pack.unpackCString_closure + StgClosure *runFinalizzerBatch_closure; // GHC.Internal.Weak.Finalizze.runFinalizzerBatch_closure + StgClosure *stackOverflow_closure; // GHC.Internal.IO.Exception.stackOverflow_closure + StgClosure *heapOverflow_closure; // GHC.Internal.IO.Exception.heapOverflow_closure + StgClosure *allocationLimitExceeded_closure; // GHC.Internal.IO.Exception.allocationLimitExceeded_closure + StgClosure *blockedIndefinitelyOnMVar_closure; // GHC.Internal.IO.Exception.blockedIndefinitelyOnMVar_closure + StgClosure *blockedIndefinitelyOnSTM_closure; // GHC.Internal.IO.Exception.blockedIndefinitelyOnSTM_closure + StgClosure *cannotCompactFunction_closure; // GHC.Internal.IO.Exception.cannotCompactFunction_closure + StgClosure *cannotCompactPinned_closure; // GHC.Internal.IO.Exception.cannotCompactPinned_closure + StgClosure *cannotCompactMutable_closure; // GHC.Internal.IO.Exception.cannotCompactMutable_closure + StgClosure *nonTermination_closure; // GHC.Internal.Control.Exception.Base.nonTermination_closure + StgClosure *nestedAtomically_closure; // GHC.Internal.Control.Exception.Base.nestedAtomically_closure + StgClosure *noMatchingContinuationPrompt_closure; // GHC.Internal.Control.Exception.Base.noMatchingContinuationPrompt_closure + StgClosure *blockedOnBadFD_closure; // GHC.Internal.Event.Thread.blockedOnBadFD_closure + StgClosure *runSparks_closure; // GHC.Internal.Conc.Sync.runSparks_closure + StgClosure *ensureIOManagerIsRunning_closure; // GHC.Internal.Conc.IO.ensureIOManagerIsRunning_closure + StgClosure *interruptIOManager_closure; // GHC.Internal.Conc.IO.interruptIOManager_closure + StgClosure *ioManagerCapabilitiesChanged_closure; // GHC.Internal.Conc.IO.ioManagerCapabilitiesChanged_closure + StgClosure *runHandlersPtr_closure; // GHC.Internal.Conc.Signal.runHandlersPtr_closure + StgClosure *flushStdHandles_closure; // GHC.Internal.TopHandler.flushStdHandles_closure + StgClosure *runMainIO_closure; // GHC.Internal.TopHandler.runMainIO_closure + StgInfoTable *Czh_con_info; // GHC.Internal.Types.Czh_con_info + StgInfoTable *Izh_con_info; // GHC.Internal.Types.Izh_con_info + StgInfoTable *Fzh_con_info; // GHC.Internal.Types.Fzh_con_info + StgInfoTable *Dzh_con_info; // GHC.Internal.Types.Dzh_con_info + StgInfoTable *Wzh_con_info; // GHC.Internal.Types.Wzh_con_info + StgClosure *absentSumFieldError_closure; // GHC.Internal.Prim.Panic.absentSumFieldError_closure + StgClosure *runAllocationLimitHandler_closure; // GHC.Internal.AllocationLimitHandler.runAllocationLimitHandler_closure + StgInfoTable *Ptr_con_info; // GHC.Internal.Ptr.Ptr_con_info + StgInfoTable *FunPtr_con_info; // GHC.Internal.Ptr.FunPtr_con_info + StgInfoTable *I8zh_con_info; // GHC.Internal.Int.I8zh_con_info + StgInfoTable *I16zh_con_info; // GHC.Internal.Int.I16zh_con_info + StgInfoTable *I32zh_con_info; // GHC.Internal.Int.I32zh_con_info + StgInfoTable *I64zh_con_info; // GHC.Internal.Int.I64zh_con_info + StgInfoTable *W8zh_con_info; // GHC.Internal.Word.W8zh_con_info + StgInfoTable *W16zh_con_info; // GHC.Internal.Word.W16zh_con_info + StgInfoTable *W32zh_con_info; // GHC.Internal.Word.W32zh_con_info + StgInfoTable *W64zh_con_info; // GHC.Internal.Word.W64zh_con_info + StgInfoTable *StablePtr_con_info; // GHC.Internal.Stable.StablePtr_con_info + StgClosure *StackSnapshot_closure; // GHC.Internal.Stack.CloneStack.StackSnapshot_closure + StgClosure *divZZeroException_closure; // GHC.Internal.Exception.Type.divZeroException_closure + StgClosure *underflowException_closure; // GHC.Internal.Exception.Type.underflowException_closure + StgClosure *overflowException_closure; // GHC.Internal.Exception.Type.overflowException_closure + StgClosure *unpackCStringzh_closure; // GHC.Internal.CString.unpackCStringzh_closure + StgInfoTable *unpackCStringzh_info; // GHC.Internal.CString.unpackCStringzh_info + StgInfoTable *unpackCStringUtf8zh_info; // GHC.Internal.CString.unpackCStringUtf8zh_info + StgClosure *raiseJSException_closure; // GHC.Internal.Wasm.Prim.Imports.raiseJSException_closure + StgClosure *JSVal_con_info; // GHC.Internal.Wasm.Prim.JSVal_con_info + StgClosure *threadDelay_closure; // GHC.Internal.Wasm.Prim.threadDelay_closure +} HsIface; + +extern const HsIface *ghc_hs_iface; ===================================== rts/posix/Signals.c ===================================== @@ -222,7 +222,7 @@ ioManagerDie (void) void ioManagerStartCap (Capability **cap) { - rts_evalIO(cap,&ghczminternal_GHCziInternalziConcziIO_ensureIOManagerIsRunning_closure,NULL); + rts_evalIO(cap,ensureIOManagerIsRunning_closure,NULL); } void @@ -493,7 +493,7 @@ startSignalHandlers(Capability *cap) RtsFlags.GcFlags.initialStkSize, rts_apply(cap, rts_apply(cap, - &ghczminternal_GHCziInternalziConcziSignal_runHandlersPtr_closure, + runHandlersPtr_closure, rts_mkPtr(cap, info)), rts_mkInt(cap, info->si_signo))); scheduleThread(cap, t); ===================================== rts/rts.buildinfo.in deleted ===================================== @@ -1,3 +0,0 @@ --- External symbols referenced by the RTS -ld-options: -#include "external-symbols.flags" ===================================== rts/rts.cabal ===================================== @@ -14,12 +14,9 @@ build-type: Configure extra-source-files: configure configure.ac - external-symbols.list.in - rts.buildinfo.in extra-tmp-files: autom4te.cache - rts.buildinfo config.log config.status @@ -334,6 +331,7 @@ library rts/storage/InfoTables.h rts/storage/MBlock.h rts/storage/TSO.h + rts/RtsToHsIface.h stg/MachRegs.h stg/MachRegs/arm32.h stg/MachRegs/arm64.h @@ -353,8 +351,6 @@ library if os(osx) ld-options: "-Wl,-search_paths_first" - -- See Note [Undefined symbols in the RTS] - "-Wl,-undefined,dynamic_lookup" if !arch(x86_64) && !arch(aarch64) ld-options: -read_only_relocs warning @@ -449,6 +445,7 @@ library RtsStartup.c RtsSymbolInfo.c RtsSymbols.c + RtsToHsIface.c RtsUtils.c STM.c Schedule.c @@ -588,33 +585,3 @@ library -- ticker/*.c -- We don't want to compile posix/ticker/*.c, these will be #included -- from Ticker.c - --- Note [Undefined symbols in the RTS] --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- The RTS is built with a number of `-u` flags. This is to handle cyclic --- dependencies between the RTS and other libraries which we normally think of as --- downstream from the RTS. "Regular" dependencies from usages in those libraries --- to definitions in the RTS are handled normally. "Reverse" dependencies from --- usages in the RTS to definitions in those libraries get the `-u` flag in the --- RTS. --- --- The symbols are specified literally, but follow C ABI conventions (as all 3 of --- C, C--, and Haskell do currently). Thus, we have to be careful to include a --- leading underscore or not based on those conventions for the given platform in --- question. --- --- A tricky part is that different linkers have different policies regarding --- undefined symbols (not defined in the current binary, or found in a shared --- library that could be loaded at run time). GNU Binutils' linker is fine with --- undefined symbols by default, but Apple's "cctools" linker is not. To appease --- that linker we either need to do a blanket `-undefined dynamic_lookup` or --- whitelist each such symbol with an additional `-U` (see the man page for more --- details). --- --- GHC already does `-undefined dynamic_lookup`, so we just do that for now, but --- we might try to get more precise with `-U` in the future. --- --- Note that the RTS also `-u`s some symbols for atomic operations that *are* defined --- by `ghc-internal`. This is needed when the RTS is compiled when the RTS is --- compiled with, e.g., the unregisterised backend since the code-generator will --- reference these symbols when compiling atomic primops in Cmm sources. ===================================== rts/wasm/JSFFI.c ===================================== @@ -115,9 +115,9 @@ __attribute__((constructor(102))) static void __ghc_wasm_jsffi_init(void) { // See Note [threadDelay on wasm] for details. rts_JSFFI_flag = HS_BOOL_TRUE; getStablePtr(( - StgPtr)&ghczminternal_GHCziInternalziWasmziPrimziImports_raiseJSException_closure); + StgPtr)ghc_hs_iface->raiseJSException_closure); rts_threadDelay_impl = getStablePtr(( - StgPtr)&ghczminternal_GHCziInternalziWasmziPrimziConcziInternal_threadDelay_closure); + StgPtr)ghc_hs_iface->threadDelay_closure); } typedef __externref_t HsJSVal; @@ -159,7 +159,7 @@ HaskellObj rts_mkJSVal(Capability *cap, HsJSVal v) { SET_HDR(w, &stg_WEAK_info, CCS_SYSTEM); w->cfinalizers = (StgClosure *)cfin; w->key = p; - w->value = Unit_closure; + w->value = ghc_hs_iface->Z0T_closure; w->finalizer = &stg_NO_FINALIZER_closure; w->link = cap->weak_ptr_list_hd; cap->weak_ptr_list_hd = w; @@ -170,7 +170,7 @@ HaskellObj rts_mkJSVal(Capability *cap, HsJSVal v) { p->payload[0] = (HaskellObj)w; HaskellObj box = (HaskellObj)allocate(cap, CONSTR_sizeW(1, 0)); - SET_HDR(box, &ghczminternal_GHCziInternalziWasmziPrimziTypes_JSVal_con_info, CCS_SYSTEM); + SET_HDR(box, ghc_hs_iface->JSVal_con_info, CCS_SYSTEM); box->payload[0] = p; return TAG_CLOSURE(1, box); @@ -186,7 +186,7 @@ STATIC_INLINE HsJSVal rts_getJSValzh(HaskellObj p) { HsJSVal rts_getJSVal(HaskellObj); HsJSVal rts_getJSVal(HaskellObj box) { - ASSERT(UNTAG_CLOSURE(box)->header.info == &ghczminternal_GHCziInternalziWasmziPrimziTypes_JSVal_con_info); + ASSERT(UNTAG_CLOSURE(box)->header.info == ghc_hs_iface->JSVal_con_info); return rts_getJSValzh(UNTAG_CLOSURE(box)->payload[0]); } @@ -235,7 +235,7 @@ void rts_schedulerLoop(void) { __attribute__((export_name("rts_promiseResolveUnit"))) void rts_promiseResolveUnit(HsStablePtr); void rts_promiseResolveUnit(HsStablePtr sp) - mk_rtsPromiseCallback(TAG_CLOSURE(1, Unit_closure)) + mk_rtsPromiseCallback(TAG_CLOSURE(1, ghc_hs_iface->Z0T_closure)) mk_rtsPromiseResolve(JSVal) mk_rtsPromiseResolve(Char) @@ -259,7 +259,7 @@ mk_rtsPromiseResolve(Bool) __attribute__((export_name("rts_promiseReject"))) void rts_promiseReject(HsStablePtr, HsJSVal); void rts_promiseReject(HsStablePtr sp, HsJSVal js_err) - mk_rtsPromiseCallback(rts_apply(cap, &ghczminternal_GHCziInternalziWasmziPrimziImports_raiseJSException_closure, rts_mkJSVal(cap, js_err))) + mk_rtsPromiseCallback(rts_apply(cap, ghc_hs_iface->raiseJSException_closure, rts_mkJSVal(cap, js_err))) __attribute__((export_name("rts_promiseThrowTo"))) void rts_promiseThrowTo(HsStablePtr, HsJSVal); @@ -276,7 +276,7 @@ void rts_promiseThrowTo(HsStablePtr sp, HsJSVal js_err) { cap, tso, rts_apply( cap, - &ghczminternal_GHCziInternalziWasmziPrimziImports_raiseJSException_closure, + ghc_hs_iface->raiseJSException_closure, rts_mkJSVal(cap, js_err))); tryWakeupThread(cap, tso); rts_schedulerLoop(); ===================================== utils/deriveConstants/Main.hs ===================================== @@ -667,6 +667,59 @@ wanteds os = concat ,structField C "StgAsyncIOResult" "errCode"] else [] + -- struct HsIface + ,structField C "HsIface" "processRemoteCompletion_closure" + ,structField C "HsIface" "runIO_closure" + ,structField C "HsIface" "runNonIO_closure" + ,structField C "HsIface" "Z0T_closure" + ,structField C "HsIface" "True_closure" + ,structField C "HsIface" "False_closure" + ,structField C "HsIface" "unpackCString_closure" + ,structField C "HsIface" "runFinalizzerBatch_closure" + ,structField C "HsIface" "stackOverflow_closure" + ,structField C "HsIface" "heapOverflow_closure" + ,structField C "HsIface" "allocationLimitExceeded_closure" + ,structField C "HsIface" "blockedIndefinitelyOnMVar_closure" + ,structField C "HsIface" "blockedIndefinitelyOnSTM_closure" + ,structField C "HsIface" "cannotCompactFunction_closure" + ,structField C "HsIface" "cannotCompactPinned_closure" + ,structField C "HsIface" "cannotCompactMutable_closure" + ,structField C "HsIface" "nonTermination_closure" + ,structField C "HsIface" "nestedAtomically_closure" + ,structField C "HsIface" "noMatchingContinuationPrompt_closure" + ,structField C "HsIface" "blockedOnBadFD_closure" + ,structField C "HsIface" "runSparks_closure" + ,structField C "HsIface" "ensureIOManagerIsRunning_closure" + ,structField C "HsIface" "interruptIOManager_closure" + ,structField C "HsIface" "ioManagerCapabilitiesChanged_closure" + ,structField C "HsIface" "runHandlersPtr_closure" + ,structField C "HsIface" "flushStdHandles_closure" + ,structField C "HsIface" "runMainIO_closure" + ,structField C "HsIface" "Czh_con_info" + ,structField C "HsIface" "Izh_con_info" + ,structField C "HsIface" "Fzh_con_info" + ,structField C "HsIface" "Dzh_con_info" + ,structField C "HsIface" "Wzh_con_info" + ,structField C "HsIface" "runAllocationLimitHandler_closure" + ,structField C "HsIface" "Ptr_con_info" + ,structField C "HsIface" "FunPtr_con_info" + ,structField C "HsIface" "I8zh_con_info" + ,structField C "HsIface" "I16zh_con_info" + ,structField C "HsIface" "I32zh_con_info" + ,structField C "HsIface" "I64zh_con_info" + ,structField C "HsIface" "W8zh_con_info" + ,structField C "HsIface" "W16zh_con_info" + ,structField C "HsIface" "W32zh_con_info" + ,structField C "HsIface" "W64zh_con_info" + ,structField C "HsIface" "StablePtr_con_info" + ,structField C "HsIface" "StackSnapshot_closure" + ,structField C "HsIface" "divZZeroException_closure" + ,structField C "HsIface" "underflowException_closure" + ,structField C "HsIface" "overflowException_closure" + ,structField C "HsIface" "unpackCStringzh_closure" + ,structField C "HsIface" "unpackCStringzh_info" + ,structField C "HsIface" "unpackCStringUtf8zh_info" + -- pre-compiled thunk types ,constantWord Haskell "MAX_SPEC_SELECTEE_SIZE" "MAX_SPEC_SELECTEE_SIZE" ,constantWord Haskell "MAX_SPEC_AP_SIZE" "MAX_SPEC_AP_SIZE" View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/edbc124b3e7843fec26d957414c9fc6f... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/edbc124b3e7843fec26d957414c9fc6f... You're receiving this email because of your account on gitlab.haskell.org.