summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/GHC/Driver/Pipeline/Execute.hs5
-rw-r--r--compiler/GHC/SysTools/Info.hs30
-rw-r--r--compiler/GHC/SysTools/Tasks.hs18
-rw-r--r--configure.ac143
-rw-r--r--driver/gcc/gcc.c66
-rw-r--r--hadrian/src/Oracles/Flag.hs13
-rw-r--r--hadrian/src/Rules/BinaryDist.hs4
-rw-r--r--hadrian/src/Rules/Register.hs7
-rw-r--r--hadrian/src/Settings/Builders/Cabal.hs4
m---------libraries/Cabal0
-rw-r--r--libraries/base/aclocal.m416
-rw-r--r--libraries/base/base.cabal9
-rw-r--r--libraries/base/configure.ac2
-rw-r--r--libraries/base/include/HsBase.h4
m---------libraries/bytestring0
-rw-r--r--libraries/ghc-prim/ghc-prim.cabal2
m---------libraries/process0
m---------libraries/text0
-rw-r--r--m4/fp_check_environ.m47
-rw-r--r--m4/fp_settings.m4145
-rw-r--r--m4/fp_setup_windows_toolchain.m4107
-rw-r--r--mk/config.mk.in12
-rwxr-xr-xmk/get-win32-tarballs.py2
-rw-r--r--rts/CheckUnload.h4
-rw-r--r--rts/HsFFI.c2
-rw-r--r--rts/LibdwPool.h4
-rw-r--r--rts/Linker.c169
-rw-r--r--rts/LinkerInternals.h48
-rw-r--r--rts/Messages.h8
-rw-r--r--rts/PathUtils.h6
-rw-r--r--rts/Profiling.h4
-rw-r--r--rts/RtsFlags.h3
-rw-r--r--rts/RtsSymbolInfo.c3
-rw-r--r--rts/RtsSymbols.c565
-rw-r--r--rts/RtsSymbols.h1
-rw-r--r--rts/StaticPtrTable.c2
-rw-r--r--rts/Stats.c12
-rw-r--r--rts/include/Stg.h10
-rw-r--r--rts/include/rts/Linker.h3
-rw-r--r--rts/include/rts/Messages.h19
-rw-r--r--rts/include/rts/PosixSource.h12
-rw-r--r--rts/include/stg/Types.h12
-rw-r--r--rts/linker/Elf.c14
-rw-r--r--rts/linker/Elf.h3
-rw-r--r--rts/linker/LoadArchive.c14
-rw-r--r--rts/linker/M32Alloc.c23
-rw-r--r--rts/linker/MMap.c127
-rw-r--r--rts/linker/MachO.c24
-rw-r--r--rts/linker/MachO.h3
-rw-r--r--rts/linker/PEi386.c756
-rw-r--r--rts/linker/PEi386.h14
-rw-r--r--rts/linker/PEi386Types.h4
-rw-r--r--rts/linker/elf_got.c2
-rw-r--r--rts/sm/GC.h4
-rw-r--r--rts/sm/GCUtils.h4
-rw-r--r--rts/sm/MarkStack.h3
-rw-r--r--testsuite/config/ghc1
-rw-r--r--testsuite/driver/runtests.py2
-rw-r--r--testsuite/driver/testglobals.py2
-rw-r--r--testsuite/driver/testlib.py4
-rw-r--r--testsuite/mk/boilerplate.mk2
-rw-r--r--testsuite/tests/codeGen/should_compile/all.T3
-rw-r--r--testsuite/tests/codeGen/should_compile/mk-big-obj.py9
-rw-r--r--testsuite/tests/codeGen/should_fail/all.T2
-rw-r--r--testsuite/tests/ghci/linking/Makefile10
-rw-r--r--testsuite/tests/ghci/linking/all.T4
-rw-r--r--testsuite/tests/ghci/linking/dyn/A.def3
-rw-r--r--testsuite/tests/ghci/linking/dyn/B.def3
-rw-r--r--testsuite/tests/ghci/linking/dyn/Makefile21
-rw-r--r--testsuite/tests/ghci/linking/dyn/all.T8
-rw-r--r--testsuite/tests/linters/Makefile3
-rw-r--r--testsuite/tests/linters/all.T6
-rwxr-xr-xtestsuite/tests/linters/regex-linters/check-rts-includes.py91
-rw-r--r--testsuite/tests/numeric/should_run/all.T3
-rw-r--r--testsuite/tests/plugins/all.T4
-rw-r--r--testsuite/tests/rts/T10672/Makefile4
-rw-r--r--testsuite/tests/rts/T16514_c.c31
-rw-r--r--testsuite/tests/rts/T16514_c.cpp45
-rw-r--r--testsuite/tests/rts/all.T7
-rw-r--r--testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr2
-rw-r--r--testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-32-mingw322
-rw-r--r--testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-64-mingw322
-rw-r--r--testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw322
-rw-r--r--testsuite/tests/rts/linker/T5435_v_gcc.stdout-mingw322
-rw-r--r--testsuite/tests/rts/linker/all.T10
-rw-r--r--testsuite/tests/rts/linker/unload_multiple_objs/all.T1
-rw-r--r--testsuite/tests/th/T13366C.hs23
-rw-r--r--testsuite/tests/th/T13366C.stdout2
-rw-r--r--testsuite/tests/th/T13366Cxx.hs (renamed from testsuite/tests/th/T13366.hs)14
-rw-r--r--testsuite/tests/th/T13366Cxx.stdout (renamed from testsuite/tests/th/T13366.stdout)2
-rw-r--r--testsuite/tests/th/all.T17
91 files changed, 1585 insertions, 1240 deletions
diff --git a/compiler/GHC/Driver/Pipeline/Execute.hs b/compiler/GHC/Driver/Pipeline/Execute.hs
index 61fc86c836..da214cdc20 100644
--- a/compiler/GHC/Driver/Pipeline/Execute.hs
+++ b/compiler/GHC/Driver/Pipeline/Execute.hs
@@ -1089,12 +1089,15 @@ enabled in the toolchain:
suggests, this tells the linker to produce a bigobj-enabled COFF object, no a
PE executable.
-We must enable bigobj output in a few places:
+Previously when we used ld.bfd we had to enable bigobj output in a few places:
* When merging object files (GHC.Driver.Pipeline.Execute.joinObjectFiles)
* When assembling (GHC.Driver.Pipeline.runPhase (RealPhase As ...))
+However, this is no longer necessary with ld.lld, which detects that the
+object is large on its own.
+
Unfortunately the big object format is not supported on 32-bit targets so
none of this can be used in that case.
diff --git a/compiler/GHC/SysTools/Info.hs b/compiler/GHC/SysTools/Info.hs
index 580e76ab8e..a953b9da21 100644
--- a/compiler/GHC/SysTools/Info.hs
+++ b/compiler/GHC/SysTools/Info.hs
@@ -68,30 +68,6 @@ The flag is only needed on ELF systems. On Windows (PE) and Mac OS X
-}
-{- Note [Windows static libGCC]
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The GCC versions being upgraded to in #10726 are configured with
-dynamic linking of libgcc supported. This results in libgcc being
-linked dynamically when a shared library is created.
-
-This introduces thus an extra dependency on GCC dll that was not
-needed before by shared libraries created with GHC. This is a particular
-issue on Windows because you get a non-obvious error due to this missing
-dependency. This dependent dll is also not commonly on your path.
-
-For this reason using the static libgcc is preferred as it preserves
-the same behaviour that existed before. There are however some very good
-reasons to have the shared version as well as described on page 181 of
-https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc.pdf :
-
-"There are several situations in which an application should use the
- shared ‘libgcc’ instead of the static version. The most common of these
- is when the application wishes to throw and catch exceptions across different
- shared libraries. In that case, each of the libraries as well as the application
- itself should use the shared ‘libgcc’. "
-
--}
-
neededLinkArgs :: LinkerInfo -> [Option]
neededLinkArgs (GnuLD o) = o
neededLinkArgs (GnuGold o) = o
@@ -166,12 +142,10 @@ getLinkerInfo' logger dflags = do
-- Process creation is also fairly expensive on win32, so
-- we short-circuit here.
return $ GnuLD $ map Option
- [ -- Emit gcc stack checks
+ [ -- Emit stack checks
-- See Note [Windows stack allocations]
"-fstack-check"
- -- Force static linking of libGCC
- -- See Note [Windows static libGCC]
- , "-static-libgcc" ]
+ ]
_ -> do
-- In practice, we use the compiler as the linker here. Pass
-- -Wl,--version to get linker version info.
diff --git a/compiler/GHC/SysTools/Tasks.hs b/compiler/GHC/SysTools/Tasks.hs
index ded526513a..d6532a6234 100644
--- a/compiler/GHC/SysTools/Tasks.hs
+++ b/compiler/GHC/SysTools/Tasks.hs
@@ -374,25 +374,11 @@ runRanlib logger dflags args = traceToolCommand logger "ranlib" $ do
runWindres :: Logger -> DynFlags -> [Option] -> IO ()
runWindres logger dflags args = traceToolCommand logger "windres" $ do
- let cc = pgm_c dflags
- cc_args = map Option (sOpt_c (settings dflags))
+ let cc_args = map Option (sOpt_c (settings dflags))
windres = pgm_windres dflags
opts = map Option (getOpts dflags opt_windres)
- quote x = "\"" ++ x ++ "\""
- args' = -- If windres.exe and gcc.exe are in a directory containing
- -- spaces then windres fails to run gcc. We therefore need
- -- to tell it what command to use...
- [ Option ("--preprocessor=" ++ quote cc) ]
- ++ map (Option . ("--preprocessor-arg=" ++) . quote)
- (map showOpt opts ++ ["-E", "-xc", "-DRC_INVOKED"])
- -- ...but if we do that then if windres calls popen then
- -- it can't understand the quoting, so we have to use
- -- --use-temp-file so that it interprets it correctly.
- -- See #1828.
- ++ [ Option "--use-temp-file" ]
- ++ args
mb_env <- getGccEnv cc_args
- runSomethingFiltered logger id "Windres" windres args' Nothing mb_env
+ runSomethingFiltered logger id "Windres" windres (opts ++ args) Nothing mb_env
touch :: Logger -> DynFlags -> String -> String -> IO ()
touch logger dflags purpose arg = traceToolCommand logger "touch" $
diff --git a/configure.ac b/configure.ac
index 95d0043f59..7f2fb42bc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -354,111 +354,10 @@ AC_SUBST(TargetHasRTSLinker)
# Requires FPTOOLS_SET_PLATFORMS_VARS to be run first.
FP_FIND_ROOT
-
-if test "$HostOS" = "mingw32"
-then
- # Find the mingw-w64 7z file to extract.
- # NB. If you update the tarballs to a new version of gcc, don't
- # forget to tweak the paths in driver/gcc/gcc.c.
- if test "$HostArch" = "i386"
- then
- mingw_arch="i686"
- tarball_dest_dir="mingw-w64/i686"
- tarball_mingw_dir="mingw32"
- else
- mingw_arch="x86_64"
- tarball_dest_dir="mingw-w64/x86_64"
- tarball_mingw_dir="mingw64"
- fi
-fi
-
-set_up_tarballs() {
- AC_MSG_NOTICE([Checking for Windows toolchain tarballs...])
- local action
- if test "$TarballsAutodownload" = "NO"
- then
- action="verify"
- else
- action="download"
- fi
- $PYTHON mk/get-win32-tarballs.py $action $mingw_arch > missing-win32-tarballs
- case $? in
- 0)
- rm missing-win32-tarballs
- ;;
- 2)
- echo
- echo "Error:"
- echo "Needed msys2 tarballs are missing. You have a few options to get them,"
- echo
- echo " * run configure with the --enable-tarballs-autodownload option"
- echo
- echo " * run mk/get-win32-tarballs.py download $mingw_arch"
- echo
- echo " * manually download the files listed in ./missing-win32-tarballs and place"
- echo " them in the ghc-tarballs directory."
- echo
- exit 1
- ;;
- *)
- echo
- echo "Error fetching msys2 tarballs; see errors above."
- exit 1
- ;;
- esac
-
- # Extract all the tarballs in one go
- if ! test -d inplace/mingw
- then
- AC_MSG_NOTICE([Extracting Windows toolchain from archives (may take a while)...])
- rm -rf inplace/mingw
- local base_dir="../ghc-tarballs/${tarball_dest_dir}"
- ( cd inplace &&
- find "${base_dir}" -name "*.tar.xz" -exec tar --xz -xf {} \; &&
- find "${base_dir}" -name "*.tar.zst" -exec tar --zstd -xf {} \; &&
- rm ".MTREE" &&
- rm ".PKGINFO" &&
- cd .. ) || AC_MSG_ERROR([Could not extract Windows toolchains.])
-
- mv "inplace/${tarball_mingw_dir}" inplace/mingw &&
- touch inplace/mingw
-
- # NB. Now since the GCC is hardcoded to use /mingw32 we need to
- # make a wrapper around it to give it the proper paths
- mv inplace/mingw/bin/gcc.exe inplace/mingw/bin/realgcc.exe
- PATH=`pwd`/inplace/mingw/bin:$PATH
- inplace/mingw/bin/realgcc.exe driver/gcc/gcc.c driver/utils/cwrapper.c driver/utils/getLocation.c -Idriver/utils -o inplace/mingw/bin/gcc.exe
-
- AC_MSG_NOTICE([In-tree MingW-w64 tree created])
- fi
-}
-
-# See Note [tooldir: How GHC finds mingw on Windows]
-if test "$HostOS" = "mingw32" -a "$EnableDistroToolchain" = "NO"
-then
- test -d inplace || mkdir inplace
-
- # NB. Download and extract the MingW-w64 distribution if required
- set_up_tarballs
-
- mingwbin="$hardtop/inplace/mingw/bin/"
- CC="${mingwbin}gcc.exe"
- LD="${mingwbin}ld.exe"
- NM="${mingwbin}nm.exe"
- RANLIB="${mingwbin}ranlib.exe"
- OBJDUMP="${mingwbin}objdump.exe"
- MergeObjsCmd="$LD"
- MergeObjsArgs="-r --oformat=pe-bigobj-x86-64"
- fp_prog_ar="${mingwbin}ar.exe"
-
- AC_PATH_PROG([Genlib],[genlib])
-fi
-
-# We don't want to bundle a MinGW-w64 toolchain
-# So we have to find these individual tools.
-# See Note [tooldir: How GHC finds mingw on Windows]
-if test "$EnableDistroToolchain" = "YES"
-then
+# Extract and configure the Windows toolchain
+if test "$HostOS" = "mingw32" -a "$EnableDistroToolchain" = "NO"; then
+ FP_SETUP_WINDOWS_TOOLCHAIN
+else
# Ideally should use AC_CHECK_TARGET_TOOL but our triples
# are screwed up. Configure doesn't think they're ever equal and
# so never tried without the prefix.
@@ -471,28 +370,28 @@ then
AC_PATH_PROG([DllWrap],[dllwrap])
AC_PATH_PROG([Windres],[windres])
AC_PATH_PROG([Genlib],[genlib])
-else
- AC_CHECK_TARGET_TOOL([Windres],[windres])
- AC_CHECK_TARGET_TOOL([DllWrap],[dllwrap])
- AC_CHECK_TARGET_TOOL([OBJDUMP],[objdump])
-fi
-DllWrapCmd="$DllWrap"
-WindresCmd="$Windres"
+ HAVE_GENLIB=False
+ if test "$HostOS" = "mingw32"; then
+ AC_CHECK_TARGET_TOOL([Windres],[windres])
+ AC_CHECK_TARGET_TOOL([DllWrap],[dllwrap])
+ AC_CHECK_TARGET_TOOL([OBJDUMP],[objdump])
-HAVE_GENLIB=False
-if test "$HostOS" = "mingw32"
-then
- if test "$Genlib" != ""; then
- GenlibCmd="$(cygpath -m $Genlib)"
- HAVE_GENLIB=True
+ if test "$Genlib" != ""; then
+ GenlibCmd="$(cygpath -m $Genlib)"
+ HAVE_GENLIB=True
+ fi
fi
fi
-AC_SUBST([DllWrapCmd])
-AC_SUBST([WindresCmd])
-AC_SUBST([GenlibCmd])
-AC_SUBST([HAVE_GENLIB])
+if test "$HostOS" = "mingw32"; then
+ DllWrapCmd="$DllWrap"
+ WindresCmd="$Windres"
+ AC_SUBST([DllWrapCmd])
+ AC_SUBST([WindresCmd])
+ AC_SUBST([GenlibCmd])
+ AC_SUBST([HAVE_GENLIB])
+fi
FP_ICONV
FP_GMP
diff --git a/driver/gcc/gcc.c b/driver/gcc/gcc.c
deleted file mode 100644
index aa63bb0498..0000000000
--- a/driver/gcc/gcc.c
+++ /dev/null
@@ -1,66 +0,0 @@
-
-/* gcc on mingw is hardcoded to use /mingw (which is c:/mingw) to
- find various files. If this is a different version of mingw to the
- one that we have in the GHC tree then things can go wrong. We
- therefore need to add various -B flags to the gcc commandline,
- so that it uses our in-tree mingw. Hence this wrapper. */
-
-#include "cwrapper.h"
-#include "getLocation.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char** argv) {
- char *binDir;
- char *exePath;
- char *preArgv[4];
- char *oldPath;
- char *newPath;
- char *base;
- char *version;
- int n;
-
- binDir = getExecutablePath();
- exePath = mkString("%s/realgcc.exe", binDir);
-
- /* We need programs like
- inplace/mingw/libexec/gcc/mingw32/4.5.0/cc1.exe
- to be able to find the DLLs in inplace/mingw/bin, so we need to
- add it to $PATH */
- oldPath = getenv("PATH");
- if (!oldPath) {
- die("Couldn't read PATH\n");
- }
- n = snprintf(NULL, 0, "PATH=%s;%s", binDir, oldPath);
- n++;
- newPath = malloc(n);
- if (!newPath) {
- die("Couldn't allocate space for PATH\n");
- }
- snprintf(newPath, n, "PATH=%s;%s", binDir, oldPath);
- n = putenv(newPath);
- if (n) {
- die("putenv failed\n");
- }
-
- /* GCC Version. */
- version = mkString("%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
-
- /* Without these -B args, gcc will still work. However, if you
- have a mingw installation in c:/mingw then it will use files
- from that in preference to the in-tree files. */
- preArgv[0] = mkString("-B%s", binDir);
- preArgv[1] = mkString("-B%s/../lib", binDir);
-#if defined(__MINGW64__)
- base = mkString("x86_64-w64-mingw32");
-#else
- base = mkString("i686-w64-mingw32");
-#endif
-
- preArgv[2] = mkString("-B%s/../lib/gcc/%s/%s" , binDir, base, version);
- preArgv[3] = mkString("-B%s/../libexec/gcc/%s/%s", binDir, base, version);
-
- run(exePath, 4, preArgv, argc - 1, argv + 1, NULL);
-}
-
diff --git a/hadrian/src/Oracles/Flag.hs b/hadrian/src/Oracles/Flag.hs
index 40ae3e8f9b..7c05be5a68 100644
--- a/hadrian/src/Oracles/Flag.hs
+++ b/hadrian/src/Oracles/Flag.hs
@@ -1,8 +1,11 @@
{-# LANGUAGE MultiWayIf #-}
module Oracles.Flag (
- Flag (..), flag, getFlag, platformSupportsSharedLibs,
- targetSupportsSMP, useLibffiForAdjustors
+ Flag (..), flag, getFlag,
+ platformSupportsSharedLibs,
+ platformSupportsGhciObjects,
+ targetSupportsSMP,
+ useLibffiForAdjustors
) where
import Hadrian.Oracles.TextFile
@@ -60,6 +63,12 @@ flag f = do
getFlag :: Flag -> Expr c b Bool
getFlag = expr . flag
+-- | Does the platform support object merging (and therefore we can build GHCi objects
+-- when appropriate).
+platformSupportsGhciObjects :: Action Bool
+platformSupportsGhciObjects =
+ not . null <$> settingsFileSetting SettingsFileSetting_MergeObjectsCommand
+
platformSupportsSharedLibs :: Action Bool
platformSupportsSharedLibs = do
windows <- isWinTarget
diff --git a/hadrian/src/Rules/BinaryDist.hs b/hadrian/src/Rules/BinaryDist.hs
index b47eff4eec..3b5dbca5a6 100644
--- a/hadrian/src/Rules/BinaryDist.hs
+++ b/hadrian/src/Rules/BinaryDist.hs
@@ -466,12 +466,12 @@ iservBins = do
-- | Create a wrapper script calls the executable given as first argument
createVersionWrapper :: String -> FilePath -> Action ()
createVersionWrapper versioned_exe install_path = do
- ccPath <- builderPath (Cc CompileC Stage2)
+ ghcPath <- builderPath (Ghc CompileCWithGhc Stage2)
top <- topDirectory
let version_wrapper_dir = top -/- "hadrian" -/- "bindist" -/- "cwrappers"
wrapper_files = [ version_wrapper_dir -/- file | file <- ["version-wrapper.c", "getLocation.c", "cwrapper.c"]]
- cmd ccPath (["-o", install_path, "-I", version_wrapper_dir
+ cmd ghcPath (["-no-hs-main", "-o", install_path, "-I"++version_wrapper_dir
, "-DEXE_PATH=\"" ++ versioned_exe ++ "\""
] ++ wrapper_files)
diff --git a/hadrian/src/Rules/Register.hs b/hadrian/src/Rules/Register.hs
index cefdf04cb7..c510e96c02 100644
--- a/hadrian/src/Rules/Register.hs
+++ b/hadrian/src/Rules/Register.hs
@@ -9,6 +9,7 @@ import Expression ( getContextData )
import Hadrian.BuildPath
import Hadrian.Expression
import Hadrian.Haskell.Cabal
+import Oracles.Flag (platformSupportsGhciObjects)
import Packages
import Rules.Rts
import {-# SOURCE #-} Rules.Library (needLibrary)
@@ -206,12 +207,14 @@ extraTargets context
-- | Given a library 'Package' this action computes all of its targets. Needing
-- all the targets should build the library such that it is ready to be
-- registered into the package database.
--- See 'packageTargets' for the explanation of the @includeGhciLib@ parameter.
+-- See 'Rules.packageTargets' for the explanation of the @includeGhciLib@
+-- parameter.
libraryTargets :: Bool -> Context -> Action [FilePath]
libraryTargets includeGhciLib context@Context {..} = do
libFile <- pkgLibraryFile context
ghciLib <- pkgGhciLibraryFile context
- ghci <- if includeGhciLib && not (wayUnit Dynamic way)
+ ghciObjsSupported <- platformSupportsGhciObjects
+ ghci <- if ghciObjsSupported && includeGhciLib && not (wayUnit Dynamic way)
then interpretInContext context $ getContextData buildGhciLib
else return False
extra <- extraTargets context
diff --git a/hadrian/src/Settings/Builders/Cabal.hs b/hadrian/src/Settings/Builders/Cabal.hs
index 1ef20147ae..c6a83ce12b 100644
--- a/hadrian/src/Settings/Builders/Cabal.hs
+++ b/hadrian/src/Settings/Builders/Cabal.hs
@@ -139,6 +139,7 @@ libraryArgs = do
package <- getPackage
withGhci <- expr ghcWithInterpreter
dynPrograms <- expr (flavour >>= dynamicGhcPrograms)
+ ghciObjsSupported <- expr platformSupportsGhciObjects
let ways = flavourWays ++ [contextWay]
hasVanilla = vanilla `elem` ways
hasProfiling = any (wayUnit Profiling) ways
@@ -149,7 +150,8 @@ libraryArgs = do
, if hasProfiling
then "--enable-library-profiling"
else "--disable-library-profiling"
- , if (hasVanilla || hasProfiling) &&
+ , if ghciObjsSupported &&
+ (hasVanilla || hasProfiling) &&
package /= rts && withGhci && not dynPrograms
then "--enable-library-for-ghci"
else "--disable-library-for-ghci"
diff --git a/libraries/Cabal b/libraries/Cabal
-Subproject d638e33dbc056048b393964286c7fe394b2730d
+Subproject 9eda67ca9a069dce44c627ca5a297b95f4155a6
diff --git a/libraries/base/aclocal.m4 b/libraries/base/aclocal.m4
index 3a028dda16..0336a092a8 100644
--- a/libraries/base/aclocal.m4
+++ b/libraries/base/aclocal.m4
@@ -253,3 +253,19 @@ AS_IF([test "$ac_res" != no],
[$6])dnl
AS_VAR_POPDEF([ac_Search])dnl
])
+
+AC_DEFUN([FP_CHECK_ENVIRON],
+[
+ dnl--------------------------------------------------------------------
+ dnl * Check whether the libc headers provide a declaration for the
+ dnl environ symbol. If not then we will provide one in RtsSymbols.c.
+ dnl See #20512, #20577, #20861.
+ dnl
+ dnl N.B. Windows declares environ in <stdlib.h>; most others declare it
+ dnl in <unistd.h>.
+ dnl--------------------------------------------------------------------
+ AC_CHECK_DECLS([environ], [], [], [
+ #include <stdlib.h>
+ #include <unistd.h>
+ ])
+])
diff --git a/libraries/base/base.cabal b/libraries/base/base.cabal
index 195e32083f..e0cd8f4197 100644
--- a/libraries/base/base.cabal
+++ b/libraries/base/base.cabal
@@ -376,8 +376,6 @@ Library
if os(windows)
-- Windows requires some extra libraries for linking because the RTS
-- is no longer re-exporting them.
- -- msvcrt: standard C library. The RTS will automatically include this,
- -- but is added for completeness.
-- mingwex: provides C99 compatibility. libm is a stub on MingW.
-- mingw32: Unfortunately required because of a resource leak between
-- mingwex and mingw32. the __math_err symbol is defined in
@@ -387,8 +385,11 @@ Library
-- ole32: provides UUID functionality.
-- rpcrt4: provides RPC UUID creation.
-- ntdll: provides access to functions to inspect window handles
- extra-libraries: wsock32, user32, shell32, msvcrt, mingw32,
- mingwex, ws2_32, shlwapi, ole32, rpcrt4, ntdll
+ -- kernel32: provides GetConsoleCP
+ -- advapi32: provides advanced kernel functions
+ extra-libraries:
+ wsock32, user32, shell32, mingw32, kernel32, advapi32,
+ mingwex, ws2_32, shlwapi, ole32, rpcrt4, ntdll
-- Minimum supported Windows version.
-- These numbers can be found at:
-- https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx
diff --git a/libraries/base/configure.ac b/libraries/base/configure.ac
index e034549476..6fc96d92f4 100644
--- a/libraries/base/configure.ac
+++ b/libraries/base/configure.ac
@@ -189,6 +189,8 @@ FP_CHECK_CONSTS([SIGINT], [
dnl ** can we open files in binary mode?
FP_CHECK_CONST([O_BINARY], [#include <fcntl.h>], [0])
+FP_CHECK_ENVIRON
+
# We don't use iconv or libcharset on Windows, but if configure finds
# them then it can cause problems. So we don't even try looking if
# we are on Windows.
diff --git a/libraries/base/include/HsBase.h b/libraries/base/include/HsBase.h
index d5884473ca..243d9698ee 100644
--- a/libraries/base/include/HsBase.h
+++ b/libraries/base/include/HsBase.h
@@ -552,9 +552,9 @@ INLINE int __hscore_open(char *file, int how, mode_t mode) {
#include <crt_externs.h>
INLINE char **__hscore_environ(void) { return *(_NSGetEnviron()); }
#else
-/* ToDo: write a feature test that doesn't assume 'environ' to
- * be in scope at link-time. */
+#if !HAVE_DECL_ENVIRON
extern char** environ;
+#endif
INLINE char **__hscore_environ(void) { return environ; }
#endif
diff --git a/libraries/bytestring b/libraries/bytestring
-Subproject e84481a06ae4b50984469a79f2c1af4b2f02029
+Subproject a44600feac0d6461964f10f505f8318a4b6aa71
diff --git a/libraries/ghc-prim/ghc-prim.cabal b/libraries/ghc-prim/ghc-prim.cabal
index dbe5d18667..4be29843ae 100644
--- a/libraries/ghc-prim/ghc-prim.cabal
+++ b/libraries/ghc-prim/ghc-prim.cabal
@@ -68,7 +68,7 @@ Library
-- mingw32 which is required by mingwex.
-- user32: provides access to apis to modify user components (UI etc)
-- on Windows. Required because of mingw32.
- extra-libraries: user32, mingw32, mingwex
+ extra-libraries: user32, mingw32, mingwex, ucrt
if os(linux)
-- we need libm, but for musl and other's we might need libc, as libm
diff --git a/libraries/process b/libraries/process
-Subproject 7fd28338c82c89deb3e5db117e87633898046d7
+Subproject 1785cf0314854e4023cd35d05c4e01a9b40a77e
diff --git a/libraries/text b/libraries/text
-Subproject 7b13f15ded23953d5b52b9e74bfe7e2cbc8bb69
+Subproject 5a43fecb62e9769c4cf8b456c7b273901048ea7
diff --git a/m4/fp_check_environ.m4 b/m4/fp_check_environ.m4
index 88bf0a52de..f0daedc9c0 100644
--- a/m4/fp_check_environ.m4
+++ b/m4/fp_check_environ.m4
@@ -4,11 +4,14 @@ AC_DEFUN([FP_CHECK_ENVIRON],
[
dnl--------------------------------------------------------------------
dnl * Check whether the libc headers provide a declaration for the
- dnl environ symbol. If not then we will provide one in RtsSymbols.c.
+ dnl environ symbol. If not then we will provide one in RtsSymbols.c.
dnl See #20512, #20577, #20861.
+ dnl
+ dnl N.B. Windows declares environ in <stdlib.h>; most others declare it
+ dnl in <unistd.h>.
dnl--------------------------------------------------------------------
AC_CHECK_DECLS([environ], [], [], [
+ #include <stdlib.h>
#include <unistd.h>
])
])
-
diff --git a/m4/fp_settings.m4 b/m4/fp_settings.m4
index 09a24f33e1..4db7cd46af 100644
--- a/m4/fp_settings.m4
+++ b/m4/fp_settings.m4
@@ -1,104 +1,113 @@
# FP_SETTINGS
# ----------------------------------
# Set the variables used in the settings file
-# See Note [tooldir: How GHC finds mingw on Windows]
AC_DEFUN([FP_SETTINGS],
[
- if test "$windows" = YES -a "$EnableDistroToolchain" = "NO"
- then
+ SettingsUseDistroMINGW="$EnableDistroToolchain"
+
+ if test "$windows" = YES -a "$EnableDistroToolchain" = "NO"; then
+ # Handle the Windows toolchain installed in FP_SETUP_WINDOWS_TOOLCHAIN.
+ # See Note [tooldir: How GHC finds mingw on Windows]
mingw_bin_prefix='$$tooldir/mingw/bin/'
- SettingsCCompilerCommand="${mingw_bin_prefix}gcc.exe"
- SettingsHaskellCPPCommand="${mingw_bin_prefix}gcc.exe"
- SettingsHaskellCPPFlags="$HaskellCPPArgs"
- SettingsLdCommand="${mingw_bin_prefix}ld.exe"
- # Overrides FIND_MERGE_OBJECTS in order to avoid hard-coding linker
- # path on Windows (#18550).
- SettingsMergeObjectsCommand="${SettingsLdCommand}"
- SettingsMergeObjectsFlags="-r --oformat=pe-bigobj-x86-64"
- SettingsArCommand="${mingw_bin_prefix}ar.exe"
- SettingsRanlibCommand="${mingw_bin_prefix}ranlib.exe"
- SettingsDllWrapCommand="${mingw_bin_prefix}dllwrap.exe"
- SettingsWindresCommand="${mingw_bin_prefix}windres.exe"
- SettingsTouchCommand='$$topdir/bin/touchy.exe'
- elif test "$EnableDistroToolchain" = "YES"
- then
- SettingsCCompilerCommand="$(basename $CC)"
+ SettingsCCompilerCommand="${mingw_bin_prefix}clang.exe"
SettingsCCompilerFlags="$CONF_CC_OPTS_STAGE2"
SettingsCxxCompilerFlags="$CONF_CXX_OPTS_STAGE2"
- SettingsHaskellCPPCommand="$(basename $HaskellCPPCmd)"
+ SettingsCCompilerLinkFlags="$CONF_GCC_LINKER_OPTS_STAGE2"
+ SettingsHaskellCPPCommand="${mingw_bin_prefix}clang.exe"
SettingsHaskellCPPFlags="$HaskellCPPArgs"
- SettingsLdCommand="$(basename $LdCmd)"
- SettingsMergeObjectsCommand="$(basename $MergeObjsCmd)"
- SettingsMergeObjectsFlags="$MergeObjsArgs"
- SettingsArCommand="$(basename $ArCmd)"
- SettingsDllWrapCommand="$(basename $DllWrapCmd)"
- SettingsWindresCommand="$(basename $WindresCmd)"
+ SettingsLdCommand="${mingw_bin_prefix}ld.lld.exe"
+ SettingsLdFlags=""
+ # LLD does not support object merging (#21068)
+ SettingsMergeObjectsCommand=""
+ SettingsMergeObjectsFlags=""
+ SettingsArCommand="${mingw_bin_prefix}llvm-ar.exe"
+ SettingsRanlibCommand="${mingw_bin_prefix}llvm-ranlib.exe"
+ SettingsDllWrapCommand="${mingw_bin_prefix}llvm-dllwrap.exe"
+ SettingsWindresCommand="${mingw_bin_prefix}llvm-windres.exe"
SettingsTouchCommand='$$topdir/bin/touchy.exe'
+
else
+ # This case handles the "normal" platforms (e.g. not Windows) where we
+ # don't provide the toolchain.
+
SettingsCCompilerCommand="$CC"
+ SettingsCCompilerFlags="$CONF_CC_OPTS_STAGE2"
+ SettingsCxxCompilerFlags="$CONF_CXX_OPTS_STAGE2"
SettingsHaskellCPPCommand="$HaskellCPPCmd"
SettingsHaskellCPPFlags="$HaskellCPPArgs"
+ SettingsCCompilerLinkFlags="$CONF_GCC_LINKER_OPTS_STAGE2"
SettingsLdCommand="$LdCmd"
- SettingsMergeObjectsCommand="$MergeObjsCmd"
- SettingsMergeObjectsFlags="$MergeObjsArgs"
+ SettingsLdFlags="$CONF_LD_LINKER_OPTS_STAGE2"
SettingsArCommand="$ArCmd"
SettingsRanlibCommand="$RanlibCmd"
- if test -z "$DllWrapCmd"
- then
+ SettingsMergeObjectsCommand="$MergeObjsCmd"
+ SettingsMergeObjectsFlags="$MergeObjsArgs"
+
+ if test -z "$DllWrapCmd"; then
SettingsDllWrapCommand="/bin/false"
else
SettingsDllWrapCommand="$DllWrapCmd"
fi
- if test -z "$WindresCmd"
- then
+ if test -z "$WindresCmd"; then
SettingsWindresCommand="/bin/false"
else
SettingsWindresCommand="$WindresCmd"
fi
- SettingsTouchCommand='touch'
+
+ if test "$HostOS" = "mingw32"; then
+ SettingsTouchCommand='$$topdir/bin/touchy.exe'
+ else
+ SettingsTouchCommand='touch'
+ fi
+
+ if test "$EnableDistroToolchain" = "YES"; then
+ # If the user specified --enable-distro-toolchain then we just use the
+ # executable names, not paths.
+ SettingsCCompilerCommand="$(basename $SettingsCCompilerCommand)"
+ SettingsHaskellCPPCommand="$(basename $SettingsHaskellCPPCommand)"
+ SettingsLdCommand="$(basename $SettingsLdCommand)"
+ SettingsMergeObjectsCommand="$(basename $SettingsMergeObjectsCommand)"
+ SettingsArCommand="$(basename $SettingsArCommand)"
+ SettingsDllWrapCommand="$(basename $SettingsDllWrapCommand)"
+ SettingsWindresCommand="$(basename $SettingsWindresCommand)"
+ fi
fi
- if test -z "$LibtoolCmd"
- then
- SettingsLibtoolCommand="libtool"
- else
- SettingsLibtoolCommand="$LibtoolCmd"
+
+ # Platform-agnostic tools
+ if test -z "$LibtoolCmd"; then
+ LibtoolCmd="libtool"
fi
- if test -z "$ClangCmd"
- then
- SettingsClangCommand="clang"
- else
- SettingsClangCommand="$ClangCmd"
+ SettingsLibtoolCommand="$LibtoolCmd"
+
+ if test -z "$ClangCmd"; then
+ ClangCmd="clang"
fi
- if test -z "$LlcCmd"
- then
- SettingsLlcCommand="llc"
- else
- SettingsLlcCommand="$LlcCmd"
+ SettingsClangCommand="$ClangCmd"
+
+ # LLVM backend tools
+ if test -z "$LlcCmd"; then
+ LlcCmd="llc"
fi
- if test -z "$OptCmd"
- then
- SettingsOptCommand="opt"
- else
- SettingsOptCommand="$OptCmd"
+ SettingsLlcCommand="$LlcCmd"
+
+ if test -z "$OptCmd"; then
+ OptCmd="opt"
fi
- if test -z "$OtoolCmd"
- then
- SettingsOtoolCommand="otool"
- else
- SettingsOtoolCommand="$OtoolCmd"
+ SettingsOptCommand="$OptCmd"
+
+ # Mac-only tools
+ if test -z "$OtoolCmd"; then
+ OtoolCmd="otool"
fi
- if test -z "$InstallNameToolCmd"
- then
- SettingsInstallNameToolCommand="install_name_tool"
- else
- SettingsInstallNameToolCommand="$InstallNameToolCmd"
+ SettingsOtoolCommand="$OtoolCmd"
+
+ if test -z "$InstallNameToolCmd"; then
+ InstallNameToolCmd="install_name_tool"
fi
- SettingsCCompilerFlags="$CONF_CC_OPTS_STAGE2"
- SettingsCxxCompilerFlags="$CONF_CXX_OPTS_STAGE2"
- SettingsCCompilerLinkFlags="$CONF_GCC_LINKER_OPTS_STAGE2"
+ SettingsInstallNameToolCommand="$InstallNameToolCmd"
+
SettingsCCompilerSupportsNoPie="$CONF_GCC_SUPPORTS_NO_PIE"
- SettingsLdFlags="$CONF_LD_LINKER_OPTS_STAGE2"
- SettingsUseDistroMINGW="$EnableDistroToolchain"
+
AC_SUBST(SettingsCCompilerCommand)
AC_SUBST(SettingsHaskellCPPCommand)
AC_SUBST(SettingsHaskellCPPFlags)
diff --git a/m4/fp_setup_windows_toolchain.m4 b/m4/fp_setup_windows_toolchain.m4
new file mode 100644
index 0000000000..35e322c8a0
--- /dev/null
+++ b/m4/fp_setup_windows_toolchain.m4
@@ -0,0 +1,107 @@
+AC_DEFUN([FP_SETUP_WINDOWS_TOOLCHAIN],[
+ # Find the mingw-w64 archive file to extract.
+ if test "$HostArch" = "i386"
+ then
+ mingw_arch="i686"
+ tarball_dest_dir="mingw-w64/i686"
+ tarball_mingw_dir="clang32"
+ else
+ mingw_arch="x86_64"
+ tarball_dest_dir="mingw-w64/x86_64"
+ tarball_mingw_dir="clang64"
+ fi
+
+ set_up_tarballs() {
+ AC_MSG_NOTICE([Checking for Windows toolchain tarballs...])
+ local action
+ if test "$TarballsAutodownload" = "NO"
+ then
+ action="verify"
+ else
+ action="download"
+ fi
+ $PYTHON mk/get-win32-tarballs.py $action $mingw_arch > missing-win32-tarballs
+ case $? in
+ 0)
+ rm missing-win32-tarballs
+ ;;
+ 2)
+ echo
+ echo "Error:"
+ echo "Needed msys2 tarballs are missing. You have a few options to get them,"
+ echo
+ echo " * run configure with the --enable-tarballs-autodownload option"
+ echo
+ echo " * run mk/get-win32-tarballs.py download $mingw_arch"
+ echo
+ echo " * manually download the files listed in ./missing-win32-tarballs and place"
+ echo " them in the ghc-tarballs directory."
+ echo
+ exit 1
+ ;;
+ *)
+ echo
+ echo "Error fetching msys2 tarballs; see errors above."
+ exit 1
+ ;;
+ esac
+
+ # Extract all the tarballs in one go
+ if ! test -d inplace/mingw
+ then
+ AC_MSG_NOTICE([Extracting Windows toolchain from archives (may take a while)...])
+ rm -rf inplace/mingw
+ local base_dir="../ghc-tarballs/${tarball_dest_dir}"
+ ( cd inplace &&
+ find "${base_dir}" -name "*.tar.xz" -exec tar --xz -xf {} \; &&
+ find "${base_dir}" -name "*.tar.zst" -exec tar --zstd -xf {} \; &&
+ rm ".MTREE" &&
+ rm ".PKGINFO" &&
+ cd .. ) || AC_MSG_ERROR([Could not extract Windows toolchains.])
+
+ mv "inplace/${tarball_mingw_dir}" inplace/mingw &&
+ touch inplace/mingw
+ AC_MSG_NOTICE([In-tree MingW-w64 tree created])
+ fi
+ }
+
+ # See Note [tooldir: How GHC finds mingw on Windows]
+ test -d inplace || mkdir inplace
+
+ # NB. Download and extract the MingW-w64 distribution if required
+ set_up_tarballs
+
+ # N.B. The parameters which get plopped in the `settings` file used by the
+ # resulting compiler are computed in `FP_SETTINGS`.
+
+ # Our Windows toolchain is based around Clang and LLD. We use compiler-rt
+ # for the runtime, libc++ and libc++abi for the C++ standard library
+ # implementation, and libunwind for C++ unwinding.
+ mingwbin="$hardtop/inplace/mingw/bin/"
+
+ CC="${mingwbin}clang.exe"
+ cflags="--rtlib=compiler-rt"
+ CFLAGS="$cflags"
+ CONF_CC_OPTS_STAGE1="$cflags"
+ CONF_CC_OPTS_STAGE2="$cflags"
+
+ cxxflags="--rtlib=compiler-rt --unwindlib=libunwind --stdlib=libc++"
+ CXXFLAGS="$cxxflags"
+ CONF_CXX_OPTS_STAGE1="$cxxflags"
+ CONF_CXX_OPTS_STAGE2="$cxxflags"
+
+ CONF_GCC_LINKER_OPTS_STAGE1="-fuse-ld=lld $cflags"
+ CONF_GCC_LINKER_OPTS_STAGE2="-fuse-ld=lld $cflags"
+
+ LD="${mingwbin}ld.lld.exe"
+ NM="${mingwbin}llvm-nm.exe"
+ AR="${mingwbin}llvm-ar.exe"
+ RANLIB="${mingwbin}llvm-ranlib.exe"
+ OBJDUMP="${mingwbin}llvm-objdump.exe"
+ DLLTOOL="${mingwbin}llvm-dlltool.exe"
+
+ # N.B. LLD does not support -r
+ MergeObjsCmd=""
+ MergeObjsArgs=""
+ AC_PATH_PROG([Genlib],[genlib])
+])
diff --git a/mk/config.mk.in b/mk/config.mk.in
index 06e1dabd96..e1474a34a3 100644
--- a/mk/config.mk.in
+++ b/mk/config.mk.in
@@ -655,11 +655,7 @@ SRC_HSC2HS_OPTS_STAGE0 += --cflag=-D$(HostArch_CPP)_HOST_ARCH --cflag=-D$(HostOS
SRC_HSC2HS_OPTS_STAGE1 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH --cflag=-D$(TargetOS_CPP)_HOST_OS
SRC_HSC2HS_OPTS_STAGE2 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH --cflag=-D$(TargetOS_CPP)_HOST_OS
-ifeq "$(TARGETPLATFORM)" "i386-unknown-mingw32"
-WINDRES = $(INPLACE_MINGW)/bin/windres
-else ifeq "$(TARGETPLATFORM)" "x86_64-unknown-mingw32"
-WINDRES = $(INPLACE_MINGW)/bin/windres
-endif
+WINDRES=@WindresCmd@
#-----------------------------------------------------------------------------
# Python for testsuite driver and code generators
@@ -670,11 +666,7 @@ PYTHON=@PythonCmd@
# Mingwex Library
#
HaveLibMingwEx = @HaveLibMingwEx@
-ifeq "$(TARGETPLATFORM)" "i386-unknown-mingw32"
-DLLTOOL = inplace/mingw/bin/dlltool.exe
-else ifeq "$(TARGETPLATFORM)" "x86_64-unknown-mingw32"
-DLLTOOL = inplace/mingw/bin/dlltool.exe
-endif
+DLLTOOL = @DlltoolCmd@
#-----------------------------------------------------------------------------
# Other standard (ha!) Unix utilities
diff --git a/mk/get-win32-tarballs.py b/mk/get-win32-tarballs.py
index f1ada96b48..351212ba71 100755
--- a/mk/get-win32-tarballs.py
+++ b/mk/get-win32-tarballs.py
@@ -8,7 +8,7 @@ import argparse
import sys
from sys import stderr
-TARBALL_VERSION = '0.3'
+TARBALL_VERSION = '0.7'
BASE_URL = "https://downloads.haskell.org/ghc/mingw/{}".format(TARBALL_VERSION)
DEST = Path('ghc-tarballs/mingw-w64')
ARCHS = ['i686', 'x86_64', 'sources']
diff --git a/rts/CheckUnload.h b/rts/CheckUnload.h
index de07aef1c3..5471544433 100644
--- a/rts/CheckUnload.h
+++ b/rts/CheckUnload.h
@@ -10,10 +10,10 @@
#pragma once
-#include "BeginPrivate.h"
-
#include "LinkerInternals.h"
+#include "BeginPrivate.h"
+
// Currently live objects
extern ObjectCode *objects;
diff --git a/rts/HsFFI.c b/rts/HsFFI.c
index 58651b81e9..0b9f3f0063 100644
--- a/rts/HsFFI.c
+++ b/rts/HsFFI.c
@@ -7,8 +7,8 @@
* ---------------------------------------------------------------------------*/
#include "rts/PosixSource.h"
-#include "HsFFI.h"
#include "Rts.h"
+#include "HsFFI.h"
#include "StablePtr.h"
#include "Task.h"
diff --git a/rts/LibdwPool.h b/rts/LibdwPool.h
index b1c333eebc..563934c7a9 100644
--- a/rts/LibdwPool.h
+++ b/rts/LibdwPool.h
@@ -8,11 +8,11 @@
#pragma once
-#include "BeginPrivate.h"
-
#include "Rts.h"
#include "Libdw.h"
+#include "BeginPrivate.h"
+
#if USE_LIBDW
/* Initialize the pool */
diff --git a/rts/Linker.c b/rts/Linker.c
index 43eff730b8..e0a3a07dc2 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -98,11 +98,11 @@
Note [runtime-linker-phases]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Broadly the behavior of the runtime linker can be
- split into the following four phases:
+ split into the following five phases:
- Indexing (e.g. ocVerifyImage and ocGetNames)
- - Initialization (e.g. ocResolve and ocRunInit)
- - Resolve (e.g. resolveObjs())
+ - Initialization (e.g. ocResolve)
+ - RunInit (e.g. ocRunInit)
- Lookup (e.g. lookupSymbol)
This is to enable lazy loading of symbols. Eager loading is problematic
@@ -132,14 +132,22 @@
* During resolve we attempt to resolve all the symbols needed for the
initial link. This essentially means, that for any ObjectCode given
- directly to the command-line we perform lookupSymbols on the required
- symbols. lookupSymbols may trigger the loading of additional ObjectCode
- if required.
+ directly to the command-line we perform lookupSymbol on the required
+ symbols. lookupSymbol may trigger the loading of additional ObjectCode
+ if required. After resolving an object we mark its text as executable and
+ not writable.
This phase will produce ObjectCode with status `OBJECT_RESOLVED` if
the previous status was `OBJECT_NEEDED`.
- * lookupSymbols is used to lookup any symbols required, both during initial
+ * During RunInit we run the initializers ("constructors") of the objects
+ that are in `OBJECT_RESOLVED` state and move them to `OBJECT_READY` state.
+ This must be in a separate phase since we must ensure that all needed
+ objects have been fully resolved before we can run their initializers.
+ This is particularly tricky in the presence of cyclic dependencies (see
+ #21253).
+
+ * lookupSymbol is used to lookup any symbols required, both during initial
link and during statement and expression compilations in the REPL.
Declaration of e.g. a foreign import, will eventually call lookupSymbol
which will either fail (symbol unknown) or succeed (and possibly trigger a
@@ -170,8 +178,11 @@ StrHashTable *symhash;
Mutex linker_mutex;
#endif
-/* Generic wrapper function to try and Resolve and RunInit oc files */
-int ocTryLoad( ObjectCode* oc );
+/* Generic wrapper function to try and resolve oc files */
+static int ocTryLoad( ObjectCode* oc );
+/* Run initializers */
+static int ocRunInit( ObjectCode* oc );
+static int runPendingInitializers (void);
static void ghciRemoveSymbolTable(StrHashTable *table, const SymbolName* key,
ObjectCode *owner)
@@ -185,6 +196,17 @@ static void ghciRemoveSymbolTable(StrHashTable *table, const SymbolName* key,
stgFree(pinfo);
}
+static const char *
+symbolTypeString (SymType type)
+{
+ switch (type) {
+ case SYM_TYPE_CODE: return "code";
+ case SYM_TYPE_DATA: return "data";
+ case SYM_TYPE_INDIRECT_DATA: return "indirect-data";
+ default: barf("symbolTypeString: unknown symbol type");
+ }
+}
+
/* -----------------------------------------------------------------------------
* Insert symbols into hash tables, checking for duplicates.
*
@@ -212,6 +234,7 @@ int ghciInsertSymbolTable(
const SymbolName* key,
SymbolAddr* data,
SymStrength strength,
+ SymType type,
ObjectCode *owner)
{
RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
@@ -221,9 +244,20 @@ int ghciInsertSymbolTable(
pinfo->value = data;
pinfo->owner = owner;
pinfo->strength = strength;
+ pinfo->type = type;
insertStrHashTable(table, key, pinfo);
return 1;
}
+ else if (pinfo->type != type)
+ {
+ debugBelch("Symbol type mismatch.\n");
+ debugBelch("Symbol %s was defined by %" PATH_FMT " to be a %s symbol.\n",
+ key, obj_name, symbolTypeString(type));
+ debugBelch(" yet was defined by %" PATH_FMT " to be a %s symbol.\n",
+ pinfo->owner ? pinfo->owner->fileName : WSTR("<builtin>"),
+ symbolTypeString(pinfo->type));
+ return 1;
+ }
else if (pinfo->strength == STRENGTH_STRONG)
{
/* The existing symbol is strong meaning we must never override it */
@@ -259,6 +293,7 @@ int ghciInsertSymbolTable(
return 1;
}
else if ( pinfo->owner
+ && pinfo->owner->status != OBJECT_READY
&& pinfo->owner->status != OBJECT_RESOLVED
&& pinfo->owner->status != OBJECT_NEEDED)
{
@@ -273,7 +308,9 @@ int ghciInsertSymbolTable(
This is essentially emulating the behavior of a linker wherein it will always
link in object files that are .o file arguments, but only take object files
from archives as needed. */
- if (owner && (owner->status == OBJECT_NEEDED || owner->status == OBJECT_RESOLVED)) {
+ if (owner && (owner->status == OBJECT_NEEDED
+ || owner->status == OBJECT_RESOLVED
+ || owner->status == OBJECT_READY)) {
pinfo->value = data;
pinfo->owner = owner;
pinfo->strength = strength;
@@ -398,7 +435,7 @@ initLinker_ (int retain_cafs)
for (const RtsSymbolVal *sym = rtsSyms; sym->lbl != NULL; sym++) {
if (! ghciInsertSymbolTable(WSTR("(GHCi built-in symbols)"),
symhash, sym->lbl, sym->addr,
- sym->strength, NULL)) {
+ sym->strength, sym->type, NULL)) {
barf("ghciInsertSymbolTable failed");
}
IF_DEBUG(linker, debugBelch("initLinker: inserting rts symbol %s, %p\n", sym->lbl, sym->addr));
@@ -408,7 +445,7 @@ initLinker_ (int retain_cafs)
if (! ghciInsertSymbolTable(WSTR("(GHCi built-in symbols)"), symhash,
MAYBE_LEADING_UNDERSCORE_STR("newCAF"),
retain_cafs ? newRetainedCAF : newGCdCAF,
- HS_BOOL_FALSE, NULL)) {
+ HS_BOOL_FALSE, SYM_TYPE_CODE, NULL)) {
barf("ghciInsertSymbolTable failed");
}
@@ -775,14 +812,14 @@ HsBool removeLibrarySearchPath(HsPtr dll_path_index)
}
/* -----------------------------------------------------------------------------
- * insert a symbol in the hash table
+ * insert a code symbol in the hash table
*
* Returns: 0 on failure, nonzero on success
*/
HsInt insertSymbol(pathchar* obj_name, SymbolName* key, SymbolAddr* data)
{
return ghciInsertSymbolTable(obj_name, symhash, key, data, HS_BOOL_FALSE,
- NULL);
+ SYM_TYPE_CODE, NULL);
}
/* -----------------------------------------------------------------------------
@@ -792,16 +829,15 @@ HsInt insertSymbol(pathchar* obj_name, SymbolName* key, SymbolAddr* data)
* symbol.
*/
#if defined(OBJFORMAT_PEi386)
-SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent)
+SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent, SymType *type)
{
- (void)dependent; // TODO
ASSERT_LOCK_HELD(&linker_mutex);
- return lookupSymbol_PEi386(lbl);
+ return lookupSymbol_PEi386(lbl, dependent, type);
}
#else
-SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent)
+SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent, SymType *type)
{
ASSERT_LOCK_HELD(&linker_mutex);
IF_DEBUG(linker_verbose, debugBelch("lookupSymbol: looking up '%s'\n", lbl));
@@ -825,6 +861,11 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent)
# if defined(OBJFORMAT_ELF)
SymbolAddr *ret = internal_dlsym(lbl);
+ if (type) {
+ // We assume that the symbol is code since this is usually the case
+ // and dlsym doesn't tell us.
+ *type = SYM_TYPE_CODE;
+ }
// Generally the dynamic linker would define _DYNAMIC, which is
// supposed to point to various bits of dynamic linker state (see
@@ -835,6 +876,9 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent)
if (ret == NULL && strcmp(lbl, "_DYNAMIC") == 0) {
static void *RTS_DYNAMIC = NULL;
ret = (SymbolAddr *) &RTS_DYNAMIC;
+ if (type) {
+ *type = SYM_TYPE_DATA;
+ }
}
return ret;
# elif defined(OBJFORMAT_MACHO)
@@ -848,6 +892,11 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent)
IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s with dlsym\n",
lbl));
CHECK(lbl[0] == '_');
+ if (type) {
+ // We assume that the symbol is code since this is usually the case
+ // and dlsym doesn't tell us.
+ *type = SYM_TYPE_CODE;
+ }
return internal_dlsym(lbl + 1);
# else
@@ -857,6 +906,10 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent)
static void *RTS_NO_FINI = NULL;
if (strcmp(lbl, "__fini_array_end") == 0) { return (SymbolAddr *) &RTS_NO_FINI; }
if (strcmp(lbl, "__fini_array_start") == 0) { return (SymbolAddr *) &RTS_NO_FINI; }
+ if (type) {
+ // This is an assumption
+ *type = pinfo->type;
+ }
if (dependent) {
// Add dependent as symbol's owner's dependency
@@ -945,13 +998,17 @@ SymbolAddr* lookupSymbol( SymbolName* lbl )
ACQUIRE_LOCK(&linker_mutex);
// NULL for "don't add dependent". When adding a dependency we call
// lookupDependentSymbol directly.
- SymbolAddr* r = lookupDependentSymbol(lbl, NULL);
+ SymbolAddr* r = lookupDependentSymbol(lbl, NULL, NULL);
if (!r) {
errorBelch("^^ Could not load '%s', dependency unresolved. "
"See top entry above.\n", lbl);
IF_DEBUG(linker, printLoadedObjects());
fflush(stderr);
}
+
+ if (!runPendingInitializers()) {
+ errorBelch("lookupSymbol: Failed to run initializers.");
+ }
RELEASE_LOCK(&linker_mutex);
return r;
}
@@ -1077,7 +1134,7 @@ freePreloadObjectFile (ObjectCode *oc)
*/
void freeObjectCode (ObjectCode *oc)
{
- IF_DEBUG(linker, debugBelch("freeObjectCode: %" PATH_FMT, oc->fileName));
+ IF_DEBUG(linker, ocDebugBelch(oc, "start\n"));
if (oc->type == DYNAMIC_OBJECT) {
#if defined(OBJFORMAT_ELF)
@@ -1442,7 +1499,7 @@ HsInt loadOc (ObjectCode* oc)
{
int r;
- IF_DEBUG(linker, debugBelch("loadOc: start (%s)\n", oc->fileName));
+ IF_DEBUG(linker, ocDebugBelch(oc, "start\n"));
/* verify the in-memory image */
# if defined(OBJFORMAT_ELF)
@@ -1455,7 +1512,7 @@ HsInt loadOc (ObjectCode* oc)
barf("loadObj: no verify method");
# endif
if (!r) {
- IF_DEBUG(linker, debugBelch("loadOc: ocVerifyImage_* failed\n"));
+ IF_DEBUG(linker, ocDebugBelch(oc, "ocVerifyImage_* failed\n"));
return r;
}
@@ -1473,8 +1530,7 @@ HsInt loadOc (ObjectCode* oc)
symbol table. Allocating space for jump tables in ocAllocateExtras
would just be a waste then as we'll be stopping further processing of the
library in the next few steps. If necessary, the actual allocation
- happens in `ocGetNames_PEi386` and `ocAllocateExtras_PEi386` simply
- set the correct pointers.
+ happens in `ocGetNames_PEi386` simply set the correct pointers.
*/
#if defined(NEED_SYMBOL_EXTRAS)
@@ -1482,14 +1538,14 @@ HsInt loadOc (ObjectCode* oc)
r = ocAllocateExtras_MachO ( oc );
if (!r) {
IF_DEBUG(linker,
- debugBelch("loadOc: ocAllocateExtras_MachO failed\n"));
+ ocDebugBelch(oc, "ocAllocateExtras_MachO failed\n"));
return r;
}
# elif defined(OBJFORMAT_ELF)
r = ocAllocateExtras_ELF ( oc );
if (!r) {
IF_DEBUG(linker,
- debugBelch("loadOc: ocAllocateExtras_ELF failed\n"));
+ ocDebugBelch(oc, "ocAllocateExtras_ELF failed\n"));
return r;
}
# endif
@@ -1506,16 +1562,10 @@ HsInt loadOc (ObjectCode* oc)
barf("loadObj: no getNames method");
# endif
if (!r) {
- IF_DEBUG(linker, debugBelch("loadOc: ocGetNames_* failed\n"));
+ IF_DEBUG(linker, ocDebugBelch(oc, "ocGetNames_* failed\n"));
return r;
}
-#if defined(NEED_SYMBOL_EXTRAS)
-# if defined(OBJFORMAT_PEi386)
- ocAllocateExtras_PEi386 ( oc );
-# endif
-#endif
-
/* Loaded, but not resolved yet, ensure the OC is in a consistent state.
If a target has requested the ObjectCode not to be resolved then honor
this requests. Usually this means the ObjectCode has not been initialized
@@ -1527,7 +1577,7 @@ HsInt loadOc (ObjectCode* oc)
oc->status = OBJECT_LOADED;
}
}
- IF_DEBUG(linker, debugBelch("loadOc: done (%s).\n", oc->fileName));
+ IF_DEBUG(linker, ocDebugBelch(oc, "done\n"));
return 1;
}
@@ -1562,11 +1612,13 @@ int ocTryLoad (ObjectCode* oc) {
if ( symbol.name
&& !ghciInsertSymbolTable(oc->fileName, symhash, symbol.name,
symbol.addr,
- isSymbolWeak(oc, symbol.name), oc)) {
+ isSymbolWeak(oc, symbol.name),
+ symbol.type, oc)) {
return 0;
}
}
+ IF_DEBUG(linker, ocDebugBelch(oc, "resolving\n"));
# if defined(OBJFORMAT_ELF)
r = ocResolve_ELF ( oc );
# elif defined(OBJFORMAT_PEi386)
@@ -1578,6 +1630,7 @@ int ocTryLoad (ObjectCode* oc) {
# endif
if (!r) { return r; }
+ IF_DEBUG(linker, ocDebugBelch(oc, "protecting mappings\n"));
#if defined(NEED_SYMBOL_EXTRAS)
ocProtectExtras(oc);
#endif
@@ -1589,12 +1642,24 @@ int ocTryLoad (ObjectCode* oc) {
m32_allocator_flush(oc->rw_m32);
#endif
- // run init/init_array/ctors/mod_init_func
+ IF_DEBUG(linker, ocDebugBelch(oc, "resolved\n"));
+ oc->status = OBJECT_RESOLVED;
- IF_DEBUG(linker, debugBelch("ocTryLoad: ocRunInit start\n"));
+ return 1;
+}
+
+// run init/init_array/ctors/mod_init_func
+int ocRunInit(ObjectCode *oc)
+{
+ if (oc->status != OBJECT_RESOLVED) {
+ return 1;
+ }
+
+ IF_DEBUG(linker, ocDebugBelch(oc, "running initializers\n"));
// See Note [Tracking foreign exports] in ForeignExports.c
foreignExportsLoadingObject(oc);
+ int r;
#if defined(OBJFORMAT_ELF)
r = ocRunInit_ELF ( oc );
#elif defined(OBJFORMAT_PEi386)
@@ -1607,9 +1672,22 @@ int ocTryLoad (ObjectCode* oc) {
foreignExportsFinishedLoadingObject();
if (!r) { return r; }
+ oc->status = OBJECT_READY;
- oc->status = OBJECT_RESOLVED;
+ return 1;
+}
+int runPendingInitializers (void)
+{
+ for (ObjectCode *oc = objects; oc; oc = oc->next) {
+ int r = ocRunInit(oc);
+ if (!r) {
+ errorBelch("Could not run initializers of Object Code %" PATH_FMT ".\n", OC_INFORMATIVE_FILENAME(oc));
+ IF_DEBUG(linker, printLoadedObjects());
+ fflush(stderr);
+ return r;
+ }
+ }
return 1;
}
@@ -1624,8 +1702,7 @@ static HsInt resolveObjs_ (void)
for (ObjectCode *oc = objects; oc; oc = oc->next) {
int r = ocTryLoad(oc);
- if (!r)
- {
+ if (!r) {
errorBelch("Could not load Object Code %" PATH_FMT ".\n", OC_INFORMATIVE_FILENAME(oc));
IF_DEBUG(linker, printLoadedObjects());
fflush(stderr);
@@ -1633,6 +1710,10 @@ static HsInt resolveObjs_ (void)
}
}
+ if (!runPendingInitializers()) {
+ return 0;
+ }
+
#if defined(PROFILING)
// collect any new cost centres & CCSs that were defined during runInit
refreshProfilingCCSs();
@@ -1878,19 +1959,19 @@ initSegment (Segment *s, void *start, size_t size, SegmentProt prot, int n_secti
void freeSegments (ObjectCode *oc)
{
if (oc->segments != NULL) {
- IF_DEBUG(linker, debugBelch("freeSegments: freeing %d segments\n", oc->n_segments));
+ IF_DEBUG(linker, ocDebugBelch(oc, "freeing %d segments\n", oc->n_segments));
for (int i = 0; i < oc->n_segments; i++) {
Segment *s = &oc->segments[i];
- IF_DEBUG(linker, debugBelch("freeSegments: freeing segment %d at %p size %zu\n",
- i, s->start, s->size));
+ IF_DEBUG(linker, ocDebugBelch(oc, "freeing segment %d at %p size %zu\n",
+ i, s->start, s->size));
stgFree(s->sections_idx);
s->sections_idx = NULL;
if (0 == s->size) {
- IF_DEBUG(linker, debugBelch("freeSegment: skipping segment of 0 size\n"));
+ IF_DEBUG(linker, ocDebugBelch(oc, "skipping segment of 0 size\n"));
continue;
} else {
#if RTS_LINKER_USE_MMAP
diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
index eb76a979bc..5711b16526 100644
--- a/rts/LinkerInternals.h
+++ b/rts/LinkerInternals.h
@@ -18,8 +18,6 @@
void printLoadedObjects(void);
-#include "BeginPrivate.h"
-
/* Which object file format are we targeting? */
#if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) \
|| defined(linux_android_HOST_OS) \
@@ -38,6 +36,30 @@ typedef char SymbolName;
typedef struct _ObjectCode ObjectCode;
typedef struct _Section Section;
+/*
+ * Note [Processing overflowed relocations]
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * When processing relocations whose targets exceed the relocation's maximum
+ * displacement, we can take advantage of knowledge of the symbol type to avoid
+ * linker failures. In particular, if we know that a symbol is a code symbol
+ * then we can handle the relocation by creating a "jump island", a small bit
+ * of code which immediately jumps (with an instruction sequence capable of
+ * larger displacement) to the target.
+ *
+ * This is not possible for data symbols (or, for that matter, Haskell symbols
+ * when TNTC is in use). In these cases we have to rather fail and ask the user
+ * to recompile their program as position-independent.
+ */
+
+/* What kind of thing a symbol identifies. We need to know this to determine how
+ * to process overflowing relocations. See Note [Processing overflowed relocations]. */
+typedef enum _SymType {
+ SYM_TYPE_CODE, /* the symbol is a function and can be relocated via a jump island */
+ SYM_TYPE_DATA, /* the symbol is data */
+ SYM_TYPE_INDIRECT_DATA, /* see Note [_iob_func symbol] */
+} SymType;
+
+
#if defined(OBJFORMAT_ELF)
# include "linker/ElfTypes.h"
#elif defined(OBJFORMAT_PEi386)
@@ -55,6 +77,7 @@ typedef struct _Symbol
{
SymbolName *name;
SymbolAddr *addr;
+ SymType type;
} Symbol_t;
typedef struct NativeCodeRange_ {
@@ -88,8 +111,11 @@ typedef
SECTIONKIND_EXCEPTION_UNWIND,
/* Section belongs to an import section group. e.g. .idata$. */
SECTIONKIND_IMPORT,
+ /* Section defines the head section of a BFD-style import library, e.g. idata$7. */
+ SECTIONKIND_BFD_IMPORT_LIBRARY_HEAD,
/* Section defines an import library entry, e.g. idata$7. */
- SECTIONKIND_IMPORT_LIBRARY,
+ SECTIONKIND_BFD_IMPORT_LIBRARY,
+ /* Unknown section */
SECTIONKIND_NOINFOAVAIL
}
SectionKind;
@@ -332,6 +358,12 @@ struct _ObjectCode {
(OC)->fileName \
)
+#define ocDebugBelch(oc, s, ...) \
+ debugBelch("%s(%" PATH_FMT ": " s, \
+ __func__, \
+ OC_INFORMATIVE_FILENAME(oc), \
+ ##__VA_ARGS__)
+
#if defined(THREADED_RTS)
extern Mutex linker_mutex;
@@ -339,7 +371,7 @@ extern Mutex linker_mutex;
#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
extern Mutex dl_mutex;
#endif
-#endif
+#endif /* THREADED_RTS */
/* Type of the initializer */
typedef void (*init_t) (int argc, char **argv, char **env);
@@ -366,8 +398,11 @@ typedef struct _RtsSymbolInfo {
SymbolAddr* value;
ObjectCode *owner;
SymStrength strength;
+ SymType type;
} RtsSymbolInfo;
+#include "BeginPrivate.h"
+
void exitLinker( void );
void freeObjectCode (ObjectCode *oc);
@@ -390,11 +425,12 @@ int ghciInsertSymbolTable(
const SymbolName* key,
SymbolAddr* data,
SymStrength weak,
+ SymType type,
ObjectCode *owner);
/* Lock-free version of lookupSymbol. When 'dependent' is not NULL, adds it as a
- * dependent to the owner of the symbol. */
-SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent);
+ * dependent to the owner of the symbol. The type of the symbol is stored in 'type'. */
+SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent, SymType *type);
/* Perform TLSGD symbol lookup returning the address of the resulting GOT entry,
* which in this case holds the module id and the symbol offset. */
diff --git a/rts/Messages.h b/rts/Messages.h
index 8cefcafd97..ecae7e6365 100644
--- a/rts/Messages.h
+++ b/rts/Messages.h
@@ -8,6 +8,10 @@
#pragma once
+#include "Capability.h"
+#include "Updates.h" // for DEBUG_FILL_SLOP
+#include "SMPClosureOps.h"
+
#include "BeginPrivate.h"
uint32_t messageBlackHole(Capability *cap, MessageBlackHole *msg);
@@ -18,10 +22,6 @@ void executeMessage (Capability *cap, Message *m);
void sendMessage (Capability *from_cap, Capability *to_cap, Message *msg);
#endif
-#include "Capability.h"
-#include "Updates.h" // for DEBUG_FILL_SLOP
-#include "SMPClosureOps.h"
-
INLINE_HEADER void
doneWithMsgThrowTo (Capability *cap, MessageThrowTo *m)
{
diff --git a/rts/PathUtils.h b/rts/PathUtils.h
index 8a42e34b54..df4ab3fefe 100644
--- a/rts/PathUtils.h
+++ b/rts/PathUtils.h
@@ -8,8 +8,6 @@
#pragma once
-#include "BeginPrivate.h"
-
// Use wchar_t for pathnames on Windows (#5697)
#if defined(mingw32_HOST_OS)
#include "fs_rts.h"
@@ -22,7 +20,7 @@
#define struct_stat struct _stat
#define open wopen
#define WSTR(s) L##s
-#define pathprintf swprintf
+#define pathprintf snwprintf
#define pathcopy wcscpy
#define pathsize sizeof(wchar_t)
#else
@@ -37,6 +35,8 @@
#define pathcopy strcpy
#endif
+#include "BeginPrivate.h"
+
pathchar* pathdup(pathchar *path);
pathchar* pathdir(pathchar *path);
pathchar* mkPath(char* path);
diff --git a/rts/Profiling.h b/rts/Profiling.h
index abb731217a..b3724c3c88 100644
--- a/rts/Profiling.h
+++ b/rts/Profiling.h
@@ -10,13 +10,13 @@
#include <stdio.h>
-#include "BeginPrivate.h"
#include "Rts.h"
-
#if defined(DEBUG)
#include "Arena.h"
#endif
+#include "BeginPrivate.h"
+
#if defined(PROFILING)
#define PROFILING_ONLY(s) s
#else
diff --git a/rts/RtsFlags.h b/rts/RtsFlags.h
index bfcc43af42..6c81081d4d 100644
--- a/rts/RtsFlags.h
+++ b/rts/RtsFlags.h
@@ -9,9 +9,10 @@
#pragma once
-#include "BeginPrivate.h"
#include <stdbool.h>
+#include "BeginPrivate.h"
+
/* Routines that operate-on/to-do-with RTS flags: */
#if defined(mingw32_HOST_OS)
diff --git a/rts/RtsSymbolInfo.c b/rts/RtsSymbolInfo.c
index 1110d582d6..f1f65bd6b6 100644
--- a/rts/RtsSymbolInfo.c
+++ b/rts/RtsSymbolInfo.c
@@ -7,9 +7,8 @@
* ---------------------------------------------------------------------------*/
#include "ghcplatform.h"
-#include "RtsSymbolInfo.h"
-
#include "Rts.h"
+#include "RtsSymbolInfo.h"
#include "HsFFI.h"
#include "Hash.h"
diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c
index 5f97568b62..2818df6ff3 100644
--- a/rts/RtsSymbols.c
+++ b/rts/RtsSymbols.c
@@ -7,9 +7,8 @@
* ---------------------------------------------------------------------------*/
#include "ghcplatform.h"
-#include "RtsSymbols.h"
-
#include "Rts.h"
+#include "RtsSymbols.h"
#include "TopHandler.h"
#include "HsFFI.h"
#include "CloneStack.h"
@@ -162,12 +161,12 @@ extern char **environ;
SymI_HasProto(stg_asyncDoProczh) \
SymI_HasProto(rts_InstallConsoleEvent) \
SymI_HasProto(rts_ConsoleHandlerDone) \
+ SymI_NeedsProto(__mingw_module_is_dll) \
RTS_WIN32_ONLY(SymI_NeedsProto(___chkstk_ms)) \
RTS_WIN64_ONLY(SymI_NeedsProto(___chkstk_ms)) \
- RTS_WIN32_ONLY(SymI_HasProto(_imp___environ)) \
- RTS_WIN64_ONLY(SymI_HasProto(__imp__environ)) \
- RTS_WIN32_ONLY(SymI_HasProto(_imp___iob)) \
- RTS_WIN64_ONLY(SymI_HasProto(__iob_func)) \
+ RTS_WIN64_ONLY(SymI_HasProto(__stdio_common_vswprintf_s)) \
+ RTS_WIN64_ONLY(SymI_HasProto(__stdio_common_vswprintf)) \
+ RTS_WIN64_ONLY(SymI_HasProto(_errno)) \
/* see Note [Symbols for MinGW's printf] */ \
SymI_HasProto(_lock_file) \
SymI_HasProto(_unlock_file) \
@@ -175,9 +174,9 @@ extern char **environ;
/* ^^ Need to figure out why this is needed. */ \
/* See Note [_iob_func symbol] */ \
RTS_WIN64_ONLY(SymI_HasProto_redirect( \
- __imp___acrt_iob_func, __rts_iob_func, STRENGTH_WEAK)) \
+ __imp___acrt_iob_func, __rts_iob_func, STRENGTH_WEAK, SYM_TYPE_INDIRECT_DATA)) \
RTS_WIN32_ONLY(SymI_HasProto_redirect( \
- __imp____acrt_iob_func, __rts_iob_func, STRENGTH_WEAK)) \
+ __imp____acrt_iob_func, __rts_iob_func, STRENGTH_WEAK, SYM_TYPE_INDIRECT_DATA)) \
SymI_HasProto(__mingw_vsnwprintf) \
/* ^^ Need to figure out why this is needed. */ \
SymI_HasProto(__mingw_vfprintf) \
@@ -587,36 +586,36 @@ extern char **environ;
RTS_PROF_SYMBOLS \
RTS_LIBDW_SYMBOLS \
SymI_HasProto(StgReturn) \
- SymI_HasProto(stg_gc_noregs) \
- SymI_HasProto(stg_ret_v_info) \
- SymI_HasProto(stg_ret_p_info) \
- SymI_HasProto(stg_ret_n_info) \
- SymI_HasProto(stg_ret_f_info) \
- SymI_HasProto(stg_ret_d_info) \
- SymI_HasProto(stg_ret_l_info) \
- SymI_HasProto(stg_ret_t_info) \
- SymI_HasProto(stg_ctoi_t) \
- SymI_HasProto(stg_gc_prim_p) \
- SymI_HasProto(stg_gc_prim_pp) \
- SymI_HasProto(stg_gc_prim_n) \
- SymI_HasProto(stg_enter_info) \
- SymI_HasProto(__stg_gc_enter_1) \
- SymI_HasProto(stg_gc_unpt_r1) \
- SymI_HasProto(stg_gc_unbx_r1) \
- SymI_HasProto(stg_gc_f1) \
- SymI_HasProto(stg_gc_d1) \
- SymI_HasProto(stg_gc_l1) \
- SymI_HasProto(stg_gc_pp) \
- SymI_HasProto(stg_gc_ppp) \
- SymI_HasProto(stg_gc_pppp) \
- SymI_HasProto(__stg_gc_fun) \
- SymI_HasProto(stg_gc_fun_info) \
- SymI_HasProto(stg_yield_noregs) \
- SymI_HasProto(stg_yield_to_interpreter) \
- SymI_HasProto(stg_block_noregs) \
- SymI_HasProto(stg_block_takemvar) \
- SymI_HasProto(stg_block_readmvar) \
- SymI_HasProto(stg_block_putmvar) \
+ SymI_HasDataProto(stg_gc_noregs) \
+ SymI_HasDataProto(stg_ret_v_info) \
+ SymI_HasDataProto(stg_ret_p_info) \
+ SymI_HasDataProto(stg_ret_n_info) \
+ SymI_HasDataProto(stg_ret_f_info) \
+ SymI_HasDataProto(stg_ret_d_info) \
+ SymI_HasDataProto(stg_ret_l_info) \
+ SymI_HasDataProto(stg_ret_t_info) \
+ SymI_HasDataProto(stg_ctoi_t) \
+ SymI_HasDataProto(stg_gc_prim_p) \
+ SymI_HasDataProto(stg_gc_prim_pp) \
+ SymI_HasDataProto(stg_gc_prim_n) \
+ SymI_HasDataProto(stg_enter_info) \
+ SymI_HasDataProto(__stg_gc_enter_1) \
+ SymI_HasDataProto(stg_gc_unpt_r1) \
+ SymI_HasDataProto(stg_gc_unbx_r1) \
+ SymI_HasDataProto(stg_gc_f1) \
+ SymI_HasDataProto(stg_gc_d1) \
+ SymI_HasDataProto(stg_gc_l1) \
+ SymI_HasDataProto(stg_gc_pp) \
+ SymI_HasDataProto(stg_gc_ppp) \
+ SymI_HasDataProto(stg_gc_pppp) \
+ SymI_HasDataProto(__stg_gc_fun) \
+ SymI_HasDataProto(stg_gc_fun_info) \
+ SymI_HasDataProto(stg_yield_noregs) \
+ SymI_HasDataProto(stg_yield_to_interpreter) \
+ SymI_HasDataProto(stg_block_noregs) \
+ SymI_HasDataProto(stg_block_takemvar) \
+ SymI_HasDataProto(stg_block_readmvar) \
+ SymI_HasDataProto(stg_block_putmvar) \
MAIN_CAP_SYM \
SymI_HasProto(addDLL) \
SymI_HasProto(addLibrarySearchPath) \
@@ -626,41 +625,41 @@ extern char **environ;
SymI_HasProto(__word_encodeDouble) \
SymI_HasProto(__int_encodeFloat) \
SymI_HasProto(__word_encodeFloat) \
- SymI_HasProto(stg_atomicallyzh) \
+ SymI_HasDataProto(stg_atomicallyzh) \
SymI_HasProto(barf) \
SymI_HasProto(flushEventLog) \
SymI_HasProto(deRefStablePtr) \
SymI_HasProto(debugBelch) \
SymI_HasProto(errorBelch) \
SymI_HasProto(sysErrorBelch) \
- SymI_HasProto(stg_getMaskingStatezh) \
- SymI_HasProto(stg_maskAsyncExceptionszh) \
- SymI_HasProto(stg_maskUninterruptiblezh) \
- SymI_HasProto(stg_catchzh) \
- SymI_HasProto(stg_catchRetryzh) \
- SymI_HasProto(stg_catchSTMzh) \
- SymI_HasProto(stg_clearCCSzh) \
- SymI_HasProto(stg_compactAddWithSharingzh) \
- SymI_HasProto(stg_compactAddzh) \
- SymI_HasProto(stg_compactNewzh) \
- SymI_HasProto(stg_compactResizzezh) \
- SymI_HasProto(stg_compactContainszh) \
- SymI_HasProto(stg_compactContainsAnyzh) \
- SymI_HasProto(stg_compactGetFirstBlockzh) \
- SymI_HasProto(stg_compactGetNextBlockzh) \
- SymI_HasProto(stg_compactAllocateBlockzh) \
- SymI_HasProto(stg_compactFixupPointerszh) \
- SymI_HasProto(stg_compactSizzezh) \
+ SymI_HasDataProto(stg_getMaskingStatezh) \
+ SymI_HasDataProto(stg_maskAsyncExceptionszh) \
+ SymI_HasDataProto(stg_maskUninterruptiblezh) \
+ SymI_HasDataProto(stg_catchzh) \
+ SymI_HasDataProto(stg_catchRetryzh) \
+ SymI_HasDataProto(stg_catchSTMzh) \
+ SymI_HasDataProto(stg_clearCCSzh) \
+ SymI_HasDataProto(stg_compactAddWithSharingzh) \
+ SymI_HasDataProto(stg_compactAddzh) \
+ SymI_HasDataProto(stg_compactNewzh) \
+ SymI_HasDataProto(stg_compactResizzezh) \
+ SymI_HasDataProto(stg_compactContainszh) \
+ SymI_HasDataProto(stg_compactContainsAnyzh) \
+ SymI_HasDataProto(stg_compactGetFirstBlockzh) \
+ SymI_HasDataProto(stg_compactGetNextBlockzh) \
+ SymI_HasDataProto(stg_compactAllocateBlockzh) \
+ SymI_HasDataProto(stg_compactFixupPointerszh) \
+ SymI_HasDataProto(stg_compactSizzezh) \
SymI_HasProto(closure_flags) \
SymI_HasProto(eq_thread) \
SymI_HasProto(cmp_thread) \
SymI_HasProto(createAdjustor) \
- SymI_HasProto(stg_decodeDoublezu2Intzh) \
- SymI_HasProto(stg_decodeDoublezuInt64zh) \
- SymI_HasProto(stg_decodeFloatzuIntzh) \
- SymI_HasProto(stg_delayzh) \
- SymI_HasProto(stg_deRefWeakzh) \
- SymI_HasProto(stg_deRefStablePtrzh) \
+ SymI_HasDataProto(stg_decodeDoublezu2Intzh) \
+ SymI_HasDataProto(stg_decodeDoublezuInt64zh) \
+ SymI_HasDataProto(stg_decodeFloatzuIntzh) \
+ SymI_HasDataProto(stg_delayzh) \
+ SymI_HasDataProto(stg_deRefWeakzh) \
+ SymI_HasDataProto(stg_deRefStablePtrzh) \
SymI_HasProto(dirty_MUT_VAR) \
SymI_HasProto(dirty_TVAR) \
SymI_HasProto(stg_forkzh) \
@@ -713,65 +712,65 @@ extern char **environ;
SymI_HasProto(defaultRtsConfig) \
SymI_HasProto(initLinker) \
SymI_HasProto(initLinker_) \
- SymI_HasProto(stg_unpackClosurezh) \
- SymI_HasProto(stg_closureSizzezh) \
- SymI_HasProto(stg_whereFromzh) \
- SymI_HasProto(stg_getApStackValzh) \
- SymI_HasProto(stg_getSparkzh) \
- SymI_HasProto(stg_numSparkszh) \
- SymI_HasProto(stg_isCurrentThreadBoundzh) \
- SymI_HasProto(stg_isEmptyMVarzh) \
- SymI_HasProto(stg_killThreadzh) \
+ SymI_HasDataProto(stg_unpackClosurezh) \
+ SymI_HasDataProto(stg_closureSizzezh) \
+ SymI_HasDataProto(stg_whereFromzh) \
+ SymI_HasDataProto(stg_getApStackValzh) \
+ SymI_HasDataProto(stg_getSparkzh) \
+ SymI_HasDataProto(stg_numSparkszh) \
+ SymI_HasDataProto(stg_isCurrentThreadBoundzh) \
+ SymI_HasDataProto(stg_isEmptyMVarzh) \
+ SymI_HasDataProto(stg_killThreadzh) \
SymI_HasProto(loadArchive) \
SymI_HasProto(loadObj) \
SymI_HasProto(purgeObj) \
SymI_HasProto(insertSymbol) \
SymI_HasProto(lookupSymbol) \
- SymI_HasProto(stg_makeStablePtrzh) \
- SymI_HasProto(stg_mkApUpd0zh) \
- SymI_HasProto(stg_labelThreadzh) \
- SymI_HasProto(stg_newArrayzh) \
- SymI_HasProto(stg_copyArrayzh) \
- SymI_HasProto(stg_copyMutableArrayzh) \
- SymI_HasProto(stg_cloneArrayzh) \
- SymI_HasProto(stg_cloneMutableArrayzh) \
- SymI_HasProto(stg_freezzeArrayzh) \
- SymI_HasProto(stg_thawArrayzh) \
- SymI_HasProto(stg_casArrayzh) \
- SymI_HasProto(stg_newSmallArrayzh) \
- SymI_HasProto(stg_unsafeThawSmallArrayzh) \
- SymI_HasProto(stg_cloneSmallArrayzh) \
- SymI_HasProto(stg_cloneSmallMutableArrayzh) \
- SymI_HasProto(stg_freezzeSmallArrayzh) \
- SymI_HasProto(stg_thawSmallArrayzh) \
- SymI_HasProto(stg_copySmallArrayzh) \
- SymI_HasProto(stg_copySmallMutableArrayzh) \
- SymI_HasProto(stg_casSmallArrayzh) \
- SymI_HasProto(stg_copyArray_barrier) \
- SymI_HasProto(stg_newBCOzh) \
- SymI_HasProto(stg_newByteArrayzh) \
- SymI_HasProto(stg_casIntArrayzh) \
- SymI_HasProto(stg_casInt8Arrayzh) \
- SymI_HasProto(stg_casInt16Arrayzh) \
- SymI_HasProto(stg_casInt32Arrayzh) \
- SymI_HasProto(stg_casInt64Arrayzh) \
- SymI_HasProto(stg_newMVarzh) \
- SymI_HasProto(stg_newMutVarzh) \
- SymI_HasProto(stg_newTVarzh) \
- SymI_HasProto(stg_readIOPortzh) \
- SymI_HasProto(stg_writeIOPortzh) \
- SymI_HasProto(stg_newIOPortzh) \
- SymI_HasProto(stg_noDuplicatezh) \
- SymI_HasProto(stg_atomicModifyMutVar2zh) \
- SymI_HasProto(stg_atomicModifyMutVarzuzh) \
- SymI_HasProto(stg_casMutVarzh) \
- SymI_HasProto(stg_newPinnedByteArrayzh) \
- SymI_HasProto(stg_newAlignedPinnedByteArrayzh) \
- SymI_HasProto(stg_isByteArrayPinnedzh) \
- SymI_HasProto(stg_isMutableByteArrayPinnedzh) \
- SymI_HasProto(stg_shrinkMutableByteArrayzh) \
- SymI_HasProto(stg_resizzeMutableByteArrayzh) \
- SymI_HasProto(stg_shrinkSmallMutableArrayzh) \
+ SymI_HasDataProto(stg_makeStablePtrzh) \
+ SymI_HasDataProto(stg_mkApUpd0zh) \
+ SymI_HasDataProto(stg_labelThreadzh) \
+ SymI_HasDataProto(stg_newArrayzh) \
+ SymI_HasDataProto(stg_copyArrayzh) \
+ SymI_HasDataProto(stg_copyMutableArrayzh) \
+ SymI_HasDataProto(stg_cloneArrayzh) \
+ SymI_HasDataProto(stg_cloneMutableArrayzh) \
+ SymI_HasDataProto(stg_freezzeArrayzh) \
+ SymI_HasDataProto(stg_thawArrayzh) \
+ SymI_HasDataProto(stg_casArrayzh) \
+ SymI_HasDataProto(stg_newSmallArrayzh) \
+ SymI_HasDataProto(stg_unsafeThawSmallArrayzh) \
+ SymI_HasDataProto(stg_cloneSmallArrayzh) \
+ SymI_HasDataProto(stg_cloneSmallMutableArrayzh) \
+ SymI_HasDataProto(stg_freezzeSmallArrayzh) \
+ SymI_HasDataProto(stg_thawSmallArrayzh) \
+ SymI_HasDataProto(stg_copySmallArrayzh) \
+ SymI_HasDataProto(stg_copySmallMutableArrayzh) \
+ SymI_HasDataProto(stg_casSmallArrayzh) \
+ SymI_HasDataProto(stg_copyArray_barrier) \
+ SymI_HasDataProto(stg_newBCOzh) \
+ SymI_HasDataProto(stg_newByteArrayzh) \
+ SymI_HasDataProto(stg_casIntArrayzh) \
+ SymI_HasDataProto(stg_casInt8Arrayzh) \
+ SymI_HasDataProto(stg_casInt16Arrayzh) \
+ SymI_HasDataProto(stg_casInt32Arrayzh) \
+ SymI_HasDataProto(stg_casInt64Arrayzh) \
+ SymI_HasDataProto(stg_newMVarzh) \
+ SymI_HasDataProto(stg_newMutVarzh) \
+ SymI_HasDataProto(stg_newTVarzh) \
+ SymI_HasDataProto(stg_readIOPortzh) \
+ SymI_HasDataProto(stg_writeIOPortzh) \
+ SymI_HasDataProto(stg_newIOPortzh) \
+ SymI_HasDataProto(stg_noDuplicatezh) \
+ SymI_HasDataProto(stg_atomicModifyMutVar2zh) \
+ SymI_HasDataProto(stg_atomicModifyMutVarzuzh) \
+ SymI_HasDataProto(stg_casMutVarzh) \
+ SymI_HasDataProto(stg_newPinnedByteArrayzh) \
+ SymI_HasDataProto(stg_newAlignedPinnedByteArrayzh) \
+ SymI_HasDataProto(stg_isByteArrayPinnedzh) \
+ SymI_HasDataProto(stg_isMutableByteArrayPinnedzh) \
+ SymI_HasDataProto(stg_shrinkMutableByteArrayzh) \
+ SymI_HasDataProto(stg_resizzeMutableByteArrayzh) \
+ SymI_HasDataProto(stg_shrinkSmallMutableArrayzh) \
SymI_HasProto(newSpark) \
SymI_HasProto(updateRemembSetPushThunk) \
SymI_HasProto(updateRemembSetPushThunk_) \
@@ -780,21 +779,21 @@ extern char **environ;
SymI_HasProto(performMajorGC) \
SymI_HasProto(prog_argc) \
SymI_HasProto(prog_argv) \
- SymI_HasProto(stg_putMVarzh) \
- SymI_HasProto(stg_raisezh) \
- SymI_HasProto(stg_raiseDivZZerozh) \
- SymI_HasProto(stg_raiseUnderflowzh) \
- SymI_HasProto(stg_raiseOverflowzh) \
- SymI_HasProto(stg_raiseIOzh) \
- SymI_HasProto(stg_paniczh) \
- SymI_HasProto(stg_absentErrorzh) \
- SymI_HasProto(stg_readTVarzh) \
- SymI_HasProto(stg_readTVarIOzh) \
+ SymI_HasDataProto(stg_putMVarzh) \
+ SymI_HasDataProto(stg_raisezh) \
+ SymI_HasDataProto(stg_raiseDivZZerozh) \
+ SymI_HasDataProto(stg_raiseUnderflowzh) \
+ SymI_HasDataProto(stg_raiseOverflowzh) \
+ SymI_HasDataProto(stg_raiseIOzh) \
+ SymI_HasDataProto(stg_paniczh) \
+ SymI_HasDataProto(stg_absentErrorzh) \
+ SymI_HasDataProto(stg_readTVarzh) \
+ SymI_HasDataProto(stg_readTVarIOzh) \
SymI_HasProto(resumeThread) \
SymI_HasProto(setNumCapabilities) \
SymI_HasProto(getNumberOfProcessors) \
SymI_HasProto(resolveObjs) \
- SymI_HasProto(stg_retryzh) \
+ SymI_HasDataProto(stg_retryzh) \
SymI_HasProto(rts_apply) \
SymI_HasProto(rts_checkSchedStatus) \
SymI_HasProto(rts_eval) \
@@ -861,143 +860,143 @@ extern char **environ;
SymI_HasProto(stable_ptr_table) \
SymI_HasProto(reportStackOverflow) \
SymI_HasProto(reportHeapOverflow) \
- SymI_HasProto(stg_CAF_BLACKHOLE_info) \
- SymI_HasProto(stg_BLACKHOLE_info) \
- SymI_HasProto(__stg_EAGER_BLACKHOLE_info) \
- SymI_HasProto(stg_BLOCKING_QUEUE_CLEAN_info) \
- SymI_HasProto(stg_BLOCKING_QUEUE_DIRTY_info) \
+ SymI_HasDataProto(stg_CAF_BLACKHOLE_info) \
+ SymI_HasDataProto(stg_BLACKHOLE_info) \
+ SymI_HasDataProto(__stg_EAGER_BLACKHOLE_info) \
+ SymI_HasDataProto(stg_BLOCKING_QUEUE_CLEAN_info) \
+ SymI_HasDataProto(stg_BLOCKING_QUEUE_DIRTY_info) \
SymI_HasProto(startTimer) \
- SymI_HasProto(stg_MVAR_CLEAN_info) \
- SymI_HasProto(stg_MVAR_DIRTY_info) \
- SymI_HasProto(stg_TVAR_CLEAN_info) \
- SymI_HasProto(stg_TVAR_DIRTY_info) \
- SymI_HasProto(stg_IND_STATIC_info) \
- SymI_HasProto(stg_ARR_WORDS_info) \
- SymI_HasProto(stg_MUT_ARR_PTRS_DIRTY_info) \
- SymI_HasProto(stg_MUT_ARR_PTRS_FROZEN_CLEAN_info) \
- SymI_HasProto(stg_MUT_ARR_PTRS_FROZEN_DIRTY_info) \
- SymI_HasProto(stg_SMALL_MUT_ARR_PTRS_DIRTY_info) \
- SymI_HasProto(stg_SMALL_MUT_ARR_PTRS_FROZEN_CLEAN_info) \
- SymI_HasProto(stg_SMALL_MUT_ARR_PTRS_FROZEN_DIRTY_info) \
- SymI_HasProto(stg_MUT_VAR_CLEAN_info) \
- SymI_HasProto(stg_MUT_VAR_DIRTY_info) \
- SymI_HasProto(stg_WEAK_info) \
- SymI_HasProto(stg_SRT_1_info) \
- SymI_HasProto(stg_SRT_2_info) \
- SymI_HasProto(stg_SRT_3_info) \
- SymI_HasProto(stg_SRT_4_info) \
- SymI_HasProto(stg_SRT_5_info) \
- SymI_HasProto(stg_SRT_6_info) \
- SymI_HasProto(stg_SRT_7_info) \
- SymI_HasProto(stg_SRT_8_info) \
- SymI_HasProto(stg_SRT_9_info) \
- SymI_HasProto(stg_SRT_10_info) \
- SymI_HasProto(stg_SRT_11_info) \
- SymI_HasProto(stg_SRT_12_info) \
- SymI_HasProto(stg_SRT_13_info) \
- SymI_HasProto(stg_SRT_14_info) \
- SymI_HasProto(stg_SRT_15_info) \
- SymI_HasProto(stg_SRT_16_info) \
- SymI_HasProto(stg_ap_v_info) \
- SymI_HasProto(stg_ap_f_info) \
- SymI_HasProto(stg_ap_d_info) \
- SymI_HasProto(stg_ap_l_info) \
- SymI_HasProto(stg_ap_v16_info) \
- SymI_HasProto(stg_ap_v32_info) \
- SymI_HasProto(stg_ap_v64_info) \
- SymI_HasProto(stg_ap_n_info) \
- SymI_HasProto(stg_ap_p_info) \
- SymI_HasProto(stg_ap_pv_info) \
- SymI_HasProto(stg_ap_pp_info) \
- SymI_HasProto(stg_ap_ppv_info) \
- SymI_HasProto(stg_ap_ppp_info) \
- SymI_HasProto(stg_ap_pppv_info) \
- SymI_HasProto(stg_ap_pppp_info) \
- SymI_HasProto(stg_ap_ppppp_info) \
- SymI_HasProto(stg_ap_pppppp_info) \
- SymI_HasProto(stg_ap_0_fast) \
- SymI_HasProto(stg_ap_v_fast) \
- SymI_HasProto(stg_ap_f_fast) \
- SymI_HasProto(stg_ap_d_fast) \
- SymI_HasProto(stg_ap_l_fast) \
- SymI_HasProto(stg_ap_v16_fast) \
- SymI_HasProto(stg_ap_v32_fast) \
- SymI_HasProto(stg_ap_v64_fast) \
- SymI_HasProto(stg_ap_n_fast) \
- SymI_HasProto(stg_ap_p_fast) \
- SymI_HasProto(stg_ap_pv_fast) \
- SymI_HasProto(stg_ap_pp_fast) \
- SymI_HasProto(stg_ap_ppv_fast) \
- SymI_HasProto(stg_ap_ppp_fast) \
- SymI_HasProto(stg_ap_pppv_fast) \
- SymI_HasProto(stg_ap_pppp_fast) \
- SymI_HasProto(stg_ap_ppppp_fast) \
- SymI_HasProto(stg_ap_pppppp_fast) \
- SymI_HasProto(stg_ap_1_upd_info) \
- SymI_HasProto(stg_ap_2_upd_info) \
- SymI_HasProto(stg_ap_3_upd_info) \
- SymI_HasProto(stg_ap_4_upd_info) \
- SymI_HasProto(stg_ap_5_upd_info) \
- SymI_HasProto(stg_ap_6_upd_info) \
- SymI_HasProto(stg_ap_7_upd_info) \
- SymI_HasProto(stg_exit) \
- SymI_HasProto(stg_sel_0_upd_info) \
- SymI_HasProto(stg_sel_1_upd_info) \
- SymI_HasProto(stg_sel_2_upd_info) \
- SymI_HasProto(stg_sel_3_upd_info) \
- SymI_HasProto(stg_sel_4_upd_info) \
- SymI_HasProto(stg_sel_5_upd_info) \
- SymI_HasProto(stg_sel_6_upd_info) \
- SymI_HasProto(stg_sel_7_upd_info) \
- SymI_HasProto(stg_sel_8_upd_info) \
- SymI_HasProto(stg_sel_9_upd_info) \
- SymI_HasProto(stg_sel_10_upd_info) \
- SymI_HasProto(stg_sel_11_upd_info) \
- SymI_HasProto(stg_sel_12_upd_info) \
- SymI_HasProto(stg_sel_13_upd_info) \
- SymI_HasProto(stg_sel_14_upd_info) \
- SymI_HasProto(stg_sel_15_upd_info) \
- SymI_HasProto(stg_sel_0_noupd_info) \
- SymI_HasProto(stg_sel_1_noupd_info) \
- SymI_HasProto(stg_sel_2_noupd_info) \
- SymI_HasProto(stg_sel_3_noupd_info) \
- SymI_HasProto(stg_sel_4_noupd_info) \
- SymI_HasProto(stg_sel_5_noupd_info) \
- SymI_HasProto(stg_sel_6_noupd_info) \
- SymI_HasProto(stg_sel_7_noupd_info) \
- SymI_HasProto(stg_sel_8_noupd_info) \
- SymI_HasProto(stg_sel_9_noupd_info) \
- SymI_HasProto(stg_sel_10_noupd_info) \
- SymI_HasProto(stg_sel_11_noupd_info) \
- SymI_HasProto(stg_sel_12_noupd_info) \
- SymI_HasProto(stg_sel_13_noupd_info) \
- SymI_HasProto(stg_sel_14_noupd_info) \
- SymI_HasProto(stg_sel_15_noupd_info) \
- SymI_HasProto(stg_upd_frame_info) \
- SymI_HasProto(stg_bh_upd_frame_info) \
+ SymI_HasDataProto(stg_MVAR_CLEAN_info) \
+ SymI_HasDataProto(stg_MVAR_DIRTY_info) \
+ SymI_HasDataProto(stg_TVAR_CLEAN_info) \
+ SymI_HasDataProto(stg_TVAR_DIRTY_info) \
+ SymI_HasDataProto(stg_IND_STATIC_info) \
+ SymI_HasDataProto(stg_ARR_WORDS_info) \
+ SymI_HasDataProto(stg_MUT_ARR_PTRS_DIRTY_info) \
+ SymI_HasDataProto(stg_MUT_ARR_PTRS_FROZEN_CLEAN_info) \
+ SymI_HasDataProto(stg_MUT_ARR_PTRS_FROZEN_DIRTY_info) \
+ SymI_HasDataProto(stg_SMALL_MUT_ARR_PTRS_DIRTY_info) \
+ SymI_HasDataProto(stg_SMALL_MUT_ARR_PTRS_FROZEN_CLEAN_info) \
+ SymI_HasDataProto(stg_SMALL_MUT_ARR_PTRS_FROZEN_DIRTY_info) \
+ SymI_HasDataProto(stg_MUT_VAR_CLEAN_info) \
+ SymI_HasDataProto(stg_MUT_VAR_DIRTY_info) \
+ SymI_HasDataProto(stg_WEAK_info) \
+ SymI_HasDataProto(stg_SRT_1_info) \
+ SymI_HasDataProto(stg_SRT_2_info) \
+ SymI_HasDataProto(stg_SRT_3_info) \
+ SymI_HasDataProto(stg_SRT_4_info) \
+ SymI_HasDataProto(stg_SRT_5_info) \
+ SymI_HasDataProto(stg_SRT_6_info) \
+ SymI_HasDataProto(stg_SRT_7_info) \
+ SymI_HasDataProto(stg_SRT_8_info) \
+ SymI_HasDataProto(stg_SRT_9_info) \
+ SymI_HasDataProto(stg_SRT_10_info) \
+ SymI_HasDataProto(stg_SRT_11_info) \
+ SymI_HasDataProto(stg_SRT_12_info) \
+ SymI_HasDataProto(stg_SRT_13_info) \
+ SymI_HasDataProto(stg_SRT_14_info) \
+ SymI_HasDataProto(stg_SRT_15_info) \
+ SymI_HasDataProto(stg_SRT_16_info) \
+ SymI_HasDataProto(stg_ap_v_info) \
+ SymI_HasDataProto(stg_ap_f_info) \
+ SymI_HasDataProto(stg_ap_d_info) \
+ SymI_HasDataProto(stg_ap_l_info) \
+ SymI_HasDataProto(stg_ap_v16_info) \
+ SymI_HasDataProto(stg_ap_v32_info) \
+ SymI_HasDataProto(stg_ap_v64_info) \
+ SymI_HasDataProto(stg_ap_n_info) \
+ SymI_HasDataProto(stg_ap_p_info) \
+ SymI_HasDataProto(stg_ap_pv_info) \
+ SymI_HasDataProto(stg_ap_pp_info) \
+ SymI_HasDataProto(stg_ap_ppv_info) \
+ SymI_HasDataProto(stg_ap_ppp_info) \
+ SymI_HasDataProto(stg_ap_pppv_info) \
+ SymI_HasDataProto(stg_ap_pppp_info) \
+ SymI_HasDataProto(stg_ap_ppppp_info) \
+ SymI_HasDataProto(stg_ap_pppppp_info) \
+ SymI_HasDataProto(stg_ap_0_fast) \
+ SymI_HasDataProto(stg_ap_v_fast) \
+ SymI_HasDataProto(stg_ap_f_fast) \
+ SymI_HasDataProto(stg_ap_d_fast) \
+ SymI_HasDataProto(stg_ap_l_fast) \
+ SymI_HasDataProto(stg_ap_v16_fast) \
+ SymI_HasDataProto(stg_ap_v32_fast) \
+ SymI_HasDataProto(stg_ap_v64_fast) \
+ SymI_HasDataProto(stg_ap_n_fast) \
+ SymI_HasDataProto(stg_ap_p_fast) \
+ SymI_HasDataProto(stg_ap_pv_fast) \
+ SymI_HasDataProto(stg_ap_pp_fast) \
+ SymI_HasDataProto(stg_ap_ppv_fast) \
+ SymI_HasDataProto(stg_ap_ppp_fast) \
+ SymI_HasDataProto(stg_ap_pppv_fast) \
+ SymI_HasDataProto(stg_ap_pppp_fast) \
+ SymI_HasDataProto(stg_ap_ppppp_fast) \
+ SymI_HasDataProto(stg_ap_pppppp_fast) \
+ SymI_HasDataProto(stg_ap_1_upd_info) \
+ SymI_HasDataProto(stg_ap_2_upd_info) \
+ SymI_HasDataProto(stg_ap_3_upd_info) \
+ SymI_HasDataProto(stg_ap_4_upd_info) \
+ SymI_HasDataProto(stg_ap_5_upd_info) \
+ SymI_HasDataProto(stg_ap_6_upd_info) \
+ SymI_HasDataProto(stg_ap_7_upd_info) \
+ SymI_HasDataProto(stg_exit) \
+ SymI_HasDataProto(stg_sel_0_upd_info) \
+ SymI_HasDataProto(stg_sel_1_upd_info) \
+ SymI_HasDataProto(stg_sel_2_upd_info) \
+ SymI_HasDataProto(stg_sel_3_upd_info) \
+ SymI_HasDataProto(stg_sel_4_upd_info) \
+ SymI_HasDataProto(stg_sel_5_upd_info) \
+ SymI_HasDataProto(stg_sel_6_upd_info) \
+ SymI_HasDataProto(stg_sel_7_upd_info) \
+ SymI_HasDataProto(stg_sel_8_upd_info) \
+ SymI_HasDataProto(stg_sel_9_upd_info) \
+ SymI_HasDataProto(stg_sel_10_upd_info) \
+ SymI_HasDataProto(stg_sel_11_upd_info) \
+ SymI_HasDataProto(stg_sel_12_upd_info) \
+ SymI_HasDataProto(stg_sel_13_upd_info) \
+ SymI_HasDataProto(stg_sel_14_upd_info) \
+ SymI_HasDataProto(stg_sel_15_upd_info) \
+ SymI_HasDataProto(stg_sel_0_noupd_info) \
+ SymI_HasDataProto(stg_sel_1_noupd_info) \
+ SymI_HasDataProto(stg_sel_2_noupd_info) \
+ SymI_HasDataProto(stg_sel_3_noupd_info) \
+ SymI_HasDataProto(stg_sel_4_noupd_info) \
+ SymI_HasDataProto(stg_sel_5_noupd_info) \
+ SymI_HasDataProto(stg_sel_6_noupd_info) \
+ SymI_HasDataProto(stg_sel_7_noupd_info) \
+ SymI_HasDataProto(stg_sel_8_noupd_info) \
+ SymI_HasDataProto(stg_sel_9_noupd_info) \
+ SymI_HasDataProto(stg_sel_10_noupd_info) \
+ SymI_HasDataProto(stg_sel_11_noupd_info) \
+ SymI_HasDataProto(stg_sel_12_noupd_info) \
+ SymI_HasDataProto(stg_sel_13_noupd_info) \
+ SymI_HasDataProto(stg_sel_14_noupd_info) \
+ SymI_HasDataProto(stg_sel_15_noupd_info) \
+ SymI_HasDataProto(stg_upd_frame_info) \
+ SymI_HasDataProto(stg_bh_upd_frame_info) \
SymI_HasProto(suspendThread) \
- SymI_HasProto(stg_takeMVarzh) \
- SymI_HasProto(stg_readMVarzh) \
- SymI_HasProto(stg_threadStatuszh) \
- SymI_HasProto(stg_tryPutMVarzh) \
- SymI_HasProto(stg_tryTakeMVarzh) \
- SymI_HasProto(stg_tryReadMVarzh) \
- SymI_HasProto(stg_unmaskAsyncExceptionszh) \
+ SymI_HasDataProto(stg_takeMVarzh) \
+ SymI_HasDataProto(stg_readMVarzh) \
+ SymI_HasDataProto(stg_threadStatuszh) \
+ SymI_HasDataProto(stg_tryPutMVarzh) \
+ SymI_HasDataProto(stg_tryTakeMVarzh) \
+ SymI_HasDataProto(stg_tryReadMVarzh) \
+ SymI_HasDataProto(stg_unmaskAsyncExceptionszh) \
SymI_HasProto(unloadObj) \
- SymI_HasProto(stg_unsafeThawArrayzh) \
- SymI_HasProto(stg_waitReadzh) \
- SymI_HasProto(stg_waitWritezh) \
- SymI_HasProto(stg_writeTVarzh) \
- SymI_HasProto(stg_yieldzh) \
- SymI_NeedsProto(stg_badAlignment_entry) \
- SymI_NeedsProto(stg_interp_constr1_entry) \
- SymI_NeedsProto(stg_interp_constr2_entry) \
- SymI_NeedsProto(stg_interp_constr3_entry) \
- SymI_NeedsProto(stg_interp_constr4_entry) \
- SymI_NeedsProto(stg_interp_constr5_entry) \
- SymI_NeedsProto(stg_interp_constr6_entry) \
- SymI_NeedsProto(stg_interp_constr7_entry) \
- SymI_HasProto(stg_arg_bitmaps) \
+ SymI_HasDataProto(stg_unsafeThawArrayzh) \
+ SymI_HasDataProto(stg_waitReadzh) \
+ SymI_HasDataProto(stg_waitWritezh) \
+ SymI_HasDataProto(stg_writeTVarzh) \
+ SymI_HasDataProto(stg_yieldzh) \
+ SymI_NeedsDataProto(stg_badAlignment_entry) \
+ SymI_NeedsDataProto(stg_interp_constr1_entry) \
+ SymI_NeedsDataProto(stg_interp_constr2_entry) \
+ SymI_NeedsDataProto(stg_interp_constr3_entry) \
+ SymI_NeedsDataProto(stg_interp_constr4_entry) \
+ SymI_NeedsDataProto(stg_interp_constr5_entry) \
+ SymI_NeedsDataProto(stg_interp_constr6_entry) \
+ SymI_NeedsDataProto(stg_interp_constr7_entry) \
+ SymI_HasDataProto(stg_arg_bitmaps) \
SymI_HasProto(large_alloc_lim) \
SymI_HasProto(g0) \
SymI_HasProto(allocate) \
@@ -1013,12 +1012,12 @@ extern char **environ;
SymI_HasProto(stopTimer) \
SymI_HasProto(n_capabilities) \
SymI_HasProto(enabled_capabilities) \
- SymI_HasProto(stg_traceCcszh) \
- SymI_HasProto(stg_traceEventzh) \
- SymI_HasProto(stg_traceMarkerzh) \
- SymI_HasProto(stg_traceBinaryEventzh) \
- SymI_HasProto(stg_getThreadAllocationCounterzh) \
- SymI_HasProto(stg_setThreadAllocationCounterzh) \
+ SymI_HasDataProto(stg_traceCcszh) \
+ SymI_HasDataProto(stg_traceEventzh) \
+ SymI_HasDataProto(stg_traceMarkerzh) \
+ SymI_HasDataProto(stg_traceBinaryEventzh) \
+ SymI_HasDataProto(stg_getThreadAllocationCounterzh) \
+ SymI_HasDataProto(stg_setThreadAllocationCounterzh) \
SymI_HasProto(getMonotonicNSec) \
SymI_HasProto(lockFile) \
SymI_HasProto(unlockFile) \
@@ -1072,7 +1071,7 @@ extern char **environ;
// Symbols defined by libc
#define RTS_LIBC_SYMBOLS \
- SymI_HasProto_redirect(atexit, atexit, STRENGTH_STRONG) /* See Note [Strong symbols] */ \
+ SymI_HasProto_redirect(atexit, atexit, STRENGTH_STRONG, CODE_TYPE_CODE) /* See Note [Strong symbols] */ \
SymI_HasProto(environ)
#if !defined(DYNAMIC) && defined(linux_HOST_OS)
@@ -1101,11 +1100,13 @@ extern char **environ;
#else
#define SymE_NeedsProto(vvv) SymI_NeedsProto(vvv);
#define SymE_NeedsDataProto(vvv) SymI_NeedsDataProto(vvv);
-#define SymE_HasProto(vvv) SymI_HasProto(vvv)
+#define SymE_HasProto(vvv) SymI_HasProto(vvv);
#endif
#define SymI_HasProto(vvv) /**/
-#define SymI_HasProto_redirect(vvv,xxx,strength) /**/
+#define SymI_HasDataProto(vvv) /**/
+#define SymI_HasProto_redirect(vvv,xxx,strength,ty) /**/
#define SymI_HasProto_deprecated(vvv) /**/
+
RTS_SYMBOLS
RTS_RET_SYMBOLS
RTS_POSIX_ONLY_SYMBOLS
@@ -1116,9 +1117,11 @@ RTS_LIBC_SYMBOLS
RTS_LIBGCC_SYMBOLS
RTS_FINI_ARRAY_SYMBOLS
RTS_LIBFFI_SYMBOLS
+
#undef SymI_NeedsProto
#undef SymI_NeedsDataProto
#undef SymI_HasProto
+#undef SymI_HasDataProto
#undef SymI_HasProto_redirect
#undef SymI_HasProto_deprecated
#undef SymE_HasProto
@@ -1127,13 +1130,13 @@ RTS_LIBFFI_SYMBOLS
#undef SymE_NeedsDataProto
#define SymI_HasProto(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
- (void*)(&(vvv)), STRENGTH_NORMAL },
-#define SymI_HasDataProto(vvv) \
- SymI_HasProto(vvv)
+ (void*)(&(vvv)), STRENGTH_NORMAL, SYM_TYPE_CODE },
+#define SymI_HasDataProto(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
+ (void*)(&(vvv)), STRENGTH_NORMAL, SYM_TYPE_DATA },
#define SymE_HasProto(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
- (void*)DLL_IMPORT_DATA_REF(vvv), STRENGTH_NORMAL },
-#define SymE_HasDataProto(vvv) \
- SymE_HasProto(vvv)
+ (void*)DLL_IMPORT_DATA_REF(vvv), STRENGTH_NORMAL, SYM_TYPE_CODE },
+#define SymE_HasDataProto(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
+ (void*)DLL_IMPORT_DATA_REF(vvv), STRENGTH_NORMAL, SYM_TYPE_DATA },
#define SymI_NeedsProto(vvv) SymI_HasProto(vvv)
#define SymI_NeedsDataProto(vvv) SymI_HasDataProto(vvv)
@@ -1142,9 +1145,9 @@ RTS_LIBFFI_SYMBOLS
// SymI_HasProto_redirect allows us to redirect references to one symbol to
// another symbol. See newCAF/newRetainedCAF/newGCdCAF for an example.
-#define SymI_HasProto_redirect(vvv,xxx,strength) \
+#define SymI_HasProto_redirect(vvv,xxx,strength,ty) \
{ MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
- (void*)(&(xxx)), strength },
+ (void*)(&(xxx)), strength, ty },
// SymI_HasProto_deprecated allows us to redirect references from their deprecated
// names to the undeprecated ones. e.g. access -> _access.
@@ -1154,7 +1157,7 @@ RTS_LIBFFI_SYMBOLS
// define them, since on Windows these functions shouldn't be in the top level
// namespace, but we have them for POSIX compatibility.
#define SymI_HasProto_deprecated(vvv) \
- { #vvv, (void*)0xBAADF00D, STRENGTH_WEAK },
+ { #vvv, (void*)0xBAADF00D, STRENGTH_WEAK, SYM_TYPE_CODE },
RtsSymbolVal rtsSyms[] = {
RTS_SYMBOLS
@@ -1174,5 +1177,5 @@ RtsSymbolVal rtsSyms[] = {
// lazy pointers as nonlazy.
{ "dyld_stub_binding_helper", (void*)0xDEADBEEF, STRENGTH_NORMAL },
#endif
- { 0, 0, STRENGTH_NORMAL } /* sentinel */
+ { 0, 0, STRENGTH_NORMAL, SYM_TYPE_CODE } /* sentinel */
};
diff --git a/rts/RtsSymbols.h b/rts/RtsSymbols.h
index 0efc16be0f..44760066db 100644
--- a/rts/RtsSymbols.h
+++ b/rts/RtsSymbols.h
@@ -22,6 +22,7 @@ typedef struct _RtsSymbolVal {
const SymbolName* lbl;
SymbolAddr* addr;
SymStrength strength;
+ SymType type;
} RtsSymbolVal;
extern RtsSymbolVal rtsSyms[];
diff --git a/rts/StaticPtrTable.c b/rts/StaticPtrTable.c
index 9754cfad41..282d9b7899 100644
--- a/rts/StaticPtrTable.c
+++ b/rts/StaticPtrTable.c
@@ -8,8 +8,8 @@
*
*/
-#include "StaticPtrTable.h"
#include "Rts.h"
+#include "StaticPtrTable.h"
#include "RtsUtils.h"
#include "Hash.h"
#include "StablePtr.h"
diff --git a/rts/Stats.c b/rts/Stats.c
index 16875ce5d2..8d020d53d6 100644
--- a/rts/Stats.c
+++ b/rts/Stats.c
@@ -26,16 +26,6 @@
#include <string.h> // for memset
-#if defined(mingw32_HOST_OS)
-/* On Win64, if we say "printf" then gcc thinks we are going to use
- MS format specifiers like %I64d rather than %llu */
-#define PRINTF gnu_printf
-#else
-/* However, on OS X, "gnu_printf" isn't recognised */
-#define PRINTF printf
-#endif
-
-
#if defined(THREADED_RTS)
// Protects all statistics below
Mutex stats_mutex;
@@ -79,7 +69,7 @@ static Time *GC_coll_cpu = NULL;
static Time *GC_coll_elapsed = NULL;
static Time *GC_coll_max_pause = NULL;
-static int statsPrintf( char *s, ... ) GNUC3_ATTRIBUTE(format (PRINTF, 1, 2));
+static int statsPrintf( char *s, ... ) STG_PRINTF_ATTR(1, 2);
static void statsFlush( void );
static void statsClose( void );
diff --git a/rts/include/Stg.h b/rts/include/Stg.h
index be0995445b..209db1b0f5 100644
--- a/rts/include/Stg.h
+++ b/rts/include/Stg.h
@@ -231,6 +231,16 @@
#define STG_NO_OPTIMIZE /* nothing */
#endif
+// Mark a function as accepting a printf-like format string.
+#if !defined(__GNUC__) && defined(mingw32_HOST_OS)
+/* On Win64, if we say "printf" then gcc thinks we are going to use
+ MS format specifiers like %I64d rather than %llu */
+#define STG_PRINTF_ATTR(fmt_arg, rest) GNUC3_ATTRIBUTE(format(gnu_printf, fmt_arg, rest))
+#else
+/* However, on OS X, "gnu_printf" isn't recognised */
+#define STG_PRINTF_ATTR(fmt_arg, rest) GNUC3_ATTRIBUTE(format(printf, fmt_arg, rest))
+#endif
+
/* -----------------------------------------------------------------------------
Global type definitions
-------------------------------------------------------------------------- */
diff --git a/rts/include/rts/Linker.h b/rts/include/rts/Linker.h
index 1f3719c0c7..ae463bc05e 100644
--- a/rts/include/rts/Linker.h
+++ b/rts/include/rts/Linker.h
@@ -41,7 +41,7 @@ void initLinker (void);
*/
void initLinker_ (int retain_cafs);
-/* insert a symbol in the hash table */
+/* insert a code symbol in the hash table */
HsInt insertSymbol(pathchar* obj_name, char* key, void* data);
/* lookup a symbol in the hash table */
@@ -52,6 +52,7 @@ typedef enum {
OBJECT_LOADED,
OBJECT_NEEDED,
OBJECT_RESOLVED,
+ OBJECT_READY,
OBJECT_UNLOADED,
OBJECT_DONT_RESOLVE,
OBJECT_NOT_LOADED /* The object was either never loaded or has been
diff --git a/rts/include/rts/Messages.h b/rts/include/rts/Messages.h
index f9b3009c20..7d4727486e 100644
--- a/rts/include/rts/Messages.h
+++ b/rts/include/rts/Messages.h
@@ -18,15 +18,6 @@
#include <stdarg.h>
-#if defined(mingw32_HOST_OS) && !defined(__clang__)
-/* On Win64, if we say "printf" then gcc thinks we are going to use
- MS format specifiers like %I64d rather than %llu */
-#define PRINTF gnu_printf
-#else
-/* However, on OS X, "gnu_printf" isn't recognised */
-#define PRINTF printf
-#endif
-
/* -----------------------------------------------------------------------------
* Message generation
* -------------------------------------------------------------------------- */
@@ -41,7 +32,7 @@
*/
void barf(const char *s, ...)
GNUC3_ATTRIBUTE(__noreturn__)
- GNUC3_ATTRIBUTE(format(PRINTF, 1, 2));
+ STG_PRINTF_ATTR(1, 2);
void vbarf(const char *s, va_list ap)
GNUC3_ATTRIBUTE(__noreturn__);
@@ -57,7 +48,7 @@ void vbarf(const char *s, va_list ap)
* errorBelch() invokes (*errorMsgFn)().
*/
void errorBelch(const char *s, ...)
- GNUC3_ATTRIBUTE(format (PRINTF, 1, 2));
+ STG_PRINTF_ATTR(1, 2);
void verrorBelch(const char *s, va_list ap);
@@ -71,7 +62,7 @@ void verrorBelch(const char *s, va_list ap);
* sysErrorBelch() invokes (*sysErrorMsgFn)().
*/
void sysErrorBelch(const char *s, ...)
- GNUC3_ATTRIBUTE(format (PRINTF, 1, 2));
+ STG_PRINTF_ATTR(1, 2);
void vsysErrorBelch(const char *s, va_list ap);
@@ -83,7 +74,7 @@ void vsysErrorBelch(const char *s, va_list ap);
* debugBelch() invokes (*debugMsgFn)().
*/
void debugBelch(const char *s, ...)
- GNUC3_ATTRIBUTE(format (PRINTF, 1, 2));
+ STG_PRINTF_ATTR(1, 2);
int vdebugBelch(const char *s, va_list ap);
@@ -103,5 +94,3 @@ extern RtsMsgFunction rtsFatalInternalErrorFn;
extern RtsMsgFunctionRetLen rtsDebugMsgFn;
extern RtsMsgFunction rtsErrorMsgFn;
extern RtsMsgFunction rtsSysErrorMsgFn;
-
-#undef PRINTF
diff --git a/rts/include/rts/PosixSource.h b/rts/include/rts/PosixSource.h
index 13fd7b0ff5..be6c8ecca1 100644
--- a/rts/include/rts/PosixSource.h
+++ b/rts/include/rts/PosixSource.h
@@ -36,3 +36,15 @@
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 700
#endif
+
+#if defined(mingw32_HOST_OS)
+# if defined(__USE_MINGW_ANSI_STDIO)
+# if __USE_MINGW_ANSI_STDIO != 1
+# warning "Mismatch between __USE_MINGW_ANSI_STDIO definitions. \
+If using PosixSource.h make sure it is the first header included."
+# endif
+# else
+/* Inform mingw we want the ISO rather than Windows printf format specifiers. */
+# define __USE_MINGW_ANSI_STDIO 1
+#endif
+#endif
diff --git a/rts/include/stg/Types.h b/rts/include/stg/Types.h
index 05dec27f0c..1a9b1685fa 100644
--- a/rts/include/stg/Types.h
+++ b/rts/include/stg/Types.h
@@ -20,18 +20,6 @@
#pragma once
-#if defined(mingw32_HOST_OS)
-# if defined(__USE_MINGW_ANSI_STDIO)
-# if __USE_MINGW_ANSI_STDIO != 1
-# warning "Mismatch between __USE_MINGW_ANSI_STDIO definitions. \
-If using Rts.h make sure it is the first header included."
-# endif
-# else
-/* Inform mingw we want the ISO rather than Windows printf format specifiers. */
-# define __USE_MINGW_ANSI_STDIO 1
-#endif
-#endif
-
/* ISO C 99 says:
* "C++ implementations should define these macros only when
* __STDC_LIMIT_MACROS is defined before <stdint.h> is included."
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index 70f3c8870b..ae4721e6f3 100644
--- a/rts/linker/Elf.c
+++ b/rts/linker/Elf.c
@@ -977,6 +977,13 @@ ocGetNames_ELF ( ObjectCode* oc )
}
}
+ SymType sym_type;
+ if (ELF_ST_TYPE(symbol->elf_sym->st_info) == STT_FUNC) {
+ sym_type = SYM_TYPE_CODE;
+ } else {
+ sym_type = SYM_TYPE_DATA;
+ }
+
/* And the decision is ... */
if (symbol->addr != NULL) {
@@ -988,12 +995,13 @@ ocGetNames_ELF ( ObjectCode* oc )
setWeakSymbol(oc, nm);
}
if (!ghciInsertSymbolTable(oc->fileName, symhash,
- nm, symbol->addr, isWeak, oc)
+ nm, symbol->addr, isWeak, sym_type, oc)
) {
goto fail;
}
oc->symbols[curSymbol].name = nm;
oc->symbols[curSymbol].addr = symbol->addr;
+ oc->symbols[curSymbol].type = sym_type;
curSymbol++;
}
} else {
@@ -1123,7 +1131,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
if (ELF_ST_BIND(symbol->elf_sym->st_info) == STB_LOCAL || strncmp(symbol->name, "_GLOBAL_OFFSET_TABLE_", 21) == 0) {
S = (Elf_Addr)symbol->addr;
} else {
- S_tmp = lookupDependentSymbol( symbol->name, oc );
+ S_tmp = lookupDependentSymbol( symbol->name, oc, NULL );
S = (Elf_Addr)S_tmp;
}
if (!S) {
@@ -1569,7 +1577,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
} else {
/* If not local, look up the name in our global table. */
symbol = strtab + sym.st_name;
- S_tmp = lookupDependentSymbol( symbol, oc );
+ S_tmp = lookupDependentSymbol( symbol, oc, NULL );
S = (Elf_Addr)S_tmp;
}
if (!S) {
diff --git a/rts/linker/Elf.h b/rts/linker/Elf.h
index a16255abba..12bf1772f7 100644
--- a/rts/linker/Elf.h
+++ b/rts/linker/Elf.h
@@ -2,11 +2,10 @@
#include "Rts.h"
#include "LinkerInternals.h"
+#include "linker/ElfTypes.h"
#include "BeginPrivate.h"
-#include <linker/ElfTypes.h>
-
void ocInit_ELF ( ObjectCode* oc );
void ocDeinit_ELF ( ObjectCode* oc );
int ocVerifyImage_ELF ( ObjectCode* oc );
diff --git a/rts/linker/LoadArchive.c b/rts/linker/LoadArchive.c
index 86fa5cb94b..a2641e83ad 100644
--- a/rts/linker/LoadArchive.c
+++ b/rts/linker/LoadArchive.c
@@ -246,6 +246,7 @@ HsInt loadArchive_ (pathchar *path)
char *image = NULL;
HsInt retcode = 0;
int memberSize;
+ int memberIdx = 0;
FILE *f = NULL;
int n;
size_t thisFileNameSize = (size_t)-1; /* shut up bogus GCC warning */
@@ -517,11 +518,11 @@ HsInt loadArchive_ (pathchar *path)
}
}
- int size = pathlen(path) + thisFileNameSize + 3;
- archiveMemberName = stgMallocBytes(size * pathsize,
- "loadArchive(file)");
- pathprintf(archiveMemberName, size, WSTR("%" PATH_FMT "(%.*s)"),
- path, (int)thisFileNameSize, fileName);
+ int size = pathprintf(NULL, 0, WSTR("%" PATH_FMT "(#%d:%.*s)"),
+ path, memberIdx, (int)thisFileNameSize, fileName);
+ archiveMemberName = stgMallocBytes((size+1) * sizeof(pathchar), "loadArchive(file)");
+ pathprintf(archiveMemberName, size, WSTR("%" PATH_FMT "(#%d:%.*s)"),
+ path, memberIdx, (int)thisFileNameSize, fileName);
ObjectCode *oc = mkOc(STATIC_OBJECT, path, image, memberSize, false, archiveMemberName,
misalignment);
@@ -604,6 +605,7 @@ while reading filename from `%" PATH_FMT "'", path);
}
DEBUG_LOG("successfully read one pad byte\n");
}
+ memberIdx ++;
DEBUG_LOG("reached end of archive loading while loop\n");
}
retcode = 1;
@@ -643,10 +645,10 @@ bool isArchive (pathchar *path)
}
size_t ret = fread(buffer, 1, sizeof(buffer), f);
+ fclose(f);
if (ret < sizeof(buffer)) {
return false;
}
- fclose(f);
return strncmp(ARCHIVE_HEADER, buffer, sizeof(ARCHIVE_HEADER)-1) == 0;
}
diff --git a/rts/linker/M32Alloc.c b/rts/linker/M32Alloc.c
index 5ce0342482..b1138e032c 100644
--- a/rts/linker/M32Alloc.c
+++ b/rts/linker/M32Alloc.c
@@ -460,6 +460,15 @@ m32_is_large_object(size_t size, size_t alignment)
return size >= getPageSize() - ROUND_UP(sizeof(struct m32_page_t), alignment);
}
+static void
+m32_report_allocation(struct m32_allocator_t *alloc STG_UNUSED, void *addr STG_UNUSED, size_t size STG_UNUSED)
+{
+ IF_DEBUG(linker_verbose, debugBelch(
+ "m32_allocated(%p:%s): %p - %p\n",
+ alloc, alloc->executable ? "RX": "RW",
+ addr, (uint8_t*) addr + size));
+}
+
/**
* Allocate `size` bytes of memory with the given alignment.
*
@@ -474,6 +483,8 @@ m32_alloc(struct m32_allocator_t *alloc, size_t size, size_t alignment)
if (m32_is_large_object(size,alignment)) {
// large object
size_t alsize = ROUND_UP(sizeof(struct m32_page_t), alignment);
+ // TODO: lower-bound allocation size to allocation granularity and return
+ // remainder to free pool.
struct m32_page_t *page = mmapAnonForLinker(alsize+size);
if (page == NULL) {
sysErrorBelch("m32_alloc: Failed to map pages for %zd bytes", size);
@@ -486,7 +497,9 @@ m32_alloc(struct m32_allocator_t *alloc, size_t size, size_t alignment)
SET_PAGE_TYPE(page, FILLED_PAGE);
page->filled_page.size = alsize + size;
m32_allocator_push_filled_list(&alloc->unprotected_list, (struct m32_page_t *) page);
- return (char*) page + alsize;
+ uint8_t *res = (uint8_t *) page + alsize;
+ m32_report_allocation(alloc, res, size);
+ return res;
}
// small object
@@ -508,6 +521,7 @@ m32_alloc(struct m32_allocator_t *alloc, size_t size, size_t alignment)
if (size <= pgsz - alsize) {
void * addr = (char*)alloc->pages[i] + alsize;
alloc->pages[i]->current_size = alsize + size;
+ m32_report_allocation(alloc, addr, size);
return addr;
}
@@ -534,9 +548,10 @@ m32_alloc(struct m32_allocator_t *alloc, size_t size, size_t alignment)
SET_PAGE_TYPE(page, NURSERY_PAGE);
alloc->pages[empty] = page;
// Add header size and padding
- alloc->pages[empty]->current_size =
- size+ROUND_UP(sizeof(struct m32_page_t),alignment);
- return (char*)page + ROUND_UP(sizeof(struct m32_page_t),alignment);
+ alloc->pages[empty]->current_size = size + ROUND_UP(sizeof(struct m32_page_t),alignment);
+ uint8_t *res = (uint8_t *) page + ROUND_UP(sizeof(struct m32_page_t), alignment);
+ m32_report_allocation(alloc, res, size);
+ return res;
}
#else
diff --git a/rts/linker/MMap.c b/rts/linker/MMap.c
index ff6cc720b9..2d6c2aa148 100644
--- a/rts/linker/MMap.c
+++ b/rts/linker/MMap.c
@@ -72,6 +72,123 @@ static struct MemoryRegion allMemory = {
#if defined(mingw32_HOST_OS)
+/* A wrapper for VirtualQuery() providing useful debug output */
+static int virtualQuery(void *baseAddr, PMEMORY_BASIC_INFORMATION info)
+{
+ int res = VirtualQuery (baseAddr, info, sizeof (*info));
+ IF_DEBUG(linker_verbose,
+ debugBelch("Probing region 0x%p (0x%p) - 0x%p (%" FMT_SizeT ") [%ld] with base 0x%p\n",
+ baseAddr,
+ info->BaseAddress,
+ (uint8_t *) info->BaseAddress + info->RegionSize,
+ info->RegionSize, info->State,
+ info->AllocationBase));
+ if (!res) {
+ IF_DEBUG(linker_verbose, debugBelch("Querying 0x%p failed. Aborting..\n", baseAddr));
+ return 1;
+ }
+ return 0;
+}
+
+static inline uintptr_t round_up(uintptr_t num, uint64_t factor)
+{
+ return num + factor - 1 - (num + factor - 1) % factor;
+}
+
+/*
+ * Try and find a location in the VMMAP to allocate SZ bytes starting at
+ * BASEADDR. If successful then location to use is returned and the amount of
+ * bytes you *must* allocate is returned in REQ. You are free to use less but
+ * you must allocate the amount given in REQ. If not successful NULL.
+ */
+static void *allocateBytes(void* baseAddr, void *endAddr, size_t sz, size_t *req)
+{
+ SYSTEM_INFO sys;
+ GetSystemInfo(&sys);
+
+ IF_DEBUG(linker_verbose, debugBelch("Requesting mapping of %" FMT_SizeT " bytes between %p and %p\n",
+ sz, baseAddr, endAddr));
+
+ MEMORY_BASIC_INFORMATION info;
+ uint8_t *initialAddr = baseAddr;
+ uint8_t *region = NULL;
+ while (!region
+ && initialAddr <= (uint8_t *) endAddr
+ && (void *) initialAddr < sys.lpMaximumApplicationAddress)
+ {
+ int res = virtualQuery(initialAddr, &info);
+ if (res) {
+ return NULL;
+ }
+
+ if ((info.State & MEM_FREE) == MEM_FREE) {
+ IF_DEBUG(linker_verbose, debugBelch("Free range at 0x%p of %zu bytes\n",
+ info.BaseAddress, info.RegionSize));
+
+ if (info.RegionSize >= sz) {
+ if (info.AllocationBase == 0) {
+ size_t needed_sz = round_up (sz, sys.dwAllocationGranularity);
+ if (info.RegionSize >= needed_sz) {
+ IF_DEBUG(linker_verbose, debugBelch("Range is unmapped, Allocation "
+ "required by granule...\n"));
+ *req = needed_sz;
+ region
+ = (void*)(uintptr_t)round_up ((uintptr_t)initialAddr,
+ sys.dwAllocationGranularity);
+ IF_DEBUG(linker_verbose, debugBelch("Requested %" PRId64 ", rounded: %"
+ PRId64 ".\n", sz, *req));
+ IF_DEBUG(linker_verbose, debugBelch("Aligned region claimed 0x%p -> "
+ "0x%p.\n", initialAddr, region));
+ }
+ } else {
+ IF_DEBUG(linker_verbose, debugBelch("Range is usable for us, claiming...\n"));
+ *req = sz;
+ region = initialAddr;
+ }
+ }
+ }
+ initialAddr = (uint8_t *) info.BaseAddress + info.RegionSize;
+ }
+
+ return region;
+}
+
+/* Find free address space for mapping anonymous memory. */
+static void *allocateLocalBytes(size_t sz, size_t *req)
+{
+ // We currently don't attempt to take address space from the region below
+ // the image as malloc() tends to like to use this space, but we could do if
+ // necessary.
+ size_t max_range = 0x7fffffff - sz;
+
+ static void *base_addr = NULL;
+ if (base_addr == NULL) {
+ base_addr = GetModuleHandleW(NULL);
+ }
+ uint8_t *end_addr = (uint8_t *) base_addr + max_range;
+
+ // We track the location of the last allocation to avoid having to
+ // do a linear search of address space looking for space on every allocation
+ // as this can easily devolve into quadratic complexity.
+ static void *last_alloca = NULL;
+ if (last_alloca == NULL) {
+ // Start the search at the image base
+ last_alloca = base_addr;
+ }
+
+ void *result = NULL;
+ result = allocateBytes (last_alloca, end_addr, sz, req);
+ if (result == NULL) {
+ // We failed to find suitable address space; restart the search at base_addr.
+ result = allocateBytes (base_addr, end_addr, sz, req);
+ }
+
+ if (result != NULL) {
+ last_alloca = (uint8_t *) result + *req;
+ }
+ return result;
+}
+
static DWORD
memoryAccessToProt(MemoryAccess access)
{
@@ -92,7 +209,15 @@ memoryAccessToProt(MemoryAccess access)
void *
mmapAnonForLinker (size_t bytes)
{
- return VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ size_t size = 0;
+ /* For linking purposes we want to load code within a 4GB range from the
+ load address of the application. As such we need to find a location to
+ allocate at. */
+ void* region = allocateLocalBytes (bytes, &size);
+ if (region == NULL) {
+ return NULL;
+ }
+ return VirtualAlloc(region, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
}
void
diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c
index a45ec70b39..b37e2c9bc3 100644
--- a/rts/linker/MachO.c
+++ b/rts/linker/MachO.c
@@ -241,7 +241,7 @@ resolveImports(
addr = (SymbolAddr*) (symbol->nlist->n_value);
IF_DEBUG(linker, debugBelch("resolveImports: undefined external %s has value %p\n", symbol->name, addr));
} else {
- addr = lookupDependentSymbol(symbol->name, oc);
+ addr = lookupDependentSymbol(symbol->name, oc, NULL);
IF_DEBUG(linker, debugBelch("resolveImports: looking up %s, %p\n", symbol->name, addr));
}
@@ -506,7 +506,7 @@ relocateSectionAarch64(ObjectCode * oc, Section * section)
* or asking the system, if not found
* in the symbol hashmap
*/
- value = (uint64_t)lookupDependentSymbol((char*)symbol->name, oc);
+ value = (uint64_t)lookupDependentSymbol((char*)symbol->name, oc, NULL);
if(!value)
barf("Could not lookup symbol: %s!", symbol->name);
} else {
@@ -546,7 +546,7 @@ relocateSectionAarch64(ObjectCode * oc, Section * section)
uint64_t pc = (uint64_t)section->start + ri->r_address;
uint64_t value = 0;
if(symbol->nlist->n_type & N_EXT) {
- value = (uint64_t)lookupDependentSymbol((char*)symbol->name, oc);
+ value = (uint64_t)lookupDependentSymbol((char*)symbol->name, oc, NULL);
if(!value)
barf("Could not lookup symbol: %s!", symbol->name);
} else {
@@ -739,7 +739,7 @@ relocateSection(ObjectCode* oc, int curSection)
// symtab, or it is undefined, meaning dlsym must be used
// to resolve it.
- addr = lookupDependentSymbol(nm, oc);
+ addr = lookupDependentSymbol(nm, oc, NULL);
IF_DEBUG(linker_verbose,
debugBelch("relocateSection: looked up %s, "
"external X86_64_RELOC_GOT or X86_64_RELOC_GOT_LOAD\n"
@@ -804,7 +804,7 @@ relocateSection(ObjectCode* oc, int curSection)
nm, (void *)value));
}
else {
- addr = lookupDependentSymbol(nm, oc);
+ addr = lookupDependentSymbol(nm, oc, NULL);
if (addr == NULL)
{
errorBelch("\nlookupSymbol failed in relocateSection (relocate external)\n"
@@ -1342,7 +1342,7 @@ ocGetNames_MachO(ObjectCode* oc)
if (oc->info->nlist[i].n_type & N_EXT)
{
if ( (oc->info->nlist[i].n_desc & N_WEAK_DEF)
- && lookupDependentSymbol(nm, oc)) {
+ && lookupDependentSymbol(nm, oc, NULL)) {
// weak definition, and we already have a definition
IF_DEBUG(linker_verbose, debugBelch(" weak: %s\n", nm));
}
@@ -1350,16 +1350,20 @@ ocGetNames_MachO(ObjectCode* oc)
{
IF_DEBUG(linker_verbose, debugBelch("ocGetNames_MachO: inserting %s\n", nm));
SymbolAddr* addr = oc->info->macho_symbols[i].addr;
-
+ MachOSection *sect = &oc->info->macho_sections[oc->info->macho_symbols[i].nlist->n_sect-1];
+ // TODO: Make figure out how to determine this from the object file
+ SymType sym_type = SYM_TYPE_CODE;
ghciInsertSymbolTable( oc->fileName
, symhash
, nm
, addr
, HS_BOOL_FALSE
+ , sym_type
, oc);
oc->symbols[curSymbol].name = nm;
oc->symbols[curSymbol].addr = addr;
+ oc->symbols[curSymbol].type = sym_type;
curSymbol++;
}
}
@@ -1392,10 +1396,12 @@ ocGetNames_MachO(ObjectCode* oc)
/* also set the final address to the macho_symbol */
oc->info->macho_symbols[i].addr = (void*)commonCounter;
+ /* TODO: Figure out how to determine this from object */
+ SymType sym_type = SYM_TYPE_CODE;
IF_DEBUG(linker_verbose, debugBelch("ocGetNames_MachO: inserting common symbol: %s\n", nm));
ghciInsertSymbolTable(oc->fileName, symhash, nm,
- (void*)commonCounter, HS_BOOL_FALSE, oc);
+ (void*)commonCounter, HS_BOOL_FALSE, sym_type, oc);
oc->symbols[curSymbol].name = nm;
oc->symbols[curSymbol].addr = oc->info->macho_symbols[i].addr;
curSymbol++;
@@ -1517,7 +1523,7 @@ ocResolve_MachO(ObjectCode* oc)
* have the address.
*/
if(NULL == symbol->addr) {
- symbol->addr = lookupDependentSymbol((char*)symbol->name, oc);
+ symbol->addr = lookupDependentSymbol((char*)symbol->name, oc, NULL);
if(NULL == symbol->addr) {
errorBelch("Failed to lookup symbol: %s", symbol->name);
return 0;
diff --git a/rts/linker/MachO.h b/rts/linker/MachO.h
index 518c2ce569..f55f68ddc8 100644
--- a/rts/linker/MachO.h
+++ b/rts/linker/MachO.h
@@ -1,11 +1,10 @@
#pragma once
#include "Rts.h"
+#include "MachOTypes.h"
#include "BeginPrivate.h"
-#include "MachOTypes.h"
-
void ocInit_MachO ( ObjectCode* oc );
void ocDeinit_MachO ( ObjectCode* oc );
int ocVerifyImage_MachO ( ObjectCode* oc );
diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c
index b0be4efad4..420a50feae 100644
--- a/rts/linker/PEi386.c
+++ b/rts/linker/PEi386.c
@@ -55,7 +55,58 @@
COFF_IMPORT_LIB and commonly has the file extension .lib
* GNU BFD import format - The import library format defined and used by GNU
- tools. See note below.
+ tools and commonly has the file extension .dll.a . See note below.
+
+ Note [The need for import libraries]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ In its original incarnation, PE had no native support for dynamic linking.
+ Let's examine how dynamic linking is now implemented. Consider a simple
+ program with a reference to function and data symbols provided by a DLL:
+
+ // myprogram.c
+ #include <libfoo.h>
+ int do_something() {
+ libfoo_function();
+ return libfoo_data;
+ }
+
+ The header file shipped with libfoo will look like the following:
+
+ // libfoo.h
+ __declspec(dllimport) int libfoo_function();
+ __declspec(dllimport) int libfoo_data;
+
+ When the C compiler is compiling myprogram.c, it will see these dllimport
+ declarations and use them to produce a module definition (.def) file which
+ summarizes the symbols that we expect the DLL to export. This will look like:
+
+ EXPORTS
+ libfoo_function
+ libfoo_data DATA
+
+ The C compiler will pass this file to the `dlltool` utility, which will
+ generate an *import library*. The import library will contain
+ placeholder symbols (with names starting with `__imp_`), along with
+ instructions for the dynamic linker to fix-up these references to point to
+ the "real" symbol definition.
+
+ For historical reasons involving lack of documentation, NDAs, and (probably)
+ Steve Balmer, there are two flavours of import flavours:
+
+ * Native Windows-style import libraries. These typically bear the .lib file
+ extension and encode their relocation information in the `.idata` section.
+ Documentation for this format is not available
+ [here](https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-library-format).
+ These are handled in `checkAndLoadImportLibrary()`
+
+ * GNU BFD-style import libraries. These typically have the .dll.a
+ extension and encode the relocation information in a set of sections
+ named `.idata$<N>` where `<N>` is an integer which encodes the section's
+ meaning. Somewhat ironically, despite being devised in response to the
+ native Windows format having no public documentation, there is no official
+ documentation for this format but Note [BFD import library] attempts to
+ summarize what we know. These are handled in `ocGetNames_PEi386()`.
+
Note [BFD import library]
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -77,7 +128,7 @@
Anyway, the Windows PE format specifies a simple and efficient format for
this: It's essentially a list, saying these X symbols can be found in DLL y.
- Commonly, y is a versioned name. e.g. liby_43.dll. This is an artifact of
+ Commonly, y is a versioned name. e.g. `liby_43.dll`. This is an artifact of
the days when Windows did not support side-by-side assemblies. So the
solution was to version the DLLs by renaming them to include explicit
version numbers, and to then use the import libraries to point to the right
@@ -88,35 +139,62 @@
have created their own format. This format is either named using the suffix
.dll.a or .a depending on the tool that makes them. This format is
undocumented. However the source of dlltool.c in binutils is pretty handy to
- understant it.
+ understand it (see binutils/dlltool.c; grep for ".idata section description").
To understand the implementation in GHC, this is what is important:
- the .idata section group is used to hold this information. An import library
+ The import library is generally an archive containing one object file for
+ each imported symbol. In addition, there is a "head" object, which contains
+ the name of the DLL which the symbols are imported from, among other things.
+
+ The `.idata$` section group is used to hold this information. An import library
object file will always have these section groups, but the specific
configuration depends on what the purpose of the file is. They will also
never have a CODE or DATA section, though depending on the tool that creates
them they may have the section headers, which will mostly be empty.
- You have to different possible configuration:
+ The import data sections consist of the following:
+
+ * `.idata$2` contains the Import Directory Table (IDT), which contains an entry
+ for each imported DLL. Each entry contains: a reference to the DLL's name
+ (in `.idata$7`) and references to its entries in the ILT and IAT sections.
+ This is contained in the head object.
+
+ * `.idata$6` contains the Hint Name Table (HNT). This is a table of
+ of (symbol ordinal, symbol name) pairs, which are referred to be the ILT
+ and IAT as described below.
+
+ * `.idata$5` contains the Import Address Table (IAT). This consists of an
+ array of pointers (one array for each imported DLL) which the loader will
+ update to point to the target symbol identified by the hint referenced by
+ the corresponding ILT entry. Moreover, the IAT pointers' initial values
+ also point to the corresponding HNT entry.
+
+ * `.idata$4` contains the Import Lookup Table (ILT). This contains an array
+ of references to HNT entries for each imported DLL.
- 1) Those that define a redirection. In this case the .idata$7 section will
+ * `.idata$7` contains the names of the imported DLLs. This is contained
+ in the head object.
+
+ You have two different possible configurations:
+
+ 1) Those that define a redirection. In this case the `.idata$7` section will
contain the name of the actual dll to load. This will be the only content
of the section. In the symbol table, the last symbol will be the name
used to refer to the dll in the relocation tables. This name will always
- be in the format "symbol_name_iname", however when referred to, the format
- "_head_symbol_name" is used.
+ be in the format `symbol_name_iname`, however when referred to, the format
+ `_head_symbol_name` is used.
- We record this symbol early on during GetNames and load the dll and use
+ We record this symbol early on during `ocGetNames` and load the dll and use
the module handle as the symbol address.
- 2) Symbol definitions. In this case .idata$6 will contain the symbol to load.
- This is stored in the fixed format of 2-byte ordinals followed by a null
- terminated string with the symbol name. The ordinal is to be used when
- the dll does not export symbols by name. (NOTE: We don't currently
- support this in the runtime linker, but it's easy to add should it be
- needed). The last symbol in the symbol table of the section will contain
- the name symbol which contains the dll name to use to resolve the
+ 2) Symbol definitions. In this case the HNT (`.idata$6`) will contain the
+ symbol to load. This is stored in the fixed format of 2-byte ordinals
+ followed by (null-terminated) symbol name. The ordinal is
+ to be used when the DLL does not export symbols by name. (note: We don't
+ currently support this in the runtime linker, but it's easy to add should
+ it be needed). The last symbol in the symbol table of the section will
+ contain the name symbol which contains the dll name to use to resolve the
reference.
As a technicality, this also means that the GCC format will allow us to use
@@ -125,48 +203,97 @@
required for dynamic linking support for GHC. So the runtime linker now
supports this too.
+
+ Example: Dynamic code references
+ --------------------------------
+ To see what such an import library looks like, let's first start with the case
+ of a function (e.g. `libfoo_function` above) with bind-now semantics (lazy-loading
+ will look much different). The import library will contain the following:
+
+ .section .text
+ # This stub (which Windows calls a thunk) is what calls to
+ # libfoo_function will hit if the symbol isn't declared with
+ # __declspec(dllimport)
+ libfoo_function:
+ jmp *0x0(%rip)
+ .quad __imp_libfoo_function
+
+ .section .idata$5 # IAT
+ # This is the location which the loader will
+ # update to point to the definition
+ # of libfoo_function
+ __imp_libfoo_function:
+ .quad hint1 - __image_base__
+
+ .section .idata$4 # ILT
+ # This (and hint1 below) is what tells the
+ # loader where __imp_libfoo_function should point
+ ilt1:
+ .quad hint1 - __image_base__
+
+ .section .idata$6 # HNT
+ hint1:
+ .short ORDINAL_OF_libfoo_function
+ .asciiz "libfoo_function"
+
+ To handle a reference to an IAT entry like `__imp_libfoo_function`, the GHC
+ linker will (in `lookupSymbolInDLLs`) first strip off the `__imp_` prefix to
+ find the name of the referenced dynamic symbol. It then resolves the
+ symbol's address and allocates an `IndirectAddr` where it can place the
+ address, which it will return as the resolution of the `___libfoo_function`.
+
+ Example: Dynamic data references
+ --------------------------------
+ Let's now consider the import library for a data symbol. This is essentially
+ equivalent to the code case, but without the need to emit a thunk:
+
+ .section .idata$5 # IAT
+ __imp_libfoo_data:
+ .quad hint2 - __image_base__
+
+ .section .idata$4 # ILT
+ ilt2:
+ .quad hint2 - __image_base__
+
+ .section .idata$6 # ILT
+ hint2:
+ .short ORDINAL_OF_libfoo_data
+ .asciiz "libfoo_data"
+
+
Note [Memory allocation]
~~~~~~~~~~~~~~~~~~~~~~~~
- Previously on Windows we would use VirtualAlloc to allocate enough space for
- loading the entire object file into memory and keep it there for the duration
- until the entire object file has been unloaded.
-
- This has a couple of problems, first of, VirtualAlloc and the other Virtual
- functions interact directly with the memory manager. Requesting memory from
- VirtualAlloc will always return whole pages (32k), aligned on a 4k boundary.
-
- This means for an object file of size N kbytes, we're always wasting 32-N
- kbytes of memory. Nothing else can access this memory.
-
- Because of this we're now using HeapAlloc and other heap function to create
- a private heap. Another solution would have been to write our own memory
- manager to keep track of where we have free memory, but the private heap
- solution is simpler.
-
- The private heap is created with full rights just as the pages we used to get
- from VirtualAlloc (e.g. READ/WRITE/EXECUTE). In the end we end up using
- memory much more efficiently than before. The downside is that heap memory
- is always Allocated AND Committed, thus when the heap resizes the new size is
- committed. It becomes harder to see how much we're actually using. This makes
- it seem like for small programs that we're using more memory than before.
- Certainly a clean GHCi startup will have a slightly higher commit count.
-
- The second major change in how we allocate memory is that we no longer need
- the entire object file. We now allocate the object file using normal malloc
- and instead read bits from it. All tables are stored in the Object file info
- table and are discarded as soon as they are no longer needed, e.g. after
- relocation is finished. Only section data is kept around, but this data is
- copied into the private heap.
-
- The major knock on effect of this is that we have more memory to use in the
- sub 2GB range, which means that Template Haskell should fail a lot less as we
- will violate the small memory model much less than before.
-
- Note [Section alignment]
- ~~~~~~~~~~~~~~~~~~~~~~~~
- The Windows linker aligns memory to it's section alignment requirement by
- aligning it during the copying to the private heap. We also ensure that the
- trampoline "region" we reserve is 8 bytes aligned.
+ The loading of an object begins in `preloadObjectFile`, which allocates a buffer,
+ `oc->image`, into which the object file is read. It then calls `ocVerifyImage`,
+ where we traverse the object file's header and populate `ObjectCode.sections`.
+ Specifically, we create a Section for each of the object's sections such
+ that:
+
+ * the `.start` field points to its data in the mapped image
+ * the `.size` field reflects its intended size
+ * the .`info` field contains a `SectionFormatField` with other information
+ from its section header entry (namely `VirtualSize`, `VirtualAddress`, and
+ `Characteristics`)
+
+ We then proceed to `ocGetNames`, where we again walk the section table header
+ and determine which sections need to be mapped and how (e.g. as readable-writable or
+ readable-executable). We then allocate memory for each section using the
+ appropriate m32 allocator and, where necessary, copy the data from
+ `section.start` (which points to the section in `oc->image`)
+ into the new allocation. Finally, `addSection()` updates the `section.start` field
+ to reflect the section's new home. In addition, we also allocate space for
+ the global BSS section.
+
+ At this point we have no further need for the preloaded image buffer,
+ `oc->image` and therefore free it.
+
+ Having populated the sections, we can proceed to add the object's symbols to
+ the symbol table. This is a matter of walking the object file's symbol table,
+ computing the symbol's address, and calling `ghciInsertSymbolTable`.
+
+ Finally, we enter `ocResolve`, where we resolve relocations and and allocate
+ jump islands (using the m32 allocator for backing storage) as necessary.
+
*/
#include "Rts.h"
@@ -183,10 +310,10 @@
#include "RtsSymbolInfo.h"
#include "GetEnv.h"
#include "CheckUnload.h"
+#include "LinkerInternals.h"
#include "linker/PEi386.h"
#include "linker/PEi386Types.h"
#include "linker/SymbolExtras.h"
-#include "LinkerInternals.h"
#include <windows.h>
#include <shfolder.h> /* SHGetFolderPathW */
@@ -205,7 +332,8 @@ static size_t makeSymbolExtra_PEi386(
ObjectCode* oc,
uint64_t index,
size_t s,
- SymbolName* symbol);
+ SymbolName* symbol,
+ SymType sym_type);
#endif
static void addDLLHandle(
@@ -223,34 +351,14 @@ static bool checkIfDllLoaded(
static uint32_t getSectionAlignment(
Section section);
-static uint8_t* getAlignedMemory(
- uint8_t* value,
- Section section);
-
static size_t getAlignedValue(
size_t value,
Section section);
-static void addCopySection(
- ObjectCode *oc,
- Section *s,
- SectionKind kind,
- SectionAlloc alloc,
- void* start,
- StgWord size);
-
static void releaseOcInfo(
ObjectCode* oc);
-/* Add ld symbol for PE image base. */
-#if defined(__GNUC__)
-#define __ImageBase __MINGW_LSYMBOL(_image_base__)
-#endif
-
-/* Get the base of the module. */
-/* This symbol is defined by ld. */
-extern IMAGE_DOS_HEADER __ImageBase;
-#define __image_base (void*)((HINSTANCE)&__ImageBase)
+static SymbolAddr *lookupSymbolInDLLs ( const SymbolName* lbl, ObjectCode *dependent );
const Alignments pe_alignments[] = {
{ IMAGE_SCN_ALIGN_1BYTES , 1 },
@@ -271,8 +379,6 @@ const Alignments pe_alignments[] = {
const int pe_alignments_cnt = sizeof (pe_alignments) / sizeof (Alignments);
const int default_alignment = 8;
-const int initHeapSizeMB = 15;
-static HANDLE code_heap = NULL;
/* See Note [_iob_func symbol]
In order to emulate __iob_func the memory location needs to point the
@@ -280,51 +386,19 @@ static HANDLE code_heap = NULL;
the pointer as a redirect. Essentially it's a DATA DLL reference. */
const void* __rts_iob_func = (void*)&__acrt_iob_func;
-/* Low Fragmentation Heap, try to prevent heap from increasing in size when
- space can simply be reclaimed. These are enums missing from mingw-w64's
- headers. */
-#define HEAP_LFH 2
-#define HeapOptimizeResources 3
-
void initLinker_PEi386()
{
if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
- symhash, "__image_base__", __image_base, HS_BOOL_TRUE, NULL)) {
+ symhash, "__image_base__",
+ GetModuleHandleW (NULL), HS_BOOL_TRUE,
+ SYM_TYPE_CODE, NULL)) {
barf("ghciInsertSymbolTable failed");
}
#if defined(mingw32_HOST_OS)
addDLLHandle(WSTR("*.exe"), GetModuleHandle(NULL));
- /*
- * Most of these are included by base, but GCC always includes them
- * So lets make sure we always have them too.
- *
- * In most cases they would have been loaded by the
- * addDLLHandle above.
- */
- addDLL(WSTR("msvcrt"));
- addDLL(WSTR("kernel32"));
- addDLL(WSTR("advapi32"));
- addDLL(WSTR("shell32"));
- addDLL(WSTR("user32"));
#endif
- /* See Note [Memory allocation]. */
- /* Create a private heap which we will use to store all code and data. */
- SYSTEM_INFO sSysInfo;
- GetSystemInfo(&sSysInfo);
- code_heap = HeapCreate (HEAP_CREATE_ENABLE_EXECUTE,
- initHeapSizeMB * sSysInfo.dwPageSize , 0);
- if (!code_heap)
- barf ("Could not create private heap during initialization. Aborting.");
-
- /* Set some flags for the new code heap. */
- HeapSetInformation(code_heap, HeapEnableTerminationOnCorruption, NULL, 0);
- unsigned long HeapInformation = HEAP_LFH;
- HeapSetInformation(code_heap, HeapEnableTerminationOnCorruption,
- &HeapInformation, sizeof(HeapInformation));
- HeapSetInformation(code_heap, HeapOptimizeResources, NULL, 0);
-
/* Register the cleanup routine as an exit handler, this gives other exit handlers
a chance to run which may need linker information. Exit handlers are ran in
reverse registration order so this needs to be before the linker loads anything. */
@@ -333,19 +407,11 @@ void initLinker_PEi386()
void exitLinker_PEi386()
{
- /* See Note [Memory allocation]. */
- if (code_heap) {
- HeapDestroy (code_heap);
- code_heap = NULL;
- }
}
/* A list thereof. */
static OpenedDLL* opened_dlls = NULL;
-/* A list thereof. */
-static IndirectAddr* indirects = NULL;
-
/* Adds a DLL instance to the list of DLLs in which to search for symbols. */
static void addDLLHandle(pathchar* dll_name, HINSTANCE instance) {
@@ -425,34 +491,22 @@ void freePreloadObjectFile_PEi386(ObjectCode *oc)
}
if (oc->info) {
- if (oc->info->image) {
- HeapFree(code_heap, 0, oc->info->image);
- oc->info->image = NULL;
- }
-
/* Release the unwinder information.
See Note [Exception Unwinding]. */
if (oc->info->xdata) {
if (!RtlDeleteFunctionTable (oc->info->xdata->start))
- debugBelch ("Unable to remove Exception handlers for %" PATH_FMT,
+ debugBelch ("Unable to remove Exception handlers for %" PATH_FMT "\n",
oc->fileName);
oc->info->xdata = NULL;
oc->info->pdata = NULL;
}
- if (oc->info->ch_info)
+
+ if (oc->info->ch_info) {
stgFree (oc->info->ch_info);
+ }
stgFree (oc->info);
oc->info = NULL;
}
-
- IndirectAddr *ia, *ia_next;
- ia = indirects;
- while (ia != NULL) {
- ia_next = ia->next;
- stgFree(ia);
- ia = ia_next;
- }
- indirects = NULL;
}
static void releaseOcInfo(ObjectCode* oc) {
@@ -537,7 +591,7 @@ COFF_OBJ_TYPE getObjectType ( char* image, pathchar* fileName )
*************/
COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc )
{
- COFF_OBJ_TYPE coff_type = getObjectType (oc->image, oc->fileName);
+ COFF_OBJ_TYPE coff_type = getObjectType (oc->image, OC_INFORMATIVE_FILENAME(oc));
COFF_HEADER_INFO* info
= stgMallocBytes (sizeof(COFF_HEADER_INFO), "getHeaderInfo");
@@ -827,16 +881,6 @@ static uint32_t getSectionAlignment(
}
/* ----------------------
- * return a memory location aligned to the section requirements
- */
-static uint8_t* getAlignedMemory(
- uint8_t* value, Section section) {
- uint32_t alignment = getSectionAlignment(section);
- uintptr_t mask = (uintptr_t)alignment - 1;
- return (uint8_t*)(((uintptr_t)value + mask) & ~mask);
-}
-
-/* ----------------------
* return a value aligned to the section requirements
*/
static size_t getAlignedValue(
@@ -1027,7 +1071,7 @@ zapTrailingAtSign ( SymbolName* sym )
#endif
SymbolAddr*
-lookupSymbolInDLLs ( const SymbolName* lbl )
+lookupSymbolInDLLs ( const SymbolName* lbl, ObjectCode *dependent )
{
OpenedDLL* o_dll;
SymbolAddr* sym;
@@ -1041,6 +1085,7 @@ lookupSymbolInDLLs ( const SymbolName* lbl )
return sym;
}
+ // TODO: Drop this
/* Ticket #2283.
Long description: http://support.microsoft.com/kb/132044
tl;dr:
@@ -1052,15 +1097,15 @@ lookupSymbolInDLLs ( const SymbolName* lbl )
sym = GetProcAddress(o_dll->instance,
lbl + 6 + STRIP_LEADING_UNDERSCORE);
if (sym != NULL) {
- IndirectAddr* ret;
- ret = stgMallocBytes( sizeof(IndirectAddr), "lookupSymbolInDLLs" );
- ret->addr = sym;
- ret->next = indirects;
- indirects = ret;
+ SymbolAddr** indirect = m32_alloc(dependent->rw_m32, sizeof(SymbolAddr*), 8);
+ if (indirect == NULL) {
+ barf("lookupSymbolInDLLs: Failed to allocation indirection");
+ }
+ *indirect = sym;
IF_DEBUG(linker,
debugBelch("warning: %s from %S is linked instead of %s\n",
lbl+6+STRIP_LEADING_UNDERSCORE, o_dll->name, lbl));
- return (void*) & ret->addr;
+ return (void*) indirect;
}
}
@@ -1151,8 +1196,6 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
oc->n_sections = info->numberOfSections + 1;
oc->info = stgCallocBytes (sizeof(struct ObjectCodeFormatInfo), 1,
"ocVerifyImage_PEi386(info)");
- oc->info->secBytesTotal = 0;
- oc->info->secBytesUsed = 0;
oc->info->init = NULL;
oc->info->finit = NULL;
oc->info->ch_info = info;
@@ -1223,31 +1266,14 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
memcpy (section->info->relocs, reltab + relocs_offset,
noRelocs * sizeof (COFF_reloc));
}
-
- oc->info->secBytesTotal += getAlignedValue (section->size, *section);
}
/* Initialize the last section's info field which contains the .bss
- section, it doesn't need an info so set it to NULL. */
+ section, the .info of which will be initialized by ocGetNames. Discard the
+ .info that we computed above. */
+ stgFree(sections[info->numberOfSections].info);
sections[info->numberOfSections].info = NULL;
- /* Calculate space for trampolines nearby.
- We get back 8-byte aligned memory (is that guaranteed?), but
- the offsets to the sections within the file are all 4 mod 8
- (is that guaranteed?). We therefore need to offset the image
- by 4, so that all the pointers are 8-byte aligned, so that
- pointer tagging works. */
- /* For 32-bit case we don't need this, hence we use macro
- PEi386_IMAGE_OFFSET, which equals to 4 for 64-bit case and 0 for
- 32-bit case. */
- /* We allocate trampolines area for all symbols right behind
- image data, aligned on 8. */
- oc->info->trampoline
- = (PEi386_IMAGE_OFFSET + 2 * default_alignment
- + oc->info->secBytesTotal) & ~0x7;
- oc->info->secBytesTotal
- = oc->info->trampoline + info->numberOfSymbols * sizeof(SymbolExtra);
-
/* No further verification after this point; only debug printing. */
i = 0;
IF_DEBUG(linker, i=1);
@@ -1301,6 +1327,10 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
return false;
}
+ i = 0;
+ IF_DEBUG(linker_verbose, i=1);
+ if (i == 0) return true;
+
/* Print the section table. */
debugBelch("\n" );
for (i = 0; i < info->numberOfSections; i++) {
@@ -1395,123 +1425,93 @@ bool
ocGetNames_PEi386 ( ObjectCode* oc )
{
bool has_code_section = false;
-
- SymbolName* sname = NULL;
- SymbolAddr* addr = NULL;
- unsigned int i;
-
COFF_HEADER_INFO *info = oc->info->ch_info;
/* Copy section information into the ObjectCode. */
- for (i = 0; i < info->numberOfSections; i++) {
- uint8_t* start;
- uint8_t* end;
- uint32_t sz;
-
+ for (unsigned int i = 0; i < info->numberOfSections; i++) {
/* By default consider all section as CODE or DATA,
which means we want to load them. */
SectionKind kind = SECTIONKIND_CODE_OR_RODATA;
- Section section = oc->sections[i];
+ Section *section = &oc->sections[i];
+ uint32_t alignment = getSectionAlignment(*section);
- IF_DEBUG(linker, debugBelch("section name = %s\n", section.info->name ));
+ // These will be computed below and determine how we will handle the
+ // section
+ size_t sz = section->size;
+ bool do_copy = true;
+ bool do_zero = false;
+
+ IF_DEBUG(linker, debugBelch("section name = %s (%x)\n", section->info->name, section->info->props ));
/* The PE file section flag indicates whether the section
contains code or data. */
- if (section.info->props & IMAGE_SCN_CNT_CODE) {
- has_code_section = has_code_section || section.size > 0;
+ if (section->info->props & IMAGE_SCN_CNT_CODE) {
+ has_code_section = has_code_section || section->size > 0;
kind = SECTIONKIND_CODE_OR_RODATA;
}
- if (section.info->props & IMAGE_SCN_CNT_INITIALIZED_DATA)
- kind = SECTIONKIND_CODE_OR_RODATA;
+ if (section->info->props & IMAGE_SCN_MEM_WRITE) {
+ kind = SECTIONKIND_RWDATA;
+ }
/* Check next if it contains any uninitialized data */
- if (section.info->props & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ if (section->info->props & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
kind = SECTIONKIND_RWDATA;
+ do_copy = false;
+ }
/* Finally check if it can be discarded.
This will also ignore .debug sections */
- if ( section.info->props & IMAGE_SCN_MEM_DISCARDABLE
- || section.info->props & IMAGE_SCN_LNK_REMOVE)
+ if ( section->info->props & IMAGE_SCN_MEM_DISCARDABLE
+ || section->info->props & IMAGE_SCN_LNK_REMOVE) {
kind = SECTIONKIND_OTHER;
+ }
- if (0==strncmp(".ctors", section.info->name, 6)) {
+ if (0==strncmp(".ctors", section->info->name, 6)) {
kind = SECTIONKIND_INIT_ARRAY;
oc->info->init = &oc->sections[i];
}
- if (0==strncmp(".dtors", section.info->name, 6)) {
+ if (0==strncmp(".dtors", section->info->name, 6)) {
kind = SECTIONKIND_FINIT_ARRAY;
oc->info->finit = &oc->sections[i];
}
- if ( 0 == strncmp(".stab" , section.info->name, 5 )
- || 0 == strncmp(".stabstr" , section.info->name, 8 )
- || 0 == strncmp(".debug" , section.info->name, 6 )
- || 0 == strncmp(".rdata$zzz", section.info->name, 10))
+ if ( 0 == strncmp(".stab" , section->info->name, 5 )
+ || 0 == strncmp(".stabstr" , section->info->name, 8 )
+ || 0 == strncmp(".debug" , section->info->name, 6 )
+ || 0 == strncmp(".rdata$zzz", section->info->name, 10))
kind = SECTIONKIND_DEBUG;
/* Exception Unwind information. See Note [Exception Unwinding]. */
- if (0 == strncmp(".xdata" , section.info->name, 6 )) {
+ if (0 == strncmp(".xdata" , section->info->name, 6 )) {
kind = SECTIONKIND_EXCEPTION_UNWIND;
oc->info->xdata = &oc->sections[i];
}
/* Exception handler tables, See Note [Exception Unwinding]. */
- if (0 == strncmp(".pdata" , section.info->name, 6 )) {
+ if (0 == strncmp(".pdata" , section->info->name, 6 )) {
kind = SECTIONKIND_EXCEPTION_TABLE;
oc->info->pdata = &oc->sections[i];
}
- if (0==strncmp(".idata", section.info->name, 6))
+ if (0==strncmp(".idata", section->info->name, 6)) {
kind = SECTIONKIND_IMPORT;
+ }
+
/* See Note [BFD import library]. */
- if (0==strncmp(".idata$7", section.info->name, 8))
- kind = SECTIONKIND_IMPORT_LIBRARY;
-
- if (0==strncmp(".idata$6", section.info->name, 8)) {
- /* The first two bytes contain the ordinal of the function
- in the format of lowpart highpart. The two bytes combined
- for the total range of 16 bits which is the function export limit
- of DLLs. */
- sname = (SymbolName*)section.start+2;
- COFF_symbol* sym = &oc->info->symbols[info->numberOfSymbols-1];
- addr = get_sym_name( getSymShortName (info, sym), oc);
-
- IF_DEBUG(linker,
- debugBelch("addImportSymbol `%s' => `%s'\n",
- sname, (char*)addr));
- /* We're going to free the any data associated with the import
- library without copying the sections. So we have to duplicate
- the symbol name and values before the pointers become invalid. */
- sname = strdup (sname);
- addr = strdup (addr);
- if (!ghciInsertSymbolTable(oc->fileName, symhash, sname,
- addr, false, oc)) {
- releaseOcInfo (oc);
- stgFree (oc->image);
- oc->image = NULL;
- return false;
- }
- setImportSymbol (oc, sname);
-
- /* Don't process this oc any further. Just exit. */
- oc->n_symbols = 0;
- oc->symbols = NULL;
- stgFree (oc->image);
- oc->image = NULL;
- releaseOcInfo (oc);
- oc->status = OBJECT_DONT_RESOLVE;
- return true;
+ if (0==strncmp(".idata$7", section->info->name, 8)) {
+ kind = SECTIONKIND_BFD_IMPORT_LIBRARY_HEAD;
}
- /* Allocate space for any (local, anonymous) .bss sections. */
- if (0==strncmp(".bss", section.info->name, 4)) {
- uint32_t bss_sz;
- uint8_t* zspace;
+ if (0==strncmp(".idata$6", section->info->name, 8)) {
+ kind = SECTIONKIND_BFD_IMPORT_LIBRARY;
+ }
+ /* Allocate space for any (local, anonymous) .bss sections. */
+ if (0==strncmp(".bss", section->info->name, 4)) {
/* sof 10/05: the PE spec text isn't too clear regarding what
* the SizeOfRawData field is supposed to hold for object
* file sections containing just uninitialized data -- for executables,
@@ -1531,42 +1531,49 @@ ocGetNames_PEi386 ( ObjectCode* oc )
*
* TODO: check if this comment is still relevant.
*/
- if (section.info->virtualSize == 0 && section.size == 0) continue;
+ if (section->info->virtualSize == 0 && section->size == 0) {
+ IF_DEBUG(linker_verbose, debugBelch("skipping empty .bss section\n"));
+ continue;
+ }
+
/* This is a non-empty .bss section.
Allocate zeroed space for it */
- bss_sz = section.info->virtualSize;
- if (bss_sz < section.size) { bss_sz = section.size; }
- zspace = stgCallocBytes(1, bss_sz, "ocGetNames_PEi386(anonymous bss)");
- oc->sections[i].start = zspace;
- oc->sections[i].size = bss_sz;
- section = oc->sections[i];
- /* debugBelch("BSS anon section at 0x%x\n", zspace); */
+ kind = SECTIONKIND_RWDATA;
+ do_zero = true;
+ do_copy = false;
+ IF_DEBUG(linker_verbose, debugBelch("BSS anon section\n"));
}
- /* Allocate space for the sections since we have a real oc.
- We initially mark it the region as non-accessible. But will adjust
- as we go along. */
- if (!oc->info->image) {
- /* See Note [Memory allocation]. */
- ASSERT(code_heap);
- oc->info->image
- = HeapAlloc (code_heap, HEAP_ZERO_MEMORY, oc->info->secBytesTotal);
- if (!oc->info->image)
- barf ("Could not allocate any heap memory from private heap.");
+ CHECK(section->size == 0 || section->info->virtualSize == 0);
+ if (sz < section->info->virtualSize) {
+ sz = section->info->virtualSize;
}
- CHECK(section.size == 0 || section.info->virtualSize == 0);
- sz = section.size;
- if (sz < section.info->virtualSize) sz = section.info->virtualSize;
+ // Ignore these section types
+ if (kind == SECTIONKIND_OTHER || sz == 0) {
+ continue;
+ }
- start = section.start;
- end = start + sz;
+ // Allocate memory for the section.
+ uint8_t *start;
+ if (kind == SECTIONKIND_CODE_OR_RODATA) {
+ start = m32_alloc(oc->rx_m32, sz, alignment);
+ } else {
+ start = m32_alloc(oc->rw_m32, sz, alignment);
+ }
+ if (!start) {
+ barf("Could not allocate any heap memory from private heap (requested %" FMT_SizeT " bytes).",
+ sz);
+ }
- if (kind != SECTIONKIND_OTHER && end > start) {
- /* See Note [Section alignment]. */
- addCopySection(oc, &oc->sections[i], kind, SECTION_NOMEM, start, sz);
- addProddableBlock(oc, oc->sections[i].start, sz);
+ if (do_copy) {
+ memcpy(start, section->start, sz);
+ } else if (do_zero) {
+ memset(start, 0, sz);
}
+
+ addSection(section, kind, SECTION_NOMEM, start, sz, 0, 0, 0);
+ addProddableBlock(oc, oc->sections[i].start, sz);
}
/* Copy exported symbols into the ObjectCode. */
@@ -1577,7 +1584,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
/* Work out the size of the global BSS section */
StgWord globalBssSize = 0;
- for (i=0; i < info->numberOfSymbols; i++) {
+ for (unsigned int i=0; i < info->numberOfSymbols; i++) {
COFF_symbol* sym = &oc->info->symbols[i];
if (getSymSectionNumber (info, sym) == IMAGE_SYM_UNDEFINED
&& getSymValue (info, sym) > 0
@@ -1590,12 +1597,14 @@ ocGetNames_PEi386 ( ObjectCode* oc )
/* Allocate BSS space */
SymbolAddr* bss = NULL;
if (globalBssSize > 0) {
- bss = stgCallocBytes(1, globalBssSize,
- "ocGetNames_PEi386(non-anonymous bss)");
+ bss = m32_alloc(oc->rw_m32, globalBssSize, 16);
+ if (bss == NULL) {
+ barf("ocGetNames_PEi386: Failed to allocate global bss section");
+ }
addSection(&oc->sections[oc->n_sections-1],
SECTIONKIND_RWDATA, SECTION_MALLOC,
bss, globalBssSize, 0, 0, 0);
- IF_DEBUG(linker, debugBelch("bss @ %p %" FMT_Word "\n", bss, globalBssSize));
+ IF_DEBUG(linker_verbose, debugBelch("bss @ %p %" FMT_Word "\n", bss, globalBssSize));
addProddableBlock(oc, bss, globalBssSize);
} else {
addSection(&oc->sections[oc->n_sections-1],
@@ -1607,22 +1616,31 @@ ocGetNames_PEi386 ( ObjectCode* oc )
stgFree (oc->image);
oc->image = NULL;
- for (i = 0; i < (uint32_t)oc->n_symbols; i++) {
+ for (unsigned int i = 0; i < (uint32_t)oc->n_symbols; i++) {
COFF_symbol* sym = &oc->info->symbols[i];
int32_t secNumber = getSymSectionNumber (info, sym);
uint32_t symValue = getSymValue (info, sym);
uint8_t symStorageClass = getSymStorageClass (info, sym);
- addr = NULL;
+ SymbolAddr *addr = NULL;
bool isWeak = false;
- sname = get_sym_name (getSymShortName (info, sym), oc);
+ SymbolName *sname = get_sym_name (getSymShortName (info, sym), oc);
Section *section = secNumber > 0 ? &oc->sections[secNumber-1] : NULL;
+ SymType type;
+ switch (getSymType(oc->info->ch_info, sym)) {
+ case 0x00: type = SYM_TYPE_DATA; break;
+ case 0x20: type = SYM_TYPE_CODE; break;
+ default:
+ debugBelch("Invalid symbol type: 0x%x\n", getSymType(oc->info->ch_info, sym));
+ return 1;
+ }
+
if ( secNumber != IMAGE_SYM_UNDEFINED
&& secNumber > 0
&& section
- && section->kind != SECTIONKIND_IMPORT_LIBRARY) {
+ && section->kind != SECTIONKIND_BFD_IMPORT_LIBRARY) {
/* This symbol is global and defined, viz, exported */
/* for IMAGE_SYMCLASS_EXTERNAL
&& !IMAGE_SYM_UNDEFINED,
@@ -1647,10 +1665,18 @@ ocGetNames_PEi386 ( ObjectCode* oc )
bss = (SymbolAddr*)((StgWord)bss + (StgWord)symValue);
IF_DEBUG(linker_verbose, debugBelch("bss symbol @ %p %u\n", addr, symValue));
}
+ else if (section && section->kind == SECTIONKIND_BFD_IMPORT_LIBRARY) {
+ setImportSymbol(oc, sname);
+ // There is nothing that we need to resolve in this object since we
+ // will never call the import stubs in its text section
+ oc->status = OBJECT_DONT_RESOLVE;
+
+ IF_DEBUG(linker_verbose, debugBelch("import symbol %s\n", sname));
+ }
else if (secNumber > 0
&& section
- && section->kind == SECTIONKIND_IMPORT_LIBRARY) {
- /* This is an import section. We should load the dll and lookup
+ && section->kind == SECTIONKIND_BFD_IMPORT_LIBRARY_HEAD) {
+ /* This is an Gnu BFD import section. We should load the dll and lookup
the symbols.
See Note [BFD import library]. */
char* dllName = section->start;
@@ -1707,7 +1733,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
stgFree(tmp);
sname = strdup (sname);
if (!ghciInsertSymbolTable(oc->fileName, symhash, sname,
- addr, false, oc))
+ addr, false, type, oc))
return false;
break;
@@ -1721,12 +1747,13 @@ ocGetNames_PEi386 ( ObjectCode* oc )
ASSERT(i < (uint32_t)oc->n_symbols);
oc->symbols[i].name = sname;
oc->symbols[i].addr = addr;
+ oc->symbols[i].type = type;
if (isWeak) {
setWeakSymbol(oc, sname);
}
if (! ghciInsertSymbolTable(oc->fileName, symhash, sname, addr,
- isWeak, oc))
+ isWeak, type, oc))
return false;
} else {
/* We're skipping the symbol, but if we ever load this
@@ -1743,36 +1770,34 @@ ocGetNames_PEi386 ( ObjectCode* oc )
#if defined(x86_64_HOST_ARCH)
-/* We've already reserved a room for symbol extras in loadObj,
- * so simply set correct pointer here.
- */
-bool
-ocAllocateExtras_PEi386 ( ObjectCode* oc )
-{
- /* If the ObjectCode was unloaded we don't need a trampoline, it's likely
- an import library so we're discarding it earlier. */
- if (!oc->info)
- return false;
-
- // These are allocated on-demand from m32 by makeSymbolExtra_PEi386
- oc->first_symbol_extra = 0;
- oc->n_symbol_extras = 0;
- oc->symbol_extras = NULL;
-
- return true;
-}
-
static size_t
-makeSymbolExtra_PEi386( ObjectCode* oc, uint64_t index STG_UNUSED, size_t s, char* symbol STG_UNUSED )
+makeSymbolExtra_PEi386( ObjectCode* oc, uint64_t index STG_UNUSED, size_t s, char* symbol STG_UNUSED, SymType type )
{
- SymbolExtra *extra = m32_alloc(oc->rx_m32, sizeof(SymbolExtra), 8);
-
- // jmp *-14(%rip)
- static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
- extra->addr = (uint64_t)s;
- memcpy(extra->jumpIsland, jmp, 6);
-
- return (size_t)extra->jumpIsland;
+ SymbolExtra *extra;
+
+ if (type == SYM_TYPE_CODE) {
+ // jmp *-14(%rip)
+ extra = m32_alloc(oc->rx_m32, sizeof(SymbolExtra), 8);
+ CHECK(extra);
+ extra->addr = (uint64_t)s;
+ static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
+ memcpy(extra->jumpIsland, jmp, 6);
+ IF_DEBUG(linker_verbose, debugBelch("makeSymbolExtra(code): %s -> %p\n", symbol, &extra->jumpIsland));
+ return (size_t)&extra->jumpIsland;
+ } else if (type == SYM_TYPE_INDIRECT_DATA) {
+ extra = m32_alloc(oc->rw_m32, sizeof(SymbolExtra), 8);
+ CHECK(extra);
+ void *v = *(void**) s;
+ extra->addr = (uint64_t)v;
+ IF_DEBUG(linker_verbose, debugBelch("makeSymbolExtra(data): %s -> %p\n", symbol, &extra->addr));
+ return (size_t)&extra->addr;
+ } else {
+ extra = m32_alloc(oc->rw_m32, sizeof(SymbolExtra), 8);
+ CHECK(extra);
+ extra->addr = (uint64_t)s;
+ IF_DEBUG(linker_verbose, debugBelch("makeSymbolExtra(indirect-data): %s -> %p\n", symbol, &extra->addr));
+ return (size_t)&extra->addr;
+ }
}
void ocProtectExtras(ObjectCode* oc STG_UNUSED) { }
@@ -1806,7 +1831,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
/* Ignore sections called which contain stabs debugging information. */
if (section.kind == SECTIONKIND_DEBUG)
- continue;
+ continue;
noRelocs = section.info->noRelocs;
for (j = 0; j < noRelocs; j++) {
@@ -1825,15 +1850,17 @@ ocResolve_PEi386 ( ObjectCode* oc )
uint64_t symIndex = reloc->SymbolTableIndex;
sym = &oc->info->symbols[symIndex];
+ SymType sym_type;
+
IF_DEBUG(linker_verbose,
debugBelch(
- "reloc sec %2d num %3d: type 0x%-4x "
+ "reloc sec %2d num %3d: P=%p, type 0x%-4x "
"vaddr 0x%-8lx name `",
- i, j,
+ i, j, pP,
reloc->Type,
reloc->VirtualAddress );
printName (getSymShortName (info, sym), oc);
- debugBelch("'\n" ));
+ debugBelch("'\n" ));
if (getSymStorageClass (info, sym) == IMAGE_SYM_CLASS_STATIC) {
Section section = oc->sections[getSymSectionNumber (info, sym)-1];
@@ -1842,13 +1869,15 @@ ocResolve_PEi386 ( ObjectCode* oc )
} else {
copyName ( getSymShortName (info, sym), oc, symbol,
sizeof(symbol)-1 );
- S = (size_t) lookupDependentSymbol( (char*)symbol, oc );
+ S = (size_t) lookupDependentSymbol( (char*)symbol, oc, &sym_type );
if ((void*)S == NULL) {
errorBelch(" | %" PATH_FMT ": unknown symbol `%s'", oc->fileName, symbol);
releaseOcInfo (oc);
return false;
}
}
+ IF_DEBUG(linker_verbose, debugBelch("S=%zx\n", S));
+
/* All supported relocations write at least 4 bytes */
checkProddableBlock(oc, pP, 4);
switch (reloc->Type) {
@@ -1903,23 +1932,23 @@ ocResolve_PEi386 ( ObjectCode* oc )
/* If IMAGE_REL_AMD64_ADDR32NB then subtract the image base. */
if (reloc->Type == 3)
- v -= (uint64_t)__image_base;
+ v -= (uint64_t) GetModuleHandleW(NULL);
// N.B. in the case of the sign-extended relocations we must ensure that v
// fits in a signed 32-bit value. See #15808.
if (((int64_t) v > (int64_t) INT32_MAX) || ((int64_t) v < (int64_t) INT32_MIN)) {
copyName (getSymShortName (info, sym), oc,
symbol, sizeof(symbol)-1);
- S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
+ S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol, sym_type);
/* And retry */
v = S + A;
/* If IMAGE_REL_AMD64_ADDR32NB then subtract the image base. */
if (reloc->Type == 3)
- v -= (uint64_t)__image_base;
+ v -= (uint64_t) GetModuleHandleW(NULL);
if (((int64_t) v > (int64_t) INT32_MAX) || ((int64_t) v < (int64_t) INT32_MIN)) {
- barf("IMAGE_REL_AMD64_ADDR32[NB]: High bits are set in %zx for %s",
+ barf("IMAGE_REL_AMD64_ADDR32[NB]: High bits are set in 0x%zx for %s",
v, (char *)symbol);
}
}
@@ -1934,11 +1963,11 @@ ocResolve_PEi386 ( ObjectCode* oc )
/* Make the trampoline then */
copyName (getSymShortName (info, sym),
oc, symbol, sizeof(symbol)-1);
- S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
+ S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol, sym_type);
/* And retry */
v = S + (int32_t)A - ((intptr_t)pP) - 4;
if ((v > (int64_t) INT32_MAX) || (v < (int64_t) INT32_MIN)) {
- barf("IMAGE_REL_AMD64_REL32: High bits are set in %zx for %s",
+ barf("IMAGE_REL_AMD64_REL32: High bits are set in 0x%zx for %s",
v, (char *)symbol);
}
}
@@ -1965,7 +1994,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
/* Now register the exception handler for the range and point it
to the unwind data. */
- if (!RtlAddFunctionTable (section.start, numEntries, (uintptr_t)__image_base)) {
+ if (!RtlAddFunctionTable (section.start, numEntries, (uintptr_t) GetModuleHandleW(NULL))) {
sysErrorBelch("Unable to register Exception handler for %p for "
"section %s in %" PATH_FMT " (Win32 error %lu)",
section.start, section.info->name, oc->fileName,
@@ -2096,7 +2125,7 @@ ocRunInit_PEi386 ( ObjectCode *oc )
return true;
}
-SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl)
+SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl, ObjectCode *dependent, SymType *type)
{
RtsSymbolInfo *pinfo;
@@ -2109,9 +2138,17 @@ SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl)
#if !defined(x86_64_HOST_ARCH)
zapTrailingAtSign ( lbl );
#endif
- sym = lookupSymbolInDLLs(lbl);
+ if (type) {
+ // Unfortunately we can only assume that this is the case. Ideally
+ // the user would have given us an import library, which would allow
+ // us to determine the symbol type precisely.
+ *type = SYM_TYPE_CODE;
+ }
+ sym = lookupSymbolInDLLs(lbl, dependent);
return sym; // might be NULL if not found
} else {
+ if (type) *type = pinfo->type;
+
// If Windows, perform initialization of uninitialized
// Symbols from the C runtime which was loaded above.
// We do this on lookup to prevent the hit when
@@ -2123,11 +2160,12 @@ SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl)
static HMODULE msvcrt = NULL;
if (!msvcrt) msvcrt = GetModuleHandle("msvcrt");
pinfo->value = GetProcAddress(msvcrt, symBuffer);
+ return pinfo->value;
}
else if (pinfo && pinfo->owner && isSymbolImport (pinfo->owner, lbl))
{
/* See Note [BFD import library]. */
- HINSTANCE dllInstance = (HINSTANCE)lookupDependentSymbol(pinfo->value, NULL);
+ HINSTANCE dllInstance = (HINSTANCE)lookupDependentSymbol(pinfo->value, dependent, type);
if (!dllInstance && pinfo->value)
return pinfo->value;
@@ -2143,41 +2181,34 @@ SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl)
pinfo->value = GetProcAddress((HMODULE)dllInstance, lbl);
clearImportSymbol (pinfo->owner, lbl);
return pinfo->value;
+ } else {
+ if (dependent) {
+ // Add dependent as symbol's owner's dependency
+ ObjectCode *owner = pinfo->owner;
+ if (owner) {
+ // TODO: what does it mean for a symbol to not have an owner?
+ insertHashSet(dependent->dependencies, (W_)owner);
+ }
+ }
+ return loadSymbol(lbl, pinfo);
}
- return loadSymbol(lbl, pinfo);
}
}
/* -----------------------------------------------------------------------------
- * Section management.
+ * Debugging operations.
*/
- /* See Note [Section alignment]. */
-static void
-addCopySection (ObjectCode *oc, Section *s, SectionKind kind,
- SectionAlloc alloc, void* start, StgWord size) {
- char* pos = oc->info->image + oc->info->secBytesUsed;
- char* newStart = (char*)getAlignedMemory ((uint8_t*)pos, *s);
- memcpy (newStart, start, size);
- uintptr_t offset = (uintptr_t)newStart - (uintptr_t)oc->info->image;
- oc->info->secBytesUsed = (size_t)offset + size;
- start = newStart;
-
- /* Initially I wanted to apply the right memory protection to the region and
- which would leaved the gaps in between the regions as inaccessible memory
- to prevent exploits.
- The problem is protection is always on page granularity, so we can use
- less memory and be insecure or use more memory and be secure.
- For now, I've chosen lower memory over secure as the first pass, this
- doesn't regress security over the current implementation. After this
- patch I will change to different implementation that will fix the mem
- protection and keep the memory size small. */
- addSection (s, kind, alloc, start, size, 0, 0, 0);
-}
+typedef struct _SymX { SymbolName* name; uintptr_t loc; } SymX;
-/* -----------------------------------------------------------------------------
- * Debugging operations.
- */
+static int comp (const void * elem1, const void * elem2)
+{
+ SymX f = *((SymX*)elem1);
+ SymX s = *((SymX*)elem2);
+ if (f.loc > s.loc) return 1;
+ if (f.loc < s.loc) return -1;
+ return 0;
+}
pathchar*
resolveSymbolAddr_PEi386 (pathchar* buffer, int size,
@@ -2304,7 +2335,6 @@ resolveSymbolAddr_PEi386 (pathchar* buffer, int size,
else if (obj)
{
/* Try to calculate from information inside the rts. */
- typedef struct _SymX { SymbolName* name; uintptr_t loc; } SymX;
SymX* locs = stgCallocBytes (sizeof(SymX), obj->n_symbols,
"resolveSymbolAddr");
int blanks = 0;
@@ -2324,14 +2354,6 @@ resolveSymbolAddr_PEi386 (pathchar* buffer, int size,
locs[i] = sx;
}
}
- int comp (const void * elem1, const void * elem2)
- {
- SymX f = *((SymX*)elem1);
- SymX s = *((SymX*)elem2);
- if (f.loc > s.loc) return 1;
- if (f.loc < s.loc) return -1;
- return 0;
- }
qsort (locs, obj->n_symbols, sizeof (SymX), comp);
uintptr_t key = (uintptr_t)symbol;
SymX* res = NULL;
diff --git a/rts/linker/PEi386.h b/rts/linker/PEi386.h
index 8e6e844efb..c5c88459a6 100644
--- a/rts/linker/PEi386.h
+++ b/rts/linker/PEi386.h
@@ -4,7 +4,9 @@
#include "LinkerInternals.h"
#include "PathUtils.h"
#include <windows.h>
+#include <stdint.h>
#include <stdbool.h>
+#include <inttypes.h>
#include "BeginPrivate.h"
@@ -56,9 +58,8 @@ bool ocResolve_PEi386 ( ObjectCode* oc );
bool ocRunInit_PEi386 ( ObjectCode *oc );
bool ocGetNames_PEi386 ( ObjectCode* oc );
bool ocVerifyImage_PEi386 ( ObjectCode* oc );
-SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl);
-bool ocAllocateExtras_PEi386 ( ObjectCode* oc );
-SymbolAddr *lookupSymbolInDLLs ( const SymbolName* lbl );
+SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl, ObjectCode *dependent, SymType *type);
+
/* See Note [mingw-w64 name decoration scheme] */
/* We use myindex to calculate array addresses, rather than
simply doing the normal subscript thing. That's because
@@ -124,13 +125,6 @@ struct _OpenedDLL {
HINSTANCE instance;
} OpenedDLL;
-/* A record for storing indirectly linked functions from DLLs. */
-typedef
-struct _IndirectAddr {
- SymbolAddr* addr;
- struct _IndirectAddr* next;
-} IndirectAddr;
-
/* Some alignment information. */
typedef
struct _Alignments {
diff --git a/rts/linker/PEi386Types.h b/rts/linker/PEi386Types.h
index 9ad2103f92..792cc03fda 100644
--- a/rts/linker/PEi386Types.h
+++ b/rts/linker/PEi386Types.h
@@ -17,10 +17,6 @@ struct SectionFormatInfo {
uint64_t virtualAddr;
};
struct ObjectCodeFormatInfo {
- size_t secBytesTotal;
- size_t secBytesUsed;
- char* image;
- size_t trampoline;
Section* init;
Section* finit;
Section* pdata;
diff --git a/rts/linker/elf_got.c b/rts/linker/elf_got.c
index eefdae34c6..0f511e663f 100644
--- a/rts/linker/elf_got.c
+++ b/rts/linker/elf_got.c
@@ -92,7 +92,7 @@ fillGot(ObjectCode * oc) {
if( STT_NOTYPE == ELF_ST_TYPE(symbol->elf_sym->st_info)
|| STB_WEAK == ELF_ST_BIND(symbol->elf_sym->st_info)) {
if(0x0 == symbol->addr) {
- symbol->addr = lookupDependentSymbol(symbol->name, oc);
+ symbol->addr = lookupDependentSymbol(symbol->name, oc, NULL);
if(0x0 == symbol->addr) {
if(0 == strncmp(symbol->name,"_GLOBAL_OFFSET_TABLE_",21)) {
symbol->addr = oc->info->got_start;
diff --git a/rts/sm/GC.h b/rts/sm/GC.h
index da90c61302..25de588534 100644
--- a/rts/sm/GC.h
+++ b/rts/sm/GC.h
@@ -13,10 +13,10 @@
#pragma once
-#include "BeginPrivate.h"
-
#include "HeapAlloc.h"
+#include "BeginPrivate.h"
+
void GarbageCollect (uint32_t collect_gen,
bool do_heap_census,
bool is_overflow_gc,
diff --git a/rts/sm/GCUtils.h b/rts/sm/GCUtils.h
index 798a795deb..dec81e1755 100644
--- a/rts/sm/GCUtils.h
+++ b/rts/sm/GCUtils.h
@@ -13,10 +13,10 @@
#pragma once
-#include "BeginPrivate.h"
-
#include "GCTDecl.h"
+#include "BeginPrivate.h"
+
bdescr* allocGroup_sync(uint32_t n);
bdescr* allocGroupOnNode_sync(uint32_t node, uint32_t n);
diff --git a/rts/sm/MarkStack.h b/rts/sm/MarkStack.h
index ca519f871f..8ea47a1865 100644
--- a/rts/sm/MarkStack.h
+++ b/rts/sm/MarkStack.h
@@ -13,9 +13,10 @@
#pragma once
-#include "BeginPrivate.h"
#include "GCUtils.h"
+#include "BeginPrivate.h"
+
INLINE_HEADER void
push_mark_stack(StgPtr p)
{
diff --git a/testsuite/config/ghc b/testsuite/config/ghc
index 632db8fc57..d33101fef8 100644
--- a/testsuite/config/ghc
+++ b/testsuite/config/ghc
@@ -58,6 +58,7 @@ if ghc_with_dynamic_rts:
if windows:
config.supports_dynamic_hs = False
+ config.stdcxx_impl = 'c++'
if (config.have_profiling and ghc_with_threaded_rts):
config.run_ways.append('profthreaded')
diff --git a/testsuite/driver/runtests.py b/testsuite/driver/runtests.py
index d2e25eaa19..0d458924d0 100644
--- a/testsuite/driver/runtests.py
+++ b/testsuite/driver/runtests.py
@@ -232,6 +232,8 @@ else:
print('WARNING: No UTF8 locale found.')
print('You may get some spurious test failures.')
+ghc_env['LIBCXX'] = config.stdcxx_impl
+
# https://stackoverflow.com/a/22254892/1308058
def supports_colors():
"""
diff --git a/testsuite/driver/testglobals.py b/testsuite/driver/testglobals.py
index 6847cece68..b85a14e17a 100644
--- a/testsuite/driver/testglobals.py
+++ b/testsuite/driver/testglobals.py
@@ -217,6 +217,8 @@ class TestConfig:
# The path specifies the file in which to write the dependencies
self.only_report_hadrian_deps = None # type: Optional[Path]
+ # C++ standard library implementation
+ self.stdcxx_impl = 'stdc++' # or c++ for LLVM/libc++ based platforms
def validate(self) -> None:
""" Check the TestConfig for self-consistency """
diff --git a/testsuite/driver/testlib.py b/testsuite/driver/testlib.py
index 7ee179b837..9c9a1760a2 100644
--- a/testsuite/driver/testlib.py
+++ b/testsuite/driver/testlib.py
@@ -1303,7 +1303,9 @@ def framework_fail(name: Optional[TestName], way: Optional[WayName], reason: str
if_verbose(1, '*** framework failure for %s %s ' % (full_name, reason))
name2 = name if name is not None else TestName('none')
way2 = way if way is not None else WayName('none')
- t.framework_failures.append(TestResult(directory, name2, reason, way2))
+ if way not in opts.fragile_ways:
+ # If the test is fragile then we rather report this as a fragile test failure
+ t.framework_failures.append(TestResult(directory, name2, reason, way2))
def framework_warn(name: TestName, way: WayName, reason: str) -> None:
opts = getTestOpts()
diff --git a/testsuite/mk/boilerplate.mk b/testsuite/mk/boilerplate.mk
index 03c281f76d..df1b835b0c 100644
--- a/testsuite/mk/boilerplate.mk
+++ b/testsuite/mk/boilerplate.mk
@@ -308,6 +308,8 @@ ifeq "$(HostOS)" "freebsd"
LIBCXX_PLATFORM = YES
else ifeq "$(HostOS)" "openbsd"
LIBCXX_PLATFORM = YES
+else ifeq "$(HostOS)" "mingw32"
+LIBCXX_PLATFORM = YES
else
LIBCXX_PLATFORM = NO
endif
diff --git a/testsuite/tests/codeGen/should_compile/all.T b/testsuite/tests/codeGen/should_compile/all.T
index 9985580e78..a18451b98e 100644
--- a/testsuite/tests/codeGen/should_compile/all.T
+++ b/testsuite/tests/codeGen/should_compile/all.T
@@ -104,3 +104,6 @@ test('T15570',
# warning: integer constant is so large that it is unsigned
test('T18614', normal, compile, [''])
+test('mk-big-obj',
+ [unless(opsys('mingw32'), skip), pre_cmd('$PYTHON mk-big-obj.py > mk-big-obj.c')],
+ multimod_compile, ['mk-big-obj.c', '-c -v0 -no-hs-main'])
diff --git a/testsuite/tests/codeGen/should_compile/mk-big-obj.py b/testsuite/tests/codeGen/should_compile/mk-big-obj.py
new file mode 100644
index 0000000000..c03fdbf380
--- /dev/null
+++ b/testsuite/tests/codeGen/should_compile/mk-big-obj.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+
+for i in range(70000):
+ print(f'''
+ int __attribute__((section("text.test{i}")))
+ test{i}(void)
+ {{ return {i}; }}
+ ''')
+
diff --git a/testsuite/tests/codeGen/should_fail/all.T b/testsuite/tests/codeGen/should_fail/all.T
index e23fa03f82..3f2dacee46 100644
--- a/testsuite/tests/codeGen/should_fail/all.T
+++ b/testsuite/tests/codeGen/should_fail/all.T
@@ -7,7 +7,7 @@ test('T8131', [cmm_src, only_ways(llvm_ways)], compile_fail, ['-no-hs-main'])
def check_bounds_test(name):
""" A -fcheck-prim-bounds test that is expected to fail. """
test(name,
- [ignore_stderr, exit_code(3 if opsys('mingw32') else 134)],
+ [ignore_stderr, exit_code(127 if opsys('mingw32') else 134)],
compile_and_run, ['-fcheck-prim-bounds'])
check_bounds_test('CheckBoundsWriteArray')
diff --git a/testsuite/tests/ghci/linking/Makefile b/testsuite/tests/ghci/linking/Makefile
index 78d13c6e8a..7b77e91c09 100644
--- a/testsuite/tests/ghci/linking/Makefile
+++ b/testsuite/tests/ghci/linking/Makefile
@@ -24,12 +24,6 @@ else
DLL = lib$1.so
endif
-ifeq "$(LIBCXX_PLATFORM)" "YES"
-LIBCXX=c++
-else
-LIBCXX=stdc++
-endif
-
.PHONY: ghcilink002
ghcilink002 :
$(RM) -rf dir002
@@ -118,11 +112,7 @@ ghcilink006 :
echo "version: 1.0" >>$(PKG006)
echo "id: test-XXX" >>$(PKG006)
echo "key: test-XXX" >>$(PKG006)
-ifeq "$(WINDOWS)" "YES"
- echo "extra-libraries: stdc++-6" >>$(PKG006)
-else
echo "extra-libraries: $(LIBCXX)" >>$(PKG006)
-endif
'$(GHC_PKG)' init $(LOCAL_PKGCONF006)
'$(GHC_PKG)' --no-user-package-db -f $(LOCAL_PKGCONF006) register $(PKG006) -v0
#
diff --git a/testsuite/tests/ghci/linking/all.T b/testsuite/tests/ghci/linking/all.T
index 40d79cbc09..b4564f0237 100644
--- a/testsuite/tests/ghci/linking/all.T
+++ b/testsuite/tests/ghci/linking/all.T
@@ -12,8 +12,6 @@ test('ghcilink002', [extra_files(['TestLink.hs', 'f.c']),
test('ghcilink003',
[ unless(doing_ghci, skip),
- # libstdc++ is GCC-specific on FreeBSD. FreeBSD has libc++ though.
- when(opsys('freebsd'), fragile(17739)),
# from Big Sur onwards, we can't dlopen libstdc++.dylib
# anymore. Will produce:
# dlopen(libstdc++.dylib, 5): image not found
@@ -36,8 +34,6 @@ test('ghcilink005',
test('ghcilink006',
[ unless(doing_ghci, skip),
- # libstdc++ is GCC-specific on FreeBSD. FreeBSD has libc++ though.
- when(opsys('freebsd'), fragile(17739)),
# from Big Sur onwards, we can't dlopen libstdc++.dylib
# anymore. Will produce:
# dlopen(libstdc++.dylib, 5): image not found
diff --git a/testsuite/tests/ghci/linking/dyn/A.def b/testsuite/tests/ghci/linking/dyn/A.def
new file mode 100644
index 0000000000..5198ddd028
--- /dev/null
+++ b/testsuite/tests/ghci/linking/dyn/A.def
@@ -0,0 +1,3 @@
+LIBRARY libA
+EXPORTS
+foo \ No newline at end of file
diff --git a/testsuite/tests/ghci/linking/dyn/B.def b/testsuite/tests/ghci/linking/dyn/B.def
new file mode 100644
index 0000000000..bdfc2cbfbb
--- /dev/null
+++ b/testsuite/tests/ghci/linking/dyn/B.def
@@ -0,0 +1,3 @@
+LIBRARY libB
+EXPORTS
+bar
diff --git a/testsuite/tests/ghci/linking/dyn/Makefile b/testsuite/tests/ghci/linking/dyn/Makefile
index 7f14f7d08a..da8ee20790 100644
--- a/testsuite/tests/ghci/linking/dyn/Makefile
+++ b/testsuite/tests/ghci/linking/dyn/Makefile
@@ -2,6 +2,16 @@ TOP=../../../..
include $(TOP)/mk/boilerplate.mk
include $(TOP)/mk/test.mk
+# On Windows we must provide module definitions (.def files)
+# for shared libraries, lest the linker exports *everything*, including RTS
+# symbols. This would mean that we couldn't link against multiple dynamic
+# objects simultaneously as the RTS symbols would be defined multiple times.
+ifeq "$(WINDOWS)" "YES"
+DEF = "$1.def"
+else
+DEF =
+endif
+
ifeq "$(WINDOWS)" "YES"
DLL = lib$1.dll
else ifeq "$(DARWIN)" "YES"
@@ -62,16 +72,16 @@ compile_libT10458:
compile_libAB_dep:
rm -rf bin_dep
mkdir bin_dep
- '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared A.c -o "bin_dep/$(call DLL,A)"
- '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared B.c -o "bin_dep/$(call DLL,B)" -lA -L"./bin_dep"
+ '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared A.c -o "bin_dep/$(call DLL,A)" $(call DEF,A)
+ '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared B.c -o "bin_dep/$(call DLL,B)" $(call DEF,B) -lA -L"./bin_dep"
rm -f bin_dep/*.a
.PHONY: compile_libAB_dyn
compile_libAB_dyn:
rm -rf bin_dyn
mkdir bin_dyn
- '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared A.c -o "bin_dyn/$(call DLL,A)"
- '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared B.c -o "bin_dyn/$(call DLL,B)" -lA -L"./bin_dyn"
+ '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared A.c -o "bin_dyn/$(call DLL,A)" $(call DEF,A)
+ '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared B.c -o "bin_dyn/$(call DLL,B)" $(call DEF,B) -lA -L"./bin_dyn"
rm -f bin_dyn/*.a
'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -v0 -o "bin_dyn/$(call EXE,T10955dyn)" -L./bin_dyn -lB -lA T10955dyn.hs -v0
LD_LIBRARY_PATH=./bin_dyn ./bin_dyn/$(call EXE,T10955dyn)
@@ -99,6 +109,7 @@ T1407:
.PHONY: T3242
echo ":q" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -lm
+# We use gdi32 as library with an import library.
.PHONY: T13606
T13606:
- echo ":q" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -lgcc_s
+ echo ":q" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -lgdi32.a
diff --git a/testsuite/tests/ghci/linking/dyn/all.T b/testsuite/tests/ghci/linking/dyn/all.T
index 0092f7febe..9b05ed5fc3 100644
--- a/testsuite/tests/ghci/linking/dyn/all.T
+++ b/testsuite/tests/ghci/linking/dyn/all.T
@@ -16,13 +16,15 @@ test('T3242',
makefile_test, ['T3242'])
test('T10955',
- [extra_files(['A.c', 'B.c']),
- unless(doing_ghci, skip), unless(opsys('mingw32'), skip),
+ [extra_files(['A.c', 'B.c', 'A.def', 'B.def']),
+ unless(doing_ghci, skip),
+ unless(opsys('mingw32'), skip),
pre_cmd('$MAKE -s --no-print-directory compile_libAB_dep'),
extra_hc_opts('-L. -L./bin_dep')],
ghci_script, ['T10955.script'])
-test('T10955dyn', [extra_files(['A.c', 'B.c'])], makefile_test, ['compile_libAB_dyn'])
+test('T10955dyn', [extra_files(['A.c', 'B.c', 'A.def', 'B.def'])],
+ makefile_test, ['compile_libAB_dyn'])
test('T10458',
[extra_files(['A.c']),
diff --git a/testsuite/tests/linters/Makefile b/testsuite/tests/linters/Makefile
index 54ef4db132..2b4c2ad2c3 100644
--- a/testsuite/tests/linters/Makefile
+++ b/testsuite/tests/linters/Makefile
@@ -20,6 +20,9 @@ version-number:
cpp:
(cd $(TOP)/tests/linters/ && python3 regex-linters/check-cpp.py tracked)
+rts-includes:
+ (cd $(TOP)/tests/linters/ && python3 regex-linters/check-rts-includes.py tracked)
+
changelogs:
regex-linters/check-changelogs.sh $(TOP)/..
diff --git a/testsuite/tests/linters/all.T b/testsuite/tests/linters/all.T
index 16700869a4..0e06df6d50 100644
--- a/testsuite/tests/linters/all.T
+++ b/testsuite/tests/linters/all.T
@@ -23,7 +23,11 @@ test('changelogs', [ no_deps if has_ls_files() else skip
test('cpp', [ no_deps if has_ls_files() else skip
, extra_files(["regex-linters"]) ]
- , makefile_test, ['cpp'])
+ , makefile_test, ['cpp'])
+
+test('rts-includes', [ no_deps if has_ls_files() else skip
+ , extra_files(["regex-linters"]) ]
+ , makefile_test, ['rts-includes'])
test('version-number', [ no_deps if has_ls_files() else skip
, extra_files(["regex-linters"]) ]
diff --git a/testsuite/tests/linters/regex-linters/check-rts-includes.py b/testsuite/tests/linters/regex-linters/check-rts-includes.py
new file mode 100755
index 0000000000..14f22995b6
--- /dev/null
+++ b/testsuite/tests/linters/regex-linters/check-rts-includes.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+
+# A linter to warn for ASSERT macros which are separated from their argument
+# list by a space, which Clang's CPP barfs on
+
+from pathlib import Path
+from linter import run_linters, Linter, Warning
+
+from typing import List, Tuple
+import re
+
+INCLUDE_RE = re.compile('# *include ([<"][^">]+[>"])')
+
+def get_includes(file: Path) -> List[Tuple[int, str]]:
+ txt = file.read_text()
+ return [ (line_no+1, m.group(1) )
+ for (line_no, line) in enumerate(txt.split('\n'))
+ for m in [INCLUDE_RE.match(line)]
+ if m is not None
+ if m.group(1) != "rts/PosixSource.h"]
+
+def in_rts_dir(path: Path) -> bool:
+ return len(path.parts) > 0 and path.parts[0] == 'rts'
+
+class RtsHIncludeOrderLinter(Linter):
+ """
+ Verify that "PosixSource.h" is always the first #include in source files to
+ ensure __USE_MINGW_ANSI_STDIO is defined before system headers are
+ #include'd.
+ """
+ def __init__(self):
+ Linter.__init__(self)
+ self.add_path_filter(in_rts_dir)
+ self.add_path_filter(lambda path: path.suffix == '.c')
+
+ def lint(self, path: Path):
+ # We do allow a few small headers to precede Rts.h
+ ALLOWED_HEADERS = {
+ '"ghcconfig.h"',
+ '"ghcplatform.h"',
+ }
+
+ includes = get_includes(path)
+ headers = [x[1] for x in includes]
+ lines = path.read_text().split('\n')
+
+ if '"PosixSource.h"' in headers:
+ for line_no, header in includes:
+ if header == '"PosixSource.h"':
+ break
+ elif header in ALLOWED_HEADERS:
+ continue
+
+ self.add_warning(Warning(
+ path=path,
+ line_no=line_no,
+ line_content=lines[line_no-1],
+ message="PosixSource.h must be first header included in each file"))
+
+class PrivateIncludeLinter(Linter):
+ """
+ Verify that system headers are not #include'd in <BeginPrivate.h> blocks as this
+ can result in very hard-to-diagnose linking errors due to hidden library functions.
+ """
+ def __init__(self):
+ Linter.__init__(self)
+ self.add_path_filter(in_rts_dir)
+ self.add_path_filter(lambda path: path.suffix == '.h')
+
+ def lint(self, path: Path):
+ private = False
+ lines = path.read_text().split('\n')
+ for line_no, include in get_includes(path):
+ if include == '"BeginPrivate.h"':
+ private = True
+ elif include == '"EndPrivate.h"':
+ private = False
+ elif private:
+ self.add_warning(Warning(
+ path=path,
+ line_no=line_no,
+ line_content=lines[line_no-1],
+ message='System header %s found inside of <BeginPrivate.h> block' % include))
+
+linters = [
+ RtsHIncludeOrderLinter(),
+ PrivateIncludeLinter(),
+]
+
+if __name__ == '__main__':
+ run_linters(linters)
diff --git a/testsuite/tests/numeric/should_run/all.T b/testsuite/tests/numeric/should_run/all.T
index b0580c7e2c..68888545f8 100644
--- a/testsuite/tests/numeric/should_run/all.T
+++ b/testsuite/tests/numeric/should_run/all.T
@@ -41,8 +41,7 @@ test('arith018', normal, compile_and_run, [''])
test('arith019', normal, compile_and_run, [''])
test('expfloat', normal, compile_and_run, [''])
-test('FloatFnInverses', [when(opsys('mingw32'), expect_broken(15670))],
- compile_and_run, [''])
+test('FloatFnInverses', normal, compile_and_run, [''])
test('T1603', skip, compile_and_run, [''])
test('T3676', expect_broken(3676), compile_and_run, [''])
diff --git a/testsuite/tests/plugins/all.T b/testsuite/tests/plugins/all.T
index 4e8663c73b..dca05d885c 100644
--- a/testsuite/tests/plugins/all.T
+++ b/testsuite/tests/plugins/all.T
@@ -99,7 +99,7 @@ test('plugins15',
test('T10420',
[extra_files(['rule-defining-plugin/']),
-
+ when(opsys('mingw32'), expect_broken(21322)),
pre_cmd('$MAKE -s --no-print-directory -C rule-defining-plugin package.T10420 TOP={top}')],
makefile_test, [])
@@ -258,11 +258,13 @@ test('T20218b',
test('test-defaulting-plugin',
[extra_files(['defaulting-plugin/']),
+ when(opsys('mingw32'), fragile(21293)),
pre_cmd('$MAKE -s --no-print-directory -C defaulting-plugin package.test-defaulting-plugin TOP={top}')],
makefile_test, [])
test('test-defaulting-plugin-fail',
[extra_files(['defaulting-plugin/']),
+ when(opsys('mingw32'), fragile(21293)),
pre_cmd('$MAKE -s --no-print-directory -C defaulting-plugin package.test-defaulting-plugin-fail TOP={top}')],
makefile_test, [])
diff --git a/testsuite/tests/rts/T10672/Makefile b/testsuite/tests/rts/T10672/Makefile
index 5fc458857e..bcc9a5c22b 100644
--- a/testsuite/tests/rts/T10672/Makefile
+++ b/testsuite/tests/rts/T10672/Makefile
@@ -3,9 +3,9 @@ include $(TOP)/mk/boilerplate.mk
include $(TOP)/mk/test.mk
T10672_x64:
- '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_seh-1 -lstdc++-6 \
+ '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_seh-1 -l${LIBCXX} \
Main.hs Printf.hs cxxy.cpp
T10672_x86:
- '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_dw2-1 -lstdc++-6 \
+ '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_dw2-1 -${LIBCXX} \
Main.hs Printf.hs cxxy.cpp
diff --git a/testsuite/tests/rts/T16514_c.c b/testsuite/tests/rts/T16514_c.c
new file mode 100644
index 0000000000..9acb7d7d1f
--- /dev/null
+++ b/testsuite/tests/rts/T16514_c.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+
+void fn_hs();
+void fn() {
+ fn_hs();
+}
+
+void check(double sqrt2, double sqrt3, double sqrt5,
+ double sqrt8, double sqrt13, double sqrt21)
+{
+ printf("%f %f %f %f %f %f\n", sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21);
+ if (sqrt2 != 1.41421 || sqrt3 != 1.73205 || sqrt5 != 2.23607 ||
+ sqrt8 != 2.82843 || sqrt13 != 3.60555 || sqrt21 != 4.58258) {
+ fprintf(stderr, "xmm registers have been scratched\n");
+ }
+}
+
+int test() {
+ double sqrt2 = 1.41421;
+ double sqrt3 = 1.73205;
+ double sqrt5 = 2.23607;
+ double sqrt8 = 2.82843;
+ double sqrt13 = 3.60555;
+ double sqrt21 = 4.58258;
+ check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21);
+ fn();
+ check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21);
+ fn();
+ check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21);
+ return 0;
+} \ No newline at end of file
diff --git a/testsuite/tests/rts/T16514_c.cpp b/testsuite/tests/rts/T16514_c.cpp
deleted file mode 100644
index 1474741ec0..0000000000
--- a/testsuite/tests/rts/T16514_c.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <iostream>
-#include <stdexcept>
-
-extern "C" {
-
-void fn_hs();
-void fn() {
- fn_hs();
-}
-
-void check(double sqrt2, double sqrt3, double sqrt5,
- double sqrt8, double sqrt13, double sqrt21) {
- std::cout << std::fixed << sqrt2 << " " << sqrt3 << " " << sqrt5 << " "
- << sqrt8 << " " << sqrt13 << " " << sqrt21 << std::endl;
- if (sqrt2 != 1.41421 || sqrt3 != 1.73205 || sqrt5 != 2.23607 ||
- sqrt8 != 2.82843 || sqrt13 != 3.60555 || sqrt21 != 4.58258) {
- throw std::runtime_error("xmm registers have been scratched");
- }
-}
-
-int test() {
- try {
- double sqrt2 = 1.41421;
- double sqrt3 = 1.73205;
- double sqrt5 = 2.23607;
- double sqrt8 = 2.82843;
- double sqrt13 = 3.60555;
- double sqrt21 = 4.58258;
- check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21);
- fn();
- check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21);
- try {
- fn();
- } catch (const std::exception &) {
- }
- check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21);
- } catch (const std::exception &e) {
- std::cerr << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-} // extern "C"
-
diff --git a/testsuite/tests/rts/all.T b/testsuite/tests/rts/all.T
index c13f1aa0ea..75dcf5ac58 100644
--- a/testsuite/tests/rts/all.T
+++ b/testsuite/tests/rts/all.T
@@ -387,7 +387,7 @@ test('T10904', [ omit_ways(['ghci']), extra_run_opts('20000') ],
test('T10728', [extra_run_opts('+RTS -maxN3 -RTS'), only_ways(['threaded2'])],
compile_and_run, [''])
-test('T9405', [when(msys(), expect_broken(12714))], makefile_test, ['T9405'])
+test('T9405', [when(opsys('mingw32'), expect_broken(21361))], makefile_test, ['T9405'])
test('T11788', when(ghc_dynamic(), skip),
makefile_test, ['T11788'])
@@ -474,9 +474,10 @@ test('keep-cafs',
# Test proper functioning of C++ exceptions within a C++ program.
# On darwin, this requires -fcompact-unwind.
# When -fcompact-unwind becomes default, generalize test to all platforms.
-test('T11829', unless(opsys('darwin'), skip), compile_and_run, ['T11829_c.cpp -lstdc++ -fcompact-unwind'])
+test('T11829', unless(opsys('darwin'), skip), compile_and_run,
+ ['T11829_c.cpp -l{} -fcompact-unwind'.format(config.stdcxx_impl)])
-test('T16514', unless(opsys('mingw32'), skip), compile_and_run, ['T16514_c.cpp -lstdc++'])
+test('T16514', normal, compile_and_run, ['T16514_c.c'])
test('test-zeroongc', extra_run_opts('-DZ'), compile_and_run, ['-debug'])
test('T13676',
diff --git a/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr b/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr
index 3ec6cb6ca5..fb78f03676 100644
--- a/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr
+++ b/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr
@@ -3,7 +3,7 @@ GHC runtime linker: fatal error: I found a duplicate definition for symbol
whilst processing object file
/home/phyx/Documents/ghc/testsuite/tests/rts/T11223/libfoo_link_lib_3.a
The symbol was previously defined in
- /home/phyx/Documents/ghc/testsuite/tests/rts/T11223/libbar_link_lib_3.a(bar_link_lib_3.o)
+ /home/phyx/Documents/ghc/testsuite/tests/rts/T11223/libbar_link_lib_3.a(#2:bar_link_lib_3.o)
This could be caused by:
* Loading two different object files which export the same symbol
* Specifying the same object file twice on the GHCi command line
diff --git a/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-32-mingw32 b/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-32-mingw32
index 5304e84a37..389a2ccec0 100644
--- a/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-32-mingw32
+++ b/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-32-mingw32
@@ -3,7 +3,7 @@ GHC runtime linker: fatal error: I found a duplicate definition for symbol
whilst processing object file
E:\ghc-dev\msys64\home\Tamar\ghc\testsuite\tests\rts\T11223\T11223_link_order_a_b_2_fail.run\libfoo_link_lib_3.a
The symbol was previously defined in
- E:\ghc-dev\msys64\home\Tamar\ghc\testsuite\tests\rts\T11223\T11223_link_order_a_b_2_fail.run\libbar_link_lib_3.a(bar_link_lib_3.o)
+ E:\ghc-dev\msys64\home\Tamar\ghc\testsuite\tests\rts\T11223\T11223_link_order_a_b_2_fail.run\libbar_link_lib_3.a(#2:bar_link_lib_3.o)
This could be caused by:
* Loading two different object files which export the same symbol
* Specifying the same object file twice on the GHCi command line
diff --git a/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-64-mingw32 b/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-64-mingw32
index 5396070515..b6f937184b 100644
--- a/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-64-mingw32
+++ b/testsuite/tests/rts/linker/T11223/T11223_link_order_a_b_2_fail.stderr-ws-64-mingw32
@@ -3,7 +3,7 @@ GHC runtime linker: fatal error: I found a duplicate definition for symbol
whilst processing object file
E:\ghc-dev\msys64\home\Tamar\ghc\testsuite\tests\rts\T11223\T11223_link_order_a_b_2_fail.run\libfoo_link_lib_3.a
The symbol was previously defined in
- E:\ghc-dev\msys64\home\Tamar\ghc\testsuite\tests\rts\T11223\T11223_link_order_a_b_2_fail.run\libbar_link_lib_3.a(bar_link_lib_3.o)
+ E:\ghc-dev\msys64\home\Tamar\ghc\testsuite\tests\rts\T11223\T11223_link_order_a_b_2_fail.run\libbar_link_lib_3.a(#2:bar_link_lib_3.o)
This could be caused by:
* Loading two different object files which export the same symbol
* Specifying the same object file twice on the GHCi command line
diff --git a/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32 b/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32
index 293bd12fb0..f5f0ff1284 100644
--- a/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32
+++ b/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32
@@ -1,3 +1,3 @@
+success
ctors1
ctors2
-success
diff --git a/testsuite/tests/rts/linker/T5435_v_gcc.stdout-mingw32 b/testsuite/tests/rts/linker/T5435_v_gcc.stdout-mingw32
new file mode 100644
index 0000000000..ebe1f4f250
--- /dev/null
+++ b/testsuite/tests/rts/linker/T5435_v_gcc.stdout-mingw32
@@ -0,0 +1,2 @@
+success
+initializer run
diff --git a/testsuite/tests/rts/linker/all.T b/testsuite/tests/rts/linker/all.T
index e42db98922..0cb93370aa 100644
--- a/testsuite/tests/rts/linker/all.T
+++ b/testsuite/tests/rts/linker/all.T
@@ -82,6 +82,7 @@ test('T5435_dyn_gcc', extra_files(['T5435.hs', 'T5435_gcc.c']) , makefile_test,
######################################
test('linker_unload',
[extra_files(['LinkerUnload.hs', 'Test.hs']),
+ when(opsys('mingw32'), expect_broken(21354)),
req_rts_linker],
makefile_test, ['linker_unload'])
@@ -119,8 +120,9 @@ test('T7072',
test('T20918',
- [extra_files(['T20918_v.cc']),
- unless(opsys('mingw32'), skip),
- req_rts_linker],
- makefile_test, ['T20918'])
+ [extra_files(['T20918_v.cc']),
+ unless(opsys('mingw32'), skip),
+ when(opsys('mingw32'), expect_broken(2)),
+ req_rts_linker],
+ makefile_test, ['T20918'])
diff --git a/testsuite/tests/rts/linker/unload_multiple_objs/all.T b/testsuite/tests/rts/linker/unload_multiple_objs/all.T
index 52f35b4e26..85548af491 100644
--- a/testsuite/tests/rts/linker/unload_multiple_objs/all.T
+++ b/testsuite/tests/rts/linker/unload_multiple_objs/all.T
@@ -1,4 +1,5 @@
test('linker_unload_multiple_objs',
[extra_files(['../LinkerUnload.hs', 'A.hs', 'B.hs', 'C.hs', 'D.hs',]),
+ when(opsys('mingw32'), expect_broken(21354)),
req_rts_linker],
run_command, ['$MAKE -s --no-print-directory linker_unload_multiple_objs'])
diff --git a/testsuite/tests/th/T13366C.hs b/testsuite/tests/th/T13366C.hs
new file mode 100644
index 0000000000..246687dcf0
--- /dev/null
+++ b/testsuite/tests/th/T13366C.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -optc-DA_MACRO=1 -optcxx-DA_MACRO=1 #-}
+
+import Language.Haskell.TH.Syntax
+import System.IO (hFlush, stdout)
+
+foreign import ccall fc :: Int -> IO Int
+
+do addForeignSource LangC $ unlines
+ [ "#include <stdio.h>"
+ , "int fc(int x) {"
+ , " printf(\"calling f(%d)\\n\",x);"
+ , " fflush(stdout);"
+ , " return A_MACRO + x;"
+ , "}"
+ ]
+ return []
+
+main :: IO ()
+main = do
+ fc 2 >>= print
+ hFlush stdout
diff --git a/testsuite/tests/th/T13366C.stdout b/testsuite/tests/th/T13366C.stdout
new file mode 100644
index 0000000000..2ab79e85b8
--- /dev/null
+++ b/testsuite/tests/th/T13366C.stdout
@@ -0,0 +1,2 @@
+calling f(2)
+3
diff --git a/testsuite/tests/th/T13366.hs b/testsuite/tests/th/T13366Cxx.hs
index 7d998f2ae8..37ab25a4d1 100644
--- a/testsuite/tests/th/T13366.hs
+++ b/testsuite/tests/th/T13366Cxx.hs
@@ -5,18 +5,6 @@
import Language.Haskell.TH.Syntax
import System.IO (hFlush, stdout)
-foreign import ccall fc :: Int -> IO Int
-
-do addForeignSource LangC $ unlines
- [ "#include <stdio.h>"
- , "int fc(int x) {"
- , " printf(\"calling f(%d)\\n\",x);"
- , " fflush(stdout);"
- , " return A_MACRO + x;"
- , "}"
- ]
- return []
-
foreign import ccall fcxx :: Int -> IO Int
do addForeignSource LangCxx $ unlines
@@ -33,7 +21,5 @@ do addForeignSource LangCxx $ unlines
main :: IO ()
main = do
- fc 2 >>= print
- hFlush stdout
fcxx 5 >>= print
hFlush stdout
diff --git a/testsuite/tests/th/T13366.stdout b/testsuite/tests/th/T13366Cxx.stdout
index 16cfeeb9fa..bdf7a41a33 100644
--- a/testsuite/tests/th/T13366.stdout
+++ b/testsuite/tests/th/T13366Cxx.stdout
@@ -1,4 +1,2 @@
-calling f(2)
-3
calling fcxx(5)
6
diff --git a/testsuite/tests/th/all.T b/testsuite/tests/th/all.T
index d04bb08b29..2a003b8141 100644
--- a/testsuite/tests/th/all.T
+++ b/testsuite/tests/th/all.T
@@ -52,8 +52,7 @@ test('TH_NestedSplices', [], multimod_compile,
# normal way first, which is why the work is done by a Makefile rule.
test('TH_spliceE5_prof',
[req_profiling, only_ways(['normal']),
- when(ghc_dynamic(), expect_broken(11495)),
- when(opsys('mingw32'), expect_broken(18271))],
+ when(ghc_dynamic(), expect_broken(11495))],
makefile_test, ['TH_spliceE5_prof'])
test('TH_spliceE5_prof_ext', [req_profiling, req_rts_linker, only_ways(['normal'])],
@@ -395,14 +394,16 @@ test('T13018', normal, compile, ['-v0'])
test('T13123', normal, compile, ['-v0'])
test('T13098', normal, compile, ['-v0'])
test('T11046', normal, multimod_compile, ['T11046','-v0'])
-test('T13366',
+test('T13366C',
+ [expect_broken_for(13366, ['ghci'])],
+ compile_and_run,
+ ['-v0'])
+test('T13366Cxx',
[expect_broken_for(13366, ['ghci']),
- # libstdc++ is GCC-specific on FreeBSD, the test will
- # fail with clang, and pass with GCC.
- when(opsys('freebsd'), fragile(17739)),
- when(opsys('darwin'), expect_broken(16083))],
+ when(opsys('darwin'), expect_broken(16083))
+ ],
compile_and_run,
- ['-lstdc++ -v0'] if not opsys('openbsd') else ['-lc++ -lc++abi -v0'])
+ ['-l{} -v0'.format(config.stdcxx_impl)])
test('T13473', normal, multimod_compile_and_run,
['T13473.hs', '-v0 ' + config.ghc_th_way_flags])
test('T13587', expect_broken(13587), compile_and_run, ['-v0'])