From 9745fcfbffb6434bacdec69082739c9e0229c6f2 Mon Sep 17 00:00:00 2001
From: Cheng Shao <terrorjack@type.dance>
Date: Tue, 1 Oct 2024 19:09:26 +0000
Subject: [PATCH] driver: add necessary link-time flags for wasm shared libs

This commit adds necessary link-time flags for wasm shared libs, see
added comments for detailed explanation.
---
 compiler/GHC/Linker/Dynamic.hs | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/compiler/GHC/Linker/Dynamic.hs b/compiler/GHC/Linker/Dynamic.hs
index 58f7a75f4d6..b8aedd90acf 100644
--- a/compiler/GHC/Linker/Dynamic.hs
+++ b/compiler/GHC/Linker/Dynamic.hs
@@ -32,6 +32,7 @@ linkDynLib :: Logger -> TmpFs -> DynFlags -> UnitEnv -> [String] -> [UnitId] ->
 linkDynLib logger tmpfs dflags0 unit_env o_files dep_packages
  = do
     let platform   = ue_platform unit_env
+        arch       = platformArch platform
         os         = platformOS platform
 
         -- This is a rather ugly hack to fix dynamically linked
@@ -80,8 +81,13 @@ linkDynLib logger tmpfs dflags0 unit_env o_files dep_packages
     --
     --   * if -flink-rts is used, we link with the rts.
     --
+    --   * on wasm we need to ensure libHSrts*.so is listed in
+    --   WASM_DYLINK_NEEDED, otherwise dyld can't load it.
+    --
+    --
     let pkgs_without_rts = filter ((/= rtsUnitId) . unitId) pkgs_with_rts
         pkgs
+         | ArchWasm32 <- arch      = pkgs_with_rts
          | OSMinGW32 <- os         = pkgs_with_rts
          | gopt Opt_LinkRts dflags = pkgs_with_rts
          | otherwise               = pkgs_without_rts
@@ -219,7 +225,8 @@ linkDynLib logger tmpfs dflags0 unit_env o_files dep_packages
                                 -- non-PIC intra-package-relocations for
                                 -- performance (where symbolic linking works)
                                 -- See Note [-Bsymbolic assumptions by GHC]
-                                ["-Wl,-Bsymbolic" | not unregisterised]
+                                -- wasm-ld accepts --Bsymbolic instead
+                                ["-Wl,-Bsymbolic" | not unregisterised && arch /= ArchWasm32 ]
 
             runLink logger tmpfs linker_config (
                     map Option verbFlags
@@ -232,7 +239,29 @@ linkDynLib logger tmpfs dflags0 unit_env o_files dep_packages
                  ++ map Option bsymbolicFlag
                     -- Set the library soname. We use -h rather than -soname as
                     -- Solaris 10 doesn't support the latter:
-                 ++ [ Option ("-Wl,-h," ++ takeFileName output_fn) ]
+                    -- wasm-ld only accepts -soname and it's of little use anyway
+                 ++ [ Option ("-Wl,-h," ++ takeFileName output_fn) | arch /= ArchWasm32 ]
+                    -- 1. On wasm, --Bsymbolic is an optimization, not
+                    --    a requirement. We build the wasi-sdk sysroot
+                    --    shared libs as well as all Haskell shared
+                    --    libs with --Bsymbolic, but dyld can handle
+                    --    shared libs without --Bsymbolic at
+                    --    link-time. Though there will be more
+                    --    imports/exports to slow things down.
+                    -- 2. --experimental-pic silences wasm-ld warnings
+                    --    that PIC is experimental.
+                    -- 3. --unresolved-symbols=import-dynamic turns
+                    --    unresolved symbols to GOT.mem/GOT.func/env
+                    --    imports, which can be gracefully handled by
+                    --    dyld as lazy bindings. Ideally we'd only
+                    --    enable this for rts since it forward
+                    --    references ghc-prim/ghc-internal, but too
+                    --    many Haskell packages would be rejected at
+                    --    link-time even if their code refers to
+                    --    something that will not be called at
+                    --    run-time in wasm, so enabling it in the
+                    --    driver is a more pragmatic solution.
+                 ++ [ Option "-Wl,--Bsymbolic,--experimental-pic,--unresolved-symbols=import-dynamic" | arch == ArchWasm32 ]
                  ++ extra_ld_inputs
                  ++ map Option lib_path_opts
                  ++ map Option pkg_lib_path_opts
-- 
GitLab