summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-03-24 19:32:42 -0400
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-04-06 13:01:28 -0400
commit295c35c5cfda67c11222f99fb338d3cac52abac1 (patch)
tree291766a1cecec72e1db550a5c6eae6ba3726f0c5
parent3ac80a8609418f9f1e9aa025b182fb3445f14428 (diff)
downloadhaskell-295c35c5cfda67c11222f99fb338d3cac52abac1.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 c6fcce9e4c..902ef68f3a 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