1--- lib/Support/Unix/Memory.inc
2+++ lib/Support/Unix/Memory.inc
3@@ -126,8 +126,12 @@
4 Result.Address = Addr;
5 Result.Size = NumPages*PageSize;
6
7- if (PFlags & MF_EXEC)
8- Memory::InvalidateInstructionCache(Result.Address, Result.Size);
9+ // Rely on protectMappedMemory to invalidate instruction cache.
10+ if (PFlags & MF_EXEC) {
11+ EC = Memory::protectMappedMemory (Result, PFlags);
12+ if (EC != std::error_code())
13+ return MemoryBlock();
14+ }
15
16 return Result;
17 }
18@@ -156,15 +160,31 @@
19 return std::error_code(EINVAL, std::generic_category());
20
21 int Protect = getPosixProtectionFlags(Flags);
22-
23 uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize);
24 uintptr_t End = alignAddr((uint8_t *)M.Address + M.Size, PageSize);
25+
26+ bool InvalidateCache = (Flags & MF_EXEC);
27+
28+#if defined(__arm__) || defined(__aarch64__)
29+ // Certain ARM implementations treat icache clear instruction as a memory read,
30+ // and CPU segfaults on trying to clear cache on !PROT_READ page. Therefore we need
31+ // to temporarily add PROT_READ for the sake of flushing the instruction caches.
32+ if (InvalidateCache && !(Protect & PROT_READ)) {
33+ int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ);
34+ if (Result != 0)
35+ return std::error_code(errno, std::generic_category());
36+
37+ Memory::InvalidateInstructionCache(M.Address, M.Size);
38+ InvalidateCache = false;
39+ }
40+#endif
41+
42 int Result = ::mprotect((void *)Start, End - Start, Protect);
43
44 if (Result != 0)
45 return std::error_code(errno, std::generic_category());
46
47- if (Flags & MF_EXEC)
48+ if (InvalidateCache)
49 Memory::InvalidateInstructionCache(M.Address, M.Size);
50
51 return std::error_code();