Skip to content

Commit cb6fb60

Browse files
filipnavaraam11jkotas
authored
[NativeAOT] Initial osx-arm64 bring up (#75264)
* Enable NativeAOT osx-arm64 builds * Restrict alignment in VirtualReserveInner * Fix generation and handling of compact unwinding info on osx-arm64 * Fix PC check in findFDE in DWARF CFI unwinding * Handle MAP_JIT for P/Invoke on osx-arm64 * Handle P/Invoke with MAP_JIT on osx-arm64 * Fix incorrect OS_PAGE_SIZE definition * Fix TLS register trashing * Fix memory trashing caused by incorrect PREPARE_EXTERNAL_VAR_INDIRECT[_W] definitions * Ignore ESRCH in PalHijack (thread is already gone) * Make CompactUnwinder_* parametrized with registry class * Remove custom CompactUnwinder * Update llvm-libunwind-version.txt * Fix initial alignment for __module_initializer. ARM64 requires absolute symbol relocations to be aligned to native pointer size. * Allow publishing with the osx-arm64 RID * Use pointer sized alignment for fat function pointers since they contain absolute relocations. ld64 seem to silently corrupt them if they are not aligned to pointer size. Co-authored-by: Adeel Mujahid <[email protected]> Co-authored-by: Jan Kotas <[email protected]>
1 parent 8f33fd5 commit cb6fb60

File tree

15 files changed

+139
-69
lines changed

15 files changed

+139
-69
lines changed

eng/Subsets.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999

100100
<PropertyGroup>
101101
<!-- CLR NativeAot only builds in a subset of the matrix -->
102-
<NativeAotSupported Condition="('$(TargetOS)' == 'windows' or '$(TargetOS)' == 'linux' or '$(TargetOS)' == 'OSX') and ('$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64') and ('$(TargetOS)' != 'OSX' or '$(TargetArchitecture)' != 'arm64')">true</NativeAotSupported>
102+
<NativeAotSupported Condition="('$(TargetOS)' == 'windows' or '$(TargetOS)' == 'linux' or '$(TargetOS)' == 'OSX') and ('$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64')">true</NativeAotSupported>
103103

104104
<!-- If we're building clr.nativeaotlibs and not building the CLR runtime, compile libraries against NativeAOT CoreLib -->
105105
<UseNativeAotCoreLib Condition="$(_subset.Contains('+clr.nativeaotlibs+')) and !$(_subset.Contains('+clr.native+')) and !$(_subset.Contains('+clr.runtime+'))">true</UseNativeAotCoreLib>

src/coreclr/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ add_subdirectory(tools/aot/jitinterface)
139139

140140
if(NOT CLR_CROSS_COMPONENTS_BUILD)
141141
# NativeAOT only buildable for a subset of CoreCLR-supported configurations
142-
if((CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_WIN32) AND (CLR_CMAKE_HOST_ARCH_ARM64 OR CLR_CMAKE_HOST_ARCH_AMD64) AND NOT (CLR_CMAKE_HOST_OSX AND CLR_CMAKE_HOST_ARCH_ARM64))
142+
if((CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_WIN32) AND (CLR_CMAKE_HOST_ARCH_ARM64 OR CLR_CMAKE_HOST_ARCH_AMD64))
143143
add_subdirectory(nativeaot)
144144
endif()
145145
endif(NOT CLR_CROSS_COMPONENTS_BUILD)

src/coreclr/gc/unix/gcenv.unix.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ void GCToOSInterface::YieldThread(uint32_t switchCount)
633633
static void* VirtualReserveInner(size_t size, size_t alignment, uint32_t flags, uint32_t hugePagesFlag = 0)
634634
{
635635
assert(!(flags & VirtualReserveFlags::WriteWatch) && "WriteWatch not supported on Unix");
636-
if (alignment == 0)
636+
if (alignment < OS_PAGE_SIZE)
637637
{
638638
alignment = OS_PAGE_SIZE;
639639
}

src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@
6161
<Error Condition="'$(DisableUnsupportedError)' != 'true' and '$(OS)' != 'Windows_NT' and $(RuntimeIdentifier.StartsWith('win'))"
6262
Text="Cross-OS native compilation is not supported." />
6363

64-
<Error Condition="'$(DisableUnsupportedError)' != 'true' and !($(RuntimeIdentifier.EndsWith('x64')) or
65-
($(RuntimeIdentifier.EndsWith('arm64')) and !$(RuntimeIdentifier.StartsWith('osx'))))"
64+
<Error Condition="'$(DisableUnsupportedError)' != 'true' and !($(RuntimeIdentifier.EndsWith('x64')) or $(RuntimeIdentifier.EndsWith('arm64')))"
6665
Text="Native compilation does not support targeting $(RuntimeIdentifier) yet." />
6766

6867
<Error Condition="'$(DisableUnsupportedError)' != 'true' and !('$(IlcHostArch)' == 'x64' or '$(IlcHostArch)' == 'arm64')"

src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ThunkPool.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,14 @@ namespace System.Runtime
4040
{
4141
internal static class Constants
4242
{
43+
#if TARGET_ARM64 && TARGET_OSX
44+
public const uint PageSize = 0x4000; // 16k
45+
public const nuint PageSizeMask = 0x3FFF;
46+
#else
4347
public const uint PageSize = 0x1000; // 4k
44-
public const uint AllocationGranularity = 0x10000; // 64k
4548
public const nuint PageSizeMask = 0xFFF;
49+
#endif
50+
public const uint AllocationGranularity = 0x10000; // 64k
4651
public const nuint AllocationGranularityMask = 0xFFFF;
4752

4853
public static readonly int ThunkDataSize = 2 * IntPtr.Size;

src/coreclr/nativeaot/Runtime/CommonMacros.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,12 @@ inline bool IS_ALIGNED(T* val, uintptr_t alignment);
155155

156156
#define DATA_ALIGNMENT 8
157157
#ifndef OS_PAGE_SIZE
158+
#ifdef HOST_OSX
159+
#define OS_PAGE_SIZE 0x4000
160+
#else
158161
#define OS_PAGE_SIZE 0x1000
159162
#endif
163+
#endif
160164

161165
#elif defined(HOST_WASM)
162166

src/coreclr/nativeaot/Runtime/ThunksMapping.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ EXTERN_C NATIVEAOT_API void* __cdecl RhAllocateThunksMapping()
121121
return NULL;
122122
}
123123

124+
#if defined(HOST_OSX) && defined(HOST_ARM64)
125+
pthread_jit_write_protect_np(0);
126+
#endif
124127
#endif
125128

126129
int numBlocksPerMap = RhpGetNumThunkBlocksPerMapping();
@@ -223,11 +226,15 @@ EXTERN_C NATIVEAOT_API void* __cdecl RhAllocateThunksMapping()
223226
}
224227
}
225228

229+
#if defined(HOST_OSX) && defined(HOST_ARM64)
230+
pthread_jit_write_protect_np(1);
231+
#else
226232
if (!PalVirtualProtect(pThunksSection, THUNKS_MAP_SIZE, PAGE_EXECUTE_READ))
227233
{
228234
PalVirtualFree(pNewMapping, 0, MEM_RELEASE);
229235
return NULL;
230236
}
237+
#endif
231238

232239
PalFlushInstructionCache(pThunksSection, THUNKS_MAP_SIZE);
233240

src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,8 +776,16 @@ REDHAWK_PALEXPORT _Ret_maybenull_ _Post_writable_byte_size_(size) void* REDHAWK_
776776
static const size_t Alignment = 64 * 1024;
777777

778778
size_t alignedSize = size + (Alignment - OS_PAGE_SIZE);
779+
int flags = MAP_ANON | MAP_PRIVATE;
779780

780-
void * pRetVal = mmap(pAddress, alignedSize, unixProtect, MAP_ANON | MAP_PRIVATE, -1, 0);
781+
#if defined(HOST_OSX) && defined(HOST_ARM64)
782+
if (unixProtect & PROT_EXEC)
783+
{
784+
flags |= MAP_JIT;
785+
}
786+
#endif
787+
788+
void * pRetVal = mmap(pAddress, alignedSize, unixProtect, flags, -1, 0);
781789

782790
if (pRetVal != NULL)
783791
{
@@ -1057,7 +1065,7 @@ REDHAWK_PALEXPORT void REDHAWK_PALAPI PalHijack(HANDLE hThread, _In_opt_ void* p
10571065
}
10581066
#endif
10591067

1060-
if ((status != 0) && (status != EAGAIN))
1068+
if ((status != 0) && (status != EAGAIN) && (status != ESRCH))
10611069
{
10621070
// Failure to send the signal is fatal. There are only two cases when sending
10631071
// the signal can fail. First, if the signal ID is invalid and second,

src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828

2929
#if defined(TARGET_AMD64)
3030
using libunwind::Registers_x86_64;
31+
using libunwind::CompactUnwinder_x86_64;
3132
#elif defined(TARGET_ARM)
3233
using libunwind::Registers_arm;
3334
#elif defined(TARGET_ARM64)
3435
using libunwind::Registers_arm64;
36+
using libunwind::CompactUnwinder_arm64;
3537
#elif defined(TARGET_X86)
3638
using libunwind::Registers_x86;
3739
#else
@@ -501,6 +503,8 @@ struct Registers_REGDISPLAY : REGDISPLAY
501503
uint64_t getIP() const { return IP;}
502504
void setIP(uint64_t value, uint64_t location)
503505
{ IP = value; pIP = (PTR_UIntNative)location; }
506+
uint64_t getFP() const { return *pFP;}
507+
void setFP(uint64_t value, uint64_t location) { pFP = (PTR_UIntNative)location;}
504508
};
505509

506510
inline bool Registers_REGDISPLAY::validRegister(int num) const {
@@ -772,7 +776,37 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs
772776
#endif
773777

774778
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
775-
bool retVal = uc.getInfoFromDwarfSection(pc, uwInfoSections, 0 /* fdeSectionOffsetHint */);
779+
uint32_t dwarfOffsetHint = 0;
780+
781+
#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
782+
// If there is a compact unwind encoding table, look there first.
783+
if (uwInfoSections.compact_unwind_section != 0 && uc.getInfoFromCompactEncodingSection(pc, uwInfoSections)) {
784+
unw_proc_info_t procInfo;
785+
uc.getInfo(&procInfo);
786+
787+
#if defined(TARGET_ARM64)
788+
if ((procInfo.format & UNWIND_ARM64_MODE_MASK) != UNWIND_ARM64_MODE_DWARF) {
789+
CompactUnwinder_arm64<LocalAddressSpace, Registers_REGDISPLAY> compactInst;
790+
int stepRet = compactInst.stepWithCompactEncoding(procInfo.format, pc, _addressSpace, *(Registers_REGDISPLAY*)regs);
791+
return stepRet == UNW_STEP_SUCCESS;
792+
} else {
793+
dwarfOffsetHint = procInfo.format & UNWIND_ARM64_DWARF_SECTION_OFFSET;
794+
}
795+
#elif defined(TARGET_AMD64)
796+
if ((procInfo.format & UNWIND_X86_64_MODE_MASK) != UNWIND_X86_64_MODE_DWARF) {
797+
CompactUnwinder_x86_64<LocalAddressSpace, Registers_REGDISPLAY> compactInst;
798+
int stepRet = compactInst.stepWithCompactEncoding(procInfo.format, pc, _addressSpace, *(Registers_REGDISPLAY*)regs);
799+
return stepRet == UNW_STEP_SUCCESS;
800+
} else {
801+
dwarfOffsetHint = procInfo.format & UNWIND_X86_64_DWARF_SECTION_OFFSET;
802+
}
803+
#else
804+
PORTABILITY_ASSERT("DoTheStep");
805+
#endif
806+
}
807+
#endif
808+
809+
bool retVal = uc.getInfoFromDwarfSection(pc, uwInfoSections, dwarfOffsetHint);
776810
if (!retVal)
777811
{
778812
return false;

src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm64.inc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ C_FUNC(\Name):
7373
#if defined(__APPLE__)
7474
adrp \HelperReg, C_FUNC(\Name)@GOTPAGE
7575
ldr \HelperReg, [\HelperReg, C_FUNC(\Name)@GOTPAGEOFF]
76+
ldr \HelperReg, [\HelperReg]
7677
#else
7778
adrp \HelperReg, C_FUNC(\Name)
7879
ldr \HelperReg, [\HelperReg, :lo12:C_FUNC(\Name)]
@@ -82,7 +83,8 @@ C_FUNC(\Name):
8283
.macro PREPARE_EXTERNAL_VAR_INDIRECT_W Name, HelperReg
8384
#if defined(__APPLE__)
8485
adrp x\HelperReg, C_FUNC(\Name)@GOTPAGE
85-
ldr w\HelperReg, [x\HelperReg, C_FUNC(\Name)@GOTPAGEOFF]
86+
ldr x\HelperReg, [x\HelperReg, C_FUNC(\Name)@GOTPAGEOFF]
87+
ldr w\HelperReg, [x\HelperReg]
8688
#else
8789
adrp x\HelperReg, C_FUNC(\Name)
8890
ldr w\HelperReg, [x\HelperReg, :lo12:C_FUNC(\Name)]
@@ -182,6 +184,10 @@ C_FUNC(\Name):
182184
.endif
183185

184186
stp x0, lr, [sp,#-0x10]!
187+
#if defined(__APPLE__)
188+
// Apple's tls_get_var trashes xip0 (and possibly xip1)
189+
stp xip0, xip1, [sp,#-0x10]!
190+
#endif
185191

186192
// This sequence of instructions is recognized and potentially patched
187193
// by the linker (GD->IE/LE relaxation).
@@ -206,6 +212,9 @@ C_FUNC(\Name):
206212
add \target, \target, x0
207213
#endif
208214

215+
#if defined(__APPLE__)
216+
ldp xip0, xip1, [sp],#0x10
217+
#endif
209218
ldp x0, lr, [sp],#0x10
210219
.endm
211220

0 commit comments

Comments
 (0)