Skip to content

Commit 5da6444

Browse files
committed
Make it work on Arm64, and detect cases where we use the initial libcoreclr template in ways that are unsafe.
1 parent 9dfe1ba commit 5da6444

File tree

5 files changed

+57
-23
lines changed

5 files changed

+57
-23
lines changed

src/coreclr/clrdefinitions.cmake

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ if (FEATURE_STUBPRECODE_DYNAMIC_HELPERS)
217217
add_definitions(-DFEATURE_STUBPRECODE_DYNAMIC_HELPERS)
218218
endif()
219219

220-
add_definitions(-DFEATURE_MAP_THUNKS_FROM_IMAGE)
220+
if (CLR_CMAKE_TARGET_APPLE)
221+
add_definitions(-DFEATURE_MAP_THUNKS_FROM_IMAGE)
222+
endif()
221223

222224
# Use this function to enable building with a specific target OS and architecture set of defines
223225
# This is known to work for the set of defines used by the JIT and gcinfo, it is not likely correct for

src/coreclr/minipal/Unix/doublemapping.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,15 @@ bool VMToOSInterface::ReleaseRWMapping(void* pStart, size_t size)
261261
}
262262

263263
#ifndef TARGET_APPLE
264-
#define MAX_TEMPLATE_THUNK_TYPES 8 // Maximum number of times the CreateTemplate api can be called
264+
#define MAX_TEMPLATE_THUNK_TYPES 3 // Maximum number of times the CreateTemplate api can be called
265265
struct TemplateThunkMappingData
266266
{
267267
int fdImage;
268268
off_t offsetInFileOfStartOfSection;
269269
void* addrOfStartOfSection; // Always NULL if the template mapping data could not be initialized
270270
void* addrOfEndOfSection;
271271
bool imageTemplates;
272+
int templatesCreated;
272273
off_t nonImageTemplateCurrent;
273274
};
274275

@@ -281,6 +282,8 @@ struct InitializeTemplateThunkLocals
281282

282283
static TemplateThunkMappingData *s_pThunkData = NULL;
283284

285+
#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE
286+
284287
static Elf32_Word Elf32_WordMin(Elf32_Word left, Elf32_Word right)
285288
{
286289
return left < right ? left : right;
@@ -338,6 +341,7 @@ static int InitializeTemplateThunkMappingDataPhdrCallback(struct dl_phdr_info *i
338341
// This isn't the interesting .so
339342
return 0;
340343
}
344+
#endif // FEATURE_MAP_THUNKS_FROM_IMAGE
341345

342346
TemplateThunkMappingData *InitializeTemplateThunkMappingData(void* pTemplate)
343347
{
@@ -349,11 +353,14 @@ TemplateThunkMappingData *InitializeTemplateThunkMappingData(void* pTemplate)
349353
locals.data.addrOfEndOfSection = NULL;
350354
locals.data.imageTemplates = false;
351355
locals.data.nonImageTemplateCurrent = 0;
356+
locals.data.templatesCreated = 0;
352357

358+
#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE
353359
if (dladdr(pTemplate, &locals.info) != 0)
354360
{
355361
dl_iterate_phdr(InitializeTemplateThunkMappingDataPhdrCallback, &locals);
356362
}
363+
#endif // FEATURE_MAP_THUNKS_FROM_IMAGE
357364

358365
if (locals.data.addrOfStartOfSection == NULL)
359366
{
@@ -382,7 +389,7 @@ TemplateThunkMappingData *InitializeTemplateThunkMappingData(void* pTemplate)
382389
#endif
383390
if (fd != -1)
384391
{
385-
off_t maxFileSize = MAX_TEMPLATE_THUNK_TYPES * 0x10000;
392+
off_t maxFileSize = MAX_TEMPLATE_THUNK_TYPES * 0x10000; // The largest page size we support currently is 64KB.
386393
if (ftruncate(fd, maxFileSize) == -1) // Reserve a decent size chunk of logical memory for these things.
387394
{
388395
close(fd);
@@ -445,6 +452,9 @@ void* VMToOSInterface::CreateTemplate(void* pImageTemplate, size_t templateSize,
445452
return NULL;
446453
}
447454

455+
int templatesCreated = __atomic_add_fetch(&pThunkData->templatesCreated, 1, __ATOMIC_SEQ_CST);
456+
assert(templatesCreated <= MAX_TEMPLATE_THUNK_TYPES);
457+
448458
if (!pThunkData->imageTemplates)
449459
{
450460
// Need to allocate a memory mapped region to fill in the data

src/coreclr/vm/arm64/thunktemplates.S

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,33 @@
55
#include "asmconstants.h"
66

77
#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE
8-
98
#define POINTER_SIZE 0x08
9+
// Since Arm64 supports 4KB, 16KB and 64KB page sizes, as the templates is only defined for 16KB page size, this cannot be used
10+
// in a general purpose Linux environment. However it CAN be used on Apple platforms, which specify that 16KB is the system standard
11+
// page size.
1012

1113
#define THUNKS_MAP_SIZE 0x4000
1214

1315
#define PAGE_SIZE 0x4000
1416
#define PAGE_SIZE_LOG2 14
1517

1618

17-
#define DATA_SLOT(stub, field, thunksPerPage, thunkTemplateName) . - (. - C_FUNC(thunkTemplateName)) + \THUNKS_MAP_SIZE + stub##Data__##field + IN_PAGE_INDEX * STUB_THUNK_CODESIZE
19+
#define DATA_SLOT(stub, field, thunkSize, thunkTemplateName) C_FUNC(thunkTemplateName) + THUNKS_MAP_SIZE + stub##Data__##field + IN_PAGE_INDEX * thunkSize
1820

1921
// ----------
2022
// StubPrecode
2123
// ----------
2224

2325
#define STUB_PRECODE_CODESIZE 0x18 // 3 instructions, 4 bytes each (and we also have 12 bytes of padding)
2426
#define STUB_PRECODE_DATASIZE 0x18 // 2 qwords + 1 byte
25-
.set STUB_PRECODE_NUM_THUNKS_PER_MAPPING,(THUNKS_MAP_SIZE / STUB_PRECODE_CODESIZE)
27+
.set STUB_PRECODE_NUM_THUNKS_PER_MAPPING, (THUNKS_MAP_SIZE / STUB_PRECODE_CODESIZE)
2628

2729
.macro THUNKS_BLOCK_STUB_PRECODE
2830
IN_PAGE_INDEX = 0
29-
.rept STUB_PRECODE_NUM_THUNKS_PER_MAP
31+
.rept STUB_PRECODE_NUM_THUNKS_PER_MAPPING
3032

31-
ldr x10, DATA_SLOT(StubPrecode, Target, STUB_PRECODE_NUM_THUNKS_PER_MAPPING, StubPrecodeCodeTemplate)
32-
ldr x12, DATA_SLOT(StubPrecode, SecretParam, STUB_PRECODE_NUM_THUNKS_PER_MAPPING, StubPrecodeCodeTemplate)
33+
ldr x10, DATA_SLOT(StubPrecode, Target, STUB_PRECODE_CODESIZE, StubPrecodeCodeTemplate)
34+
ldr x12, DATA_SLOT(StubPrecode, SecretParam, STUB_PRECODE_CODESIZE, StubPrecodeCodeTemplate)
3335
br x10
3436

3537
brk 0xf000 // Stubs need to be 24-byte in size to allow for the data to be 2 pointers + 1 byte
@@ -53,18 +55,17 @@ LEAF_END_MARKED StubPrecodeCodeTemplate, _TEXT
5355
#define FIXUP_PRECODE_CODESIZE 0x18 // 5 instructions, 4 bytes each (and we also have 4 bytes of padding)
5456
#define FIXUP_PRECODE_DATASIZE 0x18 // 3 qwords
5557
.set FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING,(THUNKS_MAP_SIZE / FIXUP_PRECODE_CODESIZE)
56-
#define FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING (THUNKS_MAP_SIZE / FIXUP_PRECODE_CODESIZE)
5758

5859
.macro THUNKS_BLOCK_FIXUP_PRECODE
5960
IN_PAGE_INDEX = 0
6061
.rept FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING
6162

62-
ldr x11, DATA_SLOT(FixupPrecode, Target, FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING, FixupPrecodeCodeTemplate)
63+
ldr x11, DATA_SLOT(FixupPrecode, Target, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate)
6364
br x11
64-
ldr x12, DATA_SLOT(FixupPrecode, MethodDesc, FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING, FixupPrecodeCodeTemplate)
65-
ldr x11, DATA_SLOT(FixupPrecode, PrecodeFixupThunk, FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING, FixupPrecodeCodeTemplate)
65+
ldr x12, DATA_SLOT(FixupPrecode, MethodDesc, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate)
66+
ldr x11, DATA_SLOT(FixupPrecode, PrecodeFixupThunk, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate)
6667
br x11
67-
brk 0xf000 // Stubs need to be 24-byte in size to allow for the data to be 2 pointers
68+
brk 0xf000 // Stubs need to be 24-byte in size to allow for the data to be 3 pointers
6869

6970
IN_PAGE_INDEX = IN_PAGE_INDEX + 1
7071
.endr
@@ -82,23 +83,23 @@ LEAF_END_MARKED FixupPrecodeCodeTemplate, _TEXT
8283

8384
#define CALLCOUNTING_CODESIZE 0x28 // 5 instructions, 4 bytes each (and we also have 4 bytes of padding)
8485
#define CALLCOUNTING_DATASIZE 0x18 // 3 qwords
85-
#define CALLCOUNTING_NUM_THUNKS_PER_MAPPING (THUNKS_MAP_SIZE / CALLCOUNTING_CODESIZE)
86+
.set CALLCOUNTING_NUM_THUNKS_PER_MAPPING, (THUNKS_MAP_SIZE / CALLCOUNTING_CODESIZE)
8687

8788
.macro THUNKS_BLOCK_CALLCOUNTING
8889
IN_PAGE_INDEX = 0
8990
.rept CALLCOUNTING_NUM_THUNKS_PER_MAPPING
9091

91-
ldr x9, DATA_SLOT(CallCountingStub, RemainingCallCountCell)
92+
ldr x9, DATA_SLOT(CallCountingStub, RemainingCallCountCell, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate)
9293
ldrh w10, [x9]
9394
subs w10, w10, #1
9495
strh w10, [x9]
95-
beq LOCAL_LABEL(CountReachedZero\IN_PAGE_INDEX)
96-
ldr x9, DATA_SLOT(CallCountingStub, TargetForMethod)
96+
beq 0f
97+
ldr x9, DATA_SLOT(CallCountingStub, TargetForMethod, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate)
9798
br x9
98-
LOCAL_LABEL(CountReachedZero\IN_PAGE_INDEX):
99-
ldr x10, DATA_SLOT(CallCountingStub, TargetForThresholdReached)
99+
0:
100+
ldr x10, DATA_SLOT(CallCountingStub, TargetForThresholdReached, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate)
100101
br x10
101-
brk 0xf000 // Stubs need to be 16-byte in size to allow for the data to be 2 pointers
102+
brk 0xf000 // Stubs need to be 40-byte in size to allow for the data to be pointer aligned
102103

103104
IN_PAGE_INDEX = IN_PAGE_INDEX + 1
104105
.endr
@@ -109,8 +110,11 @@ LOCAL_LABEL(CountReachedZero\IN_PAGE_INDEX):
109110
LEAF_ENTRY CallCountingStubCodeTemplate
110111
THUNKS_BLOCK_CALLCOUNTING
111112
LEAF_END_MARKED CallCountingStubCodeTemplate, _TEXT
113+
#endif
112114

113-
#else
115+
#ifdef DATA_SLOT
116+
#undef DATA_SLOT
117+
#endif
114118
#define DATA_SLOT(stub, field) . - (. - C_FUNC(stub##Code\STUB_PAGE_SIZE)) + \STUB_PAGE_SIZE + stub##Data__##field
115119

116120
.irp STUB_PAGE_SIZE, 16384, 32768, 65536
@@ -144,4 +148,3 @@ LOCAL_LABEL(CountReachedZero\STUB_PAGE_SIZE):
144148
LEAF_END_MARKED CallCountingStubCode\STUB_PAGE_SIZE
145149

146150
.endr
147-
#endif

src/coreclr/vm/callcounting.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,12 @@ void CallCountingStub::StaticInitialize()
318318
EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Unsupported OS page size"));
319319
}
320320
#undef ENUM_PAGE_SIZE
321+
322+
if (CallCountingStubCodeTemplate != NULL && pageSize != 0x4000)
323+
{
324+
// This should fail if the template is used on a platform which doesn't support the supported page size for templates
325+
ThrowHR(COR_E_EXECUTIONENGINE);
326+
}
321327
#else
322328
_ASSERTE((SIZE_T)((BYTE*)CallCountingStubCode_End - (BYTE*)CallCountingStubCode) <= CallCountingStub::CodeSize);
323329
#endif

src/coreclr/vm/precode.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,13 @@ void StubPrecode::StaticInitialize()
523523
default:
524524
EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Unsupported OS page size"));
525525
}
526+
527+
if (StubPrecodeCodeTemplate != NULL && pageSize != 0x4000)
528+
{
529+
// This should fail if the template is used on a platform which doesn't support the supported page size for templates
530+
ThrowHR(COR_E_EXECUTIONENGINE);
531+
}
532+
526533
#undef ENUM_PAGE_SIZE
527534
#else
528535
_ASSERTE((SIZE_T)((BYTE*)StubPrecodeCode_End - (BYTE*)StubPrecodeCode) <= StubPrecode::CodeSize);
@@ -663,6 +670,12 @@ void FixupPrecode::StaticInitialize()
663670
EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Unsupported OS page size"));
664671
}
665672
#undef ENUM_PAGE_SIZE
673+
674+
if (FixupPrecodeCodeTemplate != NULL && pageSize != 0x4000)
675+
{
676+
// This should fail if the template is used on a platform which doesn't support the supported page size for templates
677+
ThrowHR(COR_E_EXECUTIONENGINE);
678+
}
666679
#else
667680
_ASSERTE((SIZE_T)((BYTE*)FixupPrecodeCode_End - (BYTE*)FixupPrecodeCode) <= FixupPrecode::CodeSize);
668681
#endif

0 commit comments

Comments
 (0)