-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Native Arm support on Windows #227
Comments
I'd hope that the EH code would continue to work, though there might be some small changes to the unwind structure. It looks as if Windows uses the AAPCS on Arm, so the assembly should Just Work. Hopefully there will be GitHub hosted Actions Runners for Windows/Arm soon, now that there are Arm machines in Azure, so we can add it to CI and see. |
Thanks, that sounds promising! So you wouldn’t expect any required changes in LLVM/Clang? |
Shouldn't. I can't remember if clang will unconditionally generate objc_msgSend for Windows or if it's only on x86, it might need an extra check added in CGObjCGNU.cpp to prevent it falling back to the objc_msg_lookup path. |
Great to hear, thanks! Since the CI for this is running on Azure (not GitHub Actions), it sounds like we could already give this a try. |
I have modified the tools-windows-msvc scripts to include the aarch64 windows triplet (currently in a separate branch) and tried to build the toolchain. The libobjc2 build fails while generating objc_msgSend.S:
Compiler: LLVM 14.0.5 Windows on ARM |
This is the LLVM change that errors out unsupported symbol locations on aarch64: https://www.mail-archive.com/[email protected]/msg04763.html |
Related: |
Dynamic Address RelocationAfter some consideration, I've come up with something that fixes the dynamic address relocation issue on Windows on ARM (WoA). There is no Global Offset Table (GOT) in COFF that we can use to resolve the PC-relative offset/address of the symbol in position independent code. In PIC, the runtime loader is used (ld.so) to determine the address. The linker emits a dynamic relocation. The loader performs a symbol lookup to determine the associated symbol value at runtime. ELF aarch64
Mach-O aarch64
I have generated some example assembly code (clang -S), yet the generated assembly uses a relocation scheme based on a fixed offset (load base + constant). GCC generates assembly with dynamic lookups, but is not available on WoA. However, this approach should work for a PIE or shared library as long as everything is located in one object file (Correct me if I'm wrong @davidchisnall ). COFF aarch64
The PE format is nicely documented, but lacks important details about loader interactions PE-Format Specification COFF Relocations (all supported COFF relocation types in LLVM RelocationTypesARM64). Related Links: Structured Exception HandlingAdding macros to define the platform-dependent exception handling can be done using ifdef _WIN64 and some abstraction (see objc_msgSend.x86-64.S) I'll test this on my WoA VM later this day. |
I've patched the msgSend assembly, but there is a compiler crash when building the legacy GNU ABI protocol hack:
libobjc2-protocol2-crash-logs.zip Stubbing it out fixes this crash, but linking the dll fails:
|
It looks as if the Windows spelling of |
The docs say that this comes from Ntdll.dll, which I thought was linked by default, but maybe isn't on Arm?
Thought about this too, but had no way of testing it. I’ll just try to explicitly link ntdll.
It looks as if the Windows spelling of __clear_cache is FlushInstructionCache. It should be possible to write a static function in block_to_imp.c that wraps this for compatibility.
Makes sense!
Thank you :)
|
The project builds now, after some modifications to obj_msgSend (text relocation instead of GOT, add linker directives for PE/COFF), using FlushInstructionCache in block_to_imp.c, and linking ntdll.dll. The objc_msgSend tests are still failing. I guess that is because I have not finished replacing all cfi directives with seh directives (conditionally ofc). |
Very cool! Is there a branch with your modifications to check it out? |
It is a bit hacky right now :) |
@hmelder Did you ever finish looking at this? We've had a couple of requests for this library via partners, so I am investigating the feasibility. |
I am now actively working on it (started yesterday), and currently studying aarch64 assembly and SEH on WoA
… On 13. Nov 2023, at 11:38, Anthony Roberts ***@***.***> wrote:
@hmelder <https://github.com/hmelder> Did you ever finish looking at this? We've had a couple of requests for this library via partners, so I am investigating the feasibility.
—
Reply to this email directly, view it on GitHub <#227 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AK35JFDWXL5MLAQTVYY3XHLYEH2CVAVCNFSM5XUTIG62U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOBQG44TAMZTGM2Q>.
You are receiving this because you were mentioned.
|
Okay, great! Feel free to get in contact with me (email in profile) if you have any particularly difficult issues, or run into toolchain problems |
Update: The aarch64 msgSend implementation is now working but unwinding fails, as I have not translated all CFI directives to the corresponding SEH ones. Checking out diff --git a/Test/objc_msgSend.m b/Test/objc_msgSend.m
index 4689172..49dd8da 100644
--- a/Test/objc_msgSend.m
+++ b/Test/objc_msgSend.m
@@ -91,7 +91,7 @@ __attribute__((objc_root_class))
+ (void)initialize
{
[self printf: "Format %s %d %f%c", "string", 42, 42.0, '\n'];
- @throw self;
+ //@throw self;
}
+ nothing { return 0; }
@end
@@ -179,6 +179,7 @@ int main(void)
__objc_msg_forward3 = forward_slot;
TestCls = objc_getClass("MsgTest");
int exceptionThrown = 0;
+ /*
@try {
objc_msgSend(TestCls, @selector(foo));
} @catch (id e)
@@ -187,6 +188,7 @@ int main(void)
exceptionThrown = 1;
}
assert(exceptionThrown && "An exception was thrown");
+ */
assert((id)0x42 == objc_msgSend(TestCls, @selector(foo)));
objc_msgSend(TestCls, @selector(nothing));
objc_msgSend(TestCls, @selector(missing)); Sadly, SEH directives are not documented by MS. I was able to get an intuition for it by letting clang output assembly, and from this mailing list post: https://sourceware.org/legacy-ml/binutils/2009-08/msg00193.html @anthony-linaro are you familiar with exception handling on Windows and how to translate the CFI directives properly? libobjc2/objc_msgSend.aarch64.S Line 75 in 1d2e52e
|
The clang backend seems to be very sensitive about SEH directives. I keep hitting an issue where the length of the function can't be determined: clang -cc1as: fatal error: error in backend: Failed to evaluate function length in SEH unwind info This error originates from MCWin64EH.cpp#L298 The only similar issue I found is from a recent bug report: https://discourse.llvm.org/t/why-is-lldb-not-showing-debug-info-for-my-assembly-file/65412 |
This is with the directives added in this commit: bac40ba |
@ZacWalk is the person to ask here, I think! I have sent an email to him with a link to this issue. |
Perfekt. Thank you :) |
This normally appears if there's some aspect of the instruction sequence which can't be measured immediately. In most cases, this can happen if there's some align directive in a function; the SEH unwind info needs to be created at a stage when sizes/layouts/alignments haven't been settled in the LLVM assembler yet.
I see a couple of
Indeed, although that one is for the x86_64 SEH format, which is kinda different from the ARM/ARM64 ones. I recommend reading https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling for an overall picture of how it works, then llvm/llvm-project@5b86d13 probably is the primary "reference" for the basic set of directives on AArch64. (A couple more have been added afterwards, but they're only relevant for very special cases.) Looking at the output from Clang certainly is a good way to go. One primary difference to the x86_64 form of SEH, is that each function has one prologue and zero or more epilogues. Each of these (prologue, epilogue) are tightly packed; there's exactly one SEH directive for each instruction in the prologue/epilogue regions. On x86_64, the SEH opcodes encode the distance from the start of the function, for that directive, but for ARM/ARM64, the SEH opcodes don't encode any offsets, but each one is assumed to correspond to one instruction. Thus, from Since Clang 16, Clang produces errors if there are mismatches between the count of instructions and opcodes in prologue/epilogues, see llvm/llvm-project@cbd8464. In this case, it looks like the function has a huge amount of instructions before the parts that actually are relevant for unwinding. I'm not sure what the best way to deal with this would be; either fill in with a huge amount of |
Also, some minor comments on earlier posts here:
Within PEs, this isn't a text relocation, as When referencing data in another DLL, it gets referenced indirectly via a symbol extern int var;
extern __declspec(dllimport) int var2;
int get(void) {
return var;
}
int get2(void) {
return var2;
}
In both cases, either The corresponding version of
I.e. the GOT relative uses are equivalent to |
I have been working on a SEH implementation for GCC here. Apart from pdata/xdata generation, on aarch64 there seems to be something different with the establisher frame in RtlUnwindEx and RaiseException API’s. This affects EH in GCC because it is unable to hit landing pads correctly. Just mentioning it here as you might hit that problem. If I work out what is different with those APIs I will feed back here. I did notice that EH in CLANG looked to use the UCRT handlers. Maybe this won’t be a problem for any LLVM based projects. GCC has its own EH. |
@mstorsjo thank you for this detailed explaination. This explains the behaviour I have seem when omitting the prologue and/or epilogue, or altering op codes in them. I will try to get an intuition for annotating the SEH directives by hand on arm64, as they seem to be quite delicate :) Regarding your second comment, I was not aware of the __IMP scheme and IAT in January, but already implemented it last week with the IAT in mind (As the symbol is in the same PE image, IAT access was not needed). |
That would be great! |
I'm not sure which details you're referring to here? Clang can operate either in MSVC mode or mingw mode. In MSVC mode it uses the same things as MSVC does. In mingw mode, it uses either libgcc or LLVM's libunwind for exception handling, together with libcxxabi (which should be functionally equivalent to libstdc++/libsupc++). Clang in mingw mode works just as well on top of msvcrt as on top of UCRT. Before LLVM's libunwind supported SEH, I actually was using libgcc's unwind implementation here, and I had that patched up for aarch64 at some point, see https://martin.st/temp/0001-Patch-unwind-seh.c-to-handle-aarch64-in-addition-to-.patch (although I think I switched from libgcc to LLVM's libunwind for SEH before switching from DWARF to SEH on aarch64 properly, so it might not have been fully tested). The corresponding patch for LLVM's libunwind, to extend the SEH implementation to aarch64, was roughly similarly straightforward, with a bit more boilerplate to handle: llvm/llvm-project@09cf637
IIRC, on ARM/AArch64 the "establisher frame" is the value of SP on entry to the function - which differs from what it was on x86_64. I don't remember needing to worry about this distinction within libunwind though but I presume it's required somewhere in the code generation for the landing pads? Within libgcc/libunwind, this value mostly get passed through as-is from the parameter as given to In the case of setjmp/longjmp, when using the msvcrt/UCRT implementations of these, which use |
See #249 |
With Microsoft announcing Arm-native developer toolsets at Build this year, we were wondering what it would take to get libobjc2 support this. Would this require any new implementations of the assembly, exception handling code, or compiler support? Or should the existing EH for Windows, Aarch64 implementation of objc_msgSend, and compiler support work in theory?
I realize probably no one has tried this, but it would be great to get a sense of what work would be involved to get this supported.
The text was updated successfully, but these errors were encountered: