summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/GHC/CmmToAsm/X86/CodeGen.hs164
-rw-r--r--compiler/GHC/CmmToAsm/X86/Instr.hs4
-rw-r--r--libraries/base/base.cabal9
-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.c557
-rw-r--r--rts/RtsSymbols.h1
-rw-r--r--rts/StaticPtrTable.c2
-rw-r--r--rts/include/rts/Linker.h3
-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.c734
-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/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/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
39 files changed, 1272 insertions, 822 deletions
diff --git a/compiler/GHC/CmmToAsm/X86/CodeGen.hs b/compiler/GHC/CmmToAsm/X86/CodeGen.hs
index 1fefe3a346..3d2a83c984 100644
--- a/compiler/GHC/CmmToAsm/X86/CodeGen.hs
+++ b/compiler/GHC/CmmToAsm/X86/CodeGen.hs
@@ -437,6 +437,25 @@ temporary, then do the other computation, and then use the temporary:
... (tmp) ...
-}
+{-
+Note [%rip-relative addressing on x86-64]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+On x86-64 GHC produces code for use in the "small" or, when `-fPIC` is set,
+"small PIC" code models defined by the x86-64 System V ABI (section 3.5.1 of
+specification version 0.99).
+
+In general the small code model would allow us to assume that code is located
+between 0 and 2^31 - 1. However, this is not true on Windows which, due to
+high-entropy ASLR, may place the executable image anywhere in 64-bit address
+space. This is problematic since immediate operands in x86-64 are generally
+32-bit sign-extended values (with the exception of the 64-bit MOVABS encoding).
+Consequently, to avoid overflowing we use %rip-relative addressing universally.
+Since %rip-relative addressing comes essentially for free and makes linking far
+easier, we use it even on non-Windows platforms.
+
+See also: the documentation for GCC's `-mcmodel=small` flag.
+-}
+
-- | Check whether an integer will fit in 32 bits.
-- A CmmInt is intended to be truncated to the appropriate
@@ -1139,6 +1158,22 @@ getRegister' _ is32Bit (CmmLit (CmmInt 0 width))
in
return (Any format code)
+-- Handle symbol references with LEA and %rip-relative addressing.
+-- See Note [%rip-relative addressing on x86-64].
+getRegister' platform is32Bit (CmmLit lit)
+ | is_label lit
+ , not is32Bit
+ = do let format = cmmTypeFormat (cmmLitType platform lit)
+ imm = litToImm lit
+ op = OpAddr (AddrBaseIndex EABaseRip EAIndexNone imm)
+ code dst = unitOL (LEA format op (OpReg dst))
+ return (Any format code)
+ where
+ is_label (CmmLabel {}) = True
+ is_label (CmmLabelOff {}) = True
+ is_label (CmmLabelDiffOff {}) = True
+ is_label _ = False
+
-- optimisation for loading small literals on x86_64: take advantage
-- of the automatic zero-extension from 32 to 64 bits, because the 32-bit
-- instruction forms are shorter.
@@ -1156,7 +1191,7 @@ getRegister' platform is32Bit (CmmLit lit)
-- signed literals that fit in 32 bits, but we want unsigned
-- literals here.
-- note2: all labels are small, because we're assuming the
- -- small memory model (see gcc docs, -mcmodel=small).
+ -- small memory model. See Note [%rip-relative addressing on x86-64].
getRegister' platform _ (CmmLit lit)
= do let format = cmmTypeFormat (cmmLitType platform lit)
@@ -1253,7 +1288,7 @@ getAmode e = do
-- This is all just ridiculous, since it carefully undoes
-- what mangleIndexTree has just done.
CmmMachOp (MO_Sub _rep) [x, CmmLit lit@(CmmInt i _)]
- | is32BitLit is32Bit lit
+ | is32BitLit platform lit
-- assert (rep == II32)???
-> do
(x_reg, x_code) <- getSomeReg x
@@ -1261,7 +1296,7 @@ getAmode e = do
return (Amode (AddrBaseIndex (EABaseReg x_reg) EAIndexNone off) x_code)
CmmMachOp (MO_Add _rep) [x, CmmLit lit]
- | is32BitLit is32Bit lit
+ | is32BitLit platform lit
-- assert (rep == II32)???
-> do
(x_reg, x_code) <- getSomeReg x
@@ -1292,8 +1327,16 @@ getAmode e = do
| not (isLit y) -- we already handle valid literals above.
-> x86_complex_amode x y 0 0
+ -- Handle labels with %rip-relative addressing since in general the image
+ -- may be loaded anywhere in the 64-bit address space (e.g. on Windows
+ -- with high-entropy ASLR). See Note [%rip-relative addressing on x86-64].
+ CmmLit lit
+ | not is32Bit
+ , is_label lit
+ -> return (Amode (AddrBaseIndex EABaseRip EAIndexNone (litToImm lit)) nilOL)
+
CmmLit lit
- | is32BitLit is32Bit lit
+ | is32BitLit platform lit
-> return (Amode (ImmAddr (litToImm lit) 0) nilOL)
-- Literal with offsets too big (> 32 bits) fails during the linking phase
@@ -1313,7 +1356,11 @@ getAmode e = do
_ -> do
(reg,code) <- getSomeReg e
return (Amode (AddrBaseIndex (EABaseReg reg) EAIndexNone (ImmInt 0)) code)
-
+ where
+ is_label (CmmLabel{}) = True
+ is_label (CmmLabelOff{}) = True
+ is_label (CmmLabelDiffOff{}) = True
+ is_label _ = False
-- | Like 'getAmode', but on 32-bit use simple register addressing
@@ -1362,9 +1409,8 @@ getNonClobberedOperand (CmmLit lit) =
Amode addr code <- memConstant (mkAlignment $ widthInBytes w) lit
return (OpAddr addr, code)
else do
- is32Bit <- is32BitPlatform
platform <- getPlatform
- if is32BitLit is32Bit lit && not (isFloatType (cmmLitType platform lit))
+ if is32BitLit platform lit && not (isFloatType (cmmLitType platform lit))
then return (OpImm (litToImm lit), nilOL)
else getNonClobberedOperand_generic (CmmLit lit)
@@ -1421,9 +1467,8 @@ getOperand (CmmLit lit) = do
return (OpAddr addr, code)
else do
- is32Bit <- is32BitPlatform
platform <- getPlatform
- if is32BitLit is32Bit lit && not (isFloatType (cmmLitType platform lit))
+ if is32BitLit platform lit && not (isFloatType (cmmLitType platform lit))
then return (OpImm (litToImm lit), nilOL)
else getOperand_generic (CmmLit lit)
@@ -1444,9 +1489,10 @@ getOperand_generic e = do
(reg, code) <- getSomeReg e
return (OpReg reg, code)
-isOperand :: Bool -> CmmExpr -> Bool
+isOperand :: Platform -> CmmExpr -> Bool
isOperand _ (CmmLoad _ _ _) = True
-isOperand is32Bit (CmmLit lit) = is32BitLit is32Bit lit
+isOperand platform (CmmLit lit)
+ = is32BitLit platform lit
|| isSuitableFloatingPointLit lit
isOperand _ _ = False
@@ -1517,21 +1563,28 @@ getRegOrMem e = do
(reg, code) <- getNonClobberedReg e
return (OpReg reg, code)
-is32BitLit :: Bool -> CmmLit -> Bool
-is32BitLit is32Bit lit
- | not is32Bit = case lit of
+is32BitLit :: Platform -> CmmLit -> Bool
+is32BitLit platform _lit
+ | target32Bit platform = True
+is32BitLit platform lit =
+ case lit of
CmmInt i W64 -> is32BitInteger i
- -- assume that labels are in the range 0-2^31-1: this assumes the
- -- small memory model (see gcc docs, -mcmodel=small).
- CmmLabel _ -> True
+ -- Except on Windows, assume that labels are in the range 0-2^31-1: this
+ -- assumes the small memory model. Note [%rip-relative addressing on
+ -- x86-64].
+ CmmLabel _ -> low_image
-- however we can't assume that label offsets are in this range
-- (see #15570)
- CmmLabelOff _ off -> is32BitInteger (fromIntegral off)
- CmmLabelDiffOff _ _ off _ -> is32BitInteger (fromIntegral off)
+ CmmLabelOff _ off -> low_image && is32BitInteger (fromIntegral off)
+ CmmLabelDiffOff _ _ off _ -> low_image && is32BitInteger (fromIntegral off)
_ -> True
-is32BitLit _ _ = True
-
-
+ where
+ -- Is the executable image certain to be located below 4GB? As noted in
+ -- Note [%rip-relative addressing on x86-64], this is not true on Windows.
+ low_image =
+ case platformOS platform of
+ OSMinGW32 -> False -- See Note [%rip-relative addressing on x86-64]
+ _ -> True
-- Set up a condition code for a conditional branch.
@@ -1584,14 +1637,14 @@ machOpToCond mo = case mo of
-- passed back up the tree.
condIntCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode
-condIntCode cond x y = do is32Bit <- is32BitPlatform
- condIntCode' is32Bit cond x y
+condIntCode cond x y = do platform <- getPlatform
+ condIntCode' platform cond x y
-condIntCode' :: Bool -> Cond -> CmmExpr -> CmmExpr -> NatM CondCode
+condIntCode' :: Platform -> Cond -> CmmExpr -> CmmExpr -> NatM CondCode
-- memory vs immediate
-condIntCode' is32Bit cond (CmmLoad x pk _) (CmmLit lit)
- | is32BitLit is32Bit lit = do
+condIntCode' platform cond (CmmLoad x pk _) (CmmLit lit)
+ | is32BitLit platform lit = do
Amode x_addr x_code <- getAmode x
let
imm = litToImm lit
@@ -1602,8 +1655,8 @@ condIntCode' is32Bit cond (CmmLoad x pk _) (CmmLit lit)
-- anything vs zero, using a mask
-- TODO: Add some sanity checking!!!!
-condIntCode' is32Bit cond (CmmMachOp (MO_And _) [x,o2]) (CmmLit (CmmInt 0 pk))
- | (CmmLit lit@(CmmInt mask _)) <- o2, is32BitLit is32Bit lit
+condIntCode' platform cond (CmmMachOp (MO_And _) [x,o2]) (CmmLit (CmmInt 0 pk))
+ | (CmmLit lit@(CmmInt mask _)) <- o2, is32BitLit platform lit
= do
(x_reg, x_code) <- getSomeReg x
let
@@ -1622,9 +1675,8 @@ condIntCode' _ cond x (CmmLit (CmmInt 0 pk)) = do
return (CondCode False cond code)
-- anything vs operand
-condIntCode' is32Bit cond x y
- | isOperand is32Bit y = do
- platform <- getPlatform
+condIntCode' platform cond x y
+ | isOperand platform y = do
(x_reg, x_code) <- getNonClobberedReg x
(y_op, y_code) <- getOperand y
let
@@ -1633,9 +1685,8 @@ condIntCode' is32Bit cond x y
return (CondCode False cond code)
-- operand vs. anything: invert the comparison so that we can use a
-- single comparison instruction.
- | isOperand is32Bit x
+ | isOperand platform x
, Just revcond <- maybeFlipCond cond = do
- platform <- getPlatform
(y_reg, y_code) <- getNonClobberedReg y
(x_op, x_code) <- getOperand x
let
@@ -1644,8 +1695,7 @@ condIntCode' is32Bit cond x y
return (CondCode False revcond code)
-- anything vs anything
-condIntCode' _ cond x y = do
- platform <- getPlatform
+condIntCode' platform cond x y = do
(y_reg, y_code) <- getNonClobberedReg y
(x_op, x_code) <- getRegOrMem x
let
@@ -1719,9 +1769,9 @@ assignMem_IntCode pk addr (CmmMachOp op [CmmLoad addr2 _ _,
-- general case
assignMem_IntCode pk addr src = do
- is32Bit <- is32BitPlatform
+ platform <- getPlatform
Amode addr code_addr <- getAmode addr
- (code_src, op_src) <- get_op_RI is32Bit src
+ (code_src, op_src) <- get_op_RI platform src
let
code = code_src `appOL`
code_addr `snocOL`
@@ -1733,8 +1783,8 @@ assignMem_IntCode pk addr src = do
--
return code
where
- get_op_RI :: Bool -> CmmExpr -> NatM (InstrBlock,Operand) -- code, operator
- get_op_RI is32Bit (CmmLit lit) | is32BitLit is32Bit lit
+ get_op_RI :: Platform -> CmmExpr -> NatM (InstrBlock,Operand) -- code, operator
+ get_op_RI platform (CmmLit lit) | is32BitLit platform lit
= return (nilOL, OpImm (litToImm lit))
get_op_RI _ op
= do (reg,code) <- getNonClobberedReg op
@@ -2563,12 +2613,12 @@ genCCall64 addr conv dest_regs args = do
-- pass the arg into the given register
reg_this_arg r
-- "operand" args can be directly assigned into r
- | isOperand False arg = do
+ | isOperand platform arg = do
arg_code <- getAnyReg arg
return (code, (acode `appOL` arg_code r))
-- The last non-operand arg can be directly assigned after its
-- computation without going into a temporary register
- | all (isOperand False) rest = do
+ | all (isOperand platform) rest = do
arg_code <- getAnyReg arg
return (code `appOL` arg_code r,acode)
@@ -2864,11 +2914,21 @@ genSwitch expr targets = do
else do
(reg,e_code) <- getSomeReg indexExpr
lbl <- getNewLabelNat
- let op = OpAddr (AddrBaseIndex EABaseNone (EAIndex reg (platformWordSizeInBytes platform)) (ImmCLbl lbl))
- code = e_code `appOL` toOL [
- JMP_TBL op ids (Section ReadOnlyData lbl) lbl
- ]
- return code
+ let is32bit = target32Bit platform
+ if is32bit
+ then let op = OpAddr (AddrBaseIndex EABaseNone (EAIndex reg (platformWordSizeInBytes platform)) (ImmCLbl lbl))
+ jmp_code = JMP_TBL op ids (Section ReadOnlyData lbl) lbl
+ in return $ e_code `appOL` unitOL jmp_code
+ else do
+ -- See Note [%rip-relative addressing on x86-64].
+ tableReg <- getNewRegNat (intFormat (platformWordWidth platform))
+ let op = OpAddr (AddrBaseIndex (EABaseReg tableReg) (EAIndex reg (platformWordSizeInBytes platform)) (ImmInt 0))
+ code = e_code `appOL` toOL
+ [ LEA (archWordFormat is32bit) (OpAddr (AddrBaseIndex EABaseRip EAIndexNone (ImmCLbl lbl))) (OpReg tableReg)
+ , MOV (archWordFormat is32bit) op (OpReg reg)
+ , JMP_TBL (OpReg reg) ids (Section ReadOnlyData lbl) lbl
+ ]
+ return code
where
(offset, blockIds) = switchTargetsToTable targets
ids = map (fmap DestBlockId) blockIds
@@ -3078,14 +3138,14 @@ trivialCode :: Width -> (Operand -> Operand -> Instr)
-> Maybe (Operand -> Operand -> Instr)
-> CmmExpr -> CmmExpr -> NatM Register
trivialCode width instr m a b
- = do is32Bit <- is32BitPlatform
- trivialCode' is32Bit width instr m a b
+ = do platform <- getPlatform
+ trivialCode' platform width instr m a b
-trivialCode' :: Bool -> Width -> (Operand -> Operand -> Instr)
+trivialCode' :: Platform -> Width -> (Operand -> Operand -> Instr)
-> Maybe (Operand -> Operand -> Instr)
-> CmmExpr -> CmmExpr -> NatM Register
-trivialCode' is32Bit width _ (Just revinstr) (CmmLit lit_a) b
- | is32BitLit is32Bit lit_a = do
+trivialCode' platform width _ (Just revinstr) (CmmLit lit_a) b
+ | is32BitLit platform lit_a = do
b_code <- getAnyReg b
let
code dst
diff --git a/compiler/GHC/CmmToAsm/X86/Instr.hs b/compiler/GHC/CmmToAsm/X86/Instr.hs
index 1f1515b0c9..42b9543204 100644
--- a/compiler/GHC/CmmToAsm/X86/Instr.hs
+++ b/compiler/GHC/CmmToAsm/X86/Instr.hs
@@ -196,6 +196,10 @@ data Instr
-- Moves.
| MOV Format Operand Operand
+ -- ^ N.B. when used with the 'II64' 'Format', the source
+ -- operand is interpreted to be a 32-bit sign-extended value.
+ -- True 64-bit operands need to be moved with @MOVABS@, which we
+ -- currently don't use.
| CMOV Cond Format Operand Reg
| MOVZxL Format Operand Operand
-- ^ The format argument is the size of operand 1 (the number of bits we keep)
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/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 22484ac522..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"
@@ -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/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/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 86c0768390..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.
- 1) Those that define a redirection. In this case the .idata$7 section will
+ * `.idata$4` contains the Import Lookup Table (ILT). This contains an array
+ of references to HNT entries for each imported DLL.
+
+ * `.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,11 +491,6 @@ 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) {
@@ -439,20 +500,13 @@ void freePreloadObjectFile_PEi386(ObjectCode *oc)
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) {
@@ -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);
+
+ // 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\n", section.info->name ));
+ 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,39 +2181,21 @@ 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.
- */
-
- /* 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);
-}
-
-/* -----------------------------------------------------------------------------
* Debugging operations.
*/
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/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/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