Skip to content

Conversation

@cjacek
Copy link
Contributor

@cjacek cjacek commented Nov 14, 2024

Inferring the ARM64EC target can lead to errors. The -machine:arm64ec option may include x86_64 input files, and any valid ARM64EC input is also valid for -machine:arm64x. MSVC requires an explicit -machine argument with informative diagnostics; this patch adopts the same behavior.

@llvmbot
Copy link
Member

llvmbot commented Nov 14, 2024

@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-lld-coff

Author: Jacek Caban (cjacek)

Changes

Inferring the ARM64EC target can lead to errors. The -machine:arm64ec option may include x86_64 input files, and any valid ARM64EC input is also valid for -machine:arm64x. MSVC requires an explicit -machine argument with informative diagnostics; this patch adopts the same behavior.


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

2 Files Affected:

  • (modified) lld/COFF/SymbolTable.cpp (+12-4)
  • (modified) lld/test/COFF/arm64ec.test (+5-1)
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 35d54d4945f7f4..db265e2bb37a04 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -46,6 +46,9 @@ static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) {
     return COFF::isArm64EC(mt) || mt == AMD64;
   case ARM64X:
     return COFF::isAnyArm64(mt) || mt == AMD64;
+  case IMAGE_FILE_MACHINE_UNKNOWN:
+    // The ARM64EC target must be explicitly specified and cannot be inferred.
+    return !isArm64EC(mt);
   default:
     return ctx.config.machine == mt;
   }
@@ -74,13 +77,18 @@ void SymbolTable::addFile(InputFile *file) {
   }
 
   MachineTypes mt = file->getMachineType();
+  if (!compatibleMachineType(ctx, mt)) {
+    if (isArm64EC(mt))
+      error(toString(file) + ": incompatible machine type " + machineToStr(mt) +
+            ", use /machine:arm64ec or /machine:arm64x");
+    else
+      error(toString(file) + ": machine type " + machineToStr(mt) +
+            " conflicts with " + machineToStr(ctx.config.machine));
+    return;
+  }
   if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) {
     ctx.config.machine = mt;
     ctx.driver.addWinSysRootLibSearchPaths();
-  } else if (!compatibleMachineType(ctx, mt)) {
-    error(toString(file) + ": machine type " + machineToStr(mt) +
-          " conflicts with " + machineToStr(ctx.config.machine));
-    return;
   }
 
   ctx.driver.parseDirectives(file);
diff --git a/lld/test/COFF/arm64ec.test b/lld/test/COFF/arm64ec.test
index e50b14ce0184c8..16b596b432b12f 100644
--- a/lld/test/COFF/arm64ec.test
+++ b/lld/test/COFF/arm64ec.test
@@ -36,7 +36,7 @@ ARM64X-DATA: 03030303 01010101 02020202
 
 RUN: not lld-link -out:test.dll -machine:arm64 arm64-data-sym.obj arm64ec-data-sym.obj \
 RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT1 %s
-INCOMPAT1: lld-link: error: arm64ec-data-sym.obj: machine type arm64ec conflicts with arm64
+INCOMPAT1: lld-link: error: arm64ec-data-sym.obj: incompatible machine type arm64ec, use /machine:arm64ec or /machine:arm64x
 
 RUN: not lld-link -out:test.dll -machine:arm64ec arm64ec-data-sym.obj arm64-data-sym.obj \
 RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT2 %s
@@ -46,6 +46,10 @@ RUN: not lld-link -out:test.dll -machine:arm64 arm64-data-sym.obj x86_64-data-sy
 RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT3 %s
 INCOMPAT3: lld-link: error: x86_64-data-sym.obj: machine type x64 conflicts with arm64
 
+arm64ec machine type can't be inferred, it must be specified explicitly.
+RUN: not lld-link -out:test.dll arm64ec-data-sym.obj \
+RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT1 %s
+
 #--- arm64ec-data-sym.s
     .data
     .globl arm64ec_data_sym

@llvmbot
Copy link
Member

llvmbot commented Nov 14, 2024

@llvm/pr-subscribers-lld

Author: Jacek Caban (cjacek)

Changes

Inferring the ARM64EC target can lead to errors. The -machine:arm64ec option may include x86_64 input files, and any valid ARM64EC input is also valid for -machine:arm64x. MSVC requires an explicit -machine argument with informative diagnostics; this patch adopts the same behavior.


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

2 Files Affected:

  • (modified) lld/COFF/SymbolTable.cpp (+12-4)
  • (modified) lld/test/COFF/arm64ec.test (+5-1)
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 35d54d4945f7f4..db265e2bb37a04 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -46,6 +46,9 @@ static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) {
     return COFF::isArm64EC(mt) || mt == AMD64;
   case ARM64X:
     return COFF::isAnyArm64(mt) || mt == AMD64;
+  case IMAGE_FILE_MACHINE_UNKNOWN:
+    // The ARM64EC target must be explicitly specified and cannot be inferred.
+    return !isArm64EC(mt);
   default:
     return ctx.config.machine == mt;
   }
@@ -74,13 +77,18 @@ void SymbolTable::addFile(InputFile *file) {
   }
 
   MachineTypes mt = file->getMachineType();
+  if (!compatibleMachineType(ctx, mt)) {
+    if (isArm64EC(mt))
+      error(toString(file) + ": incompatible machine type " + machineToStr(mt) +
+            ", use /machine:arm64ec or /machine:arm64x");
+    else
+      error(toString(file) + ": machine type " + machineToStr(mt) +
+            " conflicts with " + machineToStr(ctx.config.machine));
+    return;
+  }
   if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) {
     ctx.config.machine = mt;
     ctx.driver.addWinSysRootLibSearchPaths();
-  } else if (!compatibleMachineType(ctx, mt)) {
-    error(toString(file) + ": machine type " + machineToStr(mt) +
-          " conflicts with " + machineToStr(ctx.config.machine));
-    return;
   }
 
   ctx.driver.parseDirectives(file);
diff --git a/lld/test/COFF/arm64ec.test b/lld/test/COFF/arm64ec.test
index e50b14ce0184c8..16b596b432b12f 100644
--- a/lld/test/COFF/arm64ec.test
+++ b/lld/test/COFF/arm64ec.test
@@ -36,7 +36,7 @@ ARM64X-DATA: 03030303 01010101 02020202
 
 RUN: not lld-link -out:test.dll -machine:arm64 arm64-data-sym.obj arm64ec-data-sym.obj \
 RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT1 %s
-INCOMPAT1: lld-link: error: arm64ec-data-sym.obj: machine type arm64ec conflicts with arm64
+INCOMPAT1: lld-link: error: arm64ec-data-sym.obj: incompatible machine type arm64ec, use /machine:arm64ec or /machine:arm64x
 
 RUN: not lld-link -out:test.dll -machine:arm64ec arm64ec-data-sym.obj arm64-data-sym.obj \
 RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT2 %s
@@ -46,6 +46,10 @@ RUN: not lld-link -out:test.dll -machine:arm64 arm64-data-sym.obj x86_64-data-sy
 RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT3 %s
 INCOMPAT3: lld-link: error: x86_64-data-sym.obj: machine type x64 conflicts with arm64
 
+arm64ec machine type can't be inferred, it must be specified explicitly.
+RUN: not lld-link -out:test.dll arm64ec-data-sym.obj \
+RUN:              -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT1 %s
+
 #--- arm64ec-data-sym.s
     .data
     .globl arm64ec_data_sym

MachineTypes mt = file->getMachineType();
if (!compatibleMachineType(ctx, mt)) {
if (isArm64EC(mt))
error(toString(file) + ": incompatible machine type " + machineToStr(mt) +
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a fan of this error message: it seems odd that if the user asked for the machine type to be inferred that the linker reports that something is incompatible. Maybe say that it is ambiguous or can't be decided/inferred?

Copy link
Member

Choose a reason for hiding this comment

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

But isn't it possible to hit this case too, e.g. if you're linking an i386 module, but you're hitting an arm64ec input file?

Copy link
Member

Choose a reason for hiding this comment

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

I.e., would it make sense to try to disambiguate these two cases here, for the sake of getting more easily understandable error messages?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I’ve improved the error message and its logic. The updated implementation now tracks if the machine type was inferred earlier, as it could have been inferred as ARM64 or AMD64 from prior input files (as demonstrated in the tests). Additionally, I noticed that ARM64X input files are allowed to infer ARM64, so I’ve added support for that behavior as well.

Inferring the ARM64EC target can lead to errors. The `-machine:arm64ec` option may
include x86_64 input files, and any valid ARM64EC input is also valid for `-machine:arm64x`.
MSVC requires an explicit `-machine` argument with informative diagnostics; this patch
adopts the same behavior.
INCOMPAT5: arm64ec-data-sym.obj: machine type arm64ec conflicts with x86

arm64x input implies arm64 target
RUN: lld-link -out:test.dll -machine:arm64 arm64x-resource.obj -dll -noentry
Copy link
Member

Choose a reason for hiding this comment

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

As we're explicitly specifying -machine:arm64 here, I don't see how this triggers the implicit arm64x -> arm64 machine type handling?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I messed up that test. After revisiting the MSVC behavior, I found that passing a single input file triggers an exception. However, when multiple files are passed, it behaves similarly to LLD without this change. I’ve now limited the impact of this change to ARM64EC, which aligns more closely with MSVC’s handling in these scenarios.

RUN: not lld-link -out:test.dll -machine:arm64 arm64-data-sym.obj arm64ec-data-sym.obj \
RUN: -dll -noentry 2>&1 | FileCheck -check-prefix=INCOMPAT1 %s
INCOMPAT1: lld-link: error: arm64ec-data-sym.obj: machine type arm64ec conflicts with arm64
INCOMPAT1: arm64ec-data-sym.obj: machine type arm64ec conflicts with arm64
Copy link
Member

Choose a reason for hiding this comment

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

What happened with the lld-link: error: prefix here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An oversight, fixed, sorry.

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, I think this is good now. But let's give @dpaoliello a chance to get back and comment as well.

@cjacek cjacek merged commit f942949 into llvm:main Nov 24, 2024
8 checks passed
@cjacek cjacek deleted the arm64ec-machine branch November 24, 2024 13:33
@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 24, 2024

LLVM Buildbot has detected a new failure on builder lldb-arm-ubuntu running on linaro-lldb-arm-ubuntu while building lld at step 6 "test".

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

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: commands/frame/recognizer/TestFrameRecognizer.py (164 of 2839)
UNSUPPORTED: lldb-api :: commands/gui/expand-threads-tree/TestGuiExpandThreadsTree.py (165 of 2839)
PASS: lldb-api :: commands/gui/invalid-args/TestInvalidArgsGui.py (166 of 2839)
UNSUPPORTED: lldb-api :: commands/gui/viewlarge/TestGuiViewLarge.py (167 of 2839)
PASS: lldb-api :: commands/help/TestHelp.py (168 of 2839)
PASS: lldb-api :: commands/log/basic/TestLogHandlers.py (169 of 2839)
PASS: lldb-api :: commands/log/invalid-args/TestInvalidArgsLog.py (170 of 2839)
PASS: lldb-api :: commands/memory/write/TestMemoryWrite.py (171 of 2839)
PASS: lldb-api :: commands/memory/read/TestMemoryRead.py (172 of 2839)
UNRESOLVED: lldb-api :: commands/gui/spawn-threads/TestGuiSpawnThreads.py (173 of 2839)
******************** TEST 'lldb-api :: commands/gui/spawn-threads/TestGuiSpawnThreads.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin --arch armv8l --build-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/dsymutil --make /usr/bin/make --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./lib /home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/commands/gui/spawn-threads -p TestGuiSpawnThreads.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 20.0.0git (https://github.com/llvm/llvm-project.git revision f942949a7cf16a082eb43943b2a4f93f9180556f)
  clang revision f942949a7cf16a082eb43943b2a4f93f9180556f
  llvm revision f942949a7cf16a082eb43943b2a4f93f9180556f
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
FAIL: LLDB (/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/bin/clang-arm) :: test_gui (TestGuiSpawnThreads.TestGuiSpawnThreadsTest)
======================================================================
ERROR: test_gui (TestGuiSpawnThreads.TestGuiSpawnThreadsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/packages/Python/lldbsuite/test/decorators.py", line 148, in wrapper
    return func(*args, **kwargs)
  File "/home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/commands/gui/spawn-threads/TestGuiSpawnThreads.py", line 44, in test_gui
    self.child.expect_exact(f"thread #{i + 2}: tid =")
  File "/usr/local/lib/python3.10/dist-packages/pexpect/spawnbase.py", line 432, in expect_exact
    return exp.expect_loop(timeout)
  File "/usr/local/lib/python3.10/dist-packages/pexpect/expect.py", line 179, in expect_loop
    return self.eof(e)
  File "/usr/local/lib/python3.10/dist-packages/pexpect/expect.py", line 122, in eof
    raise exc
pexpect.exceptions.EOF: End Of File (EOF). Exception style platform.
<pexpect.pty_spawn.spawn object at 0xe95dbfa0>
command: /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/bin/lldb
args: ['/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/bin/lldb', '--no-lldbinit', '--no-use-colors', '-O', 'settings clear -all', '-O', 'settings set symbols.enable-external-lookup false', '-O', 'settings set target.inherit-tcc true', '-O', 'settings set target.disable-aslr false', '-O', 'settings set target.detach-on-error false', '-O', 'settings set target.auto-apply-fixits false', '-O', 'settings set plugin.process.gdb-remote.packet-timeout 60', '-O', 'settings set symbols.clang-modules-cache-path "/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api"', '-O', 'settings set use-color false', '--file', '/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/commands/gui/spawn-threads/TestGuiSpawnThreads.test_gui/a.out']
buffer (last 100 chars): b''
before (last 100 chars): b'p/lit-tmp-jkuc6sro/diagnostics-5cf2d0\nPlease include the directory content when filing a bug report\n'
after: <class 'pexpect.exceptions.EOF'>

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.

5 participants