Skip to content

Commit

Permalink
[NativeAOT/Apple] Map the thunks using vm_allocate/vm_map to avoid ne…
Browse files Browse the repository at this point in the history
…ed for specific executable segment layout (dotnet#95914)
  • Loading branch information
filipnavara committed Dec 13, 2023
1 parent 4b91f91 commit 1e135d1
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,6 @@ The .NET Foundation licenses this file to you under the MIT license.
<NativeSystemLibrary Include="m" />
</ItemGroup>

<ItemGroup>
<ExtraLinkerArg Include="-segprot,__THUNKS,rx,rx" Condition="'$(_IsApplePlatform)' == 'true'" />
</ItemGroup>

<ItemGroup>
<LinkerArg Include="-gz=zlib" Condition="'$(CompressSymbols)' != 'false'" />
<LinkerArg Include="-fuse-ld=$(LinkerFlavor)" Condition="'$(LinkerFlavor)' != ''" />
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/nativeaot/Runtime/PalRedhawk.h
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ REDHAWK_PALIMPORT void REDHAWK_PALAPI PalHijack(HANDLE hThread, _In_opt_ void* p
REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalRegisterHijackCallback(_In_ PalHijackCallback callback);

REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalAllocateThunksFromTemplate(_In_ HANDLE hTemplateModule, uint32_t templateRva, size_t templateSize, _Outptr_result_bytebuffer_(templateSize) void** newThunksOut);
REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalFreeThunksFromTemplate(_In_ void *pBaseAddress);
REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalFreeThunksFromTemplate(_In_ void *pBaseAddress, size_t templateSize);

REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalMarkThunksAsValidCallTargets(
void *virtualAddress,
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/nativeaot/Runtime/ThunksMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ EXTERN_C NATIVEAOT_API void* __cdecl RhAllocateThunksMapping()
int thunkBlockSize = RhpGetThunkBlockSize();
int templateSize = thunkBlocksPerMapping * thunkBlockSize;

#ifndef TARGET_APPLE // Apple platforms cannot use the initial template
if (pThunksTemplateAddress == NULL)
{
// First, we use the thunks directly from the thunks template sections in the module until all
Expand All @@ -337,12 +338,13 @@ EXTERN_C NATIVEAOT_API void* __cdecl RhAllocateThunksMapping()
pThunkMap = pThunksTemplateAddress;
}
else
#endif
{
// We've already used the thunks template in the module for some previous thunks, and we
// cannot reuse it here. Now we need to create a new mapping of the thunks section in order to have
// more thunks

uint8_t* pModuleBase = (uint8_t*)PalGetModuleHandleFromPointer(pThunksTemplateAddress);
uint8_t* pModuleBase = (uint8_t*)PalGetModuleHandleFromPointer(RhpGetThunksBase());
int templateRva = (int)((uint8_t*)RhpGetThunksBase() - pModuleBase);

if (!PalAllocateThunksFromTemplate((HANDLE)pModuleBase, templateRva, templateSize, &pThunkMap))
Expand All @@ -357,7 +359,7 @@ EXTERN_C NATIVEAOT_API void* __cdecl RhAllocateThunksMapping()
thunkBlocksPerMapping))
{
if (pThunkMap != pThunksTemplateAddress)
PalFreeThunksFromTemplate(pThunkMap);
PalFreeThunksFromTemplate(pThunkMap, templateSize);

return NULL;
}
Expand Down
11 changes: 2 additions & 9 deletions src/coreclr/nativeaot/Runtime/amd64/ThunkPoolThunks.S
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,15 @@
.endm

#ifdef TARGET_APPLE
// Create two segments in the Mach-O file:
// __THUNKS with executable permissions
// __THUNKS_DATA with read/write permissions

.section __THUNKS,__thunks,regular,pure_instructions
// Thunk pool
.text
.p2align PAGE_SIZE_LOG2
PATCH_LABEL ThunkPool
.rept (THUNKS_MAP_SIZE / PAGE_SIZE)
.p2align PAGE_SIZE_LOG2
THUNKS_PAGE_BLOCK
.endr
.p2align PAGE_SIZE_LOG2
.section __THUNKS_DATA,__thunks,regular
.p2align PAGE_SIZE_LOG2
.space THUNKS_MAP_SIZE
.p2align PAGE_SIZE_LOG2
#else
#error Unsupported OS
#endif
Expand Down
11 changes: 2 additions & 9 deletions src/coreclr/nativeaot/Runtime/arm64/ThunkPoolThunks.S
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,15 @@
.endm

#ifdef TARGET_APPLE
// Create two segments in the Mach-O file:
// __THUNKS with executable permissions
// __THUNKS_DATA with read/write permissions

.section __THUNKS,__thunks,regular,pure_instructions
// Thunk pool
.text
.p2align PAGE_SIZE_LOG2
PATCH_LABEL ThunkPool
.rept (THUNKS_MAP_SIZE / PAGE_SIZE)
.p2align PAGE_SIZE_LOG2
THUNKS_PAGE_BLOCK
.endr
.p2align PAGE_SIZE_LOG2
.section __THUNKS_DATA,__thunks,regular
.p2align PAGE_SIZE_LOG2
.space THUNKS_MAP_SIZE
.p2align PAGE_SIZE_LOG2
#else
#error Unsupported OS
#endif
Expand Down
69 changes: 35 additions & 34 deletions src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@
#endif

#ifdef TARGET_APPLE
#include <minipal/getexepath.h>
#include <mach-o/getsect.h>
#include <mach/mach.h>
#endif

using std::nullptr_t;
Expand Down Expand Up @@ -516,59 +515,61 @@ extern "C" bool PalDetachThread(void* thread)

#if !defined(USE_PORTABLE_HELPERS) && !defined(FEATURE_RX_THUNKS)

#ifdef TARGET_APPLE
static const struct section_64 *thunks_section;
static const struct section_64 *thunks_data_section;
#endif

REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalAllocateThunksFromTemplate(HANDLE hTemplateModule, uint32_t templateRva, size_t templateSize, void** newThunksOut)
{
#ifdef TARGET_APPLE
int f;
Dl_info info;
vm_address_t addr, taddr;
vm_prot_t prot, max_prot;
kern_return_t ret;

int st = dladdr((const void*)hTemplateModule, &info);
if (st == 0)
// Allocate two contiguous ranges of memory: the first range will contain the trampolines
// and the second range will contain their data.
do
{
return UInt32_FALSE;
}
ret = vm_allocate(mach_task_self(), &addr, templateSize * 2, VM_FLAGS_ANYWHERE);
} while (ret == KERN_ABORTED);

f = open(info.dli_fname, O_RDONLY);
if (f < 0)
if (ret != KERN_SUCCESS)
{
return UInt32_FALSE;
}

// NOTE: We ignore templateRva since we would need to convert it to file offset
// and templateSize is useless too. Instead we read the sections from the
// executable and determine the size from them.
if (thunks_section == NULL)
do
{
ret = vm_remap(
mach_task_self(), &addr, templateSize, 0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
mach_task_self(), ((vm_address_t)hTemplateModule + templateRva), FALSE, &prot, &max_prot, VM_INHERIT_SHARE);
} while (ret == KERN_ABORTED);

if (ret != KERN_SUCCESS)
{
const struct mach_header_64 *hdr = (const struct mach_header_64 *)hTemplateModule;
thunks_section = getsectbynamefromheader_64(hdr, "__THUNKS", "__thunks");
thunks_data_section = getsectbynamefromheader_64(hdr, "__THUNKS_DATA", "__thunks");
do
{
ret = vm_deallocate(mach_task_self(), addr, templateSize * 2);
} while (ret == KERN_ABORTED);

return UInt32_FALSE;
}

*newThunksOut = mmap(
NULL,
thunks_section->size + thunks_data_section->size,
PROT_READ | PROT_EXEC,
MAP_PRIVATE,
f,
thunks_section->offset);
close(f);
*newThunksOut = (void*)addr;

return *newThunksOut == NULL ? UInt32_FALSE : UInt32_TRUE;
return UInt32_TRUE;
#else
PORTABILITY_ASSERT("UNIXTODO: Implement this function");
#endif
}

REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalFreeThunksFromTemplate(void *pBaseAddress)
REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalFreeThunksFromTemplate(void *pBaseAddress, size_t templateSize)
{
#ifdef TARGET_APPLE
int ret = munmap(pBaseAddress, thunks_section->size + thunks_data_section->size);
return ret == 0 ? UInt32_TRUE : UInt32_FALSE;
kern_return_t ret;

do
{
ret = vm_deallocate(mach_task_self(), (vm_address_t)pBaseAddress, templateSize * 2);
} while (ret == KERN_ABORTED);

return ret == KERN_SUCCESS ? UInt32_TRUE : UInt32_FALSE;
#else
PORTABILITY_ASSERT("UNIXTODO: Implement this function");
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalAllocateThunksFromTemplate(_In_
#endif
}

REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalFreeThunksFromTemplate(_In_ void *pBaseAddress)
REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalFreeThunksFromTemplate(_In_ void *pBaseAddress, size_t templateSize)
{
#ifdef XBOX_ONE
return TRUE;
Expand Down

0 comments on commit 1e135d1

Please sign in to comment.