Skip to content

for M1 Macs: the qemu-x86_64 emulates an ancient CPU model that doesn't support modern features, breaks Swift compiler / LLVM / ... #5561

Closed

Description

  • I have tried with the latest version of Docker Desktop
  • I have tried disabling enabled experimental features
  • I have uploaded Diagnostics

Expected behavior

I can run modern software that uses Intel instructions like pshufb in Docker for Mac (on M1 Macs) because the qemu-x86_64 that's installed using the binfmt_misc support can emulate it.

Actual behavior

I can't run modern software that makes use of newer Intel instructions because the qemu-x86_64 that gets run using binfmt_misc doesn't get passed a -cpu core2duo (or newer such as -cpu Skylake-Client/-cpu max) argument.

Information

The problem is that the qemu-x86_64 doesn't get passed a -cpu core2duo (or even better something like -cpu Skylake-Client or maybe -cpu max ("Enables all features supported by the accelerator in the current host")) argument. Really, I would recommend to just pass the newest CPU that qemu can emulate (probably -cpu max).

I got the Swift compiler to work just fine by compiling my own qemu with this patch applied:

sed -i 's/cpu_model = NULL/cpu_model = "core2duo"/g' linux-user/main.c

which just sets the default CPU model to core2duo. I then installed as the Docker for Mac default binfmt_misc handler for x86_64 using

/containers/services/binfmt/rootfs/usr/bin/binfmt -uninstall qemu-x86_64
echo ":qemu-x86_64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/var/lib/docker/overlay2/80s11o66od7msjkcmt4hal5ui/diff/amd64/usr/bin/qemu-x86_64-static-c2d:OCF" > /proc/sys/fs/binfmt_misc/register

in the actual VM which I entered using justincormack/nsenter.

Steps to reproduce the behavior

The quickest way to reproduce the problem is:

  1. Get an M1 Mac and install Docker for Mac for M1 Macs
  2. Run docker run -it --rm --platform linux/amd64 swift:5.3 bash -c 'echo "print(\"hello world\")" > /tmp/test.swift && cd /tmp && swiftc test.swift && ./test'

Expected: prints "hello world"
Actual: Output something similar to

Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
Stack dump:
0.	Program arguments: /swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend -frontend -c -primary-file /tmp//test.swift -target x86_64-unknown-linux-gnu -disable-objc-interop -color-diagnostics -module-name test -o /tmp/test-d8e021.o
1.	Swift version 5.4-dev (LLVM 1e4181b99f530d2, Swift 842cc9c88f5463b)
 #0 0x0000000005cb5c13 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x5cb5c13)
 #1 0x0000000005cb396e llvm::sys::RunSignalHandlers() (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x5cb396e)
 #2 0x0000000005cb5f9c SignalHandler(int) (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x5cb5f9c)
 #3 0x0000004000a48980 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12980)
 #4 0x00000000018a7f63 std::vector<swift::DiagnosticState::Behavior, std::allocator<swift::DiagnosticState::Behavior> >::_M_fill_insert(__gnu_cxx::__normal_iterator<swift::DiagnosticState::Behavior*, std::vector<swift::DiagnosticState::Behavior, std::allocator<swift::DiagnosticState::Behavior> > >, unsigned long, swift::DiagnosticState::Behavior const&) (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x18a7f63)
 #5 0x00000000018a237f swift::DiagnosticState::DiagnosticState() (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x18a237f)
 #6 0x00000000006ae240 swift::CompilerInstance::CompilerInstance() (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x6ae240)
 #7 0x0000000000513165 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x513165)
 #8 0x00000000004ad906 main (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x4ad906)
 #9 0x0000004002013bf7 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf7)
#10 0x00000000004ad57a _start (/swift-DEVELOPMENT-SNAPSHOT-2021-02-09-a-ubuntu18.04/usr/bin/swift-frontend+0x4ad57a)
qemu: uncaught target signal 4 (Illegal instruction) - core dumped
<unknown>:0: error: unable to execute command: Illegal instruction
<unknown>:0: error: compile command failed due to signal 4 (use -v to see invocation)

Please note the qemu: uncaught target signal 4 (Illegal instruction) - core dumped which qemu prints when it encounters the pshufb Intel instruction (which needs the Intel SSE3 feature which qemu (correctly) only emulates if you tell it to emulate a new-enough CPU using -cpu core2duo or better).

The problem here is that the Swift compiler runs a pshufb instruction which isn't available in the ancient CPU that qemu emulates if you don't pass -cpu core2duo or newer. See Swift compiler bug SR-14186 for all the details.

For a somewhat more complete test, it'd be probably good to run

docker run -it --rm --platform linux/amd64 swift:5.3 bash -c 'git clone https://github.com/apple/swift-nio.git && cd swift-nio && swift test'

which clones SwiftNIO, compiles it and runs its test suite.

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

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions