summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-03-24 19:32:42 -0400
committerBen Gamari <ben@smart-cactus.org>2022-04-01 10:28:58 -0400
commitf8fc4c93c5c101610c9a1813e89b290df7917472 (patch)
tree046d45f49ebc9d43827f9d9078d7fc6a1f02d3e3
parent70ec69903109f0bd3306d4af2c17f48545d25ced (diff)
downloadhaskell-f8fc4c93c5c101610c9a1813e89b290df7917472.tar.gz
Add a Note describing lack of object merging on Windows
See #21068.
-rw-r--r--compiler/GHC/Cmm/InitFini.hs12
-rw-r--r--compiler/GHC/Driver/Pipeline/Execute.hs30
-rw-r--r--compiler/GHC/Settings.hs3
-rw-r--r--rts/Linker.c2
4 files changed, 39 insertions, 8 deletions
diff --git a/compiler/GHC/Cmm/InitFini.hs b/compiler/GHC/Cmm/InitFini.hs
index 2a4a12ed08..6f72d8c1f8 100644
--- a/compiler/GHC/Cmm/InitFini.hs
+++ b/compiler/GHC/Cmm/InitFini.hs
@@ -49,12 +49,12 @@ and turn them back into a list of CLabels.
On Windows initializers/finalizers are a bit tricky due to the inability to
merge objects (due to the lld linker's lack of `-r` support on Windows; see
-#21068) since we instead must package foreign stubs into static archives.
-However, the linker is free to not include any constituent objects of a static
-library in the final object code if nothing depends upon them. Consequently, we
-must ensure that the initializer list for a module is defined in the module's
-object code, not its foreign stubs. This happens naturally with the plan laid
-out above.
+Note [Object merging] in GHC.Driver.Pipeline.Execute) since we instead must
+package foreign stubs into static archives. However, the linker is free to not
+include any constituent objects of a static library in the final object code if
+nothing depends upon them. Consequently, we must ensure that the initializer
+list for a module is defined in the module's object code, not its foreign
+stubs. This happens naturally with the plan laid out above.
Note that we maintain the invariant that at most one initializer and one
finalizer CmmDecl will be emitted per module.
diff --git a/compiler/GHC/Driver/Pipeline/Execute.hs b/compiler/GHC/Driver/Pipeline/Execute.hs
index 5f70164cd7..3e6c6fd6c8 100644
--- a/compiler/GHC/Driver/Pipeline/Execute.hs
+++ b/compiler/GHC/Driver/Pipeline/Execute.hs
@@ -1099,6 +1099,34 @@ Unfortunately the big object format is not supported on 32-bit targets so
none of this can be used in that case.
+Note [Object merging]
+~~~~~~~~~~~~~~~~~~~~~
+On most platforms one can "merge" a set of relocatable object files into a new,
+partiall-linked-but-still-relocatable object. In a typical UNIX-style linker,
+this is accomplished with the `ld -r` command. We rely on this for two ends:
+
+ * We rely on `ld -r` to squash together split sections, making GHCi loading
+ more efficient. See Note [Merging object files for GHCi].
+
+ * We use merging to combine a module's object code (e.g. produced by the NCG)
+ with its foreign stubs (typically produced by a C compiler).
+
+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.
+
+Note that this has somewhat non-obvious consequences when producing
+initializers and finalizers. See Note [Initializers and finalizers in Cmm]
+in GHC.Cmm.InitFini for details.
+
+
Note [Merging object files for GHCi]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GHCi can usually loads standard linkable object files using GHC's linker
@@ -1113,9 +1141,9 @@ text section section and can consequently be mapped far more efficiently. As
gcc tends to do unpredictable things to our linker command line, we opt to
invoke ld directly in this case, in contrast to our usual strategy of linking
via gcc.
-
-}
+-- | See Note [Object merging].
joinObjectFiles :: HscEnv -> [FilePath] -> FilePath -> IO ()
joinObjectFiles hsc_env o_files output_fn
| can_merge_objs = do
diff --git a/compiler/GHC/Settings.hs b/compiler/GHC/Settings.hs
index d67e632981..2014a437ca 100644
--- a/compiler/GHC/Settings.hs
+++ b/compiler/GHC/Settings.hs
@@ -101,7 +101,8 @@ data ToolSettings = ToolSettings
, toolSettings_pgm_l :: (String, [Option])
, toolSettings_pgm_lm :: Maybe (String, [Option])
-- ^ N.B. On Windows we don't have a linker which supports object
- -- merging, hence the 'Maybe'.
+ -- merging, hence the 'Maybe'. See Note [Object merging] in
+ -- "GHC.Driver.Pipeline.Execute" for details.
, toolSettings_pgm_dll :: (String, [Option])
, toolSettings_pgm_T :: String
, toolSettings_pgm_windres :: String
diff --git a/rts/Linker.c b/rts/Linker.c
index 88734bd597..43eff730b8 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -1401,6 +1401,8 @@ static HsInt loadObj_ (pathchar *path)
return 1; // success
}
+ // Things that look like object files (e.g. end in `.o`) may nevertheless be
+ // archives, as noted in Note [Object merging] in GHC.Driver.Pipeline.Execute.
if (isArchive(path)) {
if (loadArchive_(path)) {
return 1; // success