Skip to content

[LLD][COFF] Add support for locally imported EC symbols #114985

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

Merged
merged 1 commit into from
Nov 6, 2024

Conversation

cjacek
Copy link
Contributor

@cjacek cjacek commented Nov 5, 2024

Allow imported symbols to be recognized in both mangled and demangled forms. Support __imp_aux_ symbols in addition to __imp_ symbols.

Allow imported symbols to be recognized in both mangled and demangled forms.
Support __imp_aux_ symbols in addition to __imp_ symbols.
@cjacek
Copy link
Contributor Author

cjacek commented Nov 5, 2024

Locally imported symbols are problematic on ARM64EC due to the existence of both __imp_ and __imp_aux_ symbols, which provide different guarantees. For example, if we aim to match actual imports, and the symbol is defined as an x86_64 function, the _imp symbol would need to use a generated thunk, but only when referenced from ARM64EC code. MSVC does not seem to support this behavior, and I have followed that pattern here. This approach should be sufficient for most cases and allows for emitting a proper warning.

@llvmbot
Copy link
Member

llvmbot commented Nov 5, 2024

@llvm/pr-subscribers-lld

@llvm/pr-subscribers-lld-coff

Author: Jacek Caban (cjacek)

Changes

Allow imported symbols to be recognized in both mangled and demangled forms. Support __imp_aux_ symbols in addition to __imp_ symbols.


Full diff: https://github.com/llvm/llvm-project/pull/114985.diff

2 Files Affected:

  • (modified) lld/COFF/SymbolTable.cpp (+24-7)
  • (added) lld/test/COFF/locally-imported-arm64ec.test (+68)
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index aeeebbb4e332ab..35d54d4945f7f4 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -501,13 +501,30 @@ bool SymbolTable::resolveRemainingUndefines() {
     // If we can resolve a symbol by removing __imp_ prefix, do that.
     // This odd rule is for compatibility with MSVC linker.
     if (name.starts_with("__imp_")) {
-      Symbol *imp = find(name.substr(strlen("__imp_")));
-      if (imp) {
-        // The unprefixed symbol might come later in symMap, so handle it now
-        // so that the condition below can be appropriately applied.
-        auto *undef = dyn_cast<Undefined>(imp);
-        if (undef) {
-          undef->resolveWeakAlias();
+      auto findLocalSym = [&](StringRef n) {
+        Symbol *sym = find(n);
+        if (auto undef = dyn_cast_or_null<Undefined>(sym)) {
+          // The unprefixed symbol might come later in symMap, so handle it now
+          // if needed.
+          if (!undef->resolveWeakAlias())
+            sym = nullptr;
+        }
+        return sym;
+      };
+
+      StringRef impName = name.substr(strlen("__imp_"));
+      Symbol *imp = findLocalSym(impName);
+      if (!imp && isArm64EC(ctx.config.machine)) {
+        // Try to use the mangled symbol on ARM64EC.
+        std::optional<std::string> mangledName =
+            getArm64ECMangledFunctionName(impName);
+        if (mangledName)
+          imp = findLocalSym(*mangledName);
+        if (!imp && impName.consume_front("aux_")) {
+          // If it's a __imp_aux_ symbol, try skipping the aux_ prefix.
+          imp = findLocalSym(impName);
+          if (!imp && (mangledName = getArm64ECMangledFunctionName(impName)))
+            imp = findLocalSym(*mangledName);
         }
       }
       if (imp && imp->isLazy()) {
diff --git a/lld/test/COFF/locally-imported-arm64ec.test b/lld/test/COFF/locally-imported-arm64ec.test
new file mode 100644
index 00000000000000..9ec55c2dceaefc
--- /dev/null
+++ b/lld/test/COFF/locally-imported-arm64ec.test
@@ -0,0 +1,68 @@
+REQUIRES: aarch64
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows funcs.s -o funcs.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func-mangled.s -o func-mangled.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impsym.s -o impsym.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impauxsym.s -o impauxsym.obj
+
+Ensure that when both mangled and demangled symbols are present, the __imp_ symbol
+resolves to the demangled symbol.
+
+RUN: lld-link -machine:arm64ec -dll -noentry funcs.obj impsym.obj -out:impsym.dll
+
+RUN: llvm-readobj --coff-basereloc impsym.dll | FileCheck --check-prefix=RELOCS %s
+RELOCS:       Entry {
+RELOCS-NEXT:    Type: DIR64
+RELOCS-NEXT:    Address: 0x2000
+RELOCS-NEXT:  }
+
+RUN: llvm-readobj --hex-dump=.test impsym.dll | FileCheck --check-prefix=TEST %s
+TEST: 0x180003000 00200000
+
+RUN: llvm-readobj --hex-dump=.rdata impsym.dll | FileCheck --check-prefix=RDATA-DEMANGLED %s
+RDATA-MANGLED:   0x180002000 00100080 01000000
+RDATA-DEMANGLED: 0x180002000 04100080 01000000
+
+
+Ensure that when both mangled and demangled symbols are present, the __imp_aux_ symbol
+resolves to the demangled symbol.
+
+RUN: lld-link -machine:arm64ec -dll -noentry funcs.obj impauxsym.obj -out:impauxsym.dll
+RUN: llvm-readobj --hex-dump=.test impauxsym.dll | FileCheck --check-prefix=TEST %s
+RUN: llvm-readobj --hex-dump=.rdata impauxsym.dll | FileCheck --check-prefix=RDATA-DEMANGLED %s
+
+Ensure that if only the mangled symbol is present, the __imp_ symbol resolves to it.
+
+RUN: lld-link -machine:arm64ec -dll -noentry func-mangled.obj impsym.obj -out:impsym-mangled.dll
+RUN: llvm-readobj --coff-basereloc impsym-mangled.dll | FileCheck --check-prefix=RELOCS %s
+RUN: llvm-readobj --hex-dump=.test impsym-mangled.dll | FileCheck --check-prefix=TEST %s
+RUN: llvm-readobj --hex-dump=.rdata impsym-mangled.dll | FileCheck --check-prefix=RDATA-MANGLED %s
+
+Ensure that if only the mangled symbol is present, the __imp_aux_ symbol resolves to it.
+
+RUN: lld-link -machine:arm64ec -dll -noentry func-mangled.obj impauxsym.obj -out:impauxsym-mangled.dll
+RUN: llvm-readobj --hex-dump=.test impauxsym-mangled.dll | FileCheck --check-prefix=TEST %s
+RUN: llvm-readobj --hex-dump=.rdata impauxsym-mangled.dll | FileCheck --check-prefix=RDATA-MANGLED %s
+
+#--- funcs.s
+    .globl "#myfunc"
+"#myfunc":
+    ret
+    .text
+    .globl myfunc
+myfunc:
+    ret
+
+#--- func-mangled.s
+    .globl "#myfunc"
+"#myfunc":
+    ret
+
+#--- impsym.s
+    .section .test, "r"
+    .rva __imp_myfunc
+
+#--- impauxsym.s
+    .section .test, "r"
+    .rva __imp_aux_myfunc

@llvmbot
Copy link
Member

llvmbot commented Nov 5, 2024

@llvm/pr-subscribers-platform-windows

Author: Jacek Caban (cjacek)

Changes

Allow imported symbols to be recognized in both mangled and demangled forms. Support __imp_aux_ symbols in addition to __imp_ symbols.


Full diff: https://github.com/llvm/llvm-project/pull/114985.diff

2 Files Affected:

  • (modified) lld/COFF/SymbolTable.cpp (+24-7)
  • (added) lld/test/COFF/locally-imported-arm64ec.test (+68)
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index aeeebbb4e332ab..35d54d4945f7f4 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -501,13 +501,30 @@ bool SymbolTable::resolveRemainingUndefines() {
     // If we can resolve a symbol by removing __imp_ prefix, do that.
     // This odd rule is for compatibility with MSVC linker.
     if (name.starts_with("__imp_")) {
-      Symbol *imp = find(name.substr(strlen("__imp_")));
-      if (imp) {
-        // The unprefixed symbol might come later in symMap, so handle it now
-        // so that the condition below can be appropriately applied.
-        auto *undef = dyn_cast<Undefined>(imp);
-        if (undef) {
-          undef->resolveWeakAlias();
+      auto findLocalSym = [&](StringRef n) {
+        Symbol *sym = find(n);
+        if (auto undef = dyn_cast_or_null<Undefined>(sym)) {
+          // The unprefixed symbol might come later in symMap, so handle it now
+          // if needed.
+          if (!undef->resolveWeakAlias())
+            sym = nullptr;
+        }
+        return sym;
+      };
+
+      StringRef impName = name.substr(strlen("__imp_"));
+      Symbol *imp = findLocalSym(impName);
+      if (!imp && isArm64EC(ctx.config.machine)) {
+        // Try to use the mangled symbol on ARM64EC.
+        std::optional<std::string> mangledName =
+            getArm64ECMangledFunctionName(impName);
+        if (mangledName)
+          imp = findLocalSym(*mangledName);
+        if (!imp && impName.consume_front("aux_")) {
+          // If it's a __imp_aux_ symbol, try skipping the aux_ prefix.
+          imp = findLocalSym(impName);
+          if (!imp && (mangledName = getArm64ECMangledFunctionName(impName)))
+            imp = findLocalSym(*mangledName);
         }
       }
       if (imp && imp->isLazy()) {
diff --git a/lld/test/COFF/locally-imported-arm64ec.test b/lld/test/COFF/locally-imported-arm64ec.test
new file mode 100644
index 00000000000000..9ec55c2dceaefc
--- /dev/null
+++ b/lld/test/COFF/locally-imported-arm64ec.test
@@ -0,0 +1,68 @@
+REQUIRES: aarch64
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows funcs.s -o funcs.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func-mangled.s -o func-mangled.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impsym.s -o impsym.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impauxsym.s -o impauxsym.obj
+
+Ensure that when both mangled and demangled symbols are present, the __imp_ symbol
+resolves to the demangled symbol.
+
+RUN: lld-link -machine:arm64ec -dll -noentry funcs.obj impsym.obj -out:impsym.dll
+
+RUN: llvm-readobj --coff-basereloc impsym.dll | FileCheck --check-prefix=RELOCS %s
+RELOCS:       Entry {
+RELOCS-NEXT:    Type: DIR64
+RELOCS-NEXT:    Address: 0x2000
+RELOCS-NEXT:  }
+
+RUN: llvm-readobj --hex-dump=.test impsym.dll | FileCheck --check-prefix=TEST %s
+TEST: 0x180003000 00200000
+
+RUN: llvm-readobj --hex-dump=.rdata impsym.dll | FileCheck --check-prefix=RDATA-DEMANGLED %s
+RDATA-MANGLED:   0x180002000 00100080 01000000
+RDATA-DEMANGLED: 0x180002000 04100080 01000000
+
+
+Ensure that when both mangled and demangled symbols are present, the __imp_aux_ symbol
+resolves to the demangled symbol.
+
+RUN: lld-link -machine:arm64ec -dll -noentry funcs.obj impauxsym.obj -out:impauxsym.dll
+RUN: llvm-readobj --hex-dump=.test impauxsym.dll | FileCheck --check-prefix=TEST %s
+RUN: llvm-readobj --hex-dump=.rdata impauxsym.dll | FileCheck --check-prefix=RDATA-DEMANGLED %s
+
+Ensure that if only the mangled symbol is present, the __imp_ symbol resolves to it.
+
+RUN: lld-link -machine:arm64ec -dll -noentry func-mangled.obj impsym.obj -out:impsym-mangled.dll
+RUN: llvm-readobj --coff-basereloc impsym-mangled.dll | FileCheck --check-prefix=RELOCS %s
+RUN: llvm-readobj --hex-dump=.test impsym-mangled.dll | FileCheck --check-prefix=TEST %s
+RUN: llvm-readobj --hex-dump=.rdata impsym-mangled.dll | FileCheck --check-prefix=RDATA-MANGLED %s
+
+Ensure that if only the mangled symbol is present, the __imp_aux_ symbol resolves to it.
+
+RUN: lld-link -machine:arm64ec -dll -noentry func-mangled.obj impauxsym.obj -out:impauxsym-mangled.dll
+RUN: llvm-readobj --hex-dump=.test impauxsym-mangled.dll | FileCheck --check-prefix=TEST %s
+RUN: llvm-readobj --hex-dump=.rdata impauxsym-mangled.dll | FileCheck --check-prefix=RDATA-MANGLED %s
+
+#--- funcs.s
+    .globl "#myfunc"
+"#myfunc":
+    ret
+    .text
+    .globl myfunc
+myfunc:
+    ret
+
+#--- func-mangled.s
+    .globl "#myfunc"
+"#myfunc":
+    ret
+
+#--- impsym.s
+    .section .test, "r"
+    .rva __imp_myfunc
+
+#--- impauxsym.s
+    .section .test, "r"
+    .rva __imp_aux_myfunc

Copy link
Member

@mstorsjo mstorsjo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@cjacek cjacek merged commit 56077e5 into llvm:main Nov 6, 2024
12 checks passed
@cjacek cjacek deleted the arm64ec-local-imp branch November 6, 2024 11:09
@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 6, 2024

LLVM Buildbot has detected a new failure on builder openmp-offload-amdgpu-runtime running on omp-vega20-0 while building lld at step 7 "Add check check-offload".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/30/builds/9656

Here is the relevant piece of the build log for the reference
Step 7 (Add check check-offload) failure: test (failure)
******************** TEST 'libomptarget :: amdgcn-amd-amdhsa :: offloading/pgo1.c' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang -fopenmp    -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib  -fopenmp-targets=amdgcn-amd-amdhsa /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/pgo1.c -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/pgo1.c.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a -fprofile-instr-generate      -Xclang "-fprofile-instrument=clang"
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/clang -fopenmp -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test -I /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -L /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -nogpulib -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib -fopenmp-targets=amdgcn-amd-amdhsa /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/pgo1.c -o /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/pgo1.c.tmp /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./lib/libomptarget.devicertl.a -fprofile-instr-generate -Xclang -fprofile-instrument=clang
# note: command had no output on stdout or stderr
# RUN: at line 3
/home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/pgo1.c.tmp 2>&1 | /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/pgo1.c      --check-prefix="CLANG-PGO"
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/runtimes/runtimes-bins/offload/test/amdgcn-amd-amdhsa/offloading/Output/pgo1.c.tmp
# note: command had no output on stdout or stderr
# executed command: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.build/./bin/FileCheck /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/pgo1.c --check-prefix=CLANG-PGO
# .---command stderr------------
# | /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/pgo1.c:32:20: error: CLANG-PGO-NEXT: expected string not found in input
# | // CLANG-PGO-NEXT: [ 0 11 20 ]
# |                    ^
# | <stdin>:3:28: note: scanning from here
# | ======== Counters =========
# |                            ^
# | <stdin>:4:1: note: possible intended match here
# | [ 0 12 20 ]
# | ^
# | 
# | Input file: <stdin>
# | Check file: /home/ompworker/bbot/openmp-offload-amdgpu-runtime/llvm.src/offload/test/offloading/pgo1.c
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |            1: ======= GPU Profile ======= 
# |            2: Target: amdgcn-amd-amdhsa 
# |            3: ======== Counters ========= 
# | next:32'0                                X error: no match found
# |            4: [ 0 12 20 ] 
# | next:32'0     ~~~~~~~~~~~~
# | next:32'1     ?            possible intended match
# |            5: [ 10 ] 
# | next:32'0     ~~~~~~~
# |            6: [ 20 ] 
# | next:32'0     ~~~~~~~
# |            7: ========== Data =========== 
# | next:32'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            8: { 10367987278331647071 4749112401 0xffffffffffffffd8 0x0 0x0 0x0 3 0 0 } 
# | next:32'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            9: { 3666282617048535130 24 0xffffffffffffffb0 0x0 0x0 0x0 1 0 0 } 
# | next:32'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            .
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants