[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 6 commits: rts/nonmoving: Fix comment spelling
                        
                        
by Marge Bot (@marge-bot) 11 Oct '25
                    by Marge Bot (@marge-bot) 11 Oct '25
11 Oct '25
                    
                        
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
1adf774e by Ben Gamari at 2025-10-11T04:25:28-04:00
rts/nonmoving: Fix comment spelling
- - - - -
3dca409d by Ben Gamari at 2025-10-11T04:25:28-04:00
rts/nonmoving: Use atomic operations to update bd->flags
- - - - -
9418afdd by Ben Gamari at 2025-10-11T04:25:28-04:00
nonmoving: Use get_itbl instead of explicit loads
This is cleaner and also fixes unnecessary (and unsound) use of
`volatile`.
- - - - -
5af4c88b by Ben Gamari at 2025-10-11T04:25:28-04:00
rts/Scav: Handle WHITEHOLEs in scavenge_one
`scavenge_one`, used to scavenge mutable list entries, may encounter
`WHITEHOLE`s when the non-moving GC is in use via two paths:
  1. when an MVAR is being marked concurrently
  2. when the object belongs to a chain of selectors being short-cutted.
Fixes #26204.
- - - - -
b12c4af4 by Matthew Pickering at 2025-10-11T04:25:29-04:00
Add support for generating bytecode objects
This commit adds the `-fwrite-byte-code` option which makes GHC emit a
`.gbc` file which contains a serialised representation of bytecode.
The bytecode can be loaded by the compiler to avoid having to
reinterpret a module when using the bytecode interpreter (for example,
in GHCi).
There are also the new options:
* -gbcdir=<DIR>: Specify the directory to place the gbc files
* -gbcsuf=<suffix>: Specify the suffix for gbc files
The option `-fbyte-code-and-object-code` now implies
`-fwrite-byte-code`.
These performance tests fail due to https://github.com/haskell/directory/issues/204
-------------------------
Metric Increase:
    MultiComponentModules
    MultiLayerModules
    MultiComponentModulesRecomp
    MultiLayerModulesRecomp
    MultiLayerModulesTH_Make
    MultiLayerModulesTH_OneShot
    T13701
-------------------------
The bytecode serialisation part was implemented by Cheng Shao
Co-authored-by: Cheng Shao <terrorjack(a)type.dance>
- - - - -
5171df89 by Matthew Pickering at 2025-10-11T04:25:29-04:00
Revert "Add a perf test for #26425"
This test has a large memory spike currently, which makes the test
sensitive, since if you allocate a little more or less, the precise
location where GC happens shifts and you observe a different part of the
spike.
Andreas told me to revert the patch for now, and he will add it back
when he fixes the memory spike.
This reverts commit 41bdb16fd083110a06507248f648c507a2feb4af.
- - - - -
71 changed files:
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/ByteCode/Breakpoints.hs
- + compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Data/FlatBag.hs
- compiler/GHC/Data/SmallArray.hs
- compiler/GHC/Driver/Backend.hs
- compiler/GHC/Driver/Backpack.hs
- + compiler/GHC/Driver/ByteCode.hs
- compiler/GHC/Driver/Config/Finder.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Messager.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Types/SptEntry.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Finder/Types.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/Module/Location.hs
- compiler/GHC/Unit/Module/ModSummary.hs
- compiler/GHC/Unit/Module/WholeCoreBindings.hs
- compiler/GHC/Utils/Binary.hs
- compiler/ghc.cabal.in
- docs/users_guide/phases.rst
- docs/users_guide/separate_compilation.rst
- rts/include/rts/storage/Block.h
- rts/sm/NonMoving.c
- rts/sm/NonMovingMark.c
- rts/sm/Scav.c
- testsuite/tests/bytecode/T24634/T24634a.stdout
- testsuite/tests/bytecode/T24634/T24634b.stdout
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/driver/bytecode-object/A.hs
- + testsuite/tests/driver/bytecode-object/BytecodeForeign.c
- + testsuite/tests/driver/bytecode-object/BytecodeForeign.hs
- + testsuite/tests/driver/bytecode-object/BytecodeMain.hs
- + testsuite/tests/driver/bytecode-object/BytecodeTest.hs
- + testsuite/tests/driver/bytecode-object/Makefile
- + testsuite/tests/driver/bytecode-object/all.T
- + testsuite/tests/driver/bytecode-object/bytecode_object12.stderr
- + testsuite/tests/driver/bytecode-object/bytecode_object13.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object14.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object15.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object16.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object17.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object18.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object19.script
- + testsuite/tests/driver/bytecode-object/bytecode_object19.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object25.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object4.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object5.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object6.stdout
- testsuite/tests/driver/fat-iface/T22405/T22405.stdout
- testsuite/tests/driver/fat-iface/T22405/T22405b.stdout
- testsuite/tests/driver/fat-iface/fat011.stderr
- testsuite/tests/perf/compiler/Makefile
- + testsuite/tests/perf/compiler/MultiLayerModulesDefsGhciWithBytecodeFiles.script
- − testsuite/tests/perf/compiler/T26425.hs
- testsuite/tests/perf/compiler/all.T
- testsuite/tests/simplStg/should_compile/T22840.stderr
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7f9e83443dfda282e19868171a804d…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7f9e83443dfda282e19868171a804d…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/romes/26166-move-prims] Move code-gen aux symbols from ghc-internal to rts
                        
                        
by Rodrigo Mesquita (@alt-romes) 11 Oct '25
                    by Rodrigo Mesquita (@alt-romes) 11 Oct '25
11 Oct '25
                    
                        
Rodrigo Mesquita pushed to branch wip/romes/26166-move-prims at Glasgow Haskell Compiler / GHC
Commits:
fee3764a by Rodrigo Mesquita at 2025-10-11T08:07:23+01:00
Move code-gen aux symbols from ghc-internal to rts
These symbols were all previously defined in ghc-internal and made the
dependency structure awkward, where the rts may refer to some of these
symbols and had to work around that circular dependency the way
described in #26166.
Moreover, the code generator will produce code that uses these symbols!
Therefore, they should be available in the rts:
PRINCIPLE: If the code generator may produce code which uses this
symbol, then it should be defined in the rts rather than, say,
ghc-internal.
That said, the main motivation is towards fixing #26166.
Towards #26166. Pre-requisite of !14892
- - - - -
19 changed files:
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- hadrian/src/Settings/Packages.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- rts/RtsSymbols.c
- rts/include/stg/Prim.h
- libraries/ghc-internal/cbits/atomic.c → rts/prim/atomic.c
- libraries/ghc-internal/cbits/bitrev.c → rts/prim/bitrev.c
- libraries/ghc-internal/cbits/bswap.c → rts/prim/bswap.c
- libraries/ghc-internal/cbits/clz.c → rts/prim/clz.c
- libraries/ghc-internal/cbits/ctz.c → rts/prim/ctz.c
- libraries/ghc-internal/cbits/int64x2minmax.c → rts/prim/int64x2minmax.c
- libraries/ghc-internal/cbits/longlong.c → rts/prim/longlong.c
- libraries/ghc-internal/cbits/mulIntMayOflo.c → rts/prim/mulIntMayOflo.c
- libraries/ghc-internal/cbits/pdep.c → rts/prim/pdep.c
- libraries/ghc-internal/cbits/pext.c → rts/prim/pext.c
- libraries/ghc-internal/cbits/popcnt.c → rts/prim/popcnt.c
- libraries/ghc-internal/cbits/vectorQuotRem.c → rts/prim/vectorQuotRem.c
- libraries/ghc-internal/cbits/word2float.c → rts/prim/word2float.c
- rts/rts.cabal
Changes:
=====================================
compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
=====================================
@@ -438,7 +438,7 @@ lower_MO_S_Shr lbl w0 [x, y] = case someWasmTypeFromCmmType (cmmBits w0) of
 lower_MO_S_Shr _ _ _ = panic "lower_MO_S_Shr: unreachable"
 
 -- | Lower a 'MO_MulMayOflo' operation. It's translated to a ccall to
--- @hs_mulIntMayOflo@ function in @ghc-prim/cbits/mulIntMayOflo@,
+-- @hs_mulIntMayOflo@ function in @rts/prim/mulIntMayOflo@,
 -- otherwise it's quite non-trivial to implement as inline assembly.
 lower_MO_MulMayOflo ::
   CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
=====================================
hadrian/src/Settings/Packages.hs
=====================================
@@ -287,9 +287,6 @@ ghcInternalArgs = package ghcInternal ? do
 
           , builder (Cabal Flags) ? flag NeedLibatomic `cabalFlag` "need-atomic"
 
-          , builder (Cc CompileC) ? (not <$> flag CcLlvmBackend) ?
-              input "**/cbits/atomic.c"  ? arg "-Wno-sync-nand"
-
           ]
 
 -- | RTS-specific command line arguments.
@@ -413,6 +410,9 @@ rtsPackageArgs = package rts ? do
 
           , input "**/RetainerProfile.c" ? flag CcLlvmBackend ?
             arg "-Wno-incompatible-pointer-types"
+
+          , input "**/prim/atomic.c"  ? (not <$> flag CcLlvmBackend) ?
+            arg "-Wno-sync-nand"
           ]
 
     mconcat
=====================================
libraries/ghc-internal/ghc-internal.cabal.in
=====================================
@@ -442,20 +442,7 @@ Library
           cbits/sysconf.c
           cbits/fs.c
           cbits/strerror.c
-          cbits/atomic.c
-          cbits/bswap.c
-          cbits/bitrev.c
-          cbits/clz.c
-          cbits/ctz.c
           cbits/debug.c
-          cbits/int64x2minmax.c
-          cbits/longlong.c
-          cbits/mulIntMayOflo.c
-          cbits/pdep.c
-          cbits/pext.c
-          cbits/popcnt.c
-          cbits/vectorQuotRem.c
-          cbits/word2float.c
           cbits/Stack_c.c
 
       cmm-sources:
=====================================
rts/RtsSymbols.c
=====================================
@@ -1016,6 +1016,116 @@ extern char **environ;
 #define RTS_FINI_ARRAY_SYMBOLS
 #endif
 
+#define SymI_HasProtoAllSizes(symbol)                \
+      SymI_HasProto(symbol##8)                       \
+      SymI_HasProto(symbol##16)                      \
+      SymI_HasProto(symbol##32)                      \
+      SymI_HasProto(symbol##64)
+
+#if !defined(arm_HOST_ARCH)
+#define RTS_ATOMICS_SYMBOLS                          \
+      SymI_HasProtoAllSizes(hs_atomic_add)           \
+      SymI_HasProtoAllSizes(hs_atomic_sub)           \
+      SymI_HasProtoAllSizes(hs_atomic_and)           \
+      SymI_HasProtoAllSizes(hs_atomic_nand)          \
+      SymI_HasProtoAllSizes(hs_atomic_or)            \
+      SymI_HasProtoAllSizes(hs_atomic_xor)           \
+      SymI_HasProtoAllSizes(hs_cmpxchg)              \
+      SymI_HasProtoAllSizes(hs_xchg)                 \
+      SymI_HasProtoAllSizes(hs_atomicread)           \
+      SymI_HasProtoAllSizes(hs_atomicwrite)
+#else
+// No atomics on arm32. See e9abcad4cc3
+#define RTS_ATOMICS_SYMBOLS
+#endif
+
+// In rts/longlong.c
+#if WORD_SIZE_IN_BITS < 64
+#define RTS_SYMBOLS_LONGLONG                        \
+      SymI_HasProto(hs_eq64)                        \
+      SymI_HasProto(hs_ne64)                        \
+      SymI_HasProto(hs_gtWord64)                    \
+      SymI_HasProto(hs_geWord64)                    \
+      SymI_HasProto(hs_ltWord64)                    \
+      SymI_HasProto(hs_leWord64)                    \
+      SymI_HasProto(hs_gtInt64)                     \
+      SymI_HasProto(hs_geInt64)                     \
+      SymI_HasProto(hs_ltInt64)                     \
+      SymI_HasProto(hs_leInt64)                     \
+      SymI_HasProto(hs_neg64)                       \
+      SymI_HasProto(hs_add64)                       \
+      SymI_HasProto(hs_sub64)                       \
+      SymI_HasProto(hs_mul64)                       \
+      SymI_HasProto(hs_remWord64)                   \
+      SymI_HasProto(hs_quotWord64)                  \
+      SymI_HasProto(hs_remInt64)                    \
+      SymI_HasProto(hs_quotInt64)                   \
+      SymI_HasProto(hs_and64)                       \
+      SymI_HasProto(hs_or64)                        \
+      SymI_HasProto(hs_xor64)                       \
+      SymI_HasProto(hs_not64)                       \
+      SymI_HasProto(hs_uncheckedShiftL64)           \
+      SymI_HasProto(hs_uncheckedShiftRL64)          \
+      SymI_HasProto(hs_uncheckedIShiftRA64)         \
+      SymI_HasProto(hs_intToInt64)                  \
+      SymI_HasProto(hs_int64ToInt)                  \
+      SymI_HasProto(hs_wordToWord64)                \
+      SymI_HasProto(hs_word64ToWord)
+#else
+#define RTS_SYMBOLS_LONGLONG
+#endif
+
+// rts/prim/vectorQuotRem.c and rts/prim/int64x2minmax
+#if defined(__SSE2__)
+#define RTS_SYMBOLS_VECTORQUOTREM                    \
+      SymI_HasProto(hs_quotInt8X16)                  \
+      SymI_HasProto(hs_quotInt16X8)                  \
+      SymI_HasProto(hs_quotInt32X4)                  \
+      SymI_HasProto(hs_quotInt64X2)                  \
+      SymI_HasProto(hs_quotWord8X16)                 \
+      SymI_HasProto(hs_quotWord16X8)                 \
+      SymI_HasProto(hs_quotWord32X4)                 \
+      SymI_HasProto(hs_quotWord64X2)                 \
+      SymI_HasProto(hs_remInt8X16)                   \
+      SymI_HasProto(hs_remInt16X8)                   \
+      SymI_HasProto(hs_remInt32X4)                   \
+      SymI_HasProto(hs_remInt64X2)                   \
+      SymI_HasProto(hs_remWord8X16)                  \
+      SymI_HasProto(hs_remWord16X8)                  \
+      SymI_HasProto(hs_remWord32X4)                  \
+      SymI_HasProto(hs_remWord64X2)
+#define RTS_SYMBOLS_INT64X2MINMAX                    \
+      SymI_HasProto(hs_minInt64X2)                   \
+      SymI_HasProto(hs_maxInt64X2)                   \
+      SymI_HasProto(hs_minWord64X2)                  \
+      SymI_HasProto(hs_maxWord64X2)
+#else
+#define RTS_SYMBOLS_VECTORQUOTREM
+#define RTS_SYMBOLS_INT64X2MINMAX
+#endif
+
+// Symbols on files in rts/prim/*
+#define RTS_SYMBOLS_PRIM                             \
+      RTS_ATOMICS_SYMBOLS                            \
+      RTS_SYMBOLS_INT64X2MINMAX                      \
+      RTS_SYMBOLS_LONGLONG                           \
+      RTS_SYMBOLS_VECTORQUOTREM                      \
+      SymI_HasProtoAllSizes(hs_bitrev)               \
+      SymI_HasProto(hs_bswap16)                      \
+      SymI_HasProto(hs_bswap32)                      \
+      SymI_HasProto(hs_bswap64)                      \
+      SymI_HasProtoAllSizes(hs_clz)                  \
+      SymI_HasProtoAllSizes(hs_ctz)                  \
+      SymI_HasProto(hs_mulIntMayOflo)                \
+      SymI_HasProtoAllSizes(hs_pdep)                 \
+      SymI_HasProtoAllSizes(hs_pext)                 \
+      SymI_HasProtoAllSizes(hs_pext)                 \
+      SymI_HasProto(hs_popcnt)                       \
+      SymI_HasProtoAllSizes(hs_popcnt)               \
+      SymI_HasProto(hs_word2float32)                 \
+      SymI_HasProto(hs_word2float64)
+
+
 /* entirely bogus claims about types of these symbols */
 #define SymI_NeedsProto(vvv)  extern void vvv(void);
 #define SymI_NeedsDataProto(vvv)  extern StgWord vvv[];
@@ -1038,6 +1148,7 @@ RTS_ARCH_LIBGCC_SYMBOLS
 RTS_FINI_ARRAY_SYMBOLS
 RTS_LIBFFI_SYMBOLS
 RTS_ARM_OUTLINE_ATOMIC_SYMBOLS
+RTS_SYMBOLS_PRIM
 
 #undef SymI_NeedsProto
 #undef SymI_NeedsDataProto
@@ -1081,6 +1192,7 @@ RtsSymbolVal rtsSyms[] = {
       RTS_FINI_ARRAY_SYMBOLS
       RTS_LIBFFI_SYMBOLS
       RTS_ARM_OUTLINE_ATOMIC_SYMBOLS
+      RTS_SYMBOLS_PRIM
       SymI_HasDataProto(nonmoving_write_barrier_enabled)
       { 0, 0, STRENGTH_NORMAL, SYM_TYPE_CODE } /* sentinel */
 };
=====================================
rts/include/stg/Prim.h
=====================================
@@ -2,7 +2,10 @@
  *
  * (c) The GHC Team, 2014-2014
  *
- * Declarations for C fallback primitives implemented by 'ghc-internal' package.
+ * This header collects the declarations for all the C fallback implementations
+ * used by the code generator to lower certain primops and sometimes by the RTS.
+ *
+ * Corresponding C files are in rts/prim/
  *
  * Do not #include this file directly: #include "Rts.h" instead.
  *
@@ -13,7 +16,7 @@
 
 #pragma once
 
-/* libraries/ghc-internal/cbits/atomic.c */
+/* rts/prim/atomic.c */
 StgWord hs_atomic_add8(StgWord x, StgWord val);
 StgWord hs_atomic_add16(StgWord x, StgWord val);
 StgWord hs_atomic_add32(StgWord x, StgWord val);
@@ -55,12 +58,12 @@ StgWord hs_xchg16(StgWord x, StgWord val);
 StgWord hs_xchg32(StgWord x, StgWord val);
 StgWord64 hs_xchg64(StgWord x, StgWord64 val);
 
-/* libraries/ghc-internal/cbits/bswap.c */
+/* rts/prim/bswap.c */
 StgWord16 hs_bswap16(StgWord16 x);
 StgWord32 hs_bswap32(StgWord32 x);
 StgWord64 hs_bswap64(StgWord64 x);
 
-/* libraries/ghc-internal/cbits/bitrev.c
+/* rts/prim/bitrev.c
 This was done as part of issue #16164.
 See Note [Bit reversal primop] for more details about the implementation.*/
 StgWord hs_bitrev8(StgWord x);
@@ -68,7 +71,7 @@ StgWord16 hs_bitrev16(StgWord16 x);
 StgWord32 hs_bitrev32(StgWord32 x);
 StgWord64 hs_bitrev64(StgWord64 x);
 
-/* libraries/ghc-internal/cbits/longlong.c */
+/* rts/prim/longlong.c */
 #if WORD_SIZE_IN_BITS < 64
 StgInt hs_eq64 (StgWord64 a, StgWord64 b);
 StgInt hs_ne64 (StgWord64 a, StgWord64 b);
@@ -101,41 +104,75 @@ StgWord64 hs_wordToWord64  (StgWord   w);
 StgWord   hs_word64ToWord  (StgWord64 w);
 #endif
 
-/* libraries/ghc-internal/cbits/pdep.c */
+/* rts/prim/pdep.c */
 StgWord64 hs_pdep64(StgWord64 src, StgWord64 mask);
 StgWord hs_pdep32(StgWord src, StgWord mask);
 StgWord hs_pdep16(StgWord src, StgWord mask);
 StgWord hs_pdep8(StgWord src, StgWord mask);
 
-/* libraries/ghc-internal/cbits/pext.c */
+/* rts/prim/pext.c */
 StgWord64 hs_pext64(StgWord64 src, StgWord64 mask);
 StgWord hs_pext32(StgWord src, StgWord mask);
 StgWord hs_pext16(StgWord src, StgWord mask);
 StgWord hs_pext8(StgWord src, StgWord mask);
 
-/* libraries/ghc-internal/cbits/popcnt.c */
+/* rts/prim/popcnt.c */
 StgWord hs_popcnt8(StgWord x);
 StgWord hs_popcnt16(StgWord x);
 StgWord hs_popcnt32(StgWord x);
 StgWord hs_popcnt64(StgWord64 x);
 StgWord hs_popcnt(StgWord x);
 
-/* libraries/ghc-internal/cbits/word2float.c */
+/* rts/prim/word2float.c */
 StgFloat hs_word2float32(StgWord x);
 StgDouble hs_word2float64(StgWord x);
 
-/* libraries/ghc-internal/cbits/clz.c */
+/* rts/prim/clz.c */
 StgWord hs_clz8(StgWord x);
 StgWord hs_clz16(StgWord x);
 StgWord hs_clz32(StgWord x);
 StgWord hs_clz64(StgWord64 x);
 
-/* libraries/ghc-internal/cbits/ctz.c */
+/* rts/prim/ctz.c */
 StgWord hs_ctz8(StgWord x);
 StgWord hs_ctz16(StgWord x);
 StgWord hs_ctz32(StgWord x);
 StgWord hs_ctz64(StgWord64 x);
 
+/* rts/prim/mulIntMayOflo.c */
+W_ hs_mulIntMayOflo(W_ a, W_ b);
+
+
+/* rts/prim/int64x2minmax and rts/prim/vectorQuotRem */
+#if defined(__SSE2__)
+#include <stdint.h>
+#include <string.h>
+#include <emmintrin.h>
+
+__m128i hs_minInt64X2(__m128i, __m128i);
+__m128i hs_maxInt64X2(__m128i, __m128i);
+__m128i hs_minWord64X2(__m128i, __m128i);
+__m128i hs_maxWord64X2(__m128i, __m128i);
+
+__m128i hs_quotInt8X16(__m128i, __m128i);
+__m128i hs_quotInt16X8(__m128i, __m128i);
+__m128i hs_quotInt32X4(__m128i, __m128i);
+__m128i hs_quotInt64X2(__m128i, __m128i);
+__m128i hs_quotWord8X16(__m128i, __m128i);
+__m128i hs_quotWord16X8(__m128i, __m128i);
+__m128i hs_quotWord32X4(__m128i, __m128i);
+__m128i hs_quotWord64X2(__m128i, __m128i);
+__m128i hs_remInt8X16(__m128i, __m128i);
+__m128i hs_remInt16X8(__m128i, __m128i);
+__m128i hs_remInt32X4(__m128i, __m128i);
+__m128i hs_remInt64X2(__m128i, __m128i);
+__m128i hs_remWord8X16(__m128i, __m128i);
+__m128i hs_remWord16X8(__m128i, __m128i);
+__m128i hs_remWord32X4(__m128i, __m128i);
+__m128i hs_remWord64X2(__m128i, __m128i);
+
+#endif
+
 /* bitcasts, instead of creating a new C file we static inline these here. We
  * use __builtin_memcpy instead of memcpy from string.h to avoid function
  * prototype conflicts that occur in the C backend with the inclusion of
=====================================
libraries/ghc-internal/cbits/atomic.c → rts/prim/atomic.c
=====================================
@@ -12,90 +12,66 @@
 
 // FetchAddByteArrayOp_Int
 
-extern StgWord hs_atomic_add8(StgWord x, StgWord val);
-StgWord
-hs_atomic_add8(StgWord x, StgWord val)
+StgWord hs_atomic_add8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_add((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_add16(StgWord x, StgWord val);
-StgWord
-hs_atomic_add16(StgWord x, StgWord val)
+StgWord hs_atomic_add16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_add((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_add32(StgWord x, StgWord val);
-StgWord
-hs_atomic_add32(StgWord x, StgWord val)
+StgWord hs_atomic_add32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_add((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_add64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_add64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_add64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_add((volatile StgWord64 *) x, val);
 }
 
 // FetchSubByteArrayOp_Int
 
-extern StgWord hs_atomic_sub8(StgWord x, StgWord val);
-StgWord
-hs_atomic_sub8(StgWord x, StgWord val)
+StgWord hs_atomic_sub8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_sub((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_sub16(StgWord x, StgWord val);
-StgWord
-hs_atomic_sub16(StgWord x, StgWord val)
+StgWord hs_atomic_sub16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_sub((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_sub32(StgWord x, StgWord val);
-StgWord
-hs_atomic_sub32(StgWord x, StgWord val)
+StgWord hs_atomic_sub32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_sub((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_sub64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_sub64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_sub64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_sub((volatile StgWord64 *) x, val);
 }
 
 // FetchAndByteArrayOp_Int
 
-extern StgWord hs_atomic_and8(StgWord x, StgWord val);
-StgWord
-hs_atomic_and8(StgWord x, StgWord val)
+StgWord hs_atomic_and8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_and((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_and16(StgWord x, StgWord val);
-StgWord
-hs_atomic_and16(StgWord x, StgWord val)
+StgWord hs_atomic_and16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_and((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_and32(StgWord x, StgWord val);
-StgWord
-hs_atomic_and32(StgWord x, StgWord val)
+StgWord hs_atomic_and32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_and((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_and64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_and64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_and64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_and((volatile StgWord64 *) x, val);
 }
@@ -167,9 +143,7 @@ hs_atomic_and64(StgWord x, StgWord64 val)
 #pragma GCC diagnostic ignored "-Wsync-nand"
 #endif
 
-extern StgWord hs_atomic_nand8(StgWord x, StgWord val);
-StgWord
-hs_atomic_nand8(StgWord x, StgWord val)
+StgWord hs_atomic_nand8(StgWord x, StgWord val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord8 *) x, (StgWord8) val);
@@ -178,9 +152,7 @@ hs_atomic_nand8(StgWord x, StgWord val)
 #endif
 }
 
-extern StgWord hs_atomic_nand16(StgWord x, StgWord val);
-StgWord
-hs_atomic_nand16(StgWord x, StgWord val)
+StgWord hs_atomic_nand16(StgWord x, StgWord val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord16 *) x, (StgWord16) val);
@@ -189,9 +161,7 @@ hs_atomic_nand16(StgWord x, StgWord val)
 #endif
 }
 
-extern StgWord hs_atomic_nand32(StgWord x, StgWord val);
-StgWord
-hs_atomic_nand32(StgWord x, StgWord val)
+StgWord hs_atomic_nand32(StgWord x, StgWord val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord32 *) x, (StgWord32) val);
@@ -200,9 +170,7 @@ hs_atomic_nand32(StgWord x, StgWord val)
 #endif
 }
 
-extern StgWord64 hs_atomic_nand64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_nand64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_nand64(StgWord x, StgWord64 val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord64 *) x, val);
@@ -215,96 +183,72 @@ hs_atomic_nand64(StgWord x, StgWord64 val)
 
 // FetchOrByteArrayOp_Int
 
-extern StgWord hs_atomic_or8(StgWord x, StgWord val);
-StgWord
-hs_atomic_or8(StgWord x, StgWord val)
+StgWord hs_atomic_or8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_or((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_or16(StgWord x, StgWord val);
-StgWord
-hs_atomic_or16(StgWord x, StgWord val)
+StgWord hs_atomic_or16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_or((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_or32(StgWord x, StgWord val);
-StgWord
-hs_atomic_or32(StgWord x, StgWord val)
+StgWord hs_atomic_or32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_or((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_or64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_or64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_or64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_or((volatile StgWord64 *) x, val);
 }
 
 // FetchXorByteArrayOp_Int
 
-extern StgWord hs_atomic_xor8(StgWord x, StgWord val);
-StgWord
-hs_atomic_xor8(StgWord x, StgWord val)
+StgWord hs_atomic_xor8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_xor((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_xor16(StgWord x, StgWord val);
-StgWord
-hs_atomic_xor16(StgWord x, StgWord val)
+StgWord hs_atomic_xor16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_xor((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_xor32(StgWord x, StgWord val);
-StgWord
-hs_atomic_xor32(StgWord x, StgWord val)
+StgWord hs_atomic_xor32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_xor((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_xor64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_xor64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_xor64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_xor((volatile StgWord64 *) x, val);
 }
 
 // CasByteArrayOp_Int
 
-extern StgWord hs_cmpxchg8(StgWord x, StgWord old, StgWord new);
-StgWord
-hs_cmpxchg8(StgWord x, StgWord old, StgWord new)
+StgWord hs_cmpxchg8(StgWord x, StgWord old, StgWord new)
 {
   StgWord8 expected = (StgWord8) old;
   __atomic_compare_exchange_n((StgWord8 *) x, &expected, (StgWord8) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
   return expected;
 }
 
-extern StgWord hs_cmpxchg16(StgWord x, StgWord old, StgWord new);
-StgWord
-hs_cmpxchg16(StgWord x, StgWord old, StgWord new)
+StgWord hs_cmpxchg16(StgWord x, StgWord old, StgWord new)
 {
   StgWord16 expected = (StgWord16) old;
   __atomic_compare_exchange_n((StgWord16 *) x, &expected, (StgWord16) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
   return expected;
 }
 
-extern StgWord hs_cmpxchg32(StgWord x, StgWord old, StgWord new);
-StgWord
-hs_cmpxchg32(StgWord x, StgWord old, StgWord new)
+StgWord hs_cmpxchg32(StgWord x, StgWord old, StgWord new)
 {
   StgWord32 expected = (StgWord32) old;
   __atomic_compare_exchange_n((StgWord32 *) x, &expected, (StgWord32) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
   return expected;
 }
 
-extern StgWord64 hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new);
-StgWord64
-hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new)
+StgWord64 hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new)
 {
   StgWord64 expected = (StgWord64) old;
   __atomic_compare_exchange_n((StgWord64 *) x, &expected, (StgWord64) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
@@ -313,31 +257,23 @@ hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new)
 
 // Atomic exchange operations
 
-extern StgWord hs_xchg8(StgWord x, StgWord val);
-StgWord
-hs_xchg8(StgWord x, StgWord val)
+StgWord hs_xchg8(StgWord x, StgWord val)
 {
   return (StgWord) __atomic_exchange_n((StgWord8 *) x, (StgWord8) val, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_xchg16(StgWord x, StgWord val);
-StgWord
-hs_xchg16(StgWord x, StgWord val)
+StgWord hs_xchg16(StgWord x, StgWord val)
 {
   return (StgWord) __atomic_exchange_n((StgWord16 *)x, (StgWord16) val, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_xchg32(StgWord x, StgWord val);
-StgWord
-hs_xchg32(StgWord x, StgWord val)
+StgWord hs_xchg32(StgWord x, StgWord val)
 {
   return (StgWord) __atomic_exchange_n((StgWord32 *) x, (StgWord32) val, __ATOMIC_SEQ_CST);
 }
 
 //GCC provides this even on 32bit, but StgWord is still 32 bits.
-extern StgWord64 hs_xchg64(StgWord x, StgWord64 val);
-StgWord64
-hs_xchg64(StgWord x, StgWord64 val)
+StgWord64 hs_xchg64(StgWord x, StgWord64 val)
 {
   return (StgWord64) __atomic_exchange_n((StgWord64 *) x, (StgWord64) val, __ATOMIC_SEQ_CST);
 }
@@ -352,30 +288,22 @@ hs_xchg64(StgWord x, StgWord64 val)
 // primitives which the GCC documentation claims "usually" implies a full
 // barrier.
 
-extern StgWord hs_atomicread8(StgWord x);
-StgWord
-hs_atomicread8(StgWord x)
+StgWord hs_atomicread8(StgWord x)
 {
   return __atomic_load_n((StgWord8 *) x, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_atomicread16(StgWord x);
-StgWord
-hs_atomicread16(StgWord x)
+StgWord hs_atomicread16(StgWord x)
 {
   return __atomic_load_n((StgWord16 *) x, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_atomicread32(StgWord x);
-StgWord
-hs_atomicread32(StgWord x)
+StgWord hs_atomicread32(StgWord x)
 {
   return __atomic_load_n((StgWord32 *) x, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord64 hs_atomicread64(StgWord x);
-StgWord64
-hs_atomicread64(StgWord x)
+StgWord64 hs_atomicread64(StgWord x)
 {
   return __atomic_load_n((StgWord64 *) x, __ATOMIC_SEQ_CST);
 }
@@ -384,30 +312,22 @@ hs_atomicread64(StgWord x)
 // Implies a full memory barrier (see compiler/GHC/Builtin/primops.txt.pp)
 // __ATOMIC_SEQ_CST: Full barrier (see hs_atomicread8 above).
 
-extern void hs_atomicwrite8(StgWord x, StgWord val);
-void
-hs_atomicwrite8(StgWord x, StgWord val)
+void hs_atomicwrite8(StgWord x, StgWord val)
 {
   __atomic_store_n((StgWord8 *) x, (StgWord8) val, __ATOMIC_SEQ_CST);
 }
 
-extern void hs_atomicwrite16(StgWord x, StgWord val);
-void
-hs_atomicwrite16(StgWord x, StgWord val)
+void hs_atomicwrite16(StgWord x, StgWord val)
 {
   __atomic_store_n((StgWord16 *) x, (StgWord16) val, __ATOMIC_SEQ_CST);
 }
 
-extern void hs_atomicwrite32(StgWord x, StgWord val);
-void
-hs_atomicwrite32(StgWord x, StgWord val)
+void hs_atomicwrite32(StgWord x, StgWord val)
 {
   __atomic_store_n((StgWord32 *) x, (StgWord32) val, __ATOMIC_SEQ_CST);
 }
 
-extern void hs_atomicwrite64(StgWord x, StgWord64 val);
-void
-hs_atomicwrite64(StgWord x, StgWord64 val)
+void hs_atomicwrite64(StgWord x, StgWord64 val)
 {
   __atomic_store_n((StgWord64 *) x, (StgWord64) val, __ATOMIC_SEQ_CST);
 }
=====================================
libraries/ghc-internal/cbits/bitrev.c → rts/prim/bitrev.c
=====================================
@@ -27,7 +27,6 @@ For more information on how the below bit-twiddling functions came to be, see
 page.
 */
 
-extern StgWord hs_bitrev8(StgWord x);
 StgWord
 hs_bitrev8(StgWord x)
 {
@@ -37,7 +36,6 @@ hs_bitrev8(StgWord x)
   return x;
 }
 
-extern StgWord16 hs_bitrev16(StgWord16 x);
 StgWord16
 hs_bitrev16(StgWord16 x)
 {
@@ -48,7 +46,6 @@ hs_bitrev16(StgWord16 x)
   return x;
 }
 
-extern StgWord32 hs_bitrev32(StgWord32 x);
 StgWord32
 hs_bitrev32(StgWord32 x)
 {
@@ -60,7 +57,6 @@ hs_bitrev32(StgWord32 x)
   return x;
 }
 
-extern StgWord64 hs_bitrev64(StgWord64 x);
 StgWord64
 hs_bitrev64(StgWord64 x)
 {
=====================================
libraries/ghc-internal/cbits/bswap.c → rts/prim/bswap.c
=====================================
@@ -1,13 +1,11 @@
 #include "Rts.h"
 
-extern StgWord16 hs_bswap16(StgWord16 x);
 StgWord16
 hs_bswap16(StgWord16 x)
 {
   return ((x >> 8) | (x << 8));
 }
 
-extern StgWord32 hs_bswap32(StgWord32 x);
 StgWord32
 hs_bswap32(StgWord32 x)
 {
@@ -15,7 +13,6 @@ hs_bswap32(StgWord32 x)
           (x << 24) | ((x & 0xff00) << 8));
 }
 
-extern StgWord64 hs_bswap64(StgWord64 x);
 StgWord64
 hs_bswap64(StgWord64 x)
 {
=====================================
libraries/ghc-internal/cbits/clz.c → rts/prim/clz.c
=====================================
=====================================
libraries/ghc-internal/cbits/ctz.c → rts/prim/ctz.c
=====================================
=====================================
libraries/ghc-internal/cbits/int64x2minmax.c → rts/prim/int64x2minmax.c
=====================================
@@ -1,4 +1,5 @@
 #if defined(__SSE2__)
+#include "Rts.h"
 #include <stdint.h>
 #include <string.h>
 #include <emmintrin.h>
=====================================
libraries/ghc-internal/cbits/longlong.c → rts/prim/longlong.c
=====================================
=====================================
libraries/ghc-internal/cbits/mulIntMayOflo.c → rts/prim/mulIntMayOflo.c
=====================================
=====================================
libraries/ghc-internal/cbits/pdep.c → rts/prim/pdep.c
=====================================
=====================================
libraries/ghc-internal/cbits/pext.c → rts/prim/pext.c
=====================================
=====================================
libraries/ghc-internal/cbits/popcnt.c → rts/prim/popcnt.c
=====================================
@@ -13,14 +13,12 @@ static const unsigned char popcount_tab[] =
     3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
 };
 
-extern StgWord hs_popcnt8(StgWord x);
 StgWord
 hs_popcnt8(StgWord x)
 {
   return popcount_tab[(unsigned char)x];
 }
 
-extern StgWord hs_popcnt16(StgWord x);
 StgWord
 hs_popcnt16(StgWord x)
 {
@@ -28,7 +26,6 @@ hs_popcnt16(StgWord x)
       popcount_tab[(unsigned char)(x >> 8)];
 }
 
-extern StgWord hs_popcnt32(StgWord x);
 StgWord
 hs_popcnt32(StgWord x)
 {
@@ -38,7 +35,6 @@ hs_popcnt32(StgWord x)
       popcount_tab[(unsigned char)(x >> 24)];
 }
 
-extern StgWord hs_popcnt64(StgWord64 x);
 StgWord
 hs_popcnt64(StgWord64 x)
 {
@@ -54,7 +50,6 @@ hs_popcnt64(StgWord64 x)
 
 #if WORD_SIZE_IN_BITS == 32
 
-extern StgWord hs_popcnt(StgWord x);
 StgWord
 hs_popcnt(StgWord x)
 {
@@ -66,7 +61,6 @@ hs_popcnt(StgWord x)
 
 #elif WORD_SIZE_IN_BITS == 64
 
-extern StgWord hs_popcnt(StgWord x);
 StgWord
 hs_popcnt(StgWord x)
 {
=====================================
libraries/ghc-internal/cbits/vectorQuotRem.c → rts/prim/vectorQuotRem.c
=====================================
@@ -1,4 +1,5 @@
 #if defined(__SSE2__)
+#include "Rts.h"
 #include <stdint.h>
 #include <string.h>
 #include <emmintrin.h>
=====================================
libraries/ghc-internal/cbits/word2float.c → rts/prim/word2float.c
=====================================
@@ -1,13 +1,11 @@
 #include "Rts.h"
 
-extern StgFloat hs_word2float32(StgWord x);
 StgFloat
 hs_word2float32(StgWord x)
 {
   return x;
 }
 
-extern StgDouble hs_word2float64(StgWord x);
 StgDouble
 hs_word2float64(StgWord x)
 {
=====================================
rts/rts.cabal
=====================================
@@ -529,6 +529,19 @@ library
                  sm/Storage.c
                  sm/Sweep.c
                  fs.c
+                 prim/atomic.c
+                 prim/bitrev.c
+                 prim/bswap.c
+                 prim/clz.c
+                 prim/ctz.c
+                 prim/int64x2minmax.c
+                 prim/longlong.c
+                 prim/mulIntMayOflo.c
+                 prim/pdep.c
+                 prim/pext.c
+                 prim/popcnt.c
+                 prim/vectorQuotRem.c
+                 prim/word2float.c
                  -- I wish we had wildcards..., this would be:
                  -- *.c hooks/**/*.c sm/**/*.c eventlog/**/*.c linker/**/*.c
 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/fee3764abc1052dab3f30ce78587af7…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/fee3764abc1052dab3f30ce78587af7…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/T26166] 2 commits: Move code-gen aux symbols from ghc-internal to rts
                        
                        
by Rodrigo Mesquita (@alt-romes) 11 Oct '25
                    by Rodrigo Mesquita (@alt-romes) 11 Oct '25
11 Oct '25
                    
                        
Rodrigo Mesquita pushed to branch wip/T26166 at Glasgow Haskell Compiler / GHC
Commits:
fee3764a by Rodrigo Mesquita at 2025-10-11T08:07:23+01:00
Move code-gen aux symbols from ghc-internal to rts
These symbols were all previously defined in ghc-internal and made the
dependency structure awkward, where the rts may refer to some of these
symbols and had to work around that circular dependency the way
described in #26166.
Moreover, the code generator will produce code that uses these symbols!
Therefore, they should be available in the rts:
PRINCIPLE: If the code generator may produce code which uses this
symbol, then it should be defined in the rts rather than, say,
ghc-internal.
That said, the main motivation is towards fixing #26166.
Towards #26166. Pre-requisite of !14892
- - - - -
b550c607 by Ben Gamari at 2025-10-11T08:07:23+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(a)gmail.com>
- - - - -
45 changed files:
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/Linker/Dynamic.hs
- compiler/GHC/Linker/Static.hs
- hadrian/src/Settings/Packages.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/include/stg/Prim.h
- rts/posix/Signals.c
- libraries/ghc-internal/cbits/atomic.c → rts/prim/atomic.c
- libraries/ghc-internal/cbits/bitrev.c → rts/prim/bitrev.c
- libraries/ghc-internal/cbits/bswap.c → rts/prim/bswap.c
- libraries/ghc-internal/cbits/clz.c → rts/prim/clz.c
- libraries/ghc-internal/cbits/ctz.c → rts/prim/ctz.c
- libraries/ghc-internal/cbits/int64x2minmax.c → rts/prim/int64x2minmax.c
- libraries/ghc-internal/cbits/longlong.c → rts/prim/longlong.c
- libraries/ghc-internal/cbits/mulIntMayOflo.c → rts/prim/mulIntMayOflo.c
- libraries/ghc-internal/cbits/pdep.c → rts/prim/pdep.c
- libraries/ghc-internal/cbits/pext.c → rts/prim/pext.c
- libraries/ghc-internal/cbits/popcnt.c → rts/prim/popcnt.c
- libraries/ghc-internal/cbits/vectorQuotRem.c → rts/prim/vectorQuotRem.c
- libraries/ghc-internal/cbits/word2float.c → rts/prim/word2float.c
- − rts/rts.buildinfo.in
- rts/rts.cabal
- rts/wasm/JSFFI.c
- utils/deriveConstants/Main.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ca5d860ef9ff170bae878910efbdd5…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ca5d860ef9ff170bae878910efbdd5…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/marge_bot_batch_merge_job] 6 commits: rts/nonmoving: Fix comment spelling
                        
                        
by Marge Bot (@marge-bot) 10 Oct '25
                    by Marge Bot (@marge-bot) 10 Oct '25
10 Oct '25
                    
                        
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
c930c044 by Ben Gamari at 2025-10-10T19:22:16-04:00
rts/nonmoving: Fix comment spelling
- - - - -
1fd14915 by Ben Gamari at 2025-10-10T19:22:16-04:00
rts/nonmoving: Use atomic operations to update bd->flags
- - - - -
fda6eb29 by Ben Gamari at 2025-10-10T19:22:16-04:00
nonmoving: Use get_itbl instead of explicit loads
This is cleaner and also fixes unnecessary (and unsound) use of
`volatile`.
- - - - -
f187bbd5 by Ben Gamari at 2025-10-10T19:22:16-04:00
rts/Scav: Handle WHITEHOLEs in scavenge_one
`scavenge_one`, used to scavenge mutable list entries, may encounter
`WHITEHOLE`s when the non-moving GC is in use via two paths:
  1. when an MVAR is being marked concurrently
  2. when the object belongs to a chain of selectors being short-cutted.
Fixes #26204.
- - - - -
845a33b7 by Matthew Pickering at 2025-10-10T19:22:17-04:00
Add support for generating bytecode objects
This commit adds the `-fwrite-byte-code` option which makes GHC emit a
`.gbc` file which contains a serialised representation of bytecode.
The bytecode can be loaded by the compiler to avoid having to
reinterpret a module when using the bytecode interpreter (for example,
in GHCi).
There are also the new options:
* -gbcdir=<DIR>: Specify the directory to place the gbc files
* -gbcsuf=<suffix>: Specify the suffix for gbc files
The option `-fbyte-code-and-object-code` now implies
`-fwrite-byte-code`.
These performance tests fail due to https://github.com/haskell/directory/issues/204
-------------------------
Metric Increase:
    MultiComponentModules
    MultiLayerModules
    MultiComponentModulesRecomp
    MultiLayerModulesRecomp
    MultiLayerModulesTH_Make
    MultiLayerModulesTH_OneShot
    T13701
-------------------------
The bytecode serialisation part was implemented by Cheng Shao
Co-authored-by: Cheng Shao <terrorjack(a)type.dance>
- - - - -
7f9e8344 by Matthew Pickering at 2025-10-10T19:22:17-04:00
Revert "Add a perf test for #26425"
This test has a large memory spike currently, which makes the test
sensitive, since if you allocate a little more or less, the precise
location where GC happens shifts and you observe a different part of the
spike.
Andreas told me to revert the patch for now, and he will add it back
when he fixes the memory spike.
This reverts commit 41bdb16fd083110a06507248f648c507a2feb4af.
- - - - -
71 changed files:
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/ByteCode/Breakpoints.hs
- + compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Data/FlatBag.hs
- compiler/GHC/Data/SmallArray.hs
- compiler/GHC/Driver/Backend.hs
- compiler/GHC/Driver/Backpack.hs
- + compiler/GHC/Driver/ByteCode.hs
- compiler/GHC/Driver/Config/Finder.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Messager.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Types/SptEntry.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Finder/Types.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/Module/Location.hs
- compiler/GHC/Unit/Module/ModSummary.hs
- compiler/GHC/Unit/Module/WholeCoreBindings.hs
- compiler/GHC/Utils/Binary.hs
- compiler/ghc.cabal.in
- docs/users_guide/phases.rst
- docs/users_guide/separate_compilation.rst
- rts/include/rts/storage/Block.h
- rts/sm/NonMoving.c
- rts/sm/NonMovingMark.c
- rts/sm/Scav.c
- testsuite/tests/bytecode/T24634/T24634a.stdout
- testsuite/tests/bytecode/T24634/T24634b.stdout
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/driver/bytecode-object/A.hs
- + testsuite/tests/driver/bytecode-object/BytecodeForeign.c
- + testsuite/tests/driver/bytecode-object/BytecodeForeign.hs
- + testsuite/tests/driver/bytecode-object/BytecodeMain.hs
- + testsuite/tests/driver/bytecode-object/BytecodeTest.hs
- + testsuite/tests/driver/bytecode-object/Makefile
- + testsuite/tests/driver/bytecode-object/all.T
- + testsuite/tests/driver/bytecode-object/bytecode_object12.stderr
- + testsuite/tests/driver/bytecode-object/bytecode_object13.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object14.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object15.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object16.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object17.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object18.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object19.script
- + testsuite/tests/driver/bytecode-object/bytecode_object19.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object25.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object4.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object5.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object6.stdout
- testsuite/tests/driver/fat-iface/T22405/T22405.stdout
- testsuite/tests/driver/fat-iface/T22405/T22405b.stdout
- testsuite/tests/driver/fat-iface/fat011.stderr
- testsuite/tests/perf/compiler/Makefile
- + testsuite/tests/perf/compiler/MultiLayerModulesDefsGhciWithBytecodeFiles.script
- − testsuite/tests/perf/compiler/T26425.hs
- testsuite/tests/perf/compiler/all.T
- testsuite/tests/simplStg/should_compile/T22840.stderr
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/25e47f055754d7630092149d57e67c…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/25e47f055754d7630092149d57e67c…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/T26166] 2 commits: Move code-gen aux symbols from ghc-internal to rts
                        
                        
by Rodrigo Mesquita (@alt-romes) 10 Oct '25
                    by Rodrigo Mesquita (@alt-romes) 10 Oct '25
10 Oct '25
                    
                        
Rodrigo Mesquita pushed to branch wip/T26166 at Glasgow Haskell Compiler / GHC
Commits:
937fc3f0 by Rodrigo Mesquita at 2025-10-10T21:34:47+01:00
Move code-gen aux symbols from ghc-internal to rts
These symbols were all previously defined in ghc-internal and made the
dependency structure awkward, where the rts may refer to some of these
symbols and had to work around that circular dependency the way
described in #26166.
Moreover, the code generator will produce code that uses these symbols!
Therefore, they should be available in the rts:
PRINCIPLE: If the code generator may produce code which uses this
symbol, then it should be defined in the rts rather than, say,
ghc-internal.
That said, the main motivation is towards fixing #26166.
Towards #26166. Pre-requisite of !14892
- - - - -
ca5d860e by Ben Gamari at 2025-10-10T21:34:47+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(a)gmail.com>
- - - - -
45 changed files:
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/Linker/Dynamic.hs
- compiler/GHC/Linker/Static.hs
- hadrian/src/Settings/Packages.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/include/stg/Prim.h
- rts/posix/Signals.c
- libraries/ghc-internal/cbits/atomic.c → rts/prim/atomic.c
- libraries/ghc-internal/cbits/bitrev.c → rts/prim/bitrev.c
- libraries/ghc-internal/cbits/bswap.c → rts/prim/bswap.c
- libraries/ghc-internal/cbits/clz.c → rts/prim/clz.c
- libraries/ghc-internal/cbits/ctz.c → rts/prim/ctz.c
- libraries/ghc-internal/cbits/int64x2minmax.c → rts/prim/int64x2minmax.c
- libraries/ghc-internal/cbits/longlong.c → rts/prim/longlong.c
- libraries/ghc-internal/cbits/mulIntMayOflo.c → rts/prim/mulIntMayOflo.c
- libraries/ghc-internal/cbits/pdep.c → rts/prim/pdep.c
- libraries/ghc-internal/cbits/pext.c → rts/prim/pext.c
- libraries/ghc-internal/cbits/popcnt.c → rts/prim/popcnt.c
- libraries/ghc-internal/cbits/vectorQuotRem.c → rts/prim/vectorQuotRem.c
- libraries/ghc-internal/cbits/word2float.c → rts/prim/word2float.c
- − rts/rts.buildinfo.in
- rts/rts.cabal
- rts/wasm/JSFFI.c
- utils/deriveConstants/Main.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/33772e41809fd874a39e3445f45de3…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/33772e41809fd874a39e3445f45de3…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/marge_bot_batch_merge_job] 6 commits: rts/nonmoving: Fix comment spelling
                        
                        
by Marge Bot (@marge-bot) 10 Oct '25
                    by Marge Bot (@marge-bot) 10 Oct '25
10 Oct '25
                    
                        
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
bb94e232 by Ben Gamari at 2025-10-10T14:51:14-04:00
rts/nonmoving: Fix comment spelling
- - - - -
ad0fa9af by Ben Gamari at 2025-10-10T14:51:14-04:00
rts/nonmoving: Use atomic operations to update bd->flags
- - - - -
d36a9399 by Ben Gamari at 2025-10-10T14:51:15-04:00
nonmoving: Use get_itbl instead of explicit loads
This is cleaner and also fixes unnecessary (and unsound) use of
`volatile`.
- - - - -
ec91e1ae by Ben Gamari at 2025-10-10T14:51:15-04:00
rts/Scav: Handle WHITEHOLEs in scavenge_one
`scavenge_one`, used to scavenge mutable list entries, may encounter
`WHITEHOLE`s when the non-moving GC is in use via two paths:
  1. when an MVAR is being marked concurrently
  2. when the object belongs to a chain of selectors being short-cutted.
Fixes #26204.
- - - - -
4927a104 by Matthew Pickering at 2025-10-10T14:51:15-04:00
Add support for generating bytecode objects
This commit adds the `-fwrite-byte-code` option which makes GHC emit a
`.gbc` file which contains a serialised representation of bytecode.
The bytecode can be loaded by the compiler to avoid having to
reinterpret a module when using the bytecode interpreter (for example,
in GHCi).
There are also the new options:
* -gbcdir=<DIR>: Specify the directory to place the gbc files
* -gbcsuf=<suffix>: Specify the suffix for gbc files
The option `-fbyte-code-and-object-code` now implies
`-fwrite-byte-code`.
These performance tests fail due to https://github.com/haskell/directory/issues/204
-------------------------
Metric Increase:
    MultiComponentModules
    MultiLayerModules
    MultiComponentModulesRecomp
    MultiLayerModulesRecomp
    MultiLayerModulesTH_Make
    MultiLayerModulesTH_OneShot
    T13701
-------------------------
The bytecode serialisation part was implemented by Cheng Shao
Co-authored-by: Cheng Shao <terrorjack(a)type.dance>
- - - - -
25e47f05 by Matthew Pickering at 2025-10-10T14:51:15-04:00
Revert "Add a perf test for #26425"
This test has a large memory spike currently, which makes the test
sensitive, since if you allocate a little more or less, the precise
location where GC happens shifts and you observe a different part of the
spike.
Andreas told me to revert the patch for now, and he will add it back
when he fixes the memory spike.
This reverts commit 41bdb16fd083110a06507248f648c507a2feb4af.
- - - - -
71 changed files:
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/ByteCode/Breakpoints.hs
- + compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Data/FlatBag.hs
- compiler/GHC/Data/SmallArray.hs
- compiler/GHC/Driver/Backend.hs
- compiler/GHC/Driver/Backpack.hs
- + compiler/GHC/Driver/ByteCode.hs
- compiler/GHC/Driver/Config/Finder.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Messager.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Types/SptEntry.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Finder/Types.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/GHC/Unit/Module/Location.hs
- compiler/GHC/Unit/Module/ModSummary.hs
- compiler/GHC/Unit/Module/WholeCoreBindings.hs
- compiler/GHC/Utils/Binary.hs
- compiler/ghc.cabal.in
- docs/users_guide/phases.rst
- docs/users_guide/separate_compilation.rst
- rts/include/rts/storage/Block.h
- rts/sm/NonMoving.c
- rts/sm/NonMovingMark.c
- rts/sm/Scav.c
- testsuite/tests/bytecode/T24634/T24634a.stdout
- testsuite/tests/bytecode/T24634/T24634b.stdout
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/driver/bytecode-object/A.hs
- + testsuite/tests/driver/bytecode-object/BytecodeForeign.c
- + testsuite/tests/driver/bytecode-object/BytecodeForeign.hs
- + testsuite/tests/driver/bytecode-object/BytecodeMain.hs
- + testsuite/tests/driver/bytecode-object/BytecodeTest.hs
- + testsuite/tests/driver/bytecode-object/Makefile
- + testsuite/tests/driver/bytecode-object/all.T
- + testsuite/tests/driver/bytecode-object/bytecode_object12.stderr
- + testsuite/tests/driver/bytecode-object/bytecode_object13.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object14.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object15.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object16.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object17.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object18.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object19.script
- + testsuite/tests/driver/bytecode-object/bytecode_object19.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object25.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object4.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object5.stdout
- + testsuite/tests/driver/bytecode-object/bytecode_object6.stdout
- testsuite/tests/driver/fat-iface/T22405/T22405.stdout
- testsuite/tests/driver/fat-iface/T22405/T22405b.stdout
- testsuite/tests/driver/fat-iface/fat011.stderr
- testsuite/tests/perf/compiler/Makefile
- + testsuite/tests/perf/compiler/MultiLayerModulesDefsGhciWithBytecodeFiles.script
- − testsuite/tests/perf/compiler/T26425.hs
- testsuite/tests/perf/compiler/all.T
- testsuite/tests/simplStg/should_compile/T22840.stderr
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ca4c9a7813d0a57c17bfe4bb93fe44…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/ca4c9a7813d0a57c17bfe4bb93fe44…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/T26166] rts: Avoid static symbol references to ghc-internal
                        
                        
by Rodrigo Mesquita (@alt-romes) 10 Oct '25
                    by Rodrigo Mesquita (@alt-romes) 10 Oct '25
10 Oct '25
                    
                        
Rodrigo Mesquita pushed to branch wip/T26166 at Glasgow Haskell Compiler / GHC
Commits:
33772e41 by Ben Gamari at 2025-10-10T16:25:25+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(a)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
=====================================
@@ -250,6 +250,13 @@ linkBinary' staticLink logger tmpfs dflags unit_env o_files dep_units = do
                       ++ pkg_lib_path_opts
                       ++ extraLinkObj
                       ++ noteLinkObjs
+                      -- See Note [RTS/ghc-internal interface]
+                      -- (-u<sym> must come before -lghc-internal...!)
+                      ++ (if ghcInternalUnitId `elem` map unitId pkgs
+                          then [concat [ "-Wl,-u,"
+                                       , ['_' | platformLeadingUnderscore platform]
+                                       , "init_ghc_hs_iface" ]]
+                          else [])
                       ++ pkg_link_opts
                       ++ pkg_framework_opts
                       ++ (if platformOS platform == OSDarwin
=====================================
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/33772e41809fd874a39e3445f45de39…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/33772e41809fd874a39e3445f45de39…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/romes/26166-move-prims] Move code-gen aux symbols from ghc-internal to rts
                        
                        
by Rodrigo Mesquita (@alt-romes) 10 Oct '25
                    by Rodrigo Mesquita (@alt-romes) 10 Oct '25
10 Oct '25
                    
                        
Rodrigo Mesquita pushed to branch wip/romes/26166-move-prims at Glasgow Haskell Compiler / GHC
Commits:
0da0e150 by Rodrigo Mesquita at 2025-10-10T16:08:53+01:00
Move code-gen aux symbols from ghc-internal to rts
These symbols were all previously defined in ghc-internal and made the
dependency structure awkward, where the rts may refer to some of these
symbols and had to work around that circular dependency the way
described in #26166.
Moreover, the code generator will produce code that uses these symbols!
Therefore, they should be available in the rts:
PRINCIPLE: If the code generator may produce code which uses this
symbol, then it should be defined in the rts rather than, say,
ghc-internal.
That said, the main motivation is towards fixing #26166.
Towards #26166. Pre-requisite of !14892
- - - - -
19 changed files:
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- hadrian/src/Settings/Packages.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- rts/RtsSymbols.c
- rts/include/stg/Prim.h
- libraries/ghc-internal/cbits/atomic.c → rts/prim/atomic.c
- libraries/ghc-internal/cbits/bitrev.c → rts/prim/bitrev.c
- libraries/ghc-internal/cbits/bswap.c → rts/prim/bswap.c
- libraries/ghc-internal/cbits/clz.c → rts/prim/clz.c
- libraries/ghc-internal/cbits/ctz.c → rts/prim/ctz.c
- libraries/ghc-internal/cbits/int64x2minmax.c → rts/prim/int64x2minmax.c
- libraries/ghc-internal/cbits/longlong.c → rts/prim/longlong.c
- libraries/ghc-internal/cbits/mulIntMayOflo.c → rts/prim/mulIntMayOflo.c
- libraries/ghc-internal/cbits/pdep.c → rts/prim/pdep.c
- libraries/ghc-internal/cbits/pext.c → rts/prim/pext.c
- libraries/ghc-internal/cbits/popcnt.c → rts/prim/popcnt.c
- libraries/ghc-internal/cbits/vectorQuotRem.c → rts/prim/vectorQuotRem.c
- libraries/ghc-internal/cbits/word2float.c → rts/prim/word2float.c
- rts/rts.cabal
Changes:
=====================================
compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
=====================================
@@ -438,7 +438,7 @@ lower_MO_S_Shr lbl w0 [x, y] = case someWasmTypeFromCmmType (cmmBits w0) of
 lower_MO_S_Shr _ _ _ = panic "lower_MO_S_Shr: unreachable"
 
 -- | Lower a 'MO_MulMayOflo' operation. It's translated to a ccall to
--- @hs_mulIntMayOflo@ function in @ghc-prim/cbits/mulIntMayOflo@,
+-- @hs_mulIntMayOflo@ function in @rts/prim/mulIntMayOflo@,
 -- otherwise it's quite non-trivial to implement as inline assembly.
 lower_MO_MulMayOflo ::
   CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
=====================================
hadrian/src/Settings/Packages.hs
=====================================
@@ -287,9 +287,6 @@ ghcInternalArgs = package ghcInternal ? do
 
           , builder (Cabal Flags) ? flag NeedLibatomic `cabalFlag` "need-atomic"
 
-          , builder (Cc CompileC) ? (not <$> flag CcLlvmBackend) ?
-              input "**/cbits/atomic.c"  ? arg "-Wno-sync-nand"
-
           ]
 
 -- | RTS-specific command line arguments.
@@ -413,6 +410,9 @@ rtsPackageArgs = package rts ? do
 
           , input "**/RetainerProfile.c" ? flag CcLlvmBackend ?
             arg "-Wno-incompatible-pointer-types"
+
+          , input "**/prim/atomic.c"  ? (not <$> flag CcLlvmBackend) ?
+            arg "-Wno-sync-nand"
           ]
 
     mconcat
=====================================
libraries/ghc-internal/ghc-internal.cabal.in
=====================================
@@ -442,20 +442,7 @@ Library
           cbits/sysconf.c
           cbits/fs.c
           cbits/strerror.c
-          cbits/atomic.c
-          cbits/bswap.c
-          cbits/bitrev.c
-          cbits/clz.c
-          cbits/ctz.c
           cbits/debug.c
-          cbits/int64x2minmax.c
-          cbits/longlong.c
-          cbits/mulIntMayOflo.c
-          cbits/pdep.c
-          cbits/pext.c
-          cbits/popcnt.c
-          cbits/vectorQuotRem.c
-          cbits/word2float.c
           cbits/Stack_c.c
 
       cmm-sources:
=====================================
rts/RtsSymbols.c
=====================================
@@ -1016,6 +1016,116 @@ extern char **environ;
 #define RTS_FINI_ARRAY_SYMBOLS
 #endif
 
+#define SymI_HasProtoAllSizes(symbol)                \
+      SymI_HasProto(symbol##8)                       \
+      SymI_HasProto(symbol##16)                      \
+      SymI_HasProto(symbol##32)                      \
+      SymI_HasProto(symbol##64)
+
+#if !defined(arm_HOST_ARCH)
+#define RTS_ATOMICS_SYMBOLS                          \
+      SymI_HasProtoAllSizes(hs_atomic_add)           \
+      SymI_HasProtoAllSizes(hs_atomic_sub)           \
+      SymI_HasProtoAllSizes(hs_atomic_and)           \
+      SymI_HasProtoAllSizes(hs_atomic_nand)          \
+      SymI_HasProtoAllSizes(hs_atomic_or)            \
+      SymI_HasProtoAllSizes(hs_atomic_xor)           \
+      SymI_HasProtoAllSizes(hs_cmpxchg)              \
+      SymI_HasProtoAllSizes(hs_xchg)                 \
+      SymI_HasProtoAllSizes(hs_atomicread)           \
+      SymI_HasProtoAllSizes(hs_atomicwrite)
+#else
+// No atomics on arm32. See e9abcad4cc3
+#define RTS_ATOMICS_SYMBOLS
+#endif
+
+// In rts/longlong.c
+#if WORD_SIZE_IN_BITS < 64
+#define RTS_SYMBOLS_LONGLONG                        \
+      SymI_HasProto(hs_eq64)                        \
+      SymI_HasProto(hs_ne64)                        \
+      SymI_HasProto(hs_gtWord64)                    \
+      SymI_HasProto(hs_geWord64)                    \
+      SymI_HasProto(hs_ltWord64)                    \
+      SymI_HasProto(hs_leWord64)                    \
+      SymI_HasProto(hs_gtInt64)                     \
+      SymI_HasProto(hs_geInt64)                     \
+      SymI_HasProto(hs_ltInt64)                     \
+      SymI_HasProto(hs_leInt64)                     \
+      SymI_HasProto(hs_neg64)                       \
+      SymI_HasProto(hs_add64)                       \
+      SymI_HasProto(hs_sub64)                       \
+      SymI_HasProto(hs_mul64)                       \
+      SymI_HasProto(hs_remWord64)                   \
+      SymI_HasProto(hs_quotWord64)                  \
+      SymI_HasProto(hs_remInt64)                    \
+      SymI_HasProto(hs_quotInt64)                   \
+      SymI_HasProto(hs_and64)                       \
+      SymI_HasProto(hs_or64)                        \
+      SymI_HasProto(hs_xor64)                       \
+      SymI_HasProto(hs_not64)                       \
+      SymI_HasProto(hs_uncheckedShiftL64)           \
+      SymI_HasProto(hs_uncheckedShiftRL64)          \
+      SymI_HasProto(hs_uncheckedIShiftRA64)         \
+      SymI_HasProto(hs_intToInt64)                  \
+      SymI_HasProto(hs_int64ToInt)                  \
+      SymI_HasProto(hs_wordToWord64)                \
+      SymI_HasProto(hs_word64ToWord)
+#else
+#define RTS_SYMBOLS_LONGLONG
+#endif
+
+// rts/prim/vectorQuotRem.c and rts/prim/int64x2minmax
+#if defined(__SSE2__)
+#define RTS_SYMBOLS_VECTORQUOTREM                    \
+      SymI_HasProto(hs_quotInt8X16)                  \
+      SymI_HasProto(hs_quotInt16X8)                  \
+      SymI_HasProto(hs_quotInt32X4)                  \
+      SymI_HasProto(hs_quotInt64X2)                  \
+      SymI_HasProto(hs_quotWord8X16)                 \
+      SymI_HasProto(hs_quotWord16X8)                 \
+      SymI_HasProto(hs_quotWord32X4)                 \
+      SymI_HasProto(hs_quotWord64X2)                 \
+      SymI_HasProto(hs_remInt8X16)                   \
+      SymI_HasProto(hs_remInt16X8)                   \
+      SymI_HasProto(hs_remInt32X4)                   \
+      SymI_HasProto(hs_remInt64X2)                   \
+      SymI_HasProto(hs_remWord8X16)                  \
+      SymI_HasProto(hs_remWord16X8)                  \
+      SymI_HasProto(hs_remWord32X4)                  \
+      SymI_HasProto(hs_remWord64X2)
+#define RTS_SYMBOLS_INT64X2MINMAX                    \
+      SymI_HasProto(hs_minInt64X2)                   \
+      SymI_HasProto(hs_maxInt64X2)                   \
+      SymI_HasProto(hs_minWord64X2)                  \
+      SymI_HasProto(hs_maxWord64X2)
+#else
+#define RTS_SYMBOLS_VECTORQUOTREM
+#define RTS_SYMBOLS_INT64X2MINMAX
+#endif
+
+// Symbols on files in rts/prim/*
+#define RTS_SYMBOLS_PRIM                             \
+      RTS_ATOMICS_SYMBOLS                            \
+      RTS_SYMBOLS_INT64X2MINMAX                      \
+      RTS_SYMBOLS_LONGLONG                           \
+      RTS_SYMBOLS_VECTORQUOTREM                      \
+      SymI_HasProtoAllSizes(hs_bitrev)               \
+      SymI_HasProto(hs_bswap16)                      \
+      SymI_HasProto(hs_bswap32)                      \
+      SymI_HasProto(hs_bswap64)                      \
+      SymI_HasProtoAllSizes(hs_clz)                  \
+      SymI_HasProtoAllSizes(hs_ctz)                  \
+      SymI_HasProto(hs_mulIntMayOflo)                \
+      SymI_HasProtoAllSizes(hs_pdep)                 \
+      SymI_HasProtoAllSizes(hs_pext)                 \
+      SymI_HasProtoAllSizes(hs_pext)                 \
+      SymI_HasProto(hs_popcnt)                       \
+      SymI_HasProtoAllSizes(hs_popcnt)               \
+      SymI_HasProto(hs_word2float32)                 \
+      SymI_HasProto(hs_word2float64)
+
+
 /* entirely bogus claims about types of these symbols */
 #define SymI_NeedsProto(vvv)  extern void vvv(void);
 #define SymI_NeedsDataProto(vvv)  extern StgWord vvv[];
@@ -1038,6 +1148,7 @@ RTS_ARCH_LIBGCC_SYMBOLS
 RTS_FINI_ARRAY_SYMBOLS
 RTS_LIBFFI_SYMBOLS
 RTS_ARM_OUTLINE_ATOMIC_SYMBOLS
+RTS_SYMBOLS_PRIM
 
 #undef SymI_NeedsProto
 #undef SymI_NeedsDataProto
@@ -1081,6 +1192,7 @@ RtsSymbolVal rtsSyms[] = {
       RTS_FINI_ARRAY_SYMBOLS
       RTS_LIBFFI_SYMBOLS
       RTS_ARM_OUTLINE_ATOMIC_SYMBOLS
+      RTS_SYMBOLS_PRIM
       SymI_HasDataProto(nonmoving_write_barrier_enabled)
       { 0, 0, STRENGTH_NORMAL, SYM_TYPE_CODE } /* sentinel */
 };
=====================================
rts/include/stg/Prim.h
=====================================
@@ -2,7 +2,10 @@
  *
  * (c) The GHC Team, 2014-2014
  *
- * Declarations for C fallback primitives implemented by 'ghc-internal' package.
+ * This header collects the declarations for all the C fallback implementations
+ * used by the code generator to lower certain primops and sometimes by the RTS.
+ *
+ * Corresponding C files are in rts/prim/
  *
  * Do not #include this file directly: #include "Rts.h" instead.
  *
@@ -13,7 +16,7 @@
 
 #pragma once
 
-/* libraries/ghc-internal/cbits/atomic.c */
+/* rts/prim/atomic.c */
 StgWord hs_atomic_add8(StgWord x, StgWord val);
 StgWord hs_atomic_add16(StgWord x, StgWord val);
 StgWord hs_atomic_add32(StgWord x, StgWord val);
@@ -55,12 +58,12 @@ StgWord hs_xchg16(StgWord x, StgWord val);
 StgWord hs_xchg32(StgWord x, StgWord val);
 StgWord64 hs_xchg64(StgWord x, StgWord64 val);
 
-/* libraries/ghc-internal/cbits/bswap.c */
+/* rts/prim/bswap.c */
 StgWord16 hs_bswap16(StgWord16 x);
 StgWord32 hs_bswap32(StgWord32 x);
 StgWord64 hs_bswap64(StgWord64 x);
 
-/* libraries/ghc-internal/cbits/bitrev.c
+/* rts/prim/bitrev.c
 This was done as part of issue #16164.
 See Note [Bit reversal primop] for more details about the implementation.*/
 StgWord hs_bitrev8(StgWord x);
@@ -68,7 +71,7 @@ StgWord16 hs_bitrev16(StgWord16 x);
 StgWord32 hs_bitrev32(StgWord32 x);
 StgWord64 hs_bitrev64(StgWord64 x);
 
-/* libraries/ghc-internal/cbits/longlong.c */
+/* rts/prim/longlong.c */
 #if WORD_SIZE_IN_BITS < 64
 StgInt hs_eq64 (StgWord64 a, StgWord64 b);
 StgInt hs_ne64 (StgWord64 a, StgWord64 b);
@@ -101,41 +104,44 @@ StgWord64 hs_wordToWord64  (StgWord   w);
 StgWord   hs_word64ToWord  (StgWord64 w);
 #endif
 
-/* libraries/ghc-internal/cbits/pdep.c */
+/* rts/prim/pdep.c */
 StgWord64 hs_pdep64(StgWord64 src, StgWord64 mask);
 StgWord hs_pdep32(StgWord src, StgWord mask);
 StgWord hs_pdep16(StgWord src, StgWord mask);
 StgWord hs_pdep8(StgWord src, StgWord mask);
 
-/* libraries/ghc-internal/cbits/pext.c */
+/* rts/prim/pext.c */
 StgWord64 hs_pext64(StgWord64 src, StgWord64 mask);
 StgWord hs_pext32(StgWord src, StgWord mask);
 StgWord hs_pext16(StgWord src, StgWord mask);
 StgWord hs_pext8(StgWord src, StgWord mask);
 
-/* libraries/ghc-internal/cbits/popcnt.c */
+/* rts/prim/popcnt.c */
 StgWord hs_popcnt8(StgWord x);
 StgWord hs_popcnt16(StgWord x);
 StgWord hs_popcnt32(StgWord x);
 StgWord hs_popcnt64(StgWord64 x);
 StgWord hs_popcnt(StgWord x);
 
-/* libraries/ghc-internal/cbits/word2float.c */
+/* rts/prim/word2float.c */
 StgFloat hs_word2float32(StgWord x);
 StgDouble hs_word2float64(StgWord x);
 
-/* libraries/ghc-internal/cbits/clz.c */
+/* rts/prim/clz.c */
 StgWord hs_clz8(StgWord x);
 StgWord hs_clz16(StgWord x);
 StgWord hs_clz32(StgWord x);
 StgWord hs_clz64(StgWord64 x);
 
-/* libraries/ghc-internal/cbits/ctz.c */
+/* rts/prim/ctz.c */
 StgWord hs_ctz8(StgWord x);
 StgWord hs_ctz16(StgWord x);
 StgWord hs_ctz32(StgWord x);
 StgWord hs_ctz64(StgWord64 x);
 
+/* rts/prim/mulIntMayOflo.c */
+W_ hs_mulIntMayOflo(W_ a, W_ b);
+
 /* bitcasts, instead of creating a new C file we static inline these here. We
  * use __builtin_memcpy instead of memcpy from string.h to avoid function
  * prototype conflicts that occur in the C backend with the inclusion of
=====================================
libraries/ghc-internal/cbits/atomic.c → rts/prim/atomic.c
=====================================
@@ -12,90 +12,66 @@
 
 // FetchAddByteArrayOp_Int
 
-extern StgWord hs_atomic_add8(StgWord x, StgWord val);
-StgWord
-hs_atomic_add8(StgWord x, StgWord val)
+StgWord hs_atomic_add8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_add((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_add16(StgWord x, StgWord val);
-StgWord
-hs_atomic_add16(StgWord x, StgWord val)
+StgWord hs_atomic_add16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_add((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_add32(StgWord x, StgWord val);
-StgWord
-hs_atomic_add32(StgWord x, StgWord val)
+StgWord hs_atomic_add32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_add((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_add64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_add64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_add64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_add((volatile StgWord64 *) x, val);
 }
 
 // FetchSubByteArrayOp_Int
 
-extern StgWord hs_atomic_sub8(StgWord x, StgWord val);
-StgWord
-hs_atomic_sub8(StgWord x, StgWord val)
+StgWord hs_atomic_sub8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_sub((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_sub16(StgWord x, StgWord val);
-StgWord
-hs_atomic_sub16(StgWord x, StgWord val)
+StgWord hs_atomic_sub16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_sub((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_sub32(StgWord x, StgWord val);
-StgWord
-hs_atomic_sub32(StgWord x, StgWord val)
+StgWord hs_atomic_sub32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_sub((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_sub64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_sub64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_sub64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_sub((volatile StgWord64 *) x, val);
 }
 
 // FetchAndByteArrayOp_Int
 
-extern StgWord hs_atomic_and8(StgWord x, StgWord val);
-StgWord
-hs_atomic_and8(StgWord x, StgWord val)
+StgWord hs_atomic_and8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_and((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_and16(StgWord x, StgWord val);
-StgWord
-hs_atomic_and16(StgWord x, StgWord val)
+StgWord hs_atomic_and16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_and((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_and32(StgWord x, StgWord val);
-StgWord
-hs_atomic_and32(StgWord x, StgWord val)
+StgWord hs_atomic_and32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_and((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_and64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_and64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_and64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_and((volatile StgWord64 *) x, val);
 }
@@ -167,9 +143,7 @@ hs_atomic_and64(StgWord x, StgWord64 val)
 #pragma GCC diagnostic ignored "-Wsync-nand"
 #endif
 
-extern StgWord hs_atomic_nand8(StgWord x, StgWord val);
-StgWord
-hs_atomic_nand8(StgWord x, StgWord val)
+StgWord hs_atomic_nand8(StgWord x, StgWord val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord8 *) x, (StgWord8) val);
@@ -178,9 +152,7 @@ hs_atomic_nand8(StgWord x, StgWord val)
 #endif
 }
 
-extern StgWord hs_atomic_nand16(StgWord x, StgWord val);
-StgWord
-hs_atomic_nand16(StgWord x, StgWord val)
+StgWord hs_atomic_nand16(StgWord x, StgWord val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord16 *) x, (StgWord16) val);
@@ -189,9 +161,7 @@ hs_atomic_nand16(StgWord x, StgWord val)
 #endif
 }
 
-extern StgWord hs_atomic_nand32(StgWord x, StgWord val);
-StgWord
-hs_atomic_nand32(StgWord x, StgWord val)
+StgWord hs_atomic_nand32(StgWord x, StgWord val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord32 *) x, (StgWord32) val);
@@ -200,9 +170,7 @@ hs_atomic_nand32(StgWord x, StgWord val)
 #endif
 }
 
-extern StgWord64 hs_atomic_nand64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_nand64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_nand64(StgWord x, StgWord64 val)
 {
 #if USE_SYNC_FETCH_AND_NAND
   return __sync_fetch_and_nand((volatile StgWord64 *) x, val);
@@ -215,96 +183,72 @@ hs_atomic_nand64(StgWord x, StgWord64 val)
 
 // FetchOrByteArrayOp_Int
 
-extern StgWord hs_atomic_or8(StgWord x, StgWord val);
-StgWord
-hs_atomic_or8(StgWord x, StgWord val)
+StgWord hs_atomic_or8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_or((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_or16(StgWord x, StgWord val);
-StgWord
-hs_atomic_or16(StgWord x, StgWord val)
+StgWord hs_atomic_or16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_or((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_or32(StgWord x, StgWord val);
-StgWord
-hs_atomic_or32(StgWord x, StgWord val)
+StgWord hs_atomic_or32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_or((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_or64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_or64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_or64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_or((volatile StgWord64 *) x, val);
 }
 
 // FetchXorByteArrayOp_Int
 
-extern StgWord hs_atomic_xor8(StgWord x, StgWord val);
-StgWord
-hs_atomic_xor8(StgWord x, StgWord val)
+StgWord hs_atomic_xor8(StgWord x, StgWord val)
 {
   return __sync_fetch_and_xor((volatile StgWord8 *) x, (StgWord8) val);
 }
 
-extern StgWord hs_atomic_xor16(StgWord x, StgWord val);
-StgWord
-hs_atomic_xor16(StgWord x, StgWord val)
+StgWord hs_atomic_xor16(StgWord x, StgWord val)
 {
   return __sync_fetch_and_xor((volatile StgWord16 *) x, (StgWord16) val);
 }
 
-extern StgWord hs_atomic_xor32(StgWord x, StgWord val);
-StgWord
-hs_atomic_xor32(StgWord x, StgWord val)
+StgWord hs_atomic_xor32(StgWord x, StgWord val)
 {
   return __sync_fetch_and_xor((volatile StgWord32 *) x, (StgWord32) val);
 }
 
-extern StgWord64 hs_atomic_xor64(StgWord x, StgWord64 val);
-StgWord64
-hs_atomic_xor64(StgWord x, StgWord64 val)
+StgWord64 hs_atomic_xor64(StgWord x, StgWord64 val)
 {
   return __sync_fetch_and_xor((volatile StgWord64 *) x, val);
 }
 
 // CasByteArrayOp_Int
 
-extern StgWord hs_cmpxchg8(StgWord x, StgWord old, StgWord new);
-StgWord
-hs_cmpxchg8(StgWord x, StgWord old, StgWord new)
+StgWord hs_cmpxchg8(StgWord x, StgWord old, StgWord new)
 {
   StgWord8 expected = (StgWord8) old;
   __atomic_compare_exchange_n((StgWord8 *) x, &expected, (StgWord8) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
   return expected;
 }
 
-extern StgWord hs_cmpxchg16(StgWord x, StgWord old, StgWord new);
-StgWord
-hs_cmpxchg16(StgWord x, StgWord old, StgWord new)
+StgWord hs_cmpxchg16(StgWord x, StgWord old, StgWord new)
 {
   StgWord16 expected = (StgWord16) old;
   __atomic_compare_exchange_n((StgWord16 *) x, &expected, (StgWord16) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
   return expected;
 }
 
-extern StgWord hs_cmpxchg32(StgWord x, StgWord old, StgWord new);
-StgWord
-hs_cmpxchg32(StgWord x, StgWord old, StgWord new)
+StgWord hs_cmpxchg32(StgWord x, StgWord old, StgWord new)
 {
   StgWord32 expected = (StgWord32) old;
   __atomic_compare_exchange_n((StgWord32 *) x, &expected, (StgWord32) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
   return expected;
 }
 
-extern StgWord64 hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new);
-StgWord64
-hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new)
+StgWord64 hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new)
 {
   StgWord64 expected = (StgWord64) old;
   __atomic_compare_exchange_n((StgWord64 *) x, &expected, (StgWord64) new, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
@@ -313,31 +257,23 @@ hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new)
 
 // Atomic exchange operations
 
-extern StgWord hs_xchg8(StgWord x, StgWord val);
-StgWord
-hs_xchg8(StgWord x, StgWord val)
+StgWord hs_xchg8(StgWord x, StgWord val)
 {
   return (StgWord) __atomic_exchange_n((StgWord8 *) x, (StgWord8) val, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_xchg16(StgWord x, StgWord val);
-StgWord
-hs_xchg16(StgWord x, StgWord val)
+StgWord hs_xchg16(StgWord x, StgWord val)
 {
   return (StgWord) __atomic_exchange_n((StgWord16 *)x, (StgWord16) val, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_xchg32(StgWord x, StgWord val);
-StgWord
-hs_xchg32(StgWord x, StgWord val)
+StgWord hs_xchg32(StgWord x, StgWord val)
 {
   return (StgWord) __atomic_exchange_n((StgWord32 *) x, (StgWord32) val, __ATOMIC_SEQ_CST);
 }
 
 //GCC provides this even on 32bit, but StgWord is still 32 bits.
-extern StgWord64 hs_xchg64(StgWord x, StgWord64 val);
-StgWord64
-hs_xchg64(StgWord x, StgWord64 val)
+StgWord64 hs_xchg64(StgWord x, StgWord64 val)
 {
   return (StgWord64) __atomic_exchange_n((StgWord64 *) x, (StgWord64) val, __ATOMIC_SEQ_CST);
 }
@@ -352,30 +288,22 @@ hs_xchg64(StgWord x, StgWord64 val)
 // primitives which the GCC documentation claims "usually" implies a full
 // barrier.
 
-extern StgWord hs_atomicread8(StgWord x);
-StgWord
-hs_atomicread8(StgWord x)
+StgWord hs_atomicread8(StgWord x)
 {
   return __atomic_load_n((StgWord8 *) x, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_atomicread16(StgWord x);
-StgWord
-hs_atomicread16(StgWord x)
+StgWord hs_atomicread16(StgWord x)
 {
   return __atomic_load_n((StgWord16 *) x, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord hs_atomicread32(StgWord x);
-StgWord
-hs_atomicread32(StgWord x)
+StgWord hs_atomicread32(StgWord x)
 {
   return __atomic_load_n((StgWord32 *) x, __ATOMIC_SEQ_CST);
 }
 
-extern StgWord64 hs_atomicread64(StgWord x);
-StgWord64
-hs_atomicread64(StgWord x)
+StgWord64 hs_atomicread64(StgWord x)
 {
   return __atomic_load_n((StgWord64 *) x, __ATOMIC_SEQ_CST);
 }
@@ -384,30 +312,22 @@ hs_atomicread64(StgWord x)
 // Implies a full memory barrier (see compiler/GHC/Builtin/primops.txt.pp)
 // __ATOMIC_SEQ_CST: Full barrier (see hs_atomicread8 above).
 
-extern void hs_atomicwrite8(StgWord x, StgWord val);
-void
-hs_atomicwrite8(StgWord x, StgWord val)
+void hs_atomicwrite8(StgWord x, StgWord val)
 {
   __atomic_store_n((StgWord8 *) x, (StgWord8) val, __ATOMIC_SEQ_CST);
 }
 
-extern void hs_atomicwrite16(StgWord x, StgWord val);
-void
-hs_atomicwrite16(StgWord x, StgWord val)
+void hs_atomicwrite16(StgWord x, StgWord val)
 {
   __atomic_store_n((StgWord16 *) x, (StgWord16) val, __ATOMIC_SEQ_CST);
 }
 
-extern void hs_atomicwrite32(StgWord x, StgWord val);
-void
-hs_atomicwrite32(StgWord x, StgWord val)
+void hs_atomicwrite32(StgWord x, StgWord val)
 {
   __atomic_store_n((StgWord32 *) x, (StgWord32) val, __ATOMIC_SEQ_CST);
 }
 
-extern void hs_atomicwrite64(StgWord x, StgWord64 val);
-void
-hs_atomicwrite64(StgWord x, StgWord64 val)
+void hs_atomicwrite64(StgWord x, StgWord64 val)
 {
   __atomic_store_n((StgWord64 *) x, (StgWord64) val, __ATOMIC_SEQ_CST);
 }
=====================================
libraries/ghc-internal/cbits/bitrev.c → rts/prim/bitrev.c
=====================================
@@ -27,7 +27,6 @@ For more information on how the below bit-twiddling functions came to be, see
 page.
 */
 
-extern StgWord hs_bitrev8(StgWord x);
 StgWord
 hs_bitrev8(StgWord x)
 {
@@ -37,7 +36,6 @@ hs_bitrev8(StgWord x)
   return x;
 }
 
-extern StgWord16 hs_bitrev16(StgWord16 x);
 StgWord16
 hs_bitrev16(StgWord16 x)
 {
@@ -48,7 +46,6 @@ hs_bitrev16(StgWord16 x)
   return x;
 }
 
-extern StgWord32 hs_bitrev32(StgWord32 x);
 StgWord32
 hs_bitrev32(StgWord32 x)
 {
@@ -60,7 +57,6 @@ hs_bitrev32(StgWord32 x)
   return x;
 }
 
-extern StgWord64 hs_bitrev64(StgWord64 x);
 StgWord64
 hs_bitrev64(StgWord64 x)
 {
=====================================
libraries/ghc-internal/cbits/bswap.c → rts/prim/bswap.c
=====================================
@@ -1,13 +1,11 @@
 #include "Rts.h"
 
-extern StgWord16 hs_bswap16(StgWord16 x);
 StgWord16
 hs_bswap16(StgWord16 x)
 {
   return ((x >> 8) | (x << 8));
 }
 
-extern StgWord32 hs_bswap32(StgWord32 x);
 StgWord32
 hs_bswap32(StgWord32 x)
 {
@@ -15,7 +13,6 @@ hs_bswap32(StgWord32 x)
           (x << 24) | ((x & 0xff00) << 8));
 }
 
-extern StgWord64 hs_bswap64(StgWord64 x);
 StgWord64
 hs_bswap64(StgWord64 x)
 {
=====================================
libraries/ghc-internal/cbits/clz.c → rts/prim/clz.c
=====================================
=====================================
libraries/ghc-internal/cbits/ctz.c → rts/prim/ctz.c
=====================================
=====================================
libraries/ghc-internal/cbits/int64x2minmax.c → rts/prim/int64x2minmax.c
=====================================
=====================================
libraries/ghc-internal/cbits/longlong.c → rts/prim/longlong.c
=====================================
=====================================
libraries/ghc-internal/cbits/mulIntMayOflo.c → rts/prim/mulIntMayOflo.c
=====================================
=====================================
libraries/ghc-internal/cbits/pdep.c → rts/prim/pdep.c
=====================================
=====================================
libraries/ghc-internal/cbits/pext.c → rts/prim/pext.c
=====================================
=====================================
libraries/ghc-internal/cbits/popcnt.c → rts/prim/popcnt.c
=====================================
@@ -13,14 +13,12 @@ static const unsigned char popcount_tab[] =
     3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
 };
 
-extern StgWord hs_popcnt8(StgWord x);
 StgWord
 hs_popcnt8(StgWord x)
 {
   return popcount_tab[(unsigned char)x];
 }
 
-extern StgWord hs_popcnt16(StgWord x);
 StgWord
 hs_popcnt16(StgWord x)
 {
@@ -28,7 +26,6 @@ hs_popcnt16(StgWord x)
       popcount_tab[(unsigned char)(x >> 8)];
 }
 
-extern StgWord hs_popcnt32(StgWord x);
 StgWord
 hs_popcnt32(StgWord x)
 {
@@ -38,7 +35,6 @@ hs_popcnt32(StgWord x)
       popcount_tab[(unsigned char)(x >> 24)];
 }
 
-extern StgWord hs_popcnt64(StgWord64 x);
 StgWord
 hs_popcnt64(StgWord64 x)
 {
@@ -54,7 +50,6 @@ hs_popcnt64(StgWord64 x)
 
 #if WORD_SIZE_IN_BITS == 32
 
-extern StgWord hs_popcnt(StgWord x);
 StgWord
 hs_popcnt(StgWord x)
 {
@@ -66,7 +61,6 @@ hs_popcnt(StgWord x)
 
 #elif WORD_SIZE_IN_BITS == 64
 
-extern StgWord hs_popcnt(StgWord x);
 StgWord
 hs_popcnt(StgWord x)
 {
=====================================
libraries/ghc-internal/cbits/vectorQuotRem.c → rts/prim/vectorQuotRem.c
=====================================
=====================================
libraries/ghc-internal/cbits/word2float.c → rts/prim/word2float.c
=====================================
@@ -1,13 +1,11 @@
 #include "Rts.h"
 
-extern StgFloat hs_word2float32(StgWord x);
 StgFloat
 hs_word2float32(StgWord x)
 {
   return x;
 }
 
-extern StgDouble hs_word2float64(StgWord x);
 StgDouble
 hs_word2float64(StgWord x)
 {
=====================================
rts/rts.cabal
=====================================
@@ -529,6 +529,19 @@ library
                  sm/Storage.c
                  sm/Sweep.c
                  fs.c
+                 prim/atomic.c
+                 prim/bitrev.c
+                 prim/bswap.c
+                 prim/clz.c
+                 prim/ctz.c
+                 prim/int64x2minmax.c
+                 prim/longlong.c
+                 prim/mulIntMayOflo.c
+                 prim/pdep.c
+                 prim/pext.c
+                 prim/popcnt.c
+                 prim/vectorQuotRem.c
+                 prim/word2float.c
                  -- I wish we had wildcards..., this would be:
                  -- *.c hooks/**/*.c sm/**/*.c eventlog/**/*.c linker/**/*.c
 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0da0e150c3820494d6e5e0839c009b8…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0da0e150c3820494d6e5e0839c009b8…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/T26166] rts: Avoid static symbol references to ghc-internal
                        
                        
by Rodrigo Mesquita (@alt-romes) 10 Oct '25
                    by Rodrigo Mesquita (@alt-romes) 10 Oct '25
10 Oct '25
                    
                        
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(a)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/edbc124b3e7843fec26d957414c9fc6…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/edbc124b3e7843fec26d957414c9fc6…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [Git][ghc/ghc][wip/T26166] 2 commits: Move code-gen aux symbols from ghc-internal to rts
                        
                        
by Rodrigo Mesquita (@alt-romes) 10 Oct '25
                    by Rodrigo Mesquita (@alt-romes) 10 Oct '25
10 Oct '25
                    
                        
Rodrigo Mesquita pushed to branch wip/T26166 at Glasgow Haskell Compiler / GHC
Commits:
0da0e150 by Rodrigo Mesquita at 2025-10-10T16:08:53+01:00
Move code-gen aux symbols from ghc-internal to rts
These symbols were all previously defined in ghc-internal and made the
dependency structure awkward, where the rts may refer to some of these
symbols and had to work around that circular dependency the way
described in #26166.
Moreover, the code generator will produce code that uses these symbols!
Therefore, they should be available in the rts:
PRINCIPLE: If the code generator may produce code which uses this
symbol, then it should be defined in the rts rather than, say,
ghc-internal.
That said, the main motivation is towards fixing #26166.
Towards #26166. Pre-requisite of !14892
- - - - -
d3fed698 by Ben Gamari at 2025-10-10T16:08:54+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(a)gmail.com>
- - - - -
45 changed files:
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/Linker/Dynamic.hs
- compiler/GHC/Linker/Static.hs
- hadrian/src/Settings/Packages.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/include/stg/Prim.h
- rts/posix/Signals.c
- libraries/ghc-internal/cbits/atomic.c → rts/prim/atomic.c
- libraries/ghc-internal/cbits/bitrev.c → rts/prim/bitrev.c
- libraries/ghc-internal/cbits/bswap.c → rts/prim/bswap.c
- libraries/ghc-internal/cbits/clz.c → rts/prim/clz.c
- libraries/ghc-internal/cbits/ctz.c → rts/prim/ctz.c
- libraries/ghc-internal/cbits/int64x2minmax.c → rts/prim/int64x2minmax.c
- libraries/ghc-internal/cbits/longlong.c → rts/prim/longlong.c
- libraries/ghc-internal/cbits/mulIntMayOflo.c → rts/prim/mulIntMayOflo.c
- libraries/ghc-internal/cbits/pdep.c → rts/prim/pdep.c
- libraries/ghc-internal/cbits/pext.c → rts/prim/pext.c
- libraries/ghc-internal/cbits/popcnt.c → rts/prim/popcnt.c
- libraries/ghc-internal/cbits/vectorQuotRem.c → rts/prim/vectorQuotRem.c
- libraries/ghc-internal/cbits/word2float.c → rts/prim/word2float.c
- − rts/rts.buildinfo.in
- rts/rts.cabal
- rts/wasm/JSFFI.c
- utils/deriveConstants/Main.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b2a6c0b92c65e99258deeaf7070a8f…
-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b2a6c0b92c65e99258deeaf7070a8f…
You're receiving this email because of your account on gitlab.haskell.org.
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0