Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 8514226

Browse files
author
Koundinya Veluri
authored
Make CoreCLR work properly under PaX's RANDMMAP (#11382)
Make CoreCLR work properly under PaX's RANDMMAP Issues: - The ExecutableMemoryAllocator is used to attempt to map native images into a memory range near libcoreclr so that its helper table can use short relative addresses for jumps to libcoreclr - RANDMMAP typically prevents mmap calls with a specific address from reserving memory at the requested address, so the executable memory allocator fails to reserve any memory. When Server GC is enabled, the large GC heap can exacerbate the issue by taking address space near libcoreclr. - Native images are loaded far from libcoreclr, and now jump stub space needs to be allocated near the native image, but RANDMMAP typically prevents this too - NGenReserveForJumpStubs is intended to reserve some memory near mapped native images for jump stubs, but that reservation is done with a separate mmap call in the same way as above and RANDMMAP typically prevents this too - The JIT needs to allocate memory for code that may need to jump/call to a native image or libcoreclr, which may require jump stubs near the code that cannot be allocated. CodeHeapReserveForJumpStubs reserves space in code heap blocks without using a separate call to mmap, so this works, but without this environment variable by default there is still a good chance of failing. - See https://github.com/dotnet/coreclr/blob/56d550d4f8aec2dd40b72a182205d0a2463a1bc9/Documentation/design-docs/jump-stubs.md for more details Fixes #8480 - It would be ideal to fix all of the above properly, such that there would never be a need to attempt reserving memory within a certain range. Since we're running out of time for 2.0, I figured the following simpler, temporary solution that should cover most of the practical cases, may be appropriate for 2.0. - Extended ExecutableMemoryAllocator to reserve address space even when it cannot do so near libcoreclr - Had ClrVirtualAllocWithinRange use the executable memory allocator to reserve memory for jump stubs when the requested range is satisfied - This covers a maximum of ~2 GB of executable code and should cover most of the practical cases. Once this space is exhausted, under RANDMMAP, native images loaded later will fail, and for jitted code the environment variable above can be used.
1 parent 1db5bbc commit 8514226

File tree

6 files changed

+248
-41
lines changed

6 files changed

+248
-41
lines changed

src/dlls/mscordac/mscordac_unixexports.src

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ PAL_fprintf
3939
PAL__wcstoui64
4040
PAL_wcstoul
4141
PAL_iswprint
42+
PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange
4243
PAL_wcslen
4344
PAL_wcsncmp
4445
PAL_wcsrchr

src/pal/inc/pal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,6 +2850,14 @@ PALAPI
28502850
LPCVOID
28512851
PAL_GetSymbolModuleBase(void *symbol);
28522852

2853+
PALIMPORT
2854+
LPVOID
2855+
PALAPI
2856+
PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(
2857+
IN LPCVOID lpBeginAddress,
2858+
IN LPCVOID lpEndAddress,
2859+
IN SIZE_T dwSize);
2860+
28532861
PALIMPORT
28542862
LPVOID
28552863
PALAPI

src/pal/src/include/pal/virtual.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ enum VIRTUAL_CONSTANTS
6060

6161
VIRTUAL_PAGE_SIZE = 0x1000,
6262
VIRTUAL_PAGE_MASK = VIRTUAL_PAGE_SIZE - 1,
63-
BOUNDARY_64K = 0xffff
63+
VIRTUAL_64KB = 0x10000
6464
};
6565

6666
/*++
@@ -130,11 +130,22 @@ class ExecutableMemoryAllocator
130130
AllocateMemory
131131
132132
This function attempts to allocate the requested amount of memory from its reserved virtual
133-
address space. The function will return NULL if the allocation request cannot
133+
address space. The function will return null if the allocation request cannot
134134
be satisfied by the memory that is currently available in the allocator.
135135
--*/
136136
void* AllocateMemory(SIZE_T allocationSize);
137137

138+
/*++
139+
Function:
140+
AllocateMemory
141+
142+
This function attempts to allocate the requested amount of memory from its reserved virtual
143+
address space, if memory is available within the specified range. The function will return
144+
null if the allocation request cannot satisfied by the memory that is currently available in
145+
the allocator.
146+
--*/
147+
void *AllocateMemoryWithinRange(const void *beginAddress, const void *endAddress, SIZE_T allocationSize);
148+
138149
private:
139150
/*++
140151
Function:
@@ -160,12 +171,13 @@ class ExecutableMemoryAllocator
160171
// that can be used to calculate an approximate location of the memory that
161172
// is in 2GB range from the coreclr library. In addition, having precise size of libcoreclr
162173
// is not necessary for the calculations.
163-
const int32_t CoreClrLibrarySize = 100 * 1024 * 1024;
174+
static const int32_t CoreClrLibrarySize = 100 * 1024 * 1024;
164175

165176
// This constant represent the max size of the virtual memory that this allocator
166177
// will try to reserve during initialization. We want all JIT-ed code and the
167178
// entire libcoreclr to be located in a 2GB range.
168-
const int32_t MaxExecutableMemorySize = 0x7FFF0000 - CoreClrLibrarySize;
179+
static const int32_t MaxExecutableMemorySize = 0x7FFF0000;
180+
static const int32_t MaxExecutableMemorySizeNearCoreClr = MaxExecutableMemorySize - CoreClrLibrarySize;
169181

170182
// Start address of the reserved virtual address space
171183
void* m_startAddress;

src/pal/src/map/map.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2445,8 +2445,10 @@ void * MAPMapPEFile(HANDLE hFile)
24452445
#else // defined(_AMD64_)
24462446
// First try to reserve virtual memory using ExecutableAllcator. This allows all PE images to be
24472447
// near each other and close to the coreclr library which also allows the runtime to generate
2448-
// more efficient code (by avoiding usage of jump stubs).
2449-
loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(virtualSize, GetVirtualPageSize()));
2448+
// more efficient code (by avoiding usage of jump stubs). Alignment to a 64 KB granularity should
2449+
// not be necessary (alignment to page size should be sufficient), but see
2450+
// ExecutableMemoryAllocator::AllocateMemory() for the reason why it is done.
2451+
loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(virtualSize, VIRTUAL_64KB));
24502452
if (loadedBase == NULL)
24512453
{
24522454
// MAC64 requires we pass MAP_SHARED (or MAP_PRIVATE) flags - otherwise, the call is failed.

0 commit comments

Comments
 (0)