[lld] [LLD][COFF] Add support for ARM64EC auxiliary IAT (PR #108304)

Jacek Caban via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 12 08:37:32 PDT 2024


================
@@ -1071,19 +1071,39 @@ void ImportFile::parse() {
   this->hdr = hdr;
   externalName = extName;
 
-  impSym = ctx.symtab.addImportData(impName, this);
+  bool isCode = hdr->getType() == llvm::COFF::IMPORT_CODE;
+
+  if (ctx.config.machine != ARM64EC) {
+    impSym = ctx.symtab.addImportData(impName, this, location);
+  } else {
+    // In addition to the regular IAT, ARM64EC also contains an auxiliary IAT,
+    // which holds addresses that are guaranteed to be callable directly from
+    // ARM64 code. Function symbol naming is swapped: __imp_ symbols refer to
+    // the auxiliary IAT, while __imp_aux_ symbols refer to the regular IAT. For
+    // data imports, the naming is reversed.
----------------
cjacek wrote:

The way mingw-w64 handles DATA in msvcrt .def files should mostly work fine. Using `_fpreset` as an example: `__imp__fpreset` would point to msvcrt's ARM64EC export thunk, which cannot be called directly. However, since we don’t declare it as dllimport, _fpreset from the static library will be called like any other non-imported function. The `_fpreset` implementation looks like this:

```
void _fpreset (void)
{
  (* __MINGW_IMP_SYMBOL(_fpreset))();
}
```

Here, the `__imp_` symbol is treated as a pointer from the C compiler's perspective. On ARM64EC, any call via a pointer needs to pass through the call checker, so it's fine that `__imp__fpreset` points to the thunk. The call checker invoked directly by the `_fpreset` code will handle this.

However, there are some edge cases where this approach might cause problems. For example, if a caller defines `_fpreset` with the `dllimport` attribute, it would crash on ARM64EC, whereas it wouldn't on other platforms. This is a limitation of ARM64EC that we can't easily resolve (although, in this case, we could likely modify `_fpreset` to avoid using DATA, but there are other situations where that won’t be feasible).

mingw-w64-crt employs various tricks with `__imp_` symbols quite extensively. Most of this should work fine, but we should review these cases to ensure compatibility.

On a related note, we will likely need to consider defining `__imp_aux_` in mingw-w64-crt as well. I created a [Wine MR](https://gitlab.winehq.org/wine/wine/-/merge_requests/6487) with an example of how this might be done, but it will be more complex for mingw-w64, where we use these symbols in more creative ways.

> How does this work with x86_64 code in an arm64ec module? When x86_64 code calls a dllimport function, it'd load the address from __imp_func, won't that be the auxillary IAT, which contains a native arm64ec version?

According to my testing, the MSVC linker special-cases these symbols and redirects them to the `__imp_aux_` symbol. I have a draft of its implementation queued [here](https://github.com/cjacek/llvm-project/commit/075ac8295b6b5a987ff8244dea10ca690c33adaf).

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


More information about the llvm-commits mailing list