on iko/ghcjs-patch-master help sign in
[arm] various patches
commit4ba95c0ed7676abaaff132ac44c3460c623c0227 authorMoritz Angermann <moritz.angermann@gmail.com> dateMon 25 May 2020, 04:34 (6 years ago) parentfa97cf0
4 files changed+2383−1
overlays/bootstrap.nix+4−1 overlays/patches/ghc/aarch64-linker.patch+288 overlays/patches/ghc/ghci-no-dynamic-linking.patch+2028 overlays/patches/ghc/llvm-emit-nonlazybind.patch+63
overlays/bootstrap.nix+4−1
@@ -112,7 +112,7 @@ in {
112112 ++ fromUntil "8.6.4" "8.8" ./patches/ghc/global-offset-table.patch
113113 ++ fromUntil "8.6.4" "8.8" ./patches/ghc/global-offset-table-2.patch
114114 ++ always ./patches/ghc/respect-ar-path.patch
115− ++ until "8.10" ./patches/ghc/MR2537-use-one-shot-kqueue-on-macos.patch
115+ ++ until "8.12" ./patches/ghc/MR2537-use-one-shot-kqueue-on-macos.patch
116116 ++ final.lib.optional (version == "8.6.3") ./patches/ghc/T16057--ghci-doa-on-windows.patch
117117 ++ final.lib.optional (version == "8.6.3") ./patches/ghc/ghc-8.6.3-reinstallable-lib-ghc.patch
118118 ++ final.lib.optional (version == "8.6.4") ./patches/ghc/ghc-8.6.4-reinstallable-lib-ghc.patch
@@ -125,6 +125,9 @@ in {
125125 ++ final.lib.optional (versionAtLeast "8.6.4" && final.stdenv.isDarwin) ./patches/ghc/ghc-macOS-loadArchive-fix.patch
126126 ++ final.lib.optional (versionAtLeast "8.4.4" && final.stdenv.isDarwin) ./patches/ghc/ghc-darwin-gcc-version-fix.patch
127127 ++ final.lib.optional (versionAtLeast "8.6.4" && final.stdenv.buildPlatform != final.stdenv.targetPlatform) ./patches/ghc/ghc-no-system-linker.patch
128+ ++ final.lib.optional (versionAtLeast "8.6.4" && final.stdenv.buildPlatform != final.stdenv.targetPlatform) ./patches/ghc/ghci-no-dynamic-linking.patch
129+ ++ final.lib.optional (versionAtLeast "8.6.4" && final.stdenv.buildPlatform != final.stdenv.targetPlatform) ./patches/ghc/aarch64-linker.patch
130+ ++ final.lib.optional (versionAtLeast "8.6.4" && final.stdenv.buildPlatform != final.stdenv.targetPlatform) ./patches/ghc/llvm-emit-nonlazybind.patch
128131 ++ final.lib.optional (versionAtLeast "8.6.4") ./patches/ghc/Cabal-3886.patch
129132 ;
130133 in ({
overlays/patches/ghc/aarch64-linker.patchnew file+288
@@ -0,0 +1,288 @@
1+diff --git a/rts/Linker.c b/rts/Linker.c
2+index 7ed9e9d148..468bd593b6 100644
3+--- a/rts/Linker.c
4++++ b/rts/Linker.c
5+@@ -192,7 +192,7 @@ int ocTryLoad( ObjectCode* oc );
6+ *
7+ * MAP_32BIT not available on OpenBSD/amd64
8+ */
9+-#if (defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) || defined(aarch64_TARGET_ARCH)) && defined(MAP_32BIT)
10++#if (defined(x86_64_HOST_ARCH) || (defined(aarch64_TARGET_ARCH) || defined(aarch64_HOST_ARCH))) && defined(MAP_32BIT)
11+ #define TRY_MAP_32BIT MAP_32BIT
12+ #else
13+ #define TRY_MAP_32BIT 0
14+@@ -216,11 +216,18 @@ int ocTryLoad( ObjectCode* oc );
15+ * We pick a default address based on the OS, but also make this
16+ * configurable via an RTS flag (+RTS -xm)
17+ */
18+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
19++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || (defined(aarch64_TARGET_ARCH) || defined(aarch64_HOST_ARCH))
20+
21+ #define MMAP_MAX_RETRY 100
22+
23+-#if defined(MAP_32BIT)
24++#if (defined(aarch64_TARGET_ARCH) || defined(aarch64_HOST_ARCH))
25++// Try to use stg_upd_frame_info as the base. We need to be within +-4GB of that
26++// address, otherwise we violate the aarch64 memory model. Any object we load
27++// can potentially reference any of the ones we bake into the binary (and list)
28++// in RtsSymbols. Thus we'll need to be within +-4GB of those,
29++// stg_upd_frame_info is a good candidate as it's referenced often.
30++#define MMAP_32BIT_BASE_DEFAULT (void*)&stg_upd_frame_info;
31++#elif defined(MAP_32BIT)
32+ // Try to use MAP_32BIT
33+ #define MMAP_32BIT_BASE_DEFAULT 0
34+ #else
35+@@ -502,7 +509,7 @@ initLinker_ (int retain_cafs)
36+ }
37+ # endif
38+
39+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
40++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
41+ if (RtsFlags.MiscFlags.linkerMemBase != 0) {
42+ // User-override for mmap_32bit_base
43+ mmap_32bit_base = (void*)RtsFlags.MiscFlags.linkerMemBase;
44+@@ -881,8 +888,9 @@ SymbolAddr* lookupSymbol_ (SymbolName* lbl)
45+ * Symbol name only used for diagnostics output.
46+ */
47+ SymbolAddr* loadSymbol(SymbolName *lbl, RtsSymbolInfo *pinfo) {
48+- IF_DEBUG(linker, debugBelch("lookupSymbol: value of %s is %p\n", lbl,
49+- pinfo->value));
50++ IF_DEBUG(linker, debugBelch("lookupSymbol: value of %s is %p, owned by %s\n", lbl,
51++ pinfo->value,
52++ pinfo->owner ? OC_INFORMATIVE_FILENAME(pinfo->owner) : "No owner, probably built-in."));
53+ ObjectCode* oc = pinfo->owner;
54+
55+ /* Symbol can be found during linking, but hasn't been relocated. Do so now.
56+@@ -906,6 +914,27 @@ SymbolAddr* loadSymbol(SymbolName *lbl, RtsSymbolInfo *pinfo) {
57+ return pinfo->value;
58+ }
59+
60++void
61++printLoadedObjects() {
62++ ObjectCode* oc;
63++ for (oc = objects; oc; oc = oc->next) {
64++ if (oc->sections != NULL) {
65++ int i;
66++ printf("%s\n", OC_INFORMATIVE_FILENAME(oc));
67++ for (i=0; i < oc->n_sections; i++) {
68++ if(oc->sections[i].mapped_start != NULL || oc->sections[i].start != NULL) {
69++ printf("\tsec %2d[alloc: %d; kind: %d]: %p - %p; mmaped: %p - %p\n",
70++ i, oc->sections[i].alloc, oc->sections[i].kind,
71++ oc->sections[i].start,
72++ (void*)((uintptr_t)(oc->sections[i].start) + oc->sections[i].size),
73++ oc->sections[i].mapped_start,
74++ (void*)((uintptr_t)(oc->sections[i].mapped_start) + oc->sections[i].mapped_size));
75++ }
76++ }
77++ }
78++ }
79++}
80++
81+ SymbolAddr* lookupSymbol( SymbolName* lbl )
82+ {
83+ ACQUIRE_LOCK(&linker_mutex);
84+@@ -913,6 +942,7 @@ SymbolAddr* lookupSymbol( SymbolName* lbl )
85+ if (!r) {
86+ errorBelch("^^ Could not load '%s', dependency unresolved. "
87+ "See top entry above.\n", lbl);
88++ printLoadedObjects();
89+ fflush(stderr);
90+ }
91+ RELEASE_LOCK(&linker_mutex);
92+@@ -1003,6 +1033,23 @@ resolveSymbolAddr (pathchar* buffer, int size,
93+ }
94+
95+ #if RTS_LINKER_USE_MMAP
96++
97++void*
98++mmap_next(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
99++ if(addr == NULL) return mmap(addr, length, prot, flags, fd, offset);
100++ // we are going to look for up to pageSize * 1024 * 1024 (4GB) from the
101++ // address.
102++ size_t pageSize = getPageSize();
103++ for(int i = (uintptr_t)addr & (pageSize-1) ? 1 : 0; i < 1024*1024; i++) {
104++ void *target = (void*)(((uintptr_t)addr & ~(pageSize-1))+(i*pageSize));
105++ void *mem = mmap(target, length, prot, flags, fd, offset);
106++ if(mem == NULL) return mem;
107++ if(mem == target) return mem;
108++ munmap(mem, length);
109++ }
110++ return NULL;
111++}
112++
113+ //
114+ // Returns NULL on failure.
115+ //
116+@@ -1017,7 +1064,7 @@ mmapForLinker (size_t bytes, uint32_t prot, uint32_t flags, int fd, int offset)
117+ IF_DEBUG(linker, debugBelch("mmapForLinker: start\n"));
118+ size = roundUpToPage(bytes);
119+
120+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) || defined(aarch64_TARGET_ARCH)
121++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) ||( defined(aarch64_TARGET_ARCH) || defined(aarch64_HOST_ARCH))
122+
123+ size_t mmap_counter = MMAP_MAX_RETRY;
124+ mmap_again:
125+@@ -1037,9 +1084,9 @@ mmap_again:
126+ debugBelch("mmapForLinker: \tflags %#0x\n",
127+ MAP_PRIVATE | TRY_MAP_32BIT | fixed | flags));
128+
129+- result = mmap(map_addr, size,
130+- prot,
131+- MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, offset);
132++ result = mmap_next(map_addr, size,
133++ prot,
134++ MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, offset);
135+
136+ if (result == MAP_FAILED) {
137+ sysErrorBelch("mmap %" FMT_Word " bytes at %p",(W_)size,map_addr);
138+@@ -1047,7 +1094,7 @@ mmap_again:
139+ return NULL;
140+ }
141+
142+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) || defined(aarch64_TARGET_ARCH)
143++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
144+ if (mmap_32bit_base != 0) {
145+ if (result == map_addr) {
146+ mmap_32bit_base = (StgWord8*)map_addr + size;
147+@@ -1091,6 +1138,28 @@ mmap_again:
148+ goto mmap_again;
149+ }
150+ }
151++#elif (defined(aarch64_TARGET_ARCH) || defined(aarch64_HOST_ARCH))
152++ // for aarch64 we need to make sure we stay within 4GB of the
153++ // mmap_32bit_base, and we also do not want to update it.
154++// if (mmap_32bit_base != (void*)&stg_upd_frame_info) {
155++ if (result == map_addr) {
156++ mmap_32bit_base = (void*)((uintptr_t)map_addr + size);
157++ } else {
158++ // upper limit 4GB - size of the object file - 1mb wiggle room.
159++ if(llabs((uintptr_t)result - (uintptr_t)&stg_upd_frame_info) > (2<<32) - size - (2<<20)) {
160++ // not within range :(
161++ debugTrace(DEBUG_linker,
162++ "MAP_32BIT didn't work; gave us %lu bytes at 0x%p",
163++ bytes, result);
164++ munmap(result, size);
165++ // TODO: some abort/mmap_32bit_base recomputation based on
166++ // if mmap_32bit_base is changed, or still at stg_upd_frame_info
167++ goto mmap_again;
168++ } else {
169++ mmap_32bit_base = (void*)((uintptr_t)result + size);
170++ }
171++ }
172++// }
173+ #endif
174+
175+ IF_DEBUG(linker,
176+@@ -1643,6 +1712,9 @@ static HsInt resolveObjs_ (void)
177+ r = ocTryLoad(oc);
178+ if (!r)
179+ {
180++ errorBelch("Could not load Object Code %s.\n", OC_INFORMATIVE_FILENAME(oc));
181++ printLoadedObjects();
182++ fflush(stderr);
183+ return r;
184+ }
185+ }
186+diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
187+index f7ef0da81e..02cb6b814f 100644
188+--- a/rts/LinkerInternals.h
189++++ b/rts/LinkerInternals.h
190+@@ -13,6 +13,7 @@
191+
192+ #if RTS_LINKER_USE_MMAP
193+ #include <sys/mman.h>
194++void* mmap_next(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
195+ #endif
196+
197+ #include "BeginPrivate.h"
198+diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
199+index 8e477c0425..955d1151d5 100644
200+--- a/rts/linker/Elf.c
201++++ b/rts/linker/Elf.c
202+@@ -824,6 +824,26 @@ ocGetNames_ELF ( ObjectCode* oc )
203+
204+ unsigned curSymbol = 0;
205+
206++ unsigned long common_size = 0;
207++ unsigned long common_used = 0;
208++ for(ElfSymbolTable *symTab = oc->info->symbolTables;
209++ symTab != NULL; symTab = symTab->next) {
210++ for (size_t j = 0; j < symTab->n_symbols; j++) {
211++ ElfSymbol *symbol = &symTab->symbols[j];
212++ if (SHN_COMMON == symTab->symbols[j].elf_sym->st_shndx) {
213++ common_size += symbol->elf_sym->st_size;
214++ }
215++ }
216++ }
217++ void * common_mem = NULL;
218++ if(common_size > 0) {
219++ common_mem = mmapForLinker(common_size,
220++ PROT_READ | PROT_WRITE,
221++ MAP_ANON | MAP_PRIVATE,
222++ -1, 0);
223++ ASSERT(common_mem != NULL);
224++ }
225++
226+ //TODO: we ignore local symbols anyway right? So we can use the
227+ // shdr[i].sh_info to get the index of the first non-local symbol
228+ // ie we should use j = shdr[i].sh_info
229+@@ -859,12 +879,15 @@ ocGetNames_ELF ( ObjectCode* oc )
230+
231+ if (shndx == SHN_COMMON) {
232+ isLocal = false;
233+- symbol->addr = stgCallocBytes(1, symbol->elf_sym->st_size,
234+- "ocGetNames_ELF(COMMON)");
235+- /*
236+- debugBelch("COMMON symbol, size %d name %s\n",
237+- stab[j].st_size, nm);
238+- */
239++ ASSERT(common_used < common_size);
240++ ASSERT(common_mem);
241++ symbol->addr = (void*)((uintptr_t)common_mem + common_used);
242++ common_used += symbol->elf_sym->st_size;
243++ ASSERT(common_used <= common_size);
244++
245++ debugBelch("COMMON symbol, size %ld name %s allocated at %p\n",
246++ symbol->elf_sym->st_size, nm, symbol->addr);
247++
248+ /* Pointless to do addProddableBlock() for this area,
249+ since the linker should never poke around in it. */
250+ } else if ((ELF_ST_BIND(symbol->elf_sym->st_info) == STB_GLOBAL
251+diff --git a/rts/linker/elf_reloc_aarch64.c b/rts/linker/elf_reloc_aarch64.c
252+index a826c58170..7e80bc4183 100644
253+--- a/rts/linker/elf_reloc_aarch64.c
254++++ b/rts/linker/elf_reloc_aarch64.c
255+@@ -310,14 +310,14 @@ relocateObjectCodeAarch64(ObjectCode * oc) {
256+ symbol->name,
257+ OC_INFORMATIVE_FILENAME(oc)));
258+ if(encodeAddendAarch64(targetSection, rel, addend)) {
259+- sysErrorBelch("Failed to relocate symbol: %s (%s) "
260++ debugBelch("REL: Failed to relocate symbol: %s (%s) "
261+ "at %p in %p with addend 0x%" PRIx64 "\n",
262+ symbol->name,
263+ OC_INFORMATIVE_FILENAME(oc),
264+ symbol->addr,
265+ (addr_t)((uint8_t*)targetSection->start + rel->r_offset),
266+ addend);
267+- stg_exit(EXIT_FAILURE);
268++ return EXIT_FAILURE;
269+ }
270+ }
271+ }
272+@@ -349,14 +349,14 @@ relocateObjectCodeAarch64(ObjectCode * oc) {
273+ symbol->name,
274+ OC_INFORMATIVE_FILENAME(oc)));
275+ if(encodeAddendAarch64(targetSection, (Elf_Rel*)rel, addend)) {
276+- sysErrorBelch("Failed to relocate symbol: %s (%s) "
277++ debugBelch("RELA: Failed to relocate symbol: %s (%s) "
278+ "at %p in %p with addend 0x%" PRIx64 "\n",
279+ symbol->name,
280+ OC_INFORMATIVE_FILENAME(oc),
281+ symbol->addr,
282+ (addr_t)((uint8_t*)targetSection->start + rel->r_offset),
283+ addend);
284+- stg_exit(EXIT_FAILURE);
285++ return EXIT_FAILURE;
286+ }
287+ }
288+ }
overlays/patches/ghc/ghci-no-dynamic-linking.patchnew file+2028
@@ -0,0 +1,2028 @@
1+diff --git a/compiler/cmm/CmmMachOp.hs b/compiler/cmm/CmmMachOp.hs
2+index 15a5827643..fd50db511d 100644
3+--- a/compiler/cmm/CmmMachOp.hs
4++++ b/compiler/cmm/CmmMachOp.hs
5+@@ -562,6 +562,7 @@ data CallishMachOp
6+ | MO_SubIntC Width
7+ | MO_U_Mul2 Width
8+
9++ | MO_ReadBarrier
10+ | MO_WriteBarrier
11+ | MO_Touch -- Keep variables live (when using interior pointers)
12+
13+diff --git a/compiler/cmm/CmmParse.y.source b/compiler/cmm/CmmParse.y.source
14+index 4d7e288381..480cd48fd1 100644
15+--- a/compiler/cmm/CmmParse.y.source
16++++ b/compiler/cmm/CmmParse.y.source
17+@@ -998,6 +998,7 @@ machOps = listToUFM $
18+ callishMachOps :: UniqFM ([CmmExpr] -> (CallishMachOp, [CmmExpr]))
19+ callishMachOps = listToUFM $
20+ map (\(x, y) -> (mkFastString x, y)) [
21++ ( "read_barrier", (,) MO_ReadBarrier ),
22+ ( "write_barrier", (,) MO_WriteBarrier ),
23+ ( "memcpy", memcpyLikeTweakArgs MO_Memcpy ),
24+ ( "memset", memcpyLikeTweakArgs MO_Memset ),
25+diff --git a/compiler/cmm/CmmParse.hs b/compiler/cmm/CmmParse.hs
26+index 4d7e288381..480cd48fd1 100644
27+--- a/compiler/cmm/CmmParse.hs
28++++ b/compiler/cmm/CmmParse.hs
29+@@ -2559,6 +2559,7 @@
30+ callishMachOps :: UniqFM ([CmmExpr] -> (CallishMachOp, [CmmExpr]))
31+ callishMachOps = listToUFM $
32+ map (\(x, y) -> (mkFastString x, y)) [
33++ ( "read_barrier", (,) MO_ReadBarrier ),
34+ ( "write_barrier", (,) MO_WriteBarrier ),
35+ ( "memcpy", memcpyLikeTweakArgs MO_Memcpy ),
36+ ( "memset", memcpyLikeTweakArgs MO_Memset ),
37+diff --git a/compiler/cmm/PprC.hs b/compiler/cmm/PprC.hs
38+index 9e8ced88b5..3b6587778e 100644
39+--- a/compiler/cmm/PprC.hs
40++++ b/compiler/cmm/PprC.hs
41+@@ -794,6 +794,7 @@ pprCallishMachOp_for_C mop
42+ MO_F32_Exp -> text "expf"
43+ MO_F32_Sqrt -> text "sqrtf"
44+ MO_F32_Fabs -> text "fabsf"
45++ MO_ReadBarrier -> text "load_load_barrier"
46+ MO_WriteBarrier -> text "write_barrier"
47+ MO_Memcpy _ -> text "memcpy"
48+ MO_Memset _ -> text "memset"
49+diff --git a/compiler/codeGen/StgCmmBind.hs b/compiler/codeGen/StgCmmBind.hs
50+index aa2b954a95..5b9811cd0f 100644
51+--- a/compiler/codeGen/StgCmmBind.hs
52++++ b/compiler/codeGen/StgCmmBind.hs
53+@@ -629,6 +629,7 @@ emitBlackHoleCode node = do
54+
55+ when eager_blackholing $ do
56+ emitStore (cmmOffsetW dflags node (fixedHdrSizeW dflags)) currentTSOExpr
57++ -- See Note [Heap memory barriers] in SMP.h.
58+ emitPrimCall [] MO_WriteBarrier []
59+ emitStore node (CmmReg (CmmGlobal EagerBlackholeInfo))
60+
61+diff --git a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
62+index f5d06e54b6..33d5d0c83c 100644
63+--- a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
64++++ b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
65+@@ -170,17 +170,25 @@ barrier = do
66+ let s = Fence False SyncSeqCst
67+ return (unitOL s, [])
68+
69++-- | Insert a 'barrier', unless the target platform is in the provided list of
70++-- exceptions (where no code will be emitted instead).
71++barrierUnless :: [Arch] -> LlvmM StmtData
72++barrierUnless exs = do
73++ platform <- getLlvmPlatform
74++ if platformArch platform `elem` exs
75++ then return (nilOL, [])
76++ else barrier
77++
78+ -- | Foreign Calls
79+ genCall :: ForeignTarget -> [CmmFormal] -> [CmmActual]
80+ -> LlvmM StmtData
81+
82+--- Write barrier needs to be handled specially as it is implemented as an LLVM
83+--- intrinsic function.
84++-- Barriers need to be handled specially as they are implemented as LLVM
85++-- intrinsic functions.
86++genCall (PrimTarget MO_ReadBarrier) _ _ =
87++ barrierUnless [ArchX86, ArchX86_64, ArchSPARC]
88+ genCall (PrimTarget MO_WriteBarrier) _ _ = do
89+- platform <- getLlvmPlatform
90+- if platformArch platform `elem` [ArchX86, ArchX86_64, ArchSPARC]
91+- then return (nilOL, [])
92+- else barrier
93++ barrierUnless [ArchX86, ArchX86_64, ArchSPARC]
94+
95+ genCall (PrimTarget MO_Touch) _ _
96+ = return (nilOL, [])
97+@@ -817,6 +825,7 @@ cmmPrimOpFunctions mop = do
98+ -- We support MO_U_Mul2 through ordinary LLVM mul instruction, see the
99+ -- appropriate case of genCall.
100+ MO_U_Mul2 {} -> unsupported
101++ MO_ReadBarrier -> unsupported
102+ MO_WriteBarrier -> unsupported
103+ MO_Touch -> unsupported
104+ MO_UF_Conv _ -> unsupported
105+diff --git a/compiler/nativeGen/PPC/CodeGen.hs b/compiler/nativeGen/PPC/CodeGen.hs
106+index 88b9692920..fa05c68efc 100644
107+--- a/compiler/nativeGen/PPC/CodeGen.hs
108++++ b/compiler/nativeGen/PPC/CodeGen.hs
109+@@ -1096,6 +1096,8 @@ genCCall :: ForeignTarget -- function to call
110+ -> [CmmFormal] -- where to put the result
111+ -> [CmmActual] -- arguments (of mixed type)
112+ -> NatM InstrBlock
113++genCCall (PrimTarget MO_ReadBarrier) _ _
114++ = return $ unitOL LWSYNC
115+ genCCall (PrimTarget MO_WriteBarrier) _ _
116+ = return $ unitOL LWSYNC
117+
118+@@ -2023,6 +2025,7 @@ genCCall' dflags gcp target dest_regs args
119+ MO_AddIntC {} -> unsupported
120+ MO_SubIntC {} -> unsupported
121+ MO_U_Mul2 {} -> unsupported
122++ MO_ReadBarrier -> unsupported
123+ MO_WriteBarrier -> unsupported
124+ MO_Touch -> unsupported
125+ MO_Prefetch_Data _ -> unsupported
126+diff --git a/compiler/nativeGen/SPARC/CodeGen.hs b/compiler/nativeGen/SPARC/CodeGen.hs
127+index 98e062df62..29e8dbf0f9 100644
128+--- a/compiler/nativeGen/SPARC/CodeGen.hs
129++++ b/compiler/nativeGen/SPARC/CodeGen.hs
130+@@ -401,6 +401,8 @@ genCCall
131+ --
132+ -- In the SPARC case we don't need a barrier.
133+ --
134++genCCall (PrimTarget MO_ReadBarrier) _ _
135++ = return $ nilOL
136+ genCCall (PrimTarget MO_WriteBarrier) _ _
137+ = return $ nilOL
138+
139+@@ -678,6 +680,7 @@ outOfLineMachOp_table mop
140+ MO_AddIntC {} -> unsupported
141+ MO_SubIntC {} -> unsupported
142+ MO_U_Mul2 {} -> unsupported
143++ MO_ReadBarrier -> unsupported
144+ MO_WriteBarrier -> unsupported
145+ MO_Touch -> unsupported
146+ (MO_Prefetch_Data _) -> unsupported
147+diff --git a/compiler/nativeGen/X86/CodeGen.hs b/compiler/nativeGen/X86/CodeGen.hs
148+index 4551754200..98830b1233 100644
149+--- a/compiler/nativeGen/X86/CodeGen.hs
150++++ b/compiler/nativeGen/X86/CodeGen.hs
151+@@ -1809,8 +1809,9 @@ genCCall dflags _ (PrimTarget (MO_Memset align)) _
152+ dst_addr = AddrBaseIndex (EABaseReg dst) EAIndexNone
153+ (ImmInteger (n - i))
154+
155++genCCall _ _ (PrimTarget MO_ReadBarrier) _ _ = return nilOL
156+ genCCall _ _ (PrimTarget MO_WriteBarrier) _ _ = return nilOL
157+- -- write barrier compiles to no code on x86/x86-64;
158++ -- barriers compile to no code on x86/x86-64;
159+ -- we keep it this long in order to prevent earlier optimisations.
160+
161+ genCCall _ _ (PrimTarget MO_Touch) _ _ = return nilOL
162+@@ -2793,6 +2794,7 @@ outOfLineCmmOp mop res args
163+ MO_AddWordC {} -> unsupported
164+ MO_SubWordC {} -> unsupported
165+ MO_U_Mul2 {} -> unsupported
166++ MO_ReadBarrier -> unsupported
167+ MO_WriteBarrier -> unsupported
168+ MO_Touch -> unsupported
169+ (MO_Prefetch_Data _ ) -> unsupported
170+diff --git a/includes/Cmm.h b/includes/Cmm.h
171+index 7334eab8c1..ede77f0c00 100644
172+--- a/includes/Cmm.h
173++++ b/includes/Cmm.h
174+@@ -303,7 +303,9 @@
175+ #define ENTER_(ret,x) \
176+ again: \
177+ W_ info; \
178+- LOAD_INFO(ret,x) \
179++ LOAD_INFO(ret,x) \
180++ /* See Note [Heap memory barriers] in SMP.h */ \
181++ prim_read_barrier; \
182+ switch [INVALID_OBJECT .. N_CLOSURE_TYPES] \
183+ (TO_W_( %INFO_TYPE(%STD_INFO(info)) )) { \
184+ case \
185+@@ -626,6 +628,14 @@
186+ #define OVERWRITING_CLOSURE_OFS(c,n) /* nothing */
187+ #endif
188+
189++// Memory barriers.
190++// For discussion of how these are used to fence heap object
191++// accesses see Note [Heap memory barriers] in SMP.h.
192++#if defined(THREADED_RTS)
193++#define prim_read_barrier prim %read_barrier()
194++#else
195++#define prim_read_barrier /* nothing */
196++#endif
197+ #if defined(THREADED_RTS)
198+ #define prim_write_barrier prim %write_barrier()
199+ #else
200+diff --git a/includes/stg/SMP.h b/includes/stg/SMP.h
201+index 4020aef0d9..db6b4b954a 100644
202+--- a/includes/stg/SMP.h
203++++ b/includes/stg/SMP.h
204+@@ -96,6 +96,151 @@ EXTERN_INLINE void write_barrier(void);
205+ EXTERN_INLINE void store_load_barrier(void);
206+ EXTERN_INLINE void load_load_barrier(void);
207+
208++/*
209++ * Note [Heap memory barriers]
210++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~
211++ *
212++ * Machines with weak memory ordering semantics have consequences for how
213++ * closures are observed and mutated. For example, consider a thunk that needs
214++ * to be updated to an indirection. In order for the indirection to be safe for
215++ * concurrent observers to enter, said observers must read the indirection's
216++ * info table before they read the indirectee. Furthermore, the indirectee must
217++ * be set before the info table pointer. This ensures that if the observer sees
218++ * an IND info table then the indirectee is valid.
219++ *
220++ * When a closure is updated with an indirection, both its info table and its
221++ * indirectee must be written. With weak memory ordering, these two writes can
222++ * be arbitrarily reordered, and perhaps even interleaved with other threads'
223++ * reads and writes (in the absence of memory barrier instructions). Consider
224++ * this example of a bad reordering:
225++ *
226++ * - An updater writes to a closure's info table (INFO_TYPE is now IND).
227++ * - A concurrent observer branches upon reading the closure's INFO_TYPE as IND.
228++ * - A concurrent observer reads the closure's indirectee and enters it.
229++ * - An updater writes the closure's indirectee.
230++ *
231++ * Here the update to the indirectee comes too late and the concurrent observer
232++ * has jumped off into the abyss. Speculative execution can also cause us
233++ * issues, consider:
234++ *
235++ * - an observer is about to case on a value in closure's info table.
236++ * - the observer speculatively reads one or more of closure's fields.
237++ * - an updater writes to closure's info table.
238++ * - the observer takes a branch based on the new info table value, but with the
239++ * old closure fields!
240++ * - the updater writes to the closure's other fields, but its too late.
241++ *
242++ * Because of these effects, reads and writes to a closure's info table must be
243++ * ordered carefully with respect to reads and writes to the closure's other
244++ * fields, and memory barriers must be placed to ensure that reads and writes
245++ * occur in program order. Specifically, updates to an already existing closure
246++ * must follow the following pattern:
247++ *
248++ * - Update the closure's (non-info table) fields.
249++ * - Write barrier.
250++ * - Update the closure's info table.
251++ *
252++ * Observing the fields of an updateable closure (e.g. a THUNK) must follow the
253++ * following pattern:
254++ *
255++ * - Read the closure's info pointer.
256++ * - Read barrier.
257++ * - Read the closure's (non-info table) fields.
258++ *
259++ * We must also take care when we expose a newly-allocated closure to other cores
260++ * by writing a pointer to it to some shared data structure (e.g. an MVar#, a Message,
261++ * or MutVar#). Specifically, we need to ensure that all writes constructing the
262++ * closure are visible *before* the write exposing the new closure is made visible:
263++ *
264++ * - Allocate memory for the closure
265++ * - Write the closure's info pointer and fields (ordering betweeen this doesn't
266++ * matter since the closure isn't yet visible to anyone else).
267++ * - Write barrier
268++ * - Make closure visible to other cores
269++ *
270++ * Note that thread stacks are inherently thread-local and consequently allocating an
271++ * object and introducing a reference to it to our stack needs no barrier.
272++ *
273++ * There are several ways in which the mutator may make a newly-allocated
274++ * closure visible to other cores:
275++ *
276++ * - Eager blackholing a THUNK:
277++ * This is protected by an explicit write barrier in the eager blackholing
278++ * code produced by the codegen. See StgCmmBind.emitBlackHoleCode.
279++ *
280++ * - Lazy blackholing a THUNK:
281++ * This is is protected by an explicit write barrier in the thread suspension
282++ * code. See ThreadPaused.c:threadPaused.
283++ *
284++ * - Updating a BLACKHOLE:
285++ * This case is protected by explicit write barriers in the the update frame
286++ * entry code (see rts/Updates.h).
287++ *
288++ * - Blocking on an MVar# (e.g. takeMVar#):
289++ * In this case the appropriate MVar primops (e.g. stg_takeMVarzh). include
290++ * explicit memory barriers to ensure that the the newly-allocated
291++ * MVAR_TSO_QUEUE is visible to other cores.
292++ *
293++ * - Write to an MVar# (e.g. putMVar#):
294++ * This protected by the full barrier implied by the CAS in putMVar#.
295++ *
296++ * - Write to a TVar#:
297++ * This is protected by the full barrier implied by the CAS in STM.c:lock_stm.
298++ *
299++ * - Write to an Array#, ArrayArray#, or SmallArray#:
300++ * This case is protected by an explicit write barrier in the code produced
301++ * for this primop by the codegen. See StgCmmPrim.doWritePtrArrayOp and
302++ * StgCmmPrim.doWriteSmallPtrArrayOp. Relevant issue: #12469.
303++ *
304++ * - Write to MutVar# via writeMutVar#:
305++ * This case is protected by an explicit write barrier in the code produced
306++ * for this primop by the codegen.
307++ *
308++ * - Write to MutVar# via atomicModifyMutVar# or casMutVar#:
309++ * This is protected by the full barrier implied by the cmpxchg operations
310++ * in this primops.
311++ *
312++ * - Sending a Message to another capability:
313++ * This is protected by the acquition and release of the target capability's
314++ * lock in Messages.c:sendMessage.
315++ *
316++ * Finally, we must ensure that we flush all cores store buffers before
317++ * entering and leaving GC, since stacks may be read by other cores. This
318++ * happens as a side-effect of taking and release mutexes (which implies
319++ * acquire and release barriers, respectively).
320++ *
321++ * N.B. recordClosureMutated places a reference to the mutated object on
322++ * the capability-local mut_list. Consequently this does not require any memory
323++ * barrier.
324++ *
325++ * During parallel GC we need to be careful during evacuation: before replacing
326++ * a closure with a forwarding pointer we must commit a write barrier to ensure
327++ * that the copy we made in to-space is visible to other cores.
328++ *
329++ * However, we can be a bit lax when *reading* during GC. Specifically, the GC
330++ * can only make a very limited set of changes to existing closures:
331++ *
332++ * - it can replace a closure's info table with stg_WHITEHOLE.
333++ * - it can replace a previously-whitehole'd closure's info table with a
334++ * forwarding pointer
335++ * - it can replace a previously-whitehole'd closure's info table with a
336++ * valid info table pointer (done in eval_thunk_selector)
337++ * - it can update the value of a pointer field after evacuating it
338++ *
339++ * This is quite nice since we don't need to worry about an interleaving
340++ * of writes producing an invalid state: a closure's fields remain valid after
341++ * an update of its info table pointer and vice-versa.
342++ *
343++ * After a round of parallel scavenging we must also ensure that any writes the
344++ * GC thread workers made are visible to the main GC thread. This is ensured by
345++ * the full barrier implied by the atomic decrement in
346++ * GC.c:scavenge_until_all_done.
347++ *
348++ * The work-stealing queue (WSDeque) also requires barriers; these are
349++ * documented in WSDeque.c.
350++ *
351++ */
352++
353+ /* ----------------------------------------------------------------------------
354+ Implementations
355+ ------------------------------------------------------------------------- */
356+diff --git a/libraries/base/GHC/Event/Manager.hs b/libraries/base/GHC/Event/Manager.hs
357+index 3ee9116812..51306795fe 100644
358+--- a/libraries/base/GHC/Event/Manager.hs
359++++ b/libraries/base/GHC/Event/Manager.hs
360+@@ -150,9 +150,7 @@ callbackTableVar mgr fd = emFds mgr ! hashFd fd
361+
362+ haveOneShot :: Bool
363+ {-# INLINE haveOneShot #-}
364+-#if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
365+-haveOneShot = False
366+-#elif defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
367++#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
368+ haveOneShot = True
369+ #else
370+ haveOneShot = False
371+@@ -365,20 +363,9 @@ registerFd mgr cb fd evs lt = do
372+ return r
373+ {-# INLINE registerFd #-}
374+
375+-{-
376+- Building GHC with parallel IO manager on Mac freezes when
377+- compiling the dph libraries in the phase 2. As workaround, we
378+- don't use oneshot and we wake up an IO manager on Mac every time
379+- when we register an event.
380+-
381+- For more information, please read:
382+- http://ghc.haskell.org/trac/ghc/ticket/7651
383+--}
384+ -- | Wake up the event manager.
385+ wakeManager :: EventManager -> IO ()
386+-#if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
387+-wakeManager mgr = sendWakeup (emControl mgr)
388+-#elif defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
389++#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
390+ wakeManager _ = return ()
391+ #else
392+ wakeManager mgr = sendWakeup (emControl mgr)
393+diff --git a/libraries/ghc-prim/ghc-prim.cabal b/libraries/ghc-prim/ghc-prim.cabal
394+index a95f1ecaa8..4866490899 100644
395+--- a/libraries/ghc-prim/ghc-prim.cabal
396++++ b/libraries/ghc-prim/ghc-prim.cabal
397+@@ -66,6 +66,11 @@ Library
398+ -- on Windows. Required because of mingw32.
399+ extra-libraries: user32, mingw32, mingwex
400+
401++ if os(linux)
402++ -- we need libm, but for musl and other's we might need libc, as libm
403++ -- is just an empty shell.
404++ extra-libraries: c, m
405++
406+ c-sources:
407+ cbits/atomic.c
408+ cbits/bswap.c
409+diff --git a/rts/Apply.cmm b/rts/Apply.cmm
410+index 0454fd69e2..7d87d4dd75 100644
411+--- a/rts/Apply.cmm
412++++ b/rts/Apply.cmm
413+@@ -62,6 +62,8 @@ again:
414+ W_ info;
415+ P_ untaggedfun;
416+ W_ arity;
417++ // We must obey the correct heap object observation pattern in
418++ // Note [Heap memory barriers] in SMP.h.
419+ untaggedfun = UNTAG(fun);
420+ info = %INFO_PTR(untaggedfun);
421+ switch [INVALID_OBJECT .. N_CLOSURE_TYPES]
422+diff --git a/rts/Compact.cmm b/rts/Compact.cmm
423+index 061646846d..bae94a03cd 100644
424+--- a/rts/Compact.cmm
425++++ b/rts/Compact.cmm
426+@@ -53,6 +53,9 @@ import CLOSURE base_GHCziIOziException_cannotCompactPinned_closure;
427+ // data structure. It takes the location to store the address of the
428+ // compacted object as an argument, so that it can be tail-recursive.
429+ //
430++// N.B. No memory barrier (see Note [Heap memory barriers] in SMP.h) is needed
431++// here since this is essentially an allocation of a new object which won't
432++// be visible to other cores until after we return.
433+ stg_compactAddWorkerzh (
434+ P_ compact, // The Compact# object
435+ P_ p, // The object to compact
436+diff --git a/rts/Interpreter.c b/rts/Interpreter.c
437+index 9eb6560a8c..0540cf964c 100644
438+--- a/rts/Interpreter.c
439++++ b/rts/Interpreter.c
440+@@ -266,7 +266,6 @@ StgClosure * copyPAP (Capability *cap, StgPAP *oldpap)
441+ uint32_t size = PAP_sizeW(oldpap->n_args);
442+ StgPAP *pap = (StgPAP *)allocate(cap, size);
443+ enterFunCCS(&cap->r, oldpap->header.prof.ccs);
444+- SET_HDR(pap, &stg_PAP_info, cap->r.rCCCS);
445+ pap->arity = oldpap->arity;
446+ pap->n_args = oldpap->n_args;
447+ pap->fun = oldpap->fun;
448+@@ -274,6 +273,8 @@ StgClosure * copyPAP (Capability *cap, StgPAP *oldpap)
449+ for (i = 0; i < ((StgPAP *)pap)->n_args; i++) {
450+ pap->payload[i] = oldpap->payload[i];
451+ }
452++ // No write barrier is needed here as this is a new allocation
453++ SET_HDR(pap, &stg_PAP_info, cap->r.rCCCS);
454+ return (StgClosure *)pap;
455+ }
456+
457+@@ -799,7 +800,6 @@ do_apply:
458+ // build a new PAP and return it.
459+ StgPAP *new_pap;
460+ new_pap = (StgPAP *)allocate(cap, PAP_sizeW(pap->n_args + m));
461+- SET_HDR(new_pap,&stg_PAP_info,cap->r.rCCCS);
462+ new_pap->arity = pap->arity - n;
463+ new_pap->n_args = pap->n_args + m;
464+ new_pap->fun = pap->fun;
465+@@ -809,6 +809,8 @@ do_apply:
466+ for (i = 0; i < m; i++) {
467+ new_pap->payload[pap->n_args + i] = (StgClosure *)SpW(i);
468+ }
469++ // No write barrier is needed here as this is a new allocation
470++ SET_HDR(new_pap,&stg_PAP_info,cap->r.rCCCS);
471+ tagged_obj = (StgClosure *)new_pap;
472+ Sp_addW(m);
473+ goto do_return;
474+@@ -844,13 +846,14 @@ do_apply:
475+ StgPAP *pap;
476+ uint32_t i;
477+ pap = (StgPAP *)allocate(cap, PAP_sizeW(m));
478+- SET_HDR(pap, &stg_PAP_info,cap->r.rCCCS);
479+ pap->arity = arity - n;
480+ pap->fun = obj;
481+ pap->n_args = m;
482+ for (i = 0; i < m; i++) {
483+ pap->payload[i] = (StgClosure *)SpW(i);
484+ }
485++ // No write barrier is needed here as this is a new allocation
486++ SET_HDR(pap, &stg_PAP_info,cap->r.rCCCS);
487+ tagged_obj = (StgClosure *)pap;
488+ Sp_addW(m);
489+ goto do_return;
490+@@ -1081,7 +1084,6 @@ run_BCO:
491+ // the BCO
492+ size_words = BCO_BITMAP_SIZE(obj) + 2;
493+ new_aps = (StgAP_STACK *) allocate(cap, AP_STACK_sizeW(size_words));
494+- SET_HDR(new_aps,&stg_AP_STACK_info,cap->r.rCCCS);
495+ new_aps->size = size_words;
496+ new_aps->fun = &stg_dummy_ret_closure;
497+
498+@@ -1095,6 +1097,9 @@ run_BCO:
499+ new_aps->payload[i] = (StgClosure *)SpW(i-2);
500+ }
501+
502++ // No write barrier is needed here as this is a new allocation
503++ SET_HDR(new_aps,&stg_AP_STACK_info,cap->r.rCCCS);
504++
505+ // Arrange the stack to call the breakpoint IO action, and
506+ // continue execution of this BCO when the IO action returns.
507+ //
508+@@ -1423,6 +1428,8 @@ run_BCO:
509+ ap = (StgAP*)allocate(cap, AP_sizeW(n_payload));
510+ SpW(-1) = (W_)ap;
511+ ap->n_args = n_payload;
512++ // No write barrier is needed here as this is a new allocation
513++ // visible only from our stack
514+ SET_HDR(ap, &stg_AP_info, cap->r.rCCCS)
515+ Sp_subW(1);
516+ goto nextInsn;
517+@@ -1434,6 +1441,8 @@ run_BCO:
518+ ap = (StgAP*)allocate(cap, AP_sizeW(n_payload));
519+ SpW(-1) = (W_)ap;
520+ ap->n_args = n_payload;
521++ // No write barrier is needed here as this is a new allocation
522++ // visible only from our stack
523+ SET_HDR(ap, &stg_AP_NOUPD_info, cap->r.rCCCS)
524+ Sp_subW(1);
525+ goto nextInsn;
526+@@ -1447,6 +1456,8 @@ run_BCO:
527+ SpW(-1) = (W_)pap;
528+ pap->n_args = n_payload;
529+ pap->arity = arity;
530++ // No write barrier is needed here as this is a new allocation
531++ // visible only from our stack
532+ SET_HDR(pap, &stg_PAP_info, cap->r.rCCCS)
533+ Sp_subW(1);
534+ goto nextInsn;
535+@@ -1522,12 +1533,14 @@ run_BCO:
536+ itbl->layout.payload.nptrs );
537+ StgClosure* con = (StgClosure*)allocate_NONUPD(cap,request);
538+ ASSERT( itbl->layout.payload.ptrs + itbl->layout.payload.nptrs > 0);
539+- SET_HDR(con, (StgInfoTable*)BCO_LIT(o_itbl), cap->r.rCCCS);
540+ for (i = 0; i < n_words; i++) {
541+ con->payload[i] = (StgClosure*)SpW(i);
542+ }
543+ Sp_addW(n_words);
544+ Sp_subW(1);
545++ // No write barrier is needed here as this is a new allocation
546++ // visible only from our stack
547++ SET_HDR(con, (StgInfoTable*)BCO_LIT(o_itbl), cap->r.rCCCS);
548+ SpW(0) = (W_)con;
549+ IF_DEBUG(interpreter,
550+ debugBelch("\tBuilt ");
551+diff --git a/rts/Linker.c b/rts/Linker.c
552+index b7e83858b0..7ed9e9d148 100644
553+--- a/rts/Linker.c
554++++ b/rts/Linker.c
555+@@ -192,7 +192,7 @@ int ocTryLoad( ObjectCode* oc );
556+ *
557+ * MAP_32BIT not available on OpenBSD/amd64
558+ */
559+-#if defined(x86_64_HOST_ARCH) && defined(MAP_32BIT)
560++#if (defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) || defined(aarch64_TARGET_ARCH)) && defined(MAP_32BIT)
561+ #define TRY_MAP_32BIT MAP_32BIT
562+ #else
563+ #define TRY_MAP_32BIT 0
564+@@ -209,10 +209,16 @@ int ocTryLoad( ObjectCode* oc );
565+ * in the low 2Gb of the address space and try to allocate memory from
566+ * there.
567+ *
568++ * The same holds for aarch64, where the default, even with PIC, model
569++ * is 4GB. The linker is free to emit AARCH64_ADR_PREL_PG_HI21
570++ * relocations.
571++ *
572+ * We pick a default address based on the OS, but also make this
573+ * configurable via an RTS flag (+RTS -xm)
574+ */
575+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
576++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
577++
578++#define MMAP_MAX_RETRY 100
579+
580+ #if defined(MAP_32BIT)
581+ // Try to use MAP_32BIT
582+@@ -496,7 +502,7 @@ initLinker_ (int retain_cafs)
583+ }
584+ # endif
585+
586+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
587++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
588+ if (RtsFlags.MiscFlags.linkerMemBase != 0) {
589+ // User-override for mmap_32bit_base
590+ mmap_32bit_base = (void*)RtsFlags.MiscFlags.linkerMemBase;
591+@@ -1001,7 +1007,7 @@ resolveSymbolAddr (pathchar* buffer, int size,
592+ // Returns NULL on failure.
593+ //
594+ void *
595+-mmapForLinker (size_t bytes, uint32_t flags, int fd, int offset)
596++mmapForLinker (size_t bytes, uint32_t prot, uint32_t flags, int fd, int offset)
597+ {
598+ void *map_addr = NULL;
599+ void *result;
600+@@ -1011,9 +1017,14 @@ mmapForLinker (size_t bytes, uint32_t flags, int fd, int offset)
601+ IF_DEBUG(linker, debugBelch("mmapForLinker: start\n"));
602+ size = roundUpToPage(bytes);
603+
604+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
605+-mmap_again:
606++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) || defined(aarch64_TARGET_ARCH)
607+
608++ size_t mmap_counter = MMAP_MAX_RETRY;
609++mmap_again:
610++ if (0 == --mmap_counter) {
611++ sysErrorBelch("mmap, small memory model: failed to allocate within 2GB after %d retries.\n", MMAP_MAX_RETRY);
612++ stg_exit(EXIT_FAILURE);
613++ }
614+ if (mmap_32bit_base != 0) {
615+ map_addr = mmap_32bit_base;
616+ }
617+@@ -1021,13 +1032,13 @@ mmap_again:
618+
619+ IF_DEBUG(linker,
620+ debugBelch("mmapForLinker: \tprotection %#0x\n",
621+- PROT_EXEC | PROT_READ | PROT_WRITE));
622++ prot));
623+ IF_DEBUG(linker,
624+ debugBelch("mmapForLinker: \tflags %#0x\n",
625+ MAP_PRIVATE | TRY_MAP_32BIT | fixed | flags));
626+
627+ result = mmap(map_addr, size,
628+- PROT_EXEC|PROT_READ|PROT_WRITE,
629++ prot,
630+ MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, offset);
631+
632+ if (result == MAP_FAILED) {
633+@@ -1036,7 +1047,7 @@ mmap_again:
634+ return NULL;
635+ }
636+
637+-#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
638++#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) || defined(aarch64_TARGET_ARCH)
639+ if (mmap_32bit_base != 0) {
640+ if (result == map_addr) {
641+ mmap_32bit_base = (StgWord8*)map_addr + size;
642+@@ -1360,9 +1371,9 @@ preloadObjectFile (pathchar *path)
643+ * See also the misalignment logic for darwin below.
644+ */
645+ #if defined(ios_HOST_OS)
646+- image = mmap(NULL, fileSize, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
647++ image = mmapForLinker(fileSize, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
648+ #else
649+- image = mmap(NULL, fileSize, PROT_READ|PROT_WRITE|PROT_EXEC,
650++ image = mmapForLinker(fileSize, PROT_READ|PROT_WRITE|PROT_EXEC,
651+ MAP_PRIVATE, fd, 0);
652+ #endif
653+
654+@@ -1820,4 +1831,3 @@ addSection (Section *s, SectionKind kind, SectionAlloc alloc,
655+ start, (void*)((StgWord)start + size),
656+ size, kind ));
657+ }
658+-
659+diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
660+index b48fc75966..f7ef0da81e 100644
661+--- a/rts/LinkerInternals.h
662++++ b/rts/LinkerInternals.h
663+@@ -246,7 +246,7 @@ void exitLinker( void );
664+ void freeObjectCode (ObjectCode *oc);
665+ SymbolAddr* loadSymbol(SymbolName *lbl, RtsSymbolInfo *pinfo);
666+
667+-void *mmapForLinker (size_t bytes, uint32_t flags, int fd, int offset);
668++void *mmapForLinker (size_t bytes, uint32_t prot, uint32_t flags, int fd, int offset);
669+
670+ void addProddableBlock ( ObjectCode* oc, void* start, int size );
671+ void checkProddableBlock (ObjectCode *oc, void *addr, size_t size );
672+diff --git a/rts/Messages.c b/rts/Messages.c
673+index 2b13b6306c..d878db5eda 100644
674+--- a/rts/Messages.c
675++++ b/rts/Messages.c
676+@@ -173,6 +173,7 @@ uint32_t messageBlackHole(Capability *cap, MessageBlackHole *msg)
677+ "blackhole %p", (W_)msg->tso->id, msg->bh);
678+
679+ info = bh->header.info;
680++ load_load_barrier(); // See Note [Heap memory barriers] in SMP.h
681+
682+ // If we got this message in our inbox, it might be that the
683+ // BLACKHOLE has already been updated, and GC has shorted out the
684+@@ -196,6 +197,7 @@ loop:
685+ // and turns this into an infinite loop.
686+ p = UNTAG_CLOSURE((StgClosure*)VOLATILE_LOAD(&((StgInd*)bh)->indirectee));
687+ info = p->header.info;
688++ load_load_barrier(); // See Note [Heap memory barriers] in SMP.h
689+
690+ if (info == &stg_IND_info)
691+ {
692+@@ -226,7 +228,6 @@ loop:
693+ bq = (StgBlockingQueue*)allocate(cap, sizeofW(StgBlockingQueue));
694+
695+ // initialise the BLOCKING_QUEUE object
696+- SET_HDR(bq, &stg_BLOCKING_QUEUE_DIRTY_info, CCS_SYSTEM);
697+ bq->bh = bh;
698+ bq->queue = msg;
699+ bq->owner = owner;
700+@@ -238,6 +239,11 @@ loop:
701+ // a collision to update a BLACKHOLE and a BLOCKING_QUEUE
702+ // becomes orphaned (see updateThunk()).
703+ bq->link = owner->bq;
704++ SET_HDR(bq, &stg_BLOCKING_QUEUE_DIRTY_info, CCS_SYSTEM);
705++ // We are about to make the newly-constructed message visible to other cores;
706++ // a barrier is necessary to ensure that all writes are visible.
707++ // See Note [Heap memory barriers] in SMP.h.
708++ write_barrier();
709+ owner->bq = bq;
710+ dirty_TSO(cap, owner); // we modified owner->bq
711+
712+@@ -255,7 +261,7 @@ loop:
713+ }
714+
715+ // point to the BLOCKING_QUEUE from the BLACKHOLE
716+- write_barrier(); // make the BQ visible
717++ write_barrier(); // make the BQ visible, see Note [Heap memory barriers].
718+ ((StgInd*)bh)->indirectee = (StgClosure *)bq;
719+ recordClosureMutated(cap,bh); // bh was mutated
720+
721+@@ -286,10 +292,14 @@ loop:
722+
723+ msg->link = bq->queue;
724+ bq->queue = msg;
725++ // No barrier is necessary here: we are only exposing the
726++ // closure to the GC. See Note [Heap memory barriers] in SMP.h.
727+ recordClosureMutated(cap,(StgClosure*)msg);
728+
729+ if (info == &stg_BLOCKING_QUEUE_CLEAN_info) {
730+ bq->header.info = &stg_BLOCKING_QUEUE_DIRTY_info;
731++ // No barrier is necessary here: we are only exposing the
732++ // closure to the GC. See Note [Heap memory barriers] in SMP.h.
733+ recordClosureMutated(cap,(StgClosure*)bq);
734+ }
735+
736+diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
737+index cbb8e54e28..4274dfb50a 100644
738+--- a/rts/PrimOps.cmm
739++++ b/rts/PrimOps.cmm
740+@@ -105,6 +105,7 @@ stg_newPinnedByteArrayzh ( W_ n )
741+ to BA_ALIGN bytes: */
742+ p = p + ((-p - SIZEOF_StgArrBytes) & BA_MASK);
743+
744++ /* No write barrier needed since this is a new allocation. */
745+ SET_HDR(p, stg_ARR_WORDS_info, CCCS);
746+ StgArrBytes_bytes(p) = n;
747+ return (p);
748+@@ -147,6 +148,7 @@ stg_newAlignedPinnedByteArrayzh ( W_ n, W_ alignment )
749+ <alignment> is a power of 2, which is technically not guaranteed */
750+ p = p + ((-p - SIZEOF_StgArrBytes) & (alignment - 1));
751+
752++ /* No write barrier needed since this is a new allocation. */
753+ SET_HDR(p, stg_ARR_WORDS_info, CCCS);
754+ StgArrBytes_bytes(p) = n;
755+ return (p);
756+@@ -257,6 +259,7 @@ stg_newArrayzh ( W_ n /* words */, gcptr init )
757+ }
758+ TICK_ALLOC_PRIM(SIZEOF_StgMutArrPtrs, WDS(size), 0);
759+
760++ /* No write barrier needed since this is a new allocation. */
761+ SET_HDR(arr, stg_MUT_ARR_PTRS_DIRTY_info, CCCS);
762+ StgMutArrPtrs_ptrs(arr) = n;
763+ StgMutArrPtrs_size(arr) = size;
764+@@ -408,6 +411,7 @@ stg_newSmallArrayzh ( W_ n /* words */, gcptr init )
765+ }
766+ TICK_ALLOC_PRIM(SIZEOF_StgSmallMutArrPtrs, WDS(n), 0);
767+
768++ /* No write barrier needed since this is a new allocation. */
769+ SET_HDR(arr, stg_SMALL_MUT_ARR_PTRS_DIRTY_info, CCCS);
770+ StgSmallMutArrPtrs_ptrs(arr) = n;
771+
772+@@ -522,6 +526,7 @@ stg_newMutVarzh ( gcptr init )
773+ ALLOC_PRIM_P (SIZEOF_StgMutVar, stg_newMutVarzh, init);
774+
775+ mv = Hp - SIZEOF_StgMutVar + WDS(1);
776++ /* No write barrier needed since this is a new allocation. */
777+ SET_HDR(mv,stg_MUT_VAR_DIRTY_info,CCCS);
778+ StgMutVar_var(mv) = init;
779+
780+@@ -655,6 +660,7 @@ stg_mkWeakzh ( gcptr key,
781+ ALLOC_PRIM (SIZEOF_StgWeak)
782+
783+ w = Hp - SIZEOF_StgWeak + WDS(1);
784++ // No memory barrier needed as this is a new allocation.
785+ SET_HDR(w, stg_WEAK_info, CCCS);
786+
787+ StgWeak_key(w) = key;
788+@@ -770,6 +776,7 @@ stg_deRefWeakzh ( gcptr w )
789+ gcptr val;
790+
791+ info = GET_INFO(w);
792++ prim_read_barrier;
793+
794+ if (info == stg_WHITEHOLE_info) {
795+ // w is locked by another thread. Now it's not immediately clear if w is
796+@@ -1341,11 +1348,13 @@ stg_readTVarzh (P_ tvar)
797+
798+ stg_readTVarIOzh ( P_ tvar /* :: TVar a */ )
799+ {
800+- W_ result;
801++ W_ result, resultinfo;
802+
803+ again:
804+ result = StgTVar_current_value(tvar);
805+- if (%INFO_PTR(result) == stg_TREC_HEADER_info) {
806++ resultinfo = %INFO_PTR(result);
807++ prim_read_barrier;
808++ if (resultinfo == stg_TREC_HEADER_info) {
809+ goto again;
810+ }
811+ return (result);
812+@@ -1414,6 +1423,7 @@ stg_newMVarzh ()
813+ ALLOC_PRIM_ (SIZEOF_StgMVar, stg_newMVarzh);
814+
815+ mvar = Hp - SIZEOF_StgMVar + WDS(1);
816++ // No memory barrier needed as this is a new allocation.
817+ SET_HDR(mvar,stg_MVAR_DIRTY_info,CCCS);
818+ // MVARs start dirty: generation 0 has no mutable list
819+ StgMVar_head(mvar) = stg_END_TSO_QUEUE_closure;
820+@@ -1438,7 +1448,7 @@ stg_newMVarzh ()
821+
822+ stg_takeMVarzh ( P_ mvar /* :: MVar a */ )
823+ {
824+- W_ val, info, tso, q;
825++ W_ val, info, tso, q, qinfo;
826+
827+ LOCK_CLOSURE(mvar, info);
828+
829+@@ -1460,9 +1470,12 @@ stg_takeMVarzh ( P_ mvar /* :: MVar a */ )
830+
831+ q = Hp - SIZEOF_StgMVarTSOQueue + WDS(1);
832+
833+- SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
834+ StgMVarTSOQueue_link(q) = END_TSO_QUEUE;
835+ StgMVarTSOQueue_tso(q) = CurrentTSO;
836++ SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
837++ // Write barrier before we make the new MVAR_TSO_QUEUE
838++ // visible to other cores.
839++ prim_write_barrier;
840+
841+ if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
842+ StgMVar_head(mvar) = q;
843+@@ -1492,8 +1505,10 @@ loop:
844+ unlockClosure(mvar, info);
845+ return (val);
846+ }
847+- if (StgHeader_info(q) == stg_IND_info ||
848+- StgHeader_info(q) == stg_MSG_NULL_info) {
849++ qinfo = StgHeader_info(q);
850++ prim_read_barrier;
851++ if (qinfo == stg_IND_info ||
852++ qinfo == stg_MSG_NULL_info) {
853+ q = StgInd_indirectee(q);
854+ goto loop;
855+ }
856+@@ -1531,7 +1546,7 @@ loop:
857+
858+ stg_tryTakeMVarzh ( P_ mvar /* :: MVar a */ )
859+ {
860+- W_ val, info, tso, q;
861++ W_ val, info, tso, q, qinfo;
862+
863+ LOCK_CLOSURE(mvar, info);
864+
865+@@ -1558,8 +1573,11 @@ loop:
866+ return (1, val);
867+ }
868+
869+- if (StgHeader_info(q) == stg_IND_info ||
870+- StgHeader_info(q) == stg_MSG_NULL_info) {
871++ qinfo = StgHeader_info(q);
872++ prim_read_barrier;
873++
874++ if (qinfo == stg_IND_info ||
875++ qinfo == stg_MSG_NULL_info) {
876+ q = StgInd_indirectee(q);
877+ goto loop;
878+ }
879+@@ -1598,7 +1616,7 @@ loop:
880+ stg_putMVarzh ( P_ mvar, /* :: MVar a */
881+ P_ val, /* :: a */ )
882+ {
883+- W_ info, tso, q;
884++ W_ info, tso, q, qinfo;
885+
886+ LOCK_CLOSURE(mvar, info);
887+
888+@@ -1618,10 +1636,12 @@ stg_putMVarzh ( P_ mvar, /* :: MVar a */
889+
890+ q = Hp - SIZEOF_StgMVarTSOQueue + WDS(1);
891+
892+- SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
893+ StgMVarTSOQueue_link(q) = END_TSO_QUEUE;
894+ StgMVarTSOQueue_tso(q) = CurrentTSO;
895+
896++ SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
897++ prim_write_barrier;
898++
899+ if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
900+ StgMVar_head(mvar) = q;
901+ } else {
902+@@ -1648,8 +1668,12 @@ loop:
903+ unlockClosure(mvar, stg_MVAR_DIRTY_info);
904+ return ();
905+ }
906+- if (StgHeader_info(q) == stg_IND_info ||
907+- StgHeader_info(q) == stg_MSG_NULL_info) {
908++
909++ qinfo = StgHeader_info(q);
910++ prim_read_barrier;
911++
912++ if (qinfo == stg_IND_info ||
913++ qinfo == stg_MSG_NULL_info) {
914+ q = StgInd_indirectee(q);
915+ goto loop;
916+ }
917+@@ -1706,7 +1730,7 @@ loop:
918+ stg_tryPutMVarzh ( P_ mvar, /* :: MVar a */
919+ P_ val, /* :: a */ )
920+ {
921+- W_ info, tso, q;
922++ W_ info, tso, q, qinfo;
923+
924+ LOCK_CLOSURE(mvar, info);
925+
926+@@ -1729,8 +1753,12 @@ loop:
927+ unlockClosure(mvar, stg_MVAR_DIRTY_info);
928+ return (1);
929+ }
930+- if (StgHeader_info(q) == stg_IND_info ||
931+- StgHeader_info(q) == stg_MSG_NULL_info) {
932++
933++ qinfo = StgHeader_info(q);
934++ prim_read_barrier;
935++
936++ if (qinfo == stg_IND_info ||
937++ qinfo == stg_MSG_NULL_info) {
938+ q = StgInd_indirectee(q);
939+ goto loop;
940+ }
941+@@ -1801,10 +1829,12 @@ stg_readMVarzh ( P_ mvar, /* :: MVar a */ )
942+
943+ // readMVars are pushed to the front of the queue, so
944+ // they get handled immediately
945+- SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
946+ StgMVarTSOQueue_link(q) = StgMVar_head(mvar);
947+ StgMVarTSOQueue_tso(q) = CurrentTSO;
948+
949++ SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
950++ prim_write_barrier;
951++
952+ StgTSO__link(CurrentTSO) = q;
953+ StgTSO_block_info(CurrentTSO) = mvar;
954+ StgTSO_why_blocked(CurrentTSO) = BlockedOnMVarRead::I16;
955+@@ -1869,6 +1899,10 @@ stg_makeStableNamezh ( P_ obj )
956+ BYTES_TO_WDS(SIZEOF_StgStableName));
957+ SET_HDR(sn_obj, stg_STABLE_NAME_info, CCCS);
958+ StgStableName_sn(sn_obj) = index;
959++ // This will make the StableName# object visible to other threads;
960++ // be sure that its completely visible to other cores.
961++ // See Note [Heap memory barriers] in SMP.h.
962++ prim_write_barrier;
963+ snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry) = sn_obj;
964+ } else {
965+ sn_obj = snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry);
966+@@ -1910,6 +1944,7 @@ stg_newBCOzh ( P_ instrs,
967+ ALLOC_PRIM (bytes);
968+
969+ bco = Hp - bytes + WDS(1);
970++ // No memory barrier necessary as this is a new allocation.
971+ SET_HDR(bco, stg_BCO_info, CCS_MAIN);
972+
973+ StgBCO_instrs(bco) = instrs;
974+@@ -1946,6 +1981,7 @@ stg_mkApUpd0zh ( P_ bco )
975+ CCCS_ALLOC(SIZEOF_StgAP);
976+
977+ ap = Hp - SIZEOF_StgAP + WDS(1);
978++ // No memory barrier necessary as this is a new allocation.
979+ SET_HDR(ap, stg_AP_info, CCS_MAIN);
980+
981+ StgAP_n_args(ap) = HALF_W_(0);
982+@@ -1958,6 +1994,7 @@ stg_unpackClosurezh ( P_ closure )
983+ {
984+ W_ info, ptrs, nptrs, p, ptrs_arr, dat_arr;
985+ info = %GET_STD_INFO(UNTAG(closure));
986++ prim_read_barrier;
987+
988+ ptrs = TO_W_(%INFO_PTRS(info));
989+ nptrs = TO_W_(%INFO_NPTRS(info));
990+@@ -2279,7 +2316,10 @@ stg_noDuplicatezh /* no arg list: explicit stack layout */
991+
992+ stg_getApStackValzh ( P_ ap_stack, W_ offset )
993+ {
994+- if (%INFO_PTR(UNTAG(ap_stack)) == stg_AP_STACK_info) {
995++ W_ ap_stackinfo;
996++ ap_stackinfo = %INFO_PTR(UNTAG(ap_stack));
997++ prim_read_barrier;
998++ if (ap_stackinfo == stg_AP_STACK_info) {
999+ return (1,StgAP_STACK_payload(ap_stack,offset));
1000+ } else {
1001+ return (0,ap_stack);
1002+diff --git a/rts/RaiseAsync.c b/rts/RaiseAsync.c
1003+index ddd6d39ffb..59de87916e 100644
1004+--- a/rts/RaiseAsync.c
1005++++ b/rts/RaiseAsync.c
1006+@@ -870,6 +870,7 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception,
1007+ ap->payload[i] = (StgClosure *)*sp++;
1008+ }
1009+
1010++ write_barrier(); // XXX: Necessary?
1011+ SET_HDR(ap,&stg_AP_STACK_info,
1012+ ((StgClosure *)frame)->header.prof.ccs /* ToDo */);
1013+ TICK_ALLOC_UP_THK(WDS(words+1),0);
1014+diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c
1015+index 87fa98dd4f..ccfed93714 100644
1016+--- a/rts/RtsSymbols.c
1017++++ b/rts/RtsSymbols.c
1018+@@ -53,7 +53,6 @@
1019+ SymI_HasProto(signal_handlers) \
1020+ SymI_HasProto(stg_sig_install) \
1021+ SymI_HasProto(rtsTimerSignal) \
1022+- SymI_HasProto(atexit) \
1023+ SymI_NeedsDataProto(nocldstop)
1024+ #endif
1025+
1026+@@ -932,26 +931,187 @@
1027+ RTS_USER_SIGNALS_SYMBOLS \
1028+ RTS_INTCHAR_SYMBOLS
1029+
1030+-
1031+ // 64-bit support functions in libgcc.a
1032++// See https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
1033+ #if defined(__GNUC__) && SIZEOF_VOID_P <= 4 && !defined(_ABIN32)
1034+ #define RTS_LIBGCC_SYMBOLS \
1035+- SymI_NeedsProto(__divdi3) \
1036+- SymI_NeedsProto(__udivdi3) \
1037+- SymI_NeedsProto(__moddi3) \
1038+- SymI_NeedsProto(__umoddi3) \
1039+- SymI_NeedsProto(__muldi3) \
1040+- SymI_NeedsProto(__ashldi3) \
1041+- SymI_NeedsProto(__ashrdi3) \
1042+- SymI_NeedsProto(__lshrdi3) \
1043+- SymI_NeedsProto(__fixunsdfdi)
1044++ SymI_NeedsProto(__fixunsdfdi) \
1045++ /* 4 The GCC low-level runtime library */\
1046++ /* 4.1.1 Arithmetic functions */\
1047++ /* SymI_NeedsProto(__ashlsi3) */\
1048++ SymI_NeedsProto(__ashldi3) \
1049++ /* SymI_NeedsProto(__ashlti3) */\
1050++ /* These functions return the result of shifting a left by b bits. */\
1051++ /* SymI_NeedsProto(__ashrsi3) */\
1052++ SymI_NeedsProto(__ashrdi3) \
1053++ /* SymI_NeedsProto(__ashrti3) */\
1054++ /* These functions return the result of arithmetically shifting a right by b bits. */\
1055++ /* SymI_NeedsProto(__divsi3) */\
1056++ SymI_NeedsProto(__divdi3) \
1057++ /* SymI_NeedsProto(__divti3) */\
1058++ /* These functions return the quotient of the signed division of a and b. */\
1059++ /* SymI_NeedsProto(__lshrsi3) */ \
1060++ SymI_NeedsProto(__lshrdi3) \
1061++ /* SymI_NeedsProto(__lshrti3) */ \
1062++ /* These functions return the result of logically shifting a right by b bits. */\
1063++ /* SymI_NeedsProto(__modsi3) */ \
1064++ SymI_NeedsProto(__moddi3) \
1065++ /* SymI_NeedsProto(__modti3) */ \
1066++ /* These functions return the remainder of the signed division of a and b. */\
1067++ /* SymI_NeedsProto(__mulsi3) */ \
1068++ SymI_NeedsProto(__muldi3) \
1069++ /* SymI_NeedsProto(__multi3) */ \
1070++ /* These functions return the product of a and b. */\
1071++ SymI_NeedsProto(__negdi2) \
1072++ /* SymI_NeedsProto(__negti2) */ \
1073++ /* These functions return the negation of a. */\
1074++ /* SymI_NeedsProto(__udivsi3) */ \
1075++ SymI_NeedsProto(__udivdi3) \
1076++ /* SymI_NeedsProto(__udivti3) */ \
1077++ /* These functions return the quotient of the unsigned division of a and b. */\
1078++ SymI_NeedsProto(__udivmoddi4) \
1079++ /* SymI_NeedsProto(__udivmodti4) */ \
1080++ /* These functions calculate both the quotient and remainder of the unsigned division of a and b. The return value is the quotient, and the remainder is placed in variable pointed to by c. */\
1081++ /* SymI_NeedsProto(__umodsi3) */ \
1082++ SymI_NeedsProto(__umoddi3) \
1083++ /* SymI_NeedsProto(__umodti3) */ \
1084++ /* These functions return the remainder of the unsigned division of a and b. */\
1085++ /* 4.1.2 Comparison functions */\
1086++ /* The following functions implement integral comparisons. These functions implement a low-level compare, upon which the higher level comparison operators (such as less than and greater than or equal to) can be constructed. The returned values lie in the range zero to two, to allow the high-level operators to be implemented by testing the returned result using either signed or unsigned comparison. */\
1087++ SymI_NeedsProto(__cmpdi2) \
1088++ /* SymI_NeedsProto(__cmpti2) */ \
1089++ /* These functions perform a signed comparison of a and b. If a is less than b, they return 0; if a is greater than b, they return 2; and if a and b are equal they return 1. */\
1090++ SymI_NeedsProto(__ucmpdi2) \
1091++ /* SymI_NeedsProto(__ucmpti2) */ \
1092++ /* These functions perform an unsigned comparison of a and b. If a is less than b, they return 0; if a is greater than b, they return 2; and if a and b are equal they return 1. */\
1093++ /* 4.1.3 Trapping arithmetic functions */\
1094++ /* The following functions implement trapping arithmetic. These functions call the libc function abort upon signed arithmetic overflow. */\
1095++ SymI_NeedsProto(__absvsi2) \
1096++ SymI_NeedsProto(__absvdi2) \
1097++ /* These functions return the absolute value of a. */\
1098++ /* SymI_NeedsProto(__addvsi3) */ \
1099++ SymI_NeedsProto(__addvdi3) \
1100++ /* These functions return the sum of a and b; that is a + b. */\
1101++ /* SymI_NeedsProto(__mulvsi3) */ \
1102++ SymI_NeedsProto(__mulvdi3) \
1103++ /* The functions return the product of a and b; that is a * b. */\
1104++ SymI_NeedsProto(__negvsi2) \
1105++ SymI_NeedsProto(__negvdi2) \
1106++ /* These functions return the negation of a; that is -a. */\
1107++ /* SymI_NeedsProto(__subvsi3) */ \
1108++ SymI_NeedsProto(__subvdi3) \
1109++ /* These functions return the difference between b and a; that is a - b. */\
1110++ /* 4.1.4 Bit operations */\
1111++ SymI_NeedsProto(__clzsi2) \
1112++ SymI_NeedsProto(__clzdi2) \
1113++ /* SymI_NeedsProto(__clzti2) */ \
1114++ /* These functions return the number of leading 0-bits in a, starting at the most significant bit position. If a is zero, the result is undefined. */\
1115++ SymI_NeedsProto(__ctzsi2) \
1116++ SymI_NeedsProto(__ctzdi2) \
1117++ /* SymI_NeedsProto(__ctzti2) */ \
1118++ /* These functions return the number of trailing 0-bits in a, starting at the least significant bit position. If a is zero, the result is undefined. */\
1119++ SymI_NeedsProto(__ffsdi2) \
1120++ /* SymI_NeedsProto(__ffsti2) */ \
1121++ /* These functions return the index of the least significant 1-bit in a, or the value zero if a is zero. The least significant bit is index one. */\
1122++ SymI_NeedsProto(__paritysi2) \
1123++ SymI_NeedsProto(__paritydi2) \
1124++ /* SymI_NeedsProto(__parityti2) */\
1125++ /* These functions return the value zero if the number of bits set in a is even, and the value one otherwise. */\
1126++ SymI_NeedsProto(__popcountsi2) \
1127++ SymI_NeedsProto(__popcountdi2) \
1128++ /* SymI_NeedsProto(__popcountti2) */ \
1129++ /* These functions return the number of bits set in a. */\
1130++ SymI_NeedsProto(__bswapsi2) \
1131++ SymI_NeedsProto(__bswapdi2) \
1132++ /* armv6l */\
1133++ /* TODO: should check for __ARM_EABI__ */\
1134++ SymI_NeedsProto(__aeabi_d2f) \
1135++ SymI_NeedsProto(__aeabi_d2iz) \
1136++ SymI_NeedsProto(__aeabi_d2lz) \
1137++ SymI_NeedsProto(__aeabi_d2uiz) \
1138++ SymI_NeedsProto(__aeabi_d2ulz) \
1139++ SymI_NeedsProto(__aeabi_dadd) \
1140++ SymI_NeedsProto(__aeabi_dcmpeq) \
1141++ SymI_NeedsProto(__aeabi_dcmpge) \
1142++ SymI_NeedsProto(__aeabi_dcmpgt) \
1143++ SymI_NeedsProto(__aeabi_dcmple) \
1144++ SymI_NeedsProto(__aeabi_dcmplt) \
1145++ SymI_NeedsProto(__aeabi_dcmpun) \
1146++ SymI_NeedsProto(__aeabi_ddiv) \
1147++ SymI_NeedsProto(__aeabi_dmul) \
1148++ SymI_NeedsProto(__aeabi_dneg) \
1149++ SymI_NeedsProto(__aeabi_dsub) \
1150++ SymI_NeedsProto(__aeabi_f2d) \
1151++ SymI_NeedsProto(__aeabi_f2iz) \
1152++ SymI_NeedsProto(__aeabi_f2lz) \
1153++ SymI_NeedsProto(__aeabi_f2uiz) \
1154++ SymI_NeedsProto(__aeabi_f2ulz) \
1155++ SymI_NeedsProto(__aeabi_fadd) \
1156++ SymI_NeedsProto(__aeabi_fcmpeq) \
1157++ SymI_NeedsProto(__aeabi_fcmpge) \
1158++ SymI_NeedsProto(__aeabi_fcmpgt) \
1159++ SymI_NeedsProto(__aeabi_fcmple) \
1160++ SymI_NeedsProto(__aeabi_fcmplt) \
1161++ SymI_NeedsProto(__aeabi_fcmpun) \
1162++ SymI_NeedsProto(__aeabi_fdiv) \
1163++ SymI_NeedsProto(__aeabi_fmul) \
1164++ SymI_NeedsProto(__aeabi_fneg) \
1165++ SymI_NeedsProto(__aeabi_fsub) \
1166++ SymI_NeedsProto(__aeabi_i2d) \
1167++ SymI_NeedsProto(__aeabi_i2f) \
1168++ SymI_NeedsProto(__aeabi_idiv) \
1169++ SymI_NeedsProto(__aeabi_idivmod) \
1170++ SymI_NeedsProto(__aeabi_l2d) \
1171++ SymI_NeedsProto(__aeabi_l2f) \
1172++ SymI_NeedsProto(__aeabi_lasr) \
1173++ SymI_NeedsProto(__aeabi_lcmp) \
1174++ SymI_NeedsProto(__aeabi_ldivmod) \
1175++ SymI_NeedsProto(__aeabi_llsl) \
1176++ SymI_NeedsProto(__aeabi_llsr) \
1177++ SymI_NeedsProto(__aeabi_lmul) \
1178++ SymI_NeedsProto(__aeabi_ui2d) \
1179++ SymI_NeedsProto(__aeabi_ui2f) \
1180++ SymI_NeedsProto(__aeabi_uidiv) \
1181++ SymI_NeedsProto(__aeabi_uidivmod) \
1182++ SymI_NeedsProto(__aeabi_ul2d) \
1183++ SymI_NeedsProto(__aeabi_ul2f) \
1184++ SymI_NeedsProto(__aeabi_ulcmp) \
1185++ SymI_NeedsProto(__aeabi_uldivmod)
1186++
1187+ #elif defined(__GNUC__) && SIZEOF_VOID_P == 8
1188+ #define RTS_LIBGCC_SYMBOLS \
1189+ SymI_NeedsProto(__udivti3) \
1190+- SymI_NeedsProto(__umodti3)
1191++ SymI_NeedsProto(__umodti3) \
1192++ /* for aarch64 */\
1193++ SymI_NeedsProto(__netf2) \
1194++ SymI_NeedsProto(__addtf3) \
1195++ SymI_NeedsProto(__subtf3) \
1196++ SymI_NeedsProto(__multf3) \
1197++ SymI_NeedsProto(__extenddftf2) \
1198++ SymI_NeedsProto(__fixtfsi) \
1199++ SymI_NeedsProto(__fixunstfsi) \
1200++ SymI_NeedsProto(__floatsitf) \
1201++ SymI_NeedsProto(__floatunsitf)
1202+ #else
1203+ #define RTS_LIBGCC_SYMBOLS
1204+ #endif
1205++#if !defined(mingw32_HOST_OS)
1206++#define RTS_SSP_SYMBOLS \
1207++ SymI_NeedsProto(__stack_chk_guard) \
1208++ SymI_NeedsProto(__stack_chk_fail)
1209++#else
1210++#define RTS_SSP_SYMBOLS
1211++#endif
1212++#if !defined(DYNAMIC) && !defined(mingw32_HOST_OS)
1213++// we need these for static musl builds. However when
1214++// linking shared objects (DLLs) this will fail, hence
1215++// we do not include them when building with -DDYNAMIC
1216++#define RTS_LINKER_SYMBOLS \
1217++ SymI_NeedsProto(__fini_array_start) \
1218++ SymI_NeedsProto(__fini_array_end)
1219++#else
1220++#define RTS_LINKER_SYMBOLS
1221++#endif
1222+
1223+ #if defined(darwin_HOST_OS) && defined(powerpc_HOST_ARCH)
1224+ // Symbols that don't have a leading underscore
1225+@@ -963,7 +1123,11 @@
1226+ #endif
1227+
1228+ /* entirely bogus claims about types of these symbols */
1229+-#define SymI_NeedsProto(vvv) extern void vvv(void);
1230++/* to prevent a bit of define expansion, SymI_NeedsProto is a variadic
1231++ * macro. And we'll concat vvv with the __VA_ARGS__. This prevents
1232++ * vvv from getting macro expanded.
1233++ */
1234++#define SymI_NeedsProto(vvv,...) extern void vvv ## __VA_ARGS__ (void);
1235+ #define SymI_NeedsDataProto(vvv) extern StgWord vvv[];
1236+ #if defined(COMPILING_WINDOWS_DLL)
1237+ #define SymE_HasProto(vvv) SymE_HasProto(vvv);
1238+@@ -990,6 +1154,8 @@ RTS_DARWIN_ONLY_SYMBOLS
1239+ RTS_OPENBSD_ONLY_SYMBOLS
1240+ RTS_LIBGCC_SYMBOLS
1241+ RTS_LIBFFI_SYMBOLS
1242++RTS_SSP_SYMBOLS
1243++RTS_LINKER_SYMBOLS
1244+ #undef SymI_NeedsProto
1245+ #undef SymI_NeedsDataProto
1246+ #undef SymI_HasProto
1247+@@ -1009,7 +1175,7 @@ RTS_LIBFFI_SYMBOLS
1248+ #define SymE_HasDataProto(vvv) \
1249+ SymE_HasProto(vvv)
1250+
1251+-#define SymI_NeedsProto(vvv) SymI_HasProto(vvv)
1252++#define SymI_NeedsProto(vvv,...) SymI_HasProto(vvv ## __VA_ARGS__)
1253+ #define SymI_NeedsDataProto(vvv) SymI_HasDataProto(vvv)
1254+ #define SymE_NeedsProto(vvv) SymE_HasProto(vvv)
1255+ #define SymE_NeedsDataProto(vvv) SymE_HasDataProto(vvv)
1256+@@ -1030,6 +1196,8 @@ RTS_LIBFFI_SYMBOLS
1257+ #define SymI_HasProto_deprecated(vvv) \
1258+ { #vvv, (void*)0xBAADF00D, true },
1259+
1260++void *RTS_DYNAMIC = NULL;
1261++
1262+ RtsSymbolVal rtsSyms[] = {
1263+ RTS_SYMBOLS
1264+ RTS_RET_SYMBOLS
1265+@@ -1040,11 +1208,14 @@ RtsSymbolVal rtsSyms[] = {
1266+ RTS_OPENBSD_ONLY_SYMBOLS
1267+ RTS_LIBGCC_SYMBOLS
1268+ RTS_LIBFFI_SYMBOLS
1269++ RTS_SSP_SYMBOLS
1270++ RTS_LINKER_SYMBOLS
1271+ #if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
1272+ // dyld stub code contains references to this,
1273+ // but it should never be called because we treat
1274+ // lazy pointers as nonlazy.
1275+ { "dyld_stub_binding_helper", (void*)0xDEADBEEF, false },
1276+ #endif
1277++ { "_DYNAMIC", (void*)(&RTS_DYNAMIC), false },
1278+ { 0, 0, false } /* sentinel */
1279+ };
1280+diff --git a/rts/Sparks.c b/rts/Sparks.c
1281+index bd5e120863..4022691da2 100644
1282+--- a/rts/Sparks.c
1283++++ b/rts/Sparks.c
1284+@@ -182,6 +182,7 @@ pruneSparkQueue (Capability *cap)
1285+ traceEventSparkFizzle(cap);
1286+ } else {
1287+ info = spark->header.info;
1288++ load_load_barrier();
1289+ if (IS_FORWARDING_PTR(info)) {
1290+ tmp = (StgClosure*)UN_FORWARDING_PTR(info);
1291+ /* if valuable work: shift inside the pool */
1292+diff --git a/rts/StgMiscClosures.cmm b/rts/StgMiscClosures.cmm
1293+index e645442033..b368bdad2e 100644
1294+--- a/rts/StgMiscClosures.cmm
1295++++ b/rts/StgMiscClosures.cmm
1296+@@ -292,12 +292,14 @@ INFO_TABLE(stg_BLACKHOLE,1,0,BLACKHOLE,"BLACKHOLE","BLACKHOLE")
1297+ TICK_ENT_DYN_IND(); /* tick */
1298+
1299+ retry:
1300++ prim_read_barrier;
1301+ p = StgInd_indirectee(node);
1302+ if (GETTAG(p) != 0) {
1303+ return (p);
1304+ }
1305+
1306+ info = StgHeader_info(p);
1307++ prim_read_barrier;
1308+ if (info == stg_IND_info) {
1309+ // This could happen, if e.g. we got a BLOCKING_QUEUE that has
1310+ // just been replaced with an IND by another thread in
1311+@@ -313,9 +315,11 @@ retry:
1312+ ("ptr" msg) = ccall allocate(MyCapability() "ptr",
1313+ BYTES_TO_WDS(SIZEOF_MessageBlackHole));
1314+
1315+- SET_HDR(msg, stg_MSG_BLACKHOLE_info, CCS_SYSTEM);
1316+ MessageBlackHole_tso(msg) = CurrentTSO;
1317+ MessageBlackHole_bh(msg) = node;
1318++ SET_HDR(msg, stg_MSG_BLACKHOLE_info, CCS_SYSTEM);
1319++ // messageBlackHole has appropriate memory barriers when this object is exposed.
1320++ // See Note [Heap memory barriers].
1321+
1322+ (r) = ccall messageBlackHole(MyCapability() "ptr", msg "ptr");
1323+
1324+diff --git a/rts/ThreadPaused.c b/rts/ThreadPaused.c
1325+index 3f7bddeb79..eca2bb7c72 100644
1326+--- a/rts/ThreadPaused.c
1327++++ b/rts/ThreadPaused.c
1328+@@ -195,6 +195,7 @@ threadPaused(Capability *cap, StgTSO *tso)
1329+ const StgRetInfoTable *info;
1330+ const StgInfoTable *bh_info;
1331+ const StgInfoTable *cur_bh_info USED_IF_THREADS;
1332++ const StgInfoTable *frame_info;
1333+ StgClosure *bh;
1334+ StgPtr stack_end;
1335+ uint32_t words_to_squeeze = 0;
1336+@@ -218,6 +219,8 @@ threadPaused(Capability *cap, StgTSO *tso)
1337+
1338+ frame = (StgClosure *)tso->stackobj->sp;
1339+
1340++ // N.B. We know that the TSO is owned by the current capability so no
1341++ // memory barriers are needed here.
1342+ while ((P_)frame < stack_end) {
1343+ info = get_ret_itbl(frame);
1344+
1345+@@ -226,7 +229,8 @@ threadPaused(Capability *cap, StgTSO *tso)
1346+ case UPDATE_FRAME:
1347+
1348+ // If we've already marked this frame, then stop here.
1349+- if (frame->header.info == (StgInfoTable *)&stg_marked_upd_frame_info) {
1350++ frame_info = frame->header.info;
1351++ if (frame_info == (StgInfoTable *)&stg_marked_upd_frame_info) {
1352+ if (prev_was_update_frame) {
1353+ words_to_squeeze += sizeofW(StgUpdateFrame);
1354+ weight += weight_pending;
1355+diff --git a/rts/Threads.c b/rts/Threads.c
1356+index 78c5b6cc84..dc733d3dba 100644
1357+--- a/rts/Threads.c
1358++++ b/rts/Threads.c
1359+@@ -126,6 +126,8 @@ createThread(Capability *cap, W_ size)
1360+ ACQUIRE_LOCK(&sched_mutex);
1361+ tso->id = next_thread_id++; // while we have the mutex
1362+ tso->global_link = g0->threads;
1363++ /* Mutations above need no memory barrier since this lock will provide
1364++ * a release barrier */
1365+ g0->threads = tso;
1366+ RELEASE_LOCK(&sched_mutex);
1367+
1368+@@ -257,8 +259,10 @@ tryWakeupThread (Capability *cap, StgTSO *tso)
1369+ {
1370+ MessageWakeup *msg;
1371+ msg = (MessageWakeup *)allocate(cap,sizeofW(MessageWakeup));
1372+- SET_HDR(msg, &stg_MSG_TRY_WAKEUP_info, CCS_SYSTEM);
1373+ msg->tso = tso;
1374++ SET_HDR(msg, &stg_MSG_TRY_WAKEUP_info, CCS_SYSTEM);
1375++ // Ensure that writes constructing Message are committed before sending.
1376++ write_barrier();
1377+ sendMessage(cap, tso->cap, (Message*)msg);
1378+ debugTraceCap(DEBUG_sched, cap, "message: try wakeup thread %ld on cap %d",
1379+ (W_)tso->id, tso->cap->no);
1380+@@ -363,6 +367,7 @@ wakeBlockingQueue(Capability *cap, StgBlockingQueue *bq)
1381+ for (msg = bq->queue; msg != (MessageBlackHole*)END_TSO_QUEUE;
1382+ msg = msg->link) {
1383+ i = msg->header.info;
1384++ load_load_barrier();
1385+ if (i != &stg_IND_info) {
1386+ ASSERT(i == &stg_MSG_BLACKHOLE_info);
1387+ tryWakeupThread(cap,msg->tso);
1388+@@ -398,15 +403,18 @@ checkBlockingQueues (Capability *cap, StgTSO *tso)
1389+ for (bq = tso->bq; bq != (StgBlockingQueue*)END_TSO_QUEUE; bq = next) {
1390+ next = bq->link;
1391+
1392+- if (bq->header.info == &stg_IND_info) {
1393++ const StgInfoTable *bqinfo = bq->header.info;
1394++ load_load_barrier(); // XXX: Is this needed?
1395++ if (bqinfo == &stg_IND_info) {
1396+ // ToDo: could short it out right here, to avoid
1397+ // traversing this IND multiple times.
1398+ continue;
1399+ }
1400+
1401+ p = bq->bh;
1402+-
1403+- if (p->header.info != &stg_BLACKHOLE_info ||
1404++ const StgInfoTable *pinfo = p->header.info;
1405++ load_load_barrier();
1406++ if (pinfo != &stg_BLACKHOLE_info ||
1407+ ((StgInd *)p)->indirectee != (StgClosure*)bq)
1408+ {
1409+ wakeBlockingQueue(cap,bq);
1410+@@ -430,6 +438,7 @@ updateThunk (Capability *cap, StgTSO *tso, StgClosure *thunk, StgClosure *val)
1411+ const StgInfoTable *i;
1412+
1413+ i = thunk->header.info;
1414++ load_load_barrier();
1415+ if (i != &stg_BLACKHOLE_info &&
1416+ i != &stg_CAF_BLACKHOLE_info &&
1417+ i != &__stg_EAGER_BLACKHOLE_info &&
1418+@@ -450,6 +459,7 @@ updateThunk (Capability *cap, StgTSO *tso, StgClosure *thunk, StgClosure *val)
1419+ }
1420+
1421+ i = v->header.info;
1422++ load_load_barrier();
1423+ if (i == &stg_TSO_info) {
1424+ checkBlockingQueues(cap, tso);
1425+ return;
1426+@@ -673,6 +683,8 @@ threadStackOverflow (Capability *cap, StgTSO *tso)
1427+ new_stack->sp -= chunk_words;
1428+ }
1429+
1430++ // No write barriers needed; all of the writes above are to structured
1431++ // owned by our capability.
1432+ tso->stackobj = new_stack;
1433+
1434+ // we're about to run it, better mark it dirty
1435+@@ -744,6 +756,7 @@ threadStackUnderflow (Capability *cap, StgTSO *tso)
1436+ bool performTryPutMVar(Capability *cap, StgMVar *mvar, StgClosure *value)
1437+ {
1438+ const StgInfoTable *info;
1439++ const StgInfoTable *qinfo;
1440+ StgMVarTSOQueue *q;
1441+ StgTSO *tso;
1442+
1443+@@ -768,8 +781,11 @@ loop:
1444+ unlockClosure((StgClosure*)mvar, &stg_MVAR_DIRTY_info);
1445+ return true;
1446+ }
1447+- if (q->header.info == &stg_IND_info ||
1448+- q->header.info == &stg_MSG_NULL_info) {
1449++
1450++ qinfo = q->header.info;
1451++ load_load_barrier();
1452++ if (qinfo == &stg_IND_info ||
1453++ qinfo == &stg_MSG_NULL_info) {
1454+ q = (StgMVarTSOQueue*)((StgInd*)q)->indirectee;
1455+ goto loop;
1456+ }
1457+diff --git a/rts/TopHandler.c b/rts/TopHandler.c
1458+index 8e868e6e92..dd8d6a7ab7 100644
1459+--- a/rts/TopHandler.c
1460++++ b/rts/TopHandler.c
1461+@@ -29,6 +29,7 @@ StgTSO *getTopHandlerThread(void) {
1462+ StgWeak *weak = (StgWeak*)deRefStablePtr(topHandlerPtr);
1463+ RELEASE_LOCK(&m);
1464+ const StgInfoTable *info = weak->header.info;
1465++ load_load_barrier();
1466+ if (info == &stg_WEAK_info) {
1467+ StgClosure *key = ((StgWeak*)weak)->key;
1468+
1469+diff --git a/rts/Updates.h b/rts/Updates.h
1470+index 1ba398bd35..1bd3e065af 100644
1471+--- a/rts/Updates.h
1472++++ b/rts/Updates.h
1473+@@ -39,10 +39,16 @@
1474+ PROF_HDR_FIELDS(w_,ccs,p2) \
1475+ p_ updatee
1476+
1477+-
1478++/*
1479++ * Getting the memory barriers correct here is quite tricky. Essentially
1480++ * the write barrier ensures that any writes to the new indirectee are visible
1481++ * before we introduce the indirection.
1482++ * See Note [Heap memory barriers] in SMP.h.
1483++ */
1484+ #define updateWithIndirection(p1, p2, and_then) \
1485+ W_ bd; \
1486+ \
1487++ prim_write_barrier; \
1488+ OVERWRITING_CLOSURE(p1); \
1489+ StgInd_indirectee(p1) = p2; \
1490+ prim_write_barrier; \
1491+@@ -69,6 +75,8 @@ INLINE_HEADER void updateWithIndirection (Capability *cap,
1492+ ASSERT( (P_)p1 != (P_)p2 );
1493+ /* not necessarily true: ASSERT( !closure_IND(p1) ); */
1494+ /* occurs in RaiseAsync.c:raiseAsync() */
1495++ /* See Note [Heap memory barriers] in SMP.h */
1496++ write_barrier();
1497+ OVERWRITING_CLOSURE(p1);
1498+ ((StgInd *)p1)->indirectee = p2;
1499+ write_barrier();
1500+diff --git a/rts/Weak.c b/rts/Weak.c
1501+index a322d822af..ec998c214f 100644
1502+--- a/rts/Weak.c
1503++++ b/rts/Weak.c
1504+@@ -57,7 +57,9 @@ runAllCFinalizers(StgWeak *list)
1505+ // If there's no major GC between the time that the finalizer for the
1506+ // object from the oldest generation is manually called and shutdown
1507+ // we end up running the same finalizer twice. See #7170.
1508+- if (w->header.info != &stg_DEAD_WEAK_info) {
1509++ const StgInfoTable *winfo = w->header.info;
1510++ load_load_barrier();
1511++ if (winfo != &stg_DEAD_WEAK_info) {
1512+ runCFinalizers((StgCFinalizerList *)w->cfinalizers);
1513+ }
1514+ }
1515+@@ -138,6 +140,7 @@ scheduleFinalizers(Capability *cap, StgWeak *list)
1516+ size = n + mutArrPtrsCardTableSize(n);
1517+ arr = (StgMutArrPtrs *)allocate(cap, sizeofW(StgMutArrPtrs) + size);
1518+ TICK_ALLOC_PRIM(sizeofW(StgMutArrPtrs), n, 0);
1519++ // No write barrier needed here; this array is only going to referred to by this core.
1520+ SET_HDR(arr, &stg_MUT_ARR_PTRS_FROZEN_CLEAN_info, CCS_SYSTEM);
1521+ arr->ptrs = n;
1522+ arr->size = size;
1523+diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
1524+index ede0482c6b..8e477c0425 100644
1525+--- a/rts/linker/Elf.c
1526++++ b/rts/linker/Elf.c
1527+@@ -626,7 +626,7 @@ mapObjectFileSection (int fd, Elf_Word offset, Elf_Word size,
1528+
1529+ pageOffset = roundDownToPage(offset);
1530+ pageSize = roundUpToPage(offset-pageOffset+size);
1531+- p = mmapForLinker(pageSize, 0, fd, pageOffset);
1532++ p = mmapForLinker(pageSize, PROT_READ | PROT_WRITE | PROT_EXEC, 0, fd, pageOffset);
1533+ if (p == NULL) return NULL;
1534+ *mapped_size = pageSize;
1535+ *mapped_offset = pageOffset;
1536+@@ -688,7 +688,7 @@ ocGetNames_ELF ( ObjectCode* oc )
1537+ * address might be out of range for sections that are mmaped.
1538+ */
1539+ alloc = SECTION_MMAP;
1540+- start = mmap(NULL, size,
1541++ start = mmapForLinker(size,
1542+ PROT_READ | PROT_WRITE | PROT_EXEC,
1543+ MAP_ANON | MAP_PRIVATE,
1544+ -1, 0);
1545+@@ -732,7 +732,7 @@ ocGetNames_ELF ( ObjectCode* oc )
1546+ unsigned nstubs = numberOfStubsForSection(oc, i);
1547+ unsigned stub_space = STUB_SIZE * nstubs;
1548+
1549+- void * mem = mmap(NULL, size+stub_space,
1550++ void * mem = mmapForLinker(size+stub_space,
1551+ PROT_READ | PROT_WRITE | PROT_EXEC,
1552+ MAP_ANON | MAP_PRIVATE,
1553+ -1, 0);
1554+diff --git a/rts/linker/LoadArchive.c b/rts/linker/LoadArchive.c
1555+index 85eedb930d..bcc042f468 100644
1556+--- a/rts/linker/LoadArchive.c
1557++++ b/rts/linker/LoadArchive.c
1558+@@ -465,6 +465,7 @@ static HsInt loadArchive_ (pathchar *path)
1559+ /* TODO: Stop relying on file extensions to determine input formats.
1560+ Instead try to match file headers. See Trac #13103. */
1561+ isObject = (thisFileNameSize >= 2 && strncmp(fileName + thisFileNameSize - 2, ".o" , 2) == 0)
1562++ || (thisFileNameSize >= 3 && strncmp(fileName + thisFileNameSize - 3, ".lo" , 3) == 0)
1563+ || (thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".p_o", 4) == 0)
1564+ || (thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".obj", 4) == 0);
1565+
1566+@@ -497,7 +498,7 @@ static HsInt loadArchive_ (pathchar *path)
1567+ isThin);
1568+ #elif defined(darwin_HOST_OS) || defined(ios_HOST_OS)
1569+ if (RTS_LINKER_USE_MMAP)
1570+- image = mmapForLinker(memberSize, MAP_ANONYMOUS, -1, 0);
1571++ image = mmapForLinker(memberSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS, -1, 0);
1572+ else {
1573+ /* See loadObj() */
1574+ misalignment = machoGetMisalignment(f);
1575+@@ -555,7 +556,7 @@ while reading filename from `%" PATH_FMT "'", path);
1576+ }
1577+ DEBUG_LOG("Found GNU-variant file index\n");
1578+ #if RTS_LINKER_USE_MMAP
1579+- gnuFileIndex = mmapForLinker(memberSize + 1, MAP_ANONYMOUS, -1, 0);
1580++ gnuFileIndex = mmapForLinker(memberSize + 1, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS, -1, 0);
1581+ #else
1582+ gnuFileIndex = stgMallocBytes(memberSize + 1, "loadArchive(image)");
1583+ #endif
1584+diff --git a/rts/linker/M32Alloc.c b/rts/linker/M32Alloc.c
1585+index 52b182e54d..3016704bd2 100644
1586+--- a/rts/linker/M32Alloc.c
1587++++ b/rts/linker/M32Alloc.c
1588+@@ -157,7 +157,7 @@ m32_allocator_init(void)
1589+ // Preallocate the initial M32_MAX_PAGES to ensure that they don't
1590+ // fragment the memory.
1591+ size_t pgsz = getPageSize();
1592+- char* bigchunk = mmapForLinker(pgsz * M32_MAX_PAGES,MAP_ANONYMOUS,-1,0);
1593++ char* bigchunk = mmapForLinker(pgsz * M32_MAX_PAGES, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS,-1,0);
1594+ if (bigchunk == NULL)
1595+ barf("m32_allocator_init: Failed to map");
1596+
1597+@@ -249,7 +249,7 @@ m32_alloc(size_t size, size_t alignment)
1598+
1599+ if (m32_is_large_object(size,alignment)) {
1600+ // large object
1601+- return mmapForLinker(size,MAP_ANONYMOUS,-1,0);
1602++ return mmapForLinker(size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS,-1,0);
1603+ }
1604+
1605+ // small object
1606+@@ -297,7 +297,7 @@ m32_alloc(size_t size, size_t alignment)
1607+ }
1608+
1609+ // Allocate a new page
1610+- void * addr = mmapForLinker(pgsz,MAP_ANONYMOUS,-1,0);
1611++ void * addr = mmapForLinker(pgsz, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS,-1,0);
1612+ if (addr == NULL) {
1613+ return NULL;
1614+ }
1615+diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c
1616+index b6a14d142c..8a48425637 100644
1617+--- a/rts/linker/MachO.c
1618++++ b/rts/linker/MachO.c
1619+@@ -588,7 +588,7 @@ makeGot(ObjectCode * oc) {
1620+
1621+ if(got_slots > 0) {
1622+ oc->info->got_size = got_slots * sizeof(void*);
1623+- oc->info->got_start = mmap(NULL, oc->info->got_size,
1624++ oc->info->got_start = mmapForLinker(oc->info->got_size,
1625+ PROT_READ | PROT_WRITE,
1626+ MAP_ANON | MAP_PRIVATE,
1627+ -1, 0);
1628+@@ -1419,7 +1419,7 @@ ocGetNames_MachO(ObjectCode* oc)
1629+ case S_ZEROFILL:
1630+ case S_GB_ZEROFILL: {
1631+ // See Note [mmap r+w+x]
1632+- void * mem = mmap(NULL, section->size,
1633++ void * mem = mmapForLinker(section->size,
1634+ PROT_READ | PROT_WRITE,
1635+ MAP_ANON | MAP_PRIVATE,
1636+ -1, 0);
1637+@@ -1472,7 +1472,7 @@ ocGetNames_MachO(ObjectCode* oc)
1638+ * instructions (ldr, br) for each relocation.
1639+ */ 16 * n_ext_sec_sym;
1640+ // See Note [mmap r+w+x]
1641+- void * mem = mmap(NULL, section->size+stub_space,
1642++ void * mem = mmapForLinker(section->size+stub_space,
1643+ PROT_READ | PROT_WRITE,
1644+ MAP_ANON | MAP_PRIVATE,
1645+ -1, 0);
1646+@@ -1502,7 +1502,7 @@ ocGetNames_MachO(ObjectCode* oc)
1647+ case S_GB_ZEROFILL: {
1648+ char * zeroFillArea;
1649+ if (RTS_LINKER_USE_MMAP) {
1650+- zeroFillArea = mmapForLinker(section->size, MAP_ANONYMOUS,
1651++ zeroFillArea = mmapForLinker(section->size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS,
1652+ -1, 0);
1653+ if (zeroFillArea == NULL) return 0;
1654+ memset(zeroFillArea, 0, section->size);
1655+diff --git a/rts/linker/SymbolExtras.c b/rts/linker/SymbolExtras.c
1656+index 486fa4a572..f4485bba31 100644
1657+--- a/rts/linker/SymbolExtras.c
1658++++ b/rts/linker/SymbolExtras.c
1659+@@ -52,6 +52,7 @@ int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
1660+
1661+ /* Keep image and symbol_extras contiguous */
1662+ void *new = mmapForLinker(n + (sizeof(SymbolExtra) * count),
1663++ PROT_READ | PROT_WRITE | PROT_EXEC,
1664+ MAP_ANONYMOUS, -1, 0);
1665+ if (new) {
1666+ memcpy(new, oc->image, oc->fileSize);
1667+diff --git a/rts/linker/elf_got.c b/rts/linker/elf_got.c
1668+index 0395d169df..5846a94c31 100644
1669+--- a/rts/linker/elf_got.c
1670++++ b/rts/linker/elf_got.c
1671+@@ -44,7 +44,7 @@ makeGot(ObjectCode * oc) {
1672+ }
1673+ if(got_slots > 0) {
1674+ oc->info->got_size = got_slots * sizeof(void *);
1675+- void * mem = mmap(NULL, oc->info->got_size,
1676++ void * mem = mmapForLinker(oc->info->got_size,
1677+ PROT_READ | PROT_WRITE,
1678+ MAP_ANON | MAP_PRIVATE,
1679+ -1, 0);
1680+diff --git a/rts/linker/elf_reloc_aarch64.c b/rts/linker/elf_reloc_aarch64.c
1681+index c50ef04080..a826c58170 100644
1682+--- a/rts/linker/elf_reloc_aarch64.c
1683++++ b/rts/linker/elf_reloc_aarch64.c
1684+@@ -1,5 +1,6 @@
1685+ #include <stdlib.h>
1686+ #include <assert.h>
1687++#include <inttypes.h>
1688+ #include "elf_compat.h"
1689+ #include "elf_reloc_aarch64.h"
1690+ #include "util.h"
1691+@@ -60,6 +61,9 @@ encodeAddendAarch64(Section * section, Elf_Rel * rel, int64_t addend) {
1692+ /* instructions are 32bit! */
1693+ addr_t P = (addr_t)((uint8_t*)section->start + rel->r_offset);
1694+ int exp_shift = -1;
1695++
1696++ bool ret = EXIT_SUCCESS;
1697++
1698+ switch(ELF64_R_TYPE(rel->r_info)) {
1699+ /* static misc relocations */
1700+ /* static data relocations */
1701+@@ -90,12 +94,21 @@ encodeAddendAarch64(Section * section, Elf_Rel * rel, int64_t addend) {
1702+ // ... hi ] [ Rd ]
1703+ //
1704+ // imm64 = SignExtend(hi:lo:0x000,64)
1705+- assert(isInt64(32, addend));
1706+- assert((addend & 0xfff) == 0); /* page relative */
1707+-
1708+- *(inst_t *)P = (*(inst_t *)P & 0x9f00001f)
1709+- | (inst_t) (((uint64_t) addend << 17) & 0x60000000)
1710+- | (inst_t) (((uint64_t) addend >> 9) & 0x00ffffe0);
1711++ // Range is 21 bits + the 12 page relative bits
1712++ // known to be 0. -2^32 <= X < 2^32
1713++ if(!isInt64(21+12, addend)) {
1714++ IF_DEBUG(linker, debugBelch(
1715++ "R_AARCH64_ADR_PREL_PG_HI21 addend out of range: 0x%" PRIx64 "\n",
1716++ addend));
1717++ ret = EXIT_FAILURE;
1718++ } else {
1719++ assert(isInt64(21+12, addend));
1720++ assert((addend & 0xfff) == 0); /* page relative */
1721++
1722++ *(inst_t *)P = (*(inst_t *)P & 0x9f00001f)
1723++ | (inst_t) (((uint64_t) addend << 17) & 0x60000000)
1724++ | (inst_t) (((uint64_t) addend >> 9) & 0x00ffffe0);
1725++ }
1726+ break;
1727+ }
1728+ /* - control flow relocations */
1729+@@ -103,13 +116,13 @@ encodeAddendAarch64(Section * section, Elf_Rel * rel, int64_t addend) {
1730+ case COMPAT_R_AARCH64_CALL26: { /* relocate bl ... */
1731+ assert(isInt64(26+2, addend)); /* X in range */
1732+ *(inst_t *)P = (*(inst_t *)P & 0xfc000000) /* keep upper 6 (32-6)
1733+- * bits */
1734++ * bits */
1735+ | ((uint32_t)(addend >> 2) & 0x03ffffff);
1736+ break;
1737+ }
1738+ case COMPAT_R_AARCH64_ADR_GOT_PAGE: {
1739+-
1740+- assert(isInt64(32, addend)); /* X in range */
1741++ /* range is -2^32 <= X < 2^32 */
1742++ assert(isInt64(21+12, addend)); /* X in range */
1743+ assert((addend & 0xfff) == 0); /* page relative */
1744+
1745+ *(inst_t *)P = (*(inst_t *)P & 0x9f00001f)
1746+@@ -159,7 +172,7 @@ encodeAddendAarch64(Section * section, Elf_Rel * rel, int64_t addend) {
1747+ default:
1748+ abort();
1749+ }
1750+- return EXIT_SUCCESS;
1751++ return ret;
1752+ }
1753+
1754+
1755+@@ -293,7 +306,19 @@ relocateObjectCodeAarch64(ObjectCode * oc) {
1756+ int64_t addend = decodeAddendAarch64(targetSection, rel);
1757+
1758+ addend = computeAddend(targetSection, rel, symbol, addend);
1759+- encodeAddendAarch64(targetSection, rel, addend);
1760++ IF_DEBUG(linker, debugBelch("REL: relocating symbol: %s (%s)\n",
1761++ symbol->name,
1762++ OC_INFORMATIVE_FILENAME(oc)));
1763++ if(encodeAddendAarch64(targetSection, rel, addend)) {
1764++ sysErrorBelch("Failed to relocate symbol: %s (%s) "
1765++ "at %p in %p with addend 0x%" PRIx64 "\n",
1766++ symbol->name,
1767++ OC_INFORMATIVE_FILENAME(oc),
1768++ symbol->addr,
1769++ (addr_t)((uint8_t*)targetSection->start + rel->r_offset),
1770++ addend);
1771++ stg_exit(EXIT_FAILURE);
1772++ }
1773+ }
1774+ }
1775+ for(ElfRelocationATable *relaTab = oc->info->relaTable;
1776+@@ -320,7 +345,19 @@ relocateObjectCodeAarch64(ObjectCode * oc) {
1777+
1778+ addend = computeAddend(targetSection, (Elf_Rel*)rel,
1779+ symbol, addend);
1780+- encodeAddendAarch64(targetSection, (Elf_Rel*)rel, addend);
1781++ IF_DEBUG(linker, debugBelch("RELA: relocating symbol: %s (%s)\n",
1782++ symbol->name,
1783++ OC_INFORMATIVE_FILENAME(oc)));
1784++ if(encodeAddendAarch64(targetSection, (Elf_Rel*)rel, addend)) {
1785++ sysErrorBelch("Failed to relocate symbol: %s (%s) "
1786++ "at %p in %p with addend 0x%" PRIx64 "\n",
1787++ symbol->name,
1788++ OC_INFORMATIVE_FILENAME(oc),
1789++ symbol->addr,
1790++ (addr_t)((uint8_t*)targetSection->start + rel->r_offset),
1791++ addend);
1792++ stg_exit(EXIT_FAILURE);
1793++ }
1794+ }
1795+ }
1796+ return EXIT_SUCCESS;
1797+diff --git a/rts/sm/CNF.c b/rts/sm/CNF.c
1798+index 6bc58cde75..02d354fa4c 100644
1799+--- a/rts/sm/CNF.c
1800++++ b/rts/sm/CNF.c
1801+@@ -542,8 +542,9 @@ insertCompactHash (Capability *cap,
1802+ StgClosure *p, StgClosure *to)
1803+ {
1804+ insertHashTable(str->hash, (StgWord)p, (const void*)to);
1805+- if (str->header.info == &stg_COMPACT_NFDATA_CLEAN_info) {
1806+- str->header.info = &stg_COMPACT_NFDATA_DIRTY_info;
1807++ const StgInfoTable *strinfo = str->header.info;
1808++ if (strinfo == &stg_COMPACT_NFDATA_CLEAN_info) {
1809++ strinfo = &stg_COMPACT_NFDATA_DIRTY_info;
1810+ recordClosureMutated(cap, (StgClosure*)str);
1811+ }
1812+ }
1813+diff --git a/rts/sm/Evac.c b/rts/sm/Evac.c
1814+index 289031945d..f080221e28 100644
1815+--- a/rts/sm/Evac.c
1816++++ b/rts/sm/Evac.c
1817+@@ -131,7 +131,7 @@ copy_tag(StgClosure **p, const StgInfoTable *info,
1818+ #else
1819+ src->header.info = (const StgInfoTable *)MK_FORWARDING_PTR(to);
1820+ *p = TAG_CLOSURE(tag,(StgClosure*)to);
1821+-#endif
1822++#endif /* defined(PARALLEL_GC) */
1823+
1824+ #if defined(PROFILING)
1825+ // We store the size of the just evacuated object in the LDV word so that
1826+@@ -194,7 +194,7 @@ spin:
1827+ if (info == (W_)&stg_WHITEHOLE_info) {
1828+ #if defined(PROF_SPIN)
1829+ whitehole_gc_spin++;
1830+-#endif
1831++#endif /* PROF_SPIN */
1832+ busy_wait_nop();
1833+ goto spin;
1834+ }
1835+@@ -205,7 +205,7 @@ spin:
1836+ }
1837+ #else
1838+ info = (W_)src->header.info;
1839+-#endif
1840++#endif /* PARALLEL_GC */
1841+
1842+ to = alloc_for_copy(size_to_reserve, gen_no);
1843+
1844+@@ -216,8 +216,8 @@ spin:
1845+ }
1846+
1847+ write_barrier();
1848+- src->header.info = (const StgInfoTable*)MK_FORWARDING_PTR(to);
1849+ *p = (StgClosure *)to;
1850++ src->header.info = (const StgInfoTable*)MK_FORWARDING_PTR(to);
1851+
1852+ #if defined(PROFILING)
1853+ // We store the size of the just evacuated object in the LDV word so that
1854+@@ -1099,6 +1099,7 @@ selector_chain:
1855+ // need the write-barrier stuff.
1856+ // - undo the chain we've built to point to p.
1857+ SET_INFO((StgClosure *)p, (const StgInfoTable *)info_ptr);
1858++ write_barrier();
1859+ *q = (StgClosure *)p;
1860+ if (evac) evacuate(q);
1861+ unchain_thunk_selectors(prev_thunk_selector, (StgClosure *)p);
1862+@@ -1109,7 +1110,7 @@ selector_chain:
1863+ // Save the real info pointer (NOTE: not the same as get_itbl()).
1864+ info_ptr = (StgWord)p->header.info;
1865+ SET_INFO((StgClosure *)p,&stg_WHITEHOLE_info);
1866+-#endif
1867++#endif /* THREADED_RTS */
1868+
1869+ field = INFO_PTR_TO_STRUCT((StgInfoTable *)info_ptr)->layout.selector_offset;
1870+
1871+@@ -1165,6 +1166,7 @@ selector_loop:
1872+ SET_INFO((StgClosure*)p, (StgInfoTable *)info_ptr);
1873+ OVERWRITING_CLOSURE((StgClosure*)p);
1874+ SET_INFO((StgClosure*)p, &stg_WHITEHOLE_info);
1875++ write_barrier();
1876+ }
1877+ #endif
1878+
1879+diff --git a/rts/sm/GC.c b/rts/sm/GC.c
1880+index 90857abe38..09a8f411fe 100644
1881+--- a/rts/sm/GC.c
1882++++ b/rts/sm/GC.c
1883+@@ -1092,6 +1092,8 @@ loop:
1884+
1885+ // scavenge_loop() only exits when there's no work to do
1886+
1887++ // This atomic decrement also serves as a full barrier to ensure that any
1888++ // writes we made during scavenging are visible to other threads.
1889+ #if defined(DEBUG)
1890+ r = dec_running();
1891+ #else
1892+diff --git a/rts/sm/GCAux.c b/rts/sm/GCAux.c
1893+index 23ed3f0622..a1a2c79c0a 100644
1894+--- a/rts/sm/GCAux.c
1895++++ b/rts/sm/GCAux.c
1896+@@ -83,6 +83,7 @@ isAlive(StgClosure *p)
1897+ }
1898+
1899+ info = INFO_PTR_TO_STRUCT(info);
1900++ load_load_barrier();
1901+
1902+ switch (info->type) {
1903+
1904+diff --git a/rts/sm/MarkWeak.c b/rts/sm/MarkWeak.c
1905+index 88037f6a34..8ed499e9b3 100644
1906+--- a/rts/sm/MarkWeak.c
1907++++ b/rts/sm/MarkWeak.c
1908+@@ -242,16 +242,22 @@ static bool tidyWeakList(generation *gen)
1909+ last_w = &gen->old_weak_ptr_list;
1910+ for (w = gen->old_weak_ptr_list; w != NULL; w = next_w) {
1911+
1912++ info = w->header.info;
1913++ /* N.B. This function is executed only during the serial part of GC
1914++ * so consequently there is no potential for data races and therefore
1915++ * no need for memory barriers.
1916++ */
1917++
1918+ /* There might be a DEAD_WEAK on the list if finalizeWeak# was
1919+ * called on a live weak pointer object. Just remove it.
1920+ */
1921+- if (w->header.info == &stg_DEAD_WEAK_info) {
1922++ if (info == &stg_DEAD_WEAK_info) {
1923+ next_w = w->link;
1924+ *last_w = next_w;
1925+ continue;
1926+ }
1927+
1928+- info = get_itbl((StgClosure *)w);
1929++ info = INFO_PTR_TO_STRUCT(info);
1930+ switch (info->type) {
1931+
1932+ case WEAK:
1933+diff --git a/rts/sm/Sanity.c b/rts/sm/Sanity.c
1934+index 748f2f45b0..40cbb42db7 100644
1935+--- a/rts/sm/Sanity.c
1936++++ b/rts/sm/Sanity.c
1937+@@ -233,6 +233,7 @@ checkClosure( const StgClosure* p )
1938+ p = UNTAG_CONST_CLOSURE(p);
1939+
1940+ info = p->header.info;
1941++ load_load_barrier();
1942+
1943+ if (IS_FORWARDING_PTR(info)) {
1944+ barf("checkClosure: found EVACUATED closure %d", info->type);
1945+@@ -243,6 +244,7 @@ checkClosure( const StgClosure* p )
1946+ #endif
1947+
1948+ info = INFO_PTR_TO_STRUCT(info);
1949++ load_load_barrier();
1950+
1951+ switch (info->type) {
1952+
1953+@@ -564,6 +566,7 @@ checkTSO(StgTSO *tso)
1954+
1955+ next = tso->_link;
1956+ info = (const StgInfoTable*) tso->_link->header.info;
1957++ load_load_barrier();
1958+
1959+ ASSERT(next == END_TSO_QUEUE ||
1960+ info == &stg_MVAR_TSO_QUEUE_info ||
1961+diff --git a/rts/sm/Scav.c b/rts/sm/Scav.c
1962+index 39374c057f..45fe0d0c53 100644
1963+--- a/rts/sm/Scav.c
1964++++ b/rts/sm/Scav.c
1965+@@ -394,7 +394,7 @@ scavenge_block (bdescr *bd)
1966+ // time around the loop.
1967+ while (p < bd->free || (bd == ws->todo_bd && p < ws->todo_free)) {
1968+
1969+- ASSERT(bd->link == NULL);
1970++ ASSERT(bd->link == NULL);
1971+ ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
1972+ info = get_itbl((StgClosure *)p);
1973+
1974+@@ -1543,6 +1543,7 @@ scavenge_mutable_list(bdescr *bd, generation *gen)
1975+ ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
1976+
1977+ #if defined(DEBUG)
1978++ const StgInfoTable *pinfo;
1979+ switch (get_itbl((StgClosure *)p)->type) {
1980+ case MUT_VAR_CLEAN:
1981+ // can happen due to concurrent writeMutVars
1982+@@ -1562,9 +1563,10 @@ scavenge_mutable_list(bdescr *bd, generation *gen)
1983+ case TREC_CHUNK:
1984+ mutlist_TREC_CHUNK++; break;
1985+ case MUT_PRIM:
1986+- if (((StgClosure*)p)->header.info == &stg_TVAR_WATCH_QUEUE_info)
1987++ pinfo = ((StgClosure*)p)->header.info;
1988++ if (pinfo == &stg_TVAR_WATCH_QUEUE_info)
1989+ mutlist_TVAR_WATCH_QUEUE++;
1990+- else if (((StgClosure*)p)->header.info == &stg_TREC_HEADER_info)
1991++ else if (pinfo == &stg_TREC_HEADER_info)
1992+ mutlist_TREC_HEADER++;
1993+ else
1994+ mutlist_OTHERS++;
1995+diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
1996+index 52dab73709..5edd4fdcfd 100644
1997+--- a/rts/sm/Storage.c
1998++++ b/rts/sm/Storage.c
1999+@@ -407,8 +407,10 @@ lockCAF (StgRegTable *reg, StgIndStatic *caf)
2000+
2001+ // Allocate the blackhole indirection closure
2002+ bh = (StgInd *)allocate(cap, sizeofW(*bh));
2003+- SET_HDR(bh, &stg_CAF_BLACKHOLE_info, caf->header.prof.ccs);
2004+ bh->indirectee = (StgClosure *)cap->r.rCurrentTSO;
2005++ SET_HDR(bh, &stg_CAF_BLACKHOLE_info, caf->header.prof.ccs);
2006++ // Ensure that above writes are visible before we introduce reference as CAF indirectee.
2007++ write_barrier();
2008+
2009+ caf->indirectee = (StgClosure *)bh;
2010+ write_barrier();
2011+@@ -1081,6 +1083,8 @@ void
2012+ dirty_MUT_VAR(StgRegTable *reg, StgClosure *p)
2013+ {
2014+ Capability *cap = regTableToCapability(reg);
2015++ // No barrier required here as no other heap object fields are read. See
2016++ // note [Heap memory barriers] in SMP.h.
2017+ if (p->header.info == &stg_MUT_VAR_CLEAN_info) {
2018+ p->header.info = &stg_MUT_VAR_DIRTY_info;
2019+ recordClosureMutated(cap,p);
2020+@@ -1090,6 +1094,8 @@ dirty_MUT_VAR(StgRegTable *reg, StgClosure *p)
2021+ void
2022+ dirty_TVAR(Capability *cap, StgTVar *p)
2023+ {
2024++ // No barrier required here as no other heap object fields are read. See
2025++ // note [Heap memory barriers] in SMP.h.
2026+ if (p->header.info == &stg_TVAR_CLEAN_info) {
2027+ p->header.info = &stg_TVAR_DIRTY_info;
2028+ recordClosureMutated(cap,(StgClosure*)p);
overlays/patches/ghc/llvm-emit-nonlazybind.patchnew file+63
@@ -0,0 +1,63 @@
1+diff --git a/compiler/llvmGen/Llvm/PpLlvm.hs b/compiler/llvmGen/Llvm/PpLlvm.hs
2+index b350ab408d..2585326560 100644
3+--- a/compiler/llvmGen/Llvm/PpLlvm.hs
4++++ b/compiler/llvmGen/Llvm/PpLlvm.hs
5+@@ -149,11 +149,12 @@ ppLlvmFunctionHeader (LlvmFunctionDecl n l c r varg p a) args
6+ align = case a of
7+ Just a' -> text " align " <> ppr a'
8+ Nothing -> empty
9++ bind = text " nonlazybind "
10+ args' = map (\((ty,p),n) -> ppr ty <+> ppSpaceJoin p <+> char '%'
11+ <> ftext n)
12+ (zip p args)
13+ in ppr l <+> ppr c <+> ppr r <+> char '@' <> ftext n <> lparen <>
14+- (hsep $ punctuate comma args') <> ptext varg' <> rparen <> align
15++ (hsep $ punctuate comma args') <> ptext varg' <> rparen <> bind <> align
16+
17+ -- | Print out a list of function declaration.
18+ ppLlvmFunctionDecls :: LlvmFunctionDecls -> SDoc
19+diff --git a/compiler/llvmGen/Llvm/Types.hs b/compiler/llvmGen/Llvm/Types.hs
20+index bc7bbaab1b..882040897e 100644
21+--- a/compiler/llvmGen/Llvm/Types.hs
22++++ b/compiler/llvmGen/Llvm/Types.hs
23+@@ -555,6 +555,10 @@ data LlvmFuncAttr
24+ -- | This attribute disables prologue / epilogue emission for the function.
25+ -- This can have very system-specific consequences.
26+ | Naked
27++ -- | This attribute suppresses lazy symbol binding for the function. This
28++ -- may make calls to the function faster, at the cost of extra program startup
29++ -- time if the function is not called during program startup.
30++ | NonLazyBind
31+ deriving (Eq)
32+
33+ instance Outputable LlvmFuncAttr where
34+@@ -571,6 +575,7 @@ instance Outputable LlvmFuncAttr where
35+ ppr NoRedZone = text "noredzone"
36+ ppr NoImplicitFloat = text "noimplicitfloat"
37+ ppr Naked = text "naked"
38++ ppr NonLazyBind = text "nonlazybind"
39+
40+
41+ -- | Different types to call a function.
42+diff --git a/compiler/llvmGen/LlvmCodeGen/Base.hs b/compiler/llvmGen/LlvmCodeGen/Base.hs
43+index 6e20da48c1..c1dc50d316 100644
44+--- a/compiler/llvmGen/LlvmCodeGen/Base.hs
45++++ b/compiler/llvmGen/LlvmCodeGen/Base.hs
46+@@ -159,8 +159,16 @@ llvmFunArgs dflags live =
47+ isSSE _ = False
48+
49+ -- | Llvm standard fun attributes
50++--
51++-- Haskell code needs to always be marked NonLazyBind.
52++-- This prevents the compiler from forcing it through
53++-- the plt. This is an issue for haskell functions with
54++-- info tables. Other functions migth use the function
55++-- pointer and do relative computations off of it, which
56++-- in turn would point somewhere into the PLT instead of
57++-- the info-table, *if* we did not pass NonLazyBind.
58+ llvmStdFunAttrs :: [LlvmFuncAttr]
59+-llvmStdFunAttrs = [NoUnwind]
60++llvmStdFunAttrs = [NoUnwind, NonLazyBind]
61+
62+ -- | Convert a list of types to a list of function parameters
63+ -- (each with no parameter attributes)