From d2b17f3258b4d9db1de89c872f1b7cee0a3f9b74 Mon Sep 17 00:00:00 2001 From: Cheng Shao <terrorjack@type.dance> Date: Tue, 26 Mar 2024 22:06:22 +0000 Subject: [PATCH] driver: force merge objects when building dynamic objects This patch forces the driver to always merge objects when building dynamic objects even when ar -L is supported. It is an oversight of !8887: original rationale of that patch is favoring the relatively cheap ar -L operation over object merging when ar -L is supported, which makes sense but only if we are building static objects! Omitting check for whether we are building dynamic objects will result in broken .so files with undefined reference errors at executable link time when building GHC with llvm-ar. Fixes #22210. --- compiler/GHC/Driver/Pipeline/Execute.hs | 26 +++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/compiler/GHC/Driver/Pipeline/Execute.hs b/compiler/GHC/Driver/Pipeline/Execute.hs index ca3bd9067f69..908422f54785 100644 --- a/compiler/GHC/Driver/Pipeline/Execute.hs +++ b/compiler/GHC/Driver/Pipeline/Execute.hs @@ -1040,13 +1040,22 @@ this is accomplished with the `ld -r` command. We rely on this for two ends: The command used for object linking is set using the -pgmlm and -optlm command-line options. -Sadly, the LLD linker that we use on Windows does not support the `-r` flag -needed to support object merging (see #21068). For this reason on Windows we do -not support GHCi objects. To deal with foreign stubs we build a static archive -of all of a module's object files instead merging them. Consequently, we can -end up producing `.o` files which are in fact static archives. However, -toolchains generally don't have a problem with this as they use file headers, -not the filename, to determine the nature of inputs. +However, `ld -r` is broken in some cases: + + * The LLD linker that we use on Windows does not support the `-r` + flag needed to support object merging (see #21068). For this reason + on Windows we do not support GHCi objects. + * `wasm-ld -r` is prohibitively slow, especially when handling large + input objects (e.g. profiled objects). + +In these cases, we bundle a module's own object file with its foreign +stub's object file, instead of merging them. Consequently, we can end +up producing `.o` files which are in fact static archives. This can +only work if `ar -L` is supported, so the archive `.o` files can be +properly added to the final static library. We must also take care not +to produce archive `.dyn_o` when building dynamic objects, otherwise +we end up with broken `.so` files when GHC is built with `llvm-ar` +(#22210). Note that this has somewhat non-obvious consequences when producing initializers and finalizers. See Note [Initializers and finalizers in Cmm] @@ -1072,7 +1081,7 @@ via gcc. -- | See Note [Object merging]. joinObjectFiles :: HscEnv -> [FilePath] -> FilePath -> IO () joinObjectFiles hsc_env o_files output_fn - | can_merge_objs && not dashLSupported = do + | can_merge_objs && (not dashLSupported || is_dyn) = do let toolSettings' = toolSettings dflags ldIsGnuLd = toolSettings_ldIsGnuLd toolSettings' ld_r args = GHC.SysTools.runMergeObjects (hsc_logger hsc_env) (hsc_tmpfs hsc_env) (hsc_dflags hsc_env) ( @@ -1100,6 +1109,7 @@ joinObjectFiles hsc_env o_files output_fn withAtomicRename output_fn $ \tmp_ar -> liftIO $ runAr logger dflags Nothing $ map Option $ ["qc" ++ dashL, tmp_ar] ++ o_files where + is_dyn = ways dflags `hasWay` WayDyn dashLSupported = sArSupportsDashL (settings dflags) dashL = if dashLSupported then "L" else "" can_merge_objs = isJust (pgm_lm (hsc_dflags hsc_env)) -- GitLab