diff --git a/compiler/GHC/Driver/Session.hs b/compiler/GHC/Driver/Session.hs
index 0dfe13801ad98f92010bd5bb8a44a6625bf16fef..352a344dd49b88922deff3c0e2669c9233dd1c4e 100644
--- a/compiler/GHC/Driver/Session.hs
+++ b/compiler/GHC/Driver/Session.hs
@@ -126,6 +126,7 @@ module GHC.Driver.Session (
         sTargetPlatformString,
         sGhcWithInterpreter,
         sLibFFI,
+        sTargetRTSLinkerOnlySupportsSharedLibs,
         GhcNameVersion(..),
         FileSettings(..),
         PlatformMisc(..),
diff --git a/compiler/GHC/Platform.hs b/compiler/GHC/Platform.hs
index b245af5f8cd5ac3b2096534ff538192a954351bf..9020da85822bdf8949ec784d5b193766ac4165c5 100644
--- a/compiler/GHC/Platform.hs
+++ b/compiler/GHC/Platform.hs
@@ -287,6 +287,7 @@ data PlatformMisc = PlatformMisc
   , platformMisc_ghcWithInterpreter   :: Bool
   , platformMisc_libFFI               :: Bool
   , platformMisc_llvmTarget           :: String
+  , platformMisc_targetRTSLinkerOnlySupportsSharedLibs :: Bool
   }
 
 platformSOName :: Platform -> FilePath -> FilePath
diff --git a/compiler/GHC/Settings.hs b/compiler/GHC/Settings.hs
index 2e69c261625b89771a8df9750c2078559fa7f68f..1794d01e05d326f435f32f80633c370e76c48e20 100644
--- a/compiler/GHC/Settings.hs
+++ b/compiler/GHC/Settings.hs
@@ -59,6 +59,7 @@ module GHC.Settings
   , sTargetPlatformString
   , sGhcWithInterpreter
   , sLibFFI
+  , sTargetRTSLinkerOnlySupportsSharedLibs
   ) where
 
 import GHC.Prelude
@@ -273,3 +274,6 @@ sGhcWithInterpreter :: Settings -> Bool
 sGhcWithInterpreter = platformMisc_ghcWithInterpreter . sPlatformMisc
 sLibFFI :: Settings -> Bool
 sLibFFI = platformMisc_libFFI . sPlatformMisc
+
+sTargetRTSLinkerOnlySupportsSharedLibs :: Settings -> Bool
+sTargetRTSLinkerOnlySupportsSharedLibs = platformMisc_targetRTSLinkerOnlySupportsSharedLibs . sPlatformMisc
diff --git a/compiler/GHC/Settings/IO.hs b/compiler/GHC/Settings/IO.hs
index 9b13e19fbd3665ab079e1f07e9cd4212d4cde46c..7938bcad0ffe7999d421bfff3ac0a54666c47d76 100644
--- a/compiler/GHC/Settings/IO.hs
+++ b/compiler/GHC/Settings/IO.hs
@@ -151,6 +151,7 @@ initSettings top_dir = do
 
   let iserv_prog = libexec "ghc-iserv"
 
+  targetRTSLinkerOnlySupportsSharedLibs <- getBooleanSetting "target RTS linker only supports shared libraries"
   ghcWithInterpreter <- getBooleanSetting "Use interpreter"
   useLibFFI <- getBooleanSetting "Use LibFFI"
 
@@ -220,6 +221,7 @@ initSettings top_dir = do
       , platformMisc_ghcWithInterpreter = ghcWithInterpreter
       , platformMisc_libFFI = useLibFFI
       , platformMisc_llvmTarget = llvmTarget
+      , platformMisc_targetRTSLinkerOnlySupportsSharedLibs = targetRTSLinkerOnlySupportsSharedLibs
       }
 
     , sRawSettings    = settingsList
diff --git a/hadrian/bindist/Makefile b/hadrian/bindist/Makefile
index f5571b28c68ed90457312b98ea63d40be920d250..9ac474680a4dc030aabb55cf1e7a40c6d4871b6b 100644
--- a/hadrian/bindist/Makefile
+++ b/hadrian/bindist/Makefile
@@ -127,6 +127,7 @@ lib/settings : config.mk
 	@echo ',("LLVM llvm-as command", "$(SettingsLlvmAsCommand)")' >> $@
 	@echo ',("Use inplace MinGW toolchain", "$(SettingsUseDistroMINGW)")' >> $@
 	@echo
+	@echo ',("target RTS linker only supports shared libraries", "$(TargetRTSLinkerOnlySupportsSharedLibs)")' >> $@
 	@echo ',("Use interpreter", "$(GhcWithInterpreter)")' >> $@
 	@echo ',("Support SMP", "$(GhcWithSMP)")' >> $@
 	@echo ',("RTS ways", "$(GhcRTSWays)")' >> $@
diff --git a/hadrian/bindist/config.mk.in b/hadrian/bindist/config.mk.in
index f3ef11ef1cbed6ea8fc0e23a7360629e45739da2..ad3cfca81906b22e7e3c854d7f6c1c35aefab565 100644
--- a/hadrian/bindist/config.mk.in
+++ b/hadrian/bindist/config.mk.in
@@ -149,6 +149,12 @@ endif
 # `GhcUnregisterised` mode doesn't allow that.
 GhcWithSMP := $(strip $(if $(filter YESNO, $(ArchSupportsSMP)$(GhcUnregisterised)),YES,NO))
 
+ifeq "$(TargetArch_CPP)" "wasm32"
+TargetRTSLinkerOnlySupportsSharedLibs=YES
+else
+TargetRTSLinkerOnlySupportsSharedLibs=NO
+endif
+
 # Whether to include GHCi in the compiler.  Depends on whether the RTS linker
 # has support for this OS/ARCH combination.
 OsSupportsGHCi=$(strip $(patsubst $(TargetOS_CPP), YES, $(findstring $(TargetOS_CPP), mingw32 linux solaris2 freebsd dragonfly netbsd openbsd darwin kfreebsdgnu)))
@@ -231,4 +237,3 @@ SettingsLlcCommand = @SettingsLlcCommand@
 SettingsOptCommand = @SettingsOptCommand@
 SettingsLlvmAsCommand = @SettingsLlvmAsCommand@
 SettingsUseDistroMINGW = @SettingsUseDistroMINGW@
-
diff --git a/hadrian/src/Oracles/Flag.hs b/hadrian/src/Oracles/Flag.hs
index 98784c5525aac7035ef0e792c0f88ba5f3131d18..af4e268fb85d365f8f3e5d0e7f725058fe69b6c8 100644
--- a/hadrian/src/Oracles/Flag.hs
+++ b/hadrian/src/Oracles/Flag.hs
@@ -4,6 +4,7 @@ module Oracles.Flag (
     Flag (..), flag, getFlag,
     platformSupportsSharedLibs,
     platformSupportsGhciObjects,
+    targetRTSLinkerOnlySupportsSharedLibs,
     targetSupportsThreadedRts,
     targetSupportsSMP,
     useLibffiForAdjustors,
@@ -76,7 +77,28 @@ getFlag = expr . flag
 -- when appropriate).
 platformSupportsGhciObjects :: Action Bool
 -- FIXME: The name of the function is not entirely clear about which platform, it would be better named targetSupportsGhciObjects
-platformSupportsGhciObjects = isJust <$> queryTargetTarget tgtMergeObjs
+platformSupportsGhciObjects = do
+    has_merge_objs <- isJust <$> queryTargetTarget tgtMergeObjs
+    only_shared_libs <- targetRTSLinkerOnlySupportsSharedLibs
+    pure $ has_merge_objs && not only_shared_libs
+
+-- | Does the target RTS linker only support loading shared libraries?
+-- If true, this has several implications:
+-- 1. The GHC driver must not do loadArchive/loadObj etc and must
+--    always do loadDLL, regardless of whether host GHC is dynamic or
+--    not.
+-- 2. The GHC driver will always enable -dynamic-too when compiling
+--    vanilla way with TH codegen requirement.
+-- 3. ghci will always enforce dynamic ways even if -dynamic or
+--    -dynamic-too is not explicitly passed.
+-- 4. Cabal must not build ghci objects since it's not supported by
+--    the target.
+-- 5. The testsuite driver will use dyn way for TH/ghci tests even
+--    when host GHC is static.
+-- 6. TH/ghci doesn't work if stage1 is built without shared libraries
+--    (e.g. quickest/fully_static).
+targetRTSLinkerOnlySupportsSharedLibs :: Action Bool
+targetRTSLinkerOnlySupportsSharedLibs = anyTargetArch [ ArchWasm32 ]
 
 arSupportsDashL :: Stage -> Action Bool
 arSupportsDashL stage = Toolchain.arSupportsDashL . tgtAr <$> targetStage stage
diff --git a/hadrian/src/Oracles/TestSettings.hs b/hadrian/src/Oracles/TestSettings.hs
index 98da420fb33558eedcba67f46af8e9a169332b1c..76bf389f2320c4e83ba30fac325495038b3898cb 100644
--- a/hadrian/src/Oracles/TestSettings.hs
+++ b/hadrian/src/Oracles/TestSettings.hs
@@ -31,6 +31,7 @@ data TestSetting = TestHostOS
                  | TestGhcWithNativeCodeGen
                  | TestGhcWithInterpreter
                  | TestGhcCrossCompiling
+                 | TestRTSLinkerForceDyn
                  | TestGhcWithRtsLinker
                  | TestGhcUnregisterised
                  | TestGhcTablesNextToCode
@@ -63,6 +64,7 @@ testSetting key = do
         TestGhcWithNativeCodeGen  -> "GhcWithNativeCodeGen"
         TestGhcWithInterpreter    -> "GhcWithInterpreter"
         TestGhcCrossCompiling     -> "CrossCompiling"
+        TestRTSLinkerForceDyn     -> "TargetRTSLinkerOnlySupportsSharedLibs"
         TestGhcWithRtsLinker      -> "GhcWithRtsLinker"
         TestGhcUnregisterised     -> "GhcUnregisterised"
         TestGhcTablesNextToCode   -> "GhcTablesNextToCode"
diff --git a/hadrian/src/Rules/Generate.hs b/hadrian/src/Rules/Generate.hs
index 7c5b3452753bd8bda56f63242602fd83d9d5eaab..91b464eb535f544534692fbc666cedc448271ac9 100644
--- a/hadrian/src/Rules/Generate.hs
+++ b/hadrian/src/Rules/Generate.hs
@@ -438,6 +438,7 @@ generateSettings = do
         , ("LLVM llvm-as command", expr $ settingsFileSetting ToolchainSetting_LlvmAsCommand)
         , ("Use inplace MinGW toolchain", expr $ settingsFileSetting ToolchainSetting_DistroMinGW)
 
+        , ("target RTS linker only supports shared libraries", expr $ yesNo <$> targetRTSLinkerOnlySupportsSharedLibs)
         , ("Use interpreter", expr $ yesNo <$> ghcWithInterpreter)
         , ("Support SMP", expr $ yesNo <$> targetSupportsSMP)
         , ("RTS ways", unwords . map show . Set.toList <$> getRtsWays)
diff --git a/hadrian/src/Settings/Builders/RunTest.hs b/hadrian/src/Settings/Builders/RunTest.hs
index 9f90c30328cafeb0d2ec2a55ca1634b28d31fd1d..8d47882f1cdd5b720af92c1fe9f4bd4434eb533a 100644
--- a/hadrian/src/Settings/Builders/RunTest.hs
+++ b/hadrian/src/Settings/Builders/RunTest.hs
@@ -68,6 +68,7 @@ data TestCompilerArgs = TestCompilerArgs{
  ,   withNativeCodeGen :: Bool
  ,   withInterpreter   :: Bool
  ,   cross             :: Bool
+ ,   interpForceDyn    :: Bool
  ,   unregisterised    :: Bool
  ,   tables_next_to_code :: Bool
  ,   targetWithSMP       :: Bool  -- does the target support SMP
@@ -103,6 +104,7 @@ inTreeCompilerArgs stg = do
     -- have different values? Currently not possible to express.
     leadingUnderscore   <- queryTargetTarget tgtSymbolsHaveLeadingUnderscore
     withInterpreter     <- ghcWithInterpreter
+    interpForceDyn      <- targetRTSLinkerOnlySupportsSharedLibs
     unregisterised      <- queryTargetTarget tgtUnregisterised
     tables_next_to_code <- queryTargetTarget tgtTablesNextToCode
     targetWithSMP       <- targetSupportsSMP
@@ -160,6 +162,7 @@ outOfTreeCompilerArgs = do
     withNativeCodeGen   <- getBooleanSetting TestGhcWithNativeCodeGen
     withInterpreter     <- getBooleanSetting TestGhcWithInterpreter
     cross               <- getBooleanSetting TestGhcCrossCompiling
+    interpForceDyn      <- getBooleanSetting TestRTSLinkerForceDyn
     unregisterised      <- getBooleanSetting TestGhcUnregisterised
     tables_next_to_code <- getBooleanSetting TestGhcTablesNextToCode
     targetWithSMP       <- targetSupportsSMP
@@ -277,6 +280,7 @@ runTestBuilderArgs = builder Testsuite ? do
 
             , arg "-e", arg $ "config.have_interp=" ++ show withInterpreter
             , arg "-e", arg $ "config.cross=" ++ show cross
+            , arg "-e", arg $ "config.interp_force_dyn=" ++ show interpForceDyn
             , arg "-e", arg $ "config.unregisterised=" ++ show unregisterised
             , arg "-e", arg $ "config.tables_next_to_code=" ++ show tables_next_to_code
 
diff --git a/testsuite/driver/testglobals.py b/testsuite/driver/testglobals.py
index b70937d1f5c18905bf3d8df74aa18b91579435b5..726ea6359f444cb9ee44a0afee3e3175c0aba7a6 100644
--- a/testsuite/driver/testglobals.py
+++ b/testsuite/driver/testglobals.py
@@ -132,6 +132,9 @@ class TestConfig:
 
         # Are we cross-compiling?
         self.cross = False
+        
+        # Does the RTS linker only support loading shared libraries?
+        self.interp_force_dyn = False
 
         # Do we have RTS linker?
         self.have_RTS_linker = False
diff --git a/testsuite/ghc-config/ghc-config.hs b/testsuite/ghc-config/ghc-config.hs
index c50090240ad343f3d58234b1f4d3d413049216cc..95f58d06789ae5e0665d004c5a2712267e732c6d 100644
--- a/testsuite/ghc-config/ghc-config.hs
+++ b/testsuite/ghc-config/ghc-config.hs
@@ -29,6 +29,7 @@ main = do
   getGhcFieldOrFail fields "GhcRTSWays" "RTS ways"
   getGhcFieldOrFail fields "GhcLibdir" "LibDir"
   getGhcFieldOrFail fields "GhcGlobalPackageDb" "Global Package DB"
+  getGhcFieldOrDefault fields "TargetRTSLinkerOnlySupportsSharedLibs" "target RTS linker only supports shared libraries" "NO"
   getGhcFieldOrDefault fields "GhcDynamic" "GHC Dynamic" "NO"
   getGhcFieldOrDefault fields "GhcProfiled" "GHC Profiled" "NO"
   getGhcFieldOrDefault fields "LeadingUnderscore" "Leading underscore" "NO"