-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Open
Labels
backend:AArch64clang:codegenIR generation bugs: mangling, exceptions, etc.IR generation bugs: mangling, exceptions, etc.platform:windows
Description
Description
Clang writes out ARM64EC code ranges on 4-byte granularity. Windows expects code ranges on page granularity (4096 bytes). The end result is catastrophically broken code ranges in CHPE metadata.
EDIT: Attempting to executing broken code ranges will result in access violation .
Affected versions
At least Clang 21.1.4 and 21.1.5, I did not try older versions.
Reproducing
The easiest way to reproduce this is by forcefully aligning a function. This will produce a "hole" in range.
Files
code.amd64.cpp:
extern "C" {
__declspec(code_seg(".text1$aaa")) int amd64_code_before() { return 0x12340001; }
__declspec(code_seg(".text3$zzz")) int amd64_code_after() { return 0x12340005; }
}code.arm64.cpp:
extern "C" {
__declspec(code_seg(".text2$bbb")) __declspec(align(0x800)) int arm64_code_first() {
return 0x12340002;
}
__declspec(code_seg(".text2$ccc")) __declspec(align(0x800)) int arm64_code_middle() {
return 0x12340003;
}
__declspec(code_seg(".text2$ddd")) int arm64_code_last() {
return 0x12340004;
}
}main.cpp:
#include <stdio.h>
extern "C" int amd64_code_before();
extern "C" int arm64_code_first();
extern "C" int arm64_code_middle();
extern "C" int arm64_code_last();
extern "C" int amd64_code_after();
extern "C" char RtlIsEcCode(uintptr_t CodePointer);
struct range { unsigned start; unsigned length; };
extern "C" char __ImageBase;
extern "C" unsigned __chpe_metadata[];
int main() {
range* code_map = (range*)((char*)&__ImageBase + __chpe_metadata[1]);
unsigned code_map_count = __chpe_metadata[2];
printf("Code ranges:\n");
for (int i = 0; i < code_map_count; ++i) {
printf("%08X %08X\n", code_map[i].start, code_map[i].length);
}
printf("amd64_code_before %zx is_ec %u\n", (size_t)amd64_code_before - (size_t)&__ImageBase, RtlIsEcCode((uintptr_t)amd64_code_before));
printf("arm64_code_first %zx is_ec %u\n", (size_t)arm64_code_first - (size_t)&__ImageBase, RtlIsEcCode((uintptr_t)arm64_code_first));
printf("arm64_code_middle %zx is_ec %u\n", (size_t)arm64_code_middle - (size_t)&__ImageBase, RtlIsEcCode((uintptr_t)arm64_code_middle));
printf("arm64_code_last %zx is_ec %u\n", (size_t)arm64_code_last - (size_t)&__ImageBase, RtlIsEcCode((uintptr_t)arm64_code_last));
printf("amd64_code_after %zx is_ec %u\n", (size_t)amd64_code_after - (size_t)&__ImageBase, RtlIsEcCode((uintptr_t)amd64_code_after));
}build.bat:
"D:/LLVM/LLVM-21.1.5/bin/clang-cl.exe" -nologo -O2 -GS- -Fomain.cpp.obj -c main.cpp
"D:/LLVM/LLVM-21.1.5/bin/clang-cl.exe" -nologo -O2 -GS- -Focode.amd64.cpp.obj -c code.amd64.cpp
"D:/LLVM/LLVM-21.1.5/bin/clang-cl.exe" -nologo -O2 -GS- -arm64EC -Focode.arm64.cpp.obj -c code.arm64.cpp
"D:/LLVM/LLVM-21.1.5/bin/lld-link.exe" -nologo -Brepro -machine:ARM64EC -subsystem:console -out:range-test-llvm.exe "../arm64/arm64rt.lib" ucrt.lib msvcrt.lib ntdll.lib main.cpp.obj code.amd64.cpp.obj code.arm64.cpp.objOutput
Code ranges:
00001001 000003D4
00002002 00000F06
00009002 00000006
0000A801 0000081C
0000C002 00000006
amd64_code_before 9000 is_ec 0
arm64_code_first a800 is_ec 1
arm64_code_middle b000 is_ec 0
arm64_code_last b010 is_ec 0
amd64_code_after c000 is_ec 0Expected output
Code ranges:
00001001 000003D4
00002002 00000F06
00009002 00000006
0000A001 0000100C
0000C002 00000006
amd64_code_before 9000 is_ec 0
arm64_code_first a800 is_ec 1
arm64_code_middle b000 is_ec 1
arm64_code_last b010 is_ec 1
amd64_code_after c000 is_ec 0Workaround
Patching out final PE file externally to fix clangs broken code ranges.
Metadata
Metadata
Assignees
Labels
backend:AArch64clang:codegenIR generation bugs: mangling, exceptions, etc.IR generation bugs: mangling, exceptions, etc.platform:windows