[lld] [LLD][COFF] Add support for ARM64EC import call thunks. (PR #107931)

Jacek Caban via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 10 14:02:27 PDT 2024


================
@@ -1093,4 +1093,21 @@ void CHPERedirectionChunk::writeTo(uint8_t *buf) const {
   }
 }
 
+ImportThunkChunkARM64EC::ImportThunkChunkARM64EC(ImportFile *file)
+    : ImportThunkChunk(file->ctx, file->impSym), file(file) {}
+
+void ImportThunkChunkARM64EC::writeTo(uint8_t *buf) const {
+  memcpy(buf, importThunkARM64EC, sizeof(importThunkARM64EC));
+  applyArm64Addr(buf, file->impSym->getRVA(), rva, 12);
+  applyArm64Ldr(buf + 4, file->impSym->getRVA() & 0xfff);
+
+  uint32_t exitThunkRVA = exitThunk ? exitThunk->getRVA() : 0;
----------------
cjacek wrote:

Yes, this behavior would be bogus. I followed MSVC's approach in these cases and implemented it the same way (since it's an RVA, it sets x10 to the image base, which requires addrp + add). We could either zero x10 or leave it unchanged in these cases. It's unlikely to matter for the OS loader, so I can make this change if you prefer.

Emitting a warning in such scenarios might be tempting, but we can’t do that because there are valid situations where an exit thunk may be missing. For example, if an application only ever takes the function’s address and never calls it directly via the import table. In these cases, the application uses `__imp_aux_*` symbols instead of the regular `__imp_*` symbols. We still need to populate the auxiliary IAT, which requires those thunks, even if they’re never used.

If we tracked `__imp_` and `__imp_aux_` usage separately, we might be able to skip the thunk and fill the auxiliary IAT with zeroes or something similar. However, since this behavior isn’t documented, skipping thunks would require ensuring the OS loader can handle it in all cases, which is tricky to verify with black-box testing. Therefore, it feels safer to follow MSVC’s behavior.

Another situation where exit thunks may not be available is when hand-written assembly is used to make the call. In such cases, if the callee is ARM64EC, it should still work because the thunk would usually be skipped. It’s possible the thunk wouldn’t be skipped (for example, if patching is detected in the callee’s area but not the callee itself). If the call goes through the thunk, `__icall_helper_arm64ec` wouldn’t use an exit thunk if the callee is ARM64EC. It would only fail if the callee isn’t ARM64EC, which the developer may know will never be the case.

https://github.com/llvm/llvm-project/pull/107931


More information about the llvm-commits mailing list