Cheng Shao pushed to branch wip/wasm-dyld-pie at Glasgow Haskell Compiler / GHC
Commits:
-
91b6be10
by Julian Ospald at 2025-10-20T18:21:03-04:00
-
6c5269da
by Sven Tennie at 2025-10-20T18:21:44-04:00
-
3d305889
by Sven Tennie at 2025-10-20T18:21:44-04:00
-
647d3b9c
by Cheng Shao at 2025-10-24T13:13:48+02:00
-
a13ec8dd
by Cheng Shao at 2025-10-24T13:13:48+02:00
8 changed files:
- compiler/GHC/StgToJS/Linker/Linker.hs
- hadrian/src/Rules/Gmp.hs
- hadrian/src/Rules/Libffi.hs
- hadrian/src/Settings/Builders/Cabal.hs
- hadrian/src/Settings/Builders/Common.hs
- hadrian/src/Settings/Builders/DeriveConstants.hs
- hadrian/src/Settings/Builders/Hsc2Hs.hs
- utils/jsffi/dyld.mjs
Changes:
| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | {-# LANGUAGE TupleSections #-}
|
| 3 | 3 | {-# LANGUAGE LambdaCase #-}
|
| 4 | 4 | {-# LANGUAGE BlockArguments #-}
|
| 5 | +{-# LANGUAGE MultiWayIf #-}
|
|
| 5 | 6 | |
| 6 | 7 | -----------------------------------------------------------------------------
|
| 7 | 8 | -- |
|
| ... | ... | @@ -666,12 +667,19 @@ renderLinkerStats s = |
| 666 | 667 | |
| 667 | 668 | |
| 668 | 669 | getPackageArchives :: StgToJSConfig -> UnitEnv -> [UnitId] -> IO [FilePath]
|
| 669 | -getPackageArchives cfg unit_env units =
|
|
| 670 | - filterM doesFileExist [ ST.unpack p </> "lib" ++ ST.unpack l ++ profSuff <.> "a"
|
|
| 671 | - | u <- units
|
|
| 672 | - , p <- getInstalledPackageLibDirs ue_state u
|
|
| 673 | - , l <- getInstalledPackageHsLibs ue_state u
|
|
| 674 | - ]
|
|
| 670 | +getPackageArchives cfg unit_env units = do
|
|
| 671 | + fmap concat $ forM units $ \u -> do
|
|
| 672 | + let archives = [ ST.unpack p </> "lib" ++ ST.unpack l ++ profSuff <.> "a"
|
|
| 673 | + | p <- getInstalledPackageLibDirs ue_state u
|
|
| 674 | + , l <- getInstalledPackageHsLibs ue_state u
|
|
| 675 | + ]
|
|
| 676 | + foundArchives <- filterM doesFileExist archives
|
|
| 677 | + if | not (null archives)
|
|
| 678 | + , null foundArchives
|
|
| 679 | + -> do
|
|
| 680 | + throwGhcExceptionIO (InstallationError $ "Could not find any library archives for unit-id: " <> (renderWithContext (csContext cfg) $ ppr u))
|
|
| 681 | + | otherwise
|
|
| 682 | + -> pure foundArchives
|
|
| 675 | 683 | where
|
| 676 | 684 | ue_state = ue_homeUnitState unit_env
|
| 677 | 685 |
| ... | ... | @@ -11,7 +11,7 @@ import Target |
| 11 | 11 | import Utilities
|
| 12 | 12 | import Hadrian.BuildPath
|
| 13 | 13 | import Hadrian.Expression
|
| 14 | -import Settings.Builders.Common (cArgs, getStagedCCFlags)
|
|
| 14 | +import Settings.Builders.Common (getStagedCCFlags)
|
|
| 15 | 15 | |
| 16 | 16 | -- | Build in-tree GMP library objects (if GmpInTree flag is set) and return
|
| 17 | 17 | -- their paths.
|
| ... | ... | @@ -125,8 +125,7 @@ gmpRules = do |
| 125 | 125 | cFlags <-
|
| 126 | 126 | interpretInContext ctx $
|
| 127 | 127 | mconcat
|
| 128 | - [ cArgs
|
|
| 129 | - , getStagedCCFlags
|
|
| 128 | + [ getStagedCCFlags
|
|
| 130 | 129 | -- gmp symbols are only used by bignum logic in
|
| 131 | 130 | -- ghc-internal and shouldn't be exported by the
|
| 132 | 131 | -- ghc-internal shared library.
|
| ... | ... | @@ -130,17 +130,14 @@ fixLibffiMakefile top = |
| 130 | 130 | configureEnvironment :: Stage -> Action [CmdOption]
|
| 131 | 131 | configureEnvironment stage = do
|
| 132 | 132 | context <- libffiContext stage
|
| 133 | - cFlags <- interpretInContext context $ mconcat
|
|
| 134 | - [ cArgs
|
|
| 135 | - , getStagedCCFlags ]
|
|
| 136 | - ldFlags <- interpretInContext context ldArgs
|
|
| 133 | + cFlags <- interpretInContext context getStagedCCFlags
|
|
| 137 | 134 | sequence [ builderEnvironment "CC" $ Cc CompileC stage
|
| 138 | 135 | , builderEnvironment "CXX" $ Cc CompileC stage
|
| 139 | - , builderEnvironment "AR" (Ar Unpack stage)
|
|
| 136 | + , builderEnvironment "AR" $ Ar Unpack stage
|
|
| 140 | 137 | , builderEnvironment "NM" Nm
|
| 141 | 138 | , builderEnvironment "RANLIB" Ranlib
|
| 142 | 139 | , return . AddEnv "CFLAGS" $ unwords cFlags ++ " -w"
|
| 143 | - , return . AddEnv "LDFLAGS" $ unwords ldFlags ++ " -w" ]
|
|
| 140 | + , return . AddEnv "LDFLAGS" $ "-w" ]
|
|
| 144 | 141 | |
| 145 | 142 | -- Need the libffi archive and `trackAllow` all files in the build directory.
|
| 146 | 143 | -- See [Libffi indicating inputs].
|
| ... | ... | @@ -188,18 +188,16 @@ configureArgs cFlags' ldFlags' = do |
| 188 | 188 | values <- unwords <$> expr
|
| 189 | 189 | not (null values) ?
|
| 190 | 190 | arg ("--configure-option=" ++ key ++ "=" ++ values)
|
| 191 | - cFlags = mconcat [ remove ["-Werror"] cArgs
|
|
| 192 | - , getStagedCCFlags
|
|
| 191 | + cFlags = mconcat [ getStagedCCFlags
|
|
| 193 | 192 | -- See https://github.com/snowleopard/hadrian/issues/523
|
| 194 | 193 | , arg $ "-iquote"
|
| 195 | 194 | |
| 196 | 195 | , arg $ top -/- pkgPath pkg
|
| 197 | 196 | , cFlags'
|
| 198 | 197 | ]
|
| 199 | - ldFlags = ldArgs <> ldFlags'
|
|
| 200 | 198 | mconcat
|
| 201 | 199 | [ conf "CFLAGS" cFlags
|
| 202 | - , conf "LDFLAGS" ldFlags
|
|
| 200 | + , conf "LDFLAGS" ldFlags'
|
|
| 203 | 201 | , conf "--with-iconv-includes" $ arg =<< getSetting IconvIncludeDir
|
| 204 | 202 | , conf "--with-iconv-libraries" $ arg =<< getSetting IconvLibDir
|
| 205 | 203 | , conf "--with-gmp-includes" $ arg =<< getSetting GmpIncludeDir
|
| ... | ... | @@ -5,7 +5,7 @@ module Settings.Builders.Common ( |
| 5 | 5 | module Oracles.Setting,
|
| 6 | 6 | module Settings,
|
| 7 | 7 | module UserSettings,
|
| 8 | - cIncludeArgs, ldArgs, cArgs, cppArgs, cWarnings,
|
|
| 8 | + cIncludeArgs, cWarnings,
|
|
| 9 | 9 | packageDatabaseArgs, bootPackageDatabaseArgs,
|
| 10 | 10 | getStagedCCFlags, wayCcArgs
|
| 11 | 11 | ) where
|
| ... | ... | @@ -38,15 +38,6 @@ cIncludeArgs = do |
| 38 | 38 | , pure [ "-I" ++ pkgPath pkg -/- dir | dir <- incDirs ]
|
| 39 | 39 | , pure [ "-I" ++ unifyPath dir | dir <- depDirs ] ]
|
| 40 | 40 | |
| 41 | -ldArgs :: Args
|
|
| 42 | -ldArgs = mempty
|
|
| 43 | - |
|
| 44 | -cArgs :: Args
|
|
| 45 | -cArgs = mempty
|
|
| 46 | - |
|
| 47 | -cppArgs :: Args
|
|
| 48 | -cppArgs = mempty
|
|
| 49 | - |
|
| 50 | 41 | -- TODO: should be in a different file
|
| 51 | 42 | cWarnings :: Args
|
| 52 | 43 | cWarnings = mconcat
|
| ... | ... | @@ -40,8 +40,7 @@ includeCcArgs :: Args |
| 40 | 40 | includeCcArgs = do
|
| 41 | 41 | stage <- getStage
|
| 42 | 42 | rtsPath <- expr $ rtsBuildPath stage
|
| 43 | - mconcat [ cArgs
|
|
| 44 | - , cWarnings
|
|
| 43 | + mconcat [ cWarnings
|
|
| 45 | 44 | , prgFlags . ccProgram . tgtCCompiler <$> expr (targetStage Stage1)
|
| 46 | 45 | , queryTargetTarget tgtUnregisterised ? arg "-DUSE_MINIINTERPRETER"
|
| 47 | 46 | , arg "-Irts"
|
| ... | ... | @@ -50,7 +50,7 @@ getCFlags = do |
| 50 | 50 | autogen <- expr $ autogenPath context
|
| 51 | 51 | let cabalMacros = autogen -/- "cabal_macros.h"
|
| 52 | 52 | expr $ need [cabalMacros]
|
| 53 | - mconcat [ remove ["-O"] (cArgs <> getStagedCCFlags)
|
|
| 53 | + mconcat [ remove ["-O"] getStagedCCFlags
|
|
| 54 | 54 | -- Either "-E" is not part of the configured cpp args, or we can't add those args to invocations of things like this
|
| 55 | 55 | -- ROMES:TODO: , prgFlags . cppProgram . tgtCPreprocessor <$> getStagedTargetConfig
|
| 56 | 56 | , cIncludeArgs
|
| ... | ... | @@ -64,6 +64,5 @@ getCFlags = do |
| 64 | 64 | getLFlags :: Expr [String]
|
| 65 | 65 | getLFlags =
|
| 66 | 66 | mconcat [ prgFlags . ccLinkProgram . tgtCCompilerLink <$> getStagedTarget
|
| 67 | - , ldArgs
|
|
| 68 | 67 | , getContextData ldOpts
|
| 69 | 68 | , getContextData depLdOpts ] |
| ... | ... | @@ -834,6 +834,27 @@ class DyLD { |
| 834 | 834 | );
|
| 835 | 835 | }
|
| 836 | 836 | |
| 837 | + // Both wasi implementations we use provide
|
|
| 838 | + // wasi.initialize(instance) to initialize a wasip1 reactor
|
|
| 839 | + // module. However, instance does not really need to be a
|
|
| 840 | + // WebAssembly.Instance object; the wasi implementations only need
|
|
| 841 | + // to access instance.exports.memory for the wasi syscalls to
|
|
| 842 | + // work.
|
|
| 843 | + //
|
|
| 844 | + // Given we'll reuse the same wasi object across different
|
|
| 845 | + // WebAssembly.Instance objects anyway and
|
|
| 846 | + // wasi.initialize(instance) can't be called more than once, we
|
|
| 847 | + // use this simple trick and pass a fake instance object that
|
|
| 848 | + // contains just enough info for the wasi implementation to
|
|
| 849 | + // initialize its internal state. Later when we load each wasm
|
|
| 850 | + // shared library, we can just manually invoke their
|
|
| 851 | + // initialization functions.
|
|
| 852 | + this.#wasi.initialize({
|
|
| 853 | + exports: {
|
|
| 854 | + memory: this.#memory,
|
|
| 855 | + },
|
|
| 856 | + });
|
|
| 857 | + |
|
| 837 | 858 | // Keep this in sync with rts/wasm/Wasm.S!
|
| 838 | 859 | for (let i = 1; i <= 10; ++i) {
|
| 839 | 860 | this.#regs[`__R${i}`] = new WebAssembly.Global({
|
| ... | ... | @@ -930,10 +951,15 @@ class DyLD { |
| 930 | 951 | async loadDLLs(packed) {
|
| 931 | 952 | // Normalize input to an array of strings. When called from Haskell
|
| 932 | 953 | // we pass a single JSString containing NUL-separated paths.
|
| 933 | - const paths = (typeof packed === "string"
|
|
| 934 | - ? (packed.length === 0 ? [] : packed.split("\0"))
|
|
| 935 | - : [packed] // tolerate an accidental single path object
|
|
| 936 | - ).filter((s) => s.length > 0).reverse();
|
|
| 954 | + const paths = (
|
|
| 955 | + typeof packed === "string"
|
|
| 956 | + ? packed.length === 0
|
|
| 957 | + ? []
|
|
| 958 | + : packed.split("\0")
|
|
| 959 | + : [packed]
|
|
| 960 | + ) // tolerate an accidental single path object
|
|
| 961 | + .filter((s) => s.length > 0)
|
|
| 962 | + .reverse();
|
|
| 937 | 963 | |
| 938 | 964 | // Compute a single downsweep plan for the whole batch.
|
| 939 | 965 | // Note: #downsweep mutates #loadedSos to break cycles and dedup.
|
| ... | ... | @@ -1154,22 +1180,6 @@ class DyLD { |
| 1154 | 1180 | throw new Error(`cannot handle export ${k} ${v}`);
|
| 1155 | 1181 | }
|
| 1156 | 1182 | |
| 1157 | - // We call wasi.initialize when loading libc.so, then reuse the
|
|
| 1158 | - // wasi instance globally. When loading later .so files, just
|
|
| 1159 | - // manually invoke _initialize().
|
|
| 1160 | - if (soname === "libc.so") {
|
|
| 1161 | - instance.exports.__wasm_apply_data_relocs();
|
|
| 1162 | - // wasm-ld forbits --export-memory with --shared, I don't know
|
|
| 1163 | - // why but this is sufficient to make things work
|
|
| 1164 | - this.#wasi.initialize({
|
|
| 1165 | - exports: {
|
|
| 1166 | - memory: this.#memory,
|
|
| 1167 | - _initialize: instance.exports._initialize,
|
|
| 1168 | - },
|
|
| 1169 | - });
|
|
| 1170 | - continue;
|
|
| 1171 | - }
|
|
| 1172 | - |
|
| 1173 | 1183 | // See
|
| 1174 | 1184 | // https://gitlab.haskell.org/haskell-wasm/llvm-project/-/blob/release/21.x/lld/wasm/Writer.cpp#L1451,
|
| 1175 | 1185 | // __wasm_apply_data_relocs is now optional so only call it if
|
| ... | ... | @@ -1180,7 +1190,7 @@ class DyLD { |
| 1180 | 1190 | // been called upon instantiation, see
|
| 1181 | 1191 | // Writer::createStartFunction().
|
| 1182 | 1192 | if (instance.exports.__wasm_apply_data_relocs) {
|
| 1183 | - instance.exports.__wasm_apply_data_relocs();
|
|
| 1193 | + instance.exports.__wasm_apply_data_relocs();
|
|
| 1184 | 1194 | }
|
| 1185 | 1195 | |
| 1186 | 1196 | instance.exports._initialize();
|