|
| 1 | +# rosetta-multipass |
| 2 | + |
| 3 | +Would you also like to run `amd64` binaries in your [Multipass](https://multipass.run/) VMs on an M1 Mac? This is a guide/tool to enable [Rosetta](https://developer.apple.com/documentation/virtualization/running_intel_binaries_in_linux_vms_with_rosetta) without official support from Multipass. |
| 4 | + |
| 5 | +## Rosetta Installation (macOS host) |
| 6 | + |
| 7 | +First you need to [install Rosetta](https://osxdaily.com/2020/12/04/how-install-rosetta-2-apple-silicon-mac/) on your host system: |
| 8 | + |
| 9 | +```sh |
| 10 | +softwareupdate --install-rosetta --agree-to-license |
| 11 | +``` |
| 12 | + |
| 13 | +You should now have the `rosetta` translator binary: |
| 14 | + |
| 15 | +```sh |
| 16 | +% tree /Library/Apple/usr/libexec/oah |
| 17 | +/Library/Apple/usr/libexec/oah |
| 18 | +├── RosettaLinux |
| 19 | +│ └── rosetta # <- this one |
| 20 | +├── debugserver -> /usr/libexec/rosetta/debugserver |
| 21 | +├── libRosettaRuntime |
| 22 | +├── runtime -> /usr/libexec/rosetta/runtime |
| 23 | +└── translate_tool -> /usr/libexec/rosetta/translate_tool |
| 24 | +``` |
| 25 | + |
| 26 | +**Note**: If you do not get the `RosettaLinux/rosetta` binary, try following the [UTM Rosetta Guide](https://docs.getutm.app/advanced/rosetta/) first, which should install Rosetta for you. |
| 27 | + |
| 28 | +## Rosetta Installation (Ubuntu guest) |
| 29 | + |
| 30 | +Copy the `RosettaLinux/rosetta` binary to your guest VM. In this example the binary has been copied to `/bin/rosetta`, but any path should work. Make sure that you can run the binary from inside the VM: |
| 31 | + |
| 32 | +``` |
| 33 | +$ /bin/rosetta |
| 34 | +rosetta error: Rosetta is only intended to run on Apple Silicon with a macOS host using Virtualization.framework with Rosetta mode enabled |
| 35 | +Trace/breakpoint trap (core dumped) |
| 36 | +``` |
| 37 | + |
| 38 | +The error is expected, you can read more about it in a [Quick look at Rosetta on Linux](https://threedots.ovh/blog/2022/06/quick-look-at-rosetta-on-linux/). |
| 39 | + |
| 40 | +### Using `mount-rosetta.py` |
| 41 | + |
| 42 | +To fix the error you can create a FUSE mount using `mount-rosetta.py`, which implements the `ioctl` required for the Rosetta handshake: |
| 43 | + |
| 44 | +```sh |
| 45 | +sudo apt install libfuse2 |
| 46 | +sudo python -m pip install fusepy |
| 47 | +``` |
| 48 | + |
| 49 | +**Note**: To mount without root, edit `/etc/fuse.conf` and uncomment `user_allow_other`. This shouldn't be necessary unless you are developing the script. |
| 50 | + |
| 51 | +Now you can run the script: |
| 52 | + |
| 53 | +```sh |
| 54 | +sudo python mount-rosetta.py /bin/rosetta |
| 55 | +``` |
| 56 | + |
| 57 | +This will shadow the `/bin/rosetta` binary and handle the necessary `ioctl` calls. To confirm you you can run: |
| 58 | + |
| 59 | +```sh |
| 60 | +$ /bin/rosetta |
| 61 | +Usage: rosetta <x86_64 ELF to run> |
| 62 | + |
| 63 | +Optional environment variables: |
| 64 | +ROSETTA_DEBUGSERVER_PORT wait for a debugger connection on given port |
| 65 | + |
| 66 | +version: Rosetta-289.7 |
| 67 | +``` |
| 68 | + |
| 69 | +**Note**: You will have to run `mount-rosetta.py` in the background. |
| 70 | + |
| 71 | +### Installing the binfmt handler (guest) |
| 72 | + |
| 73 | +To register `rosetta` for `amd64` binaries: |
| 74 | + |
| 75 | +``` |
| 76 | +sudo apt install binfmt-support |
| 77 | +sudo update-binfmts --install rosetta /bin/rosetta \ |
| 78 | + --magic "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00" \ |
| 79 | + --mask "\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff" \ |
| 80 | + --credentials yes --preserve no --fix-binary no |
| 81 | +``` |
| 82 | + |
| 83 | +**Important**: If you want to use `--fix-binary yes` you will have to run `mount-rosetta.py` before the `update-binfmts` command. |
| 84 | + |
| 85 | +### Running an `amd64` executable |
| 86 | + |
| 87 | +You should now be able to execute a statically linked executable: |
| 88 | + |
| 89 | +```sh |
| 90 | +$ ./tests/main-static |
| 91 | +Hello from Rosetta! |
| 92 | +``` |
| 93 | + |
| 94 | +### Creating a service |
| 95 | + |
| 96 | +You can create `/etc/systemd/system/rosetta.service`: |
| 97 | + |
| 98 | +``` |
| 99 | +[Unit] |
| 100 | +Description=Rosetta Mount Service |
| 101 | +
|
| 102 | +[Service] |
| 103 | +ExecStart=/usr/bin/python3 /home/ubuntu/.local/bin/mount-rosetta.py /bin/rosetta |
| 104 | +Environment=PYTHONUNBUFFERED=1 |
| 105 | +Restart=on-failure |
| 106 | +
|
| 107 | +[Install] |
| 108 | +WantedBy=default.target |
| 109 | +``` |
| 110 | + |
| 111 | +See [here](https://github.com/torfsen/python-systemd-tutorial) for more information. |
| 112 | + |
| 113 | +``` |
| 114 | +sudo systemctl list-unit-files | grep rosetta |
| 115 | +sudo systemctl enable rosetta.service |
| 116 | +sudo systemctl start rosetta.service |
| 117 | +``` |
| 118 | + |
| 119 | +## Installing shared libraries (experimental) |
| 120 | + |
| 121 | +**Warning**: This section is super experimental and unlikely to yield great results. That being said, it is possible to run clang compiled for `amd64` and build something. |
| 122 | + |
| 123 | +Running a dynamically linked binary will not work properly at this point: |
| 124 | + |
| 125 | +``` |
| 126 | +$ ./tests/main-dynamic |
| 127 | +./tests/main-dynamic: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory |
| 128 | +``` |
| 129 | + |
| 130 | +To fix this (only tested on Ubuntu 22.04) you can run the following commands: |
| 131 | + |
| 132 | +``` |
| 133 | +sudo apt install g++-multilib-x86-64-linux-gnu gcc-multilib-x86-64-linux-gnu |
| 134 | +sudo ln -s /usr/x86_64-linux-gnu/lib64 /lib64 |
| 135 | +export LD_LIBRARY_PATH=/usr/x86_64-linux-gnu/lib |
| 136 | +``` |
| 137 | + |
| 138 | +At this point things are working: |
| 139 | + |
| 140 | +``` |
| 141 | +./tests/main-dynamic |
| 142 | +Hello from Rosetta! |
| 143 | +``` |
| 144 | + |
| 145 | +**Note**: For other distributions you can search for `multilib` or `multiarch` packages or look for guides on getting qemu usermode emulation to work. |
| 146 | + |
| 147 | +### Fixing some dynamic linker errors |
| 148 | + |
| 149 | +Since `/usr/x86_64-linux-gnu` is meant for compiling things and not running you might have to replace some `.so` files that are actually linker scripts with the binaries: |
| 150 | + |
| 151 | +``` |
| 152 | +$ sudo -i |
| 153 | +$ cd /usr/x86_64-linux-gnu/lib |
| 154 | +$ rg GROUP # lists fake files |
| 155 | +libc.so |
| 156 | +5:GROUP ( /usr/x86_64-linux-gnu/lib/libc.so.6 /usr/x86_64-linux-gnu/lib/libc_nonshared.a AS_NEEDED ( /usr/x86_64-linux-gnu/lib64/ld-linux-x86-64.so.2 ) ) |
| 157 | +libm.so |
| 158 | +4:GROUP ( /usr/x86_64-linux-gnu/lib/libm.so.6 AS_NEEDED ( /usr/x86_64-linux-gnu/lib/libmvec.so.1 ) ) |
| 159 | +
|
| 160 | +$ mv libc.so libc.so.script |
| 161 | +$ cp libc.so.6 libc.so |
| 162 | +$ mv libm.so libm.so.script |
| 163 | +$ cp libm.so.6 libm.so |
| 164 | +``` |
| 165 | + |
| 166 | +### Cross-compiling libraries |
| 167 | + |
| 168 | +If you need to install something like [zlib](https://zlib.net) for `amd64` you can use [Zig](https://zig.news/kristoff/cross-compile-a-c-c-project-with-zig-3599) for easy cross compiling: |
| 169 | + |
| 170 | +``` |
| 171 | +sudo snap install zig --classic --edge |
| 172 | +git clone https://github.com/madler/zlib |
| 173 | +cd zlib |
| 174 | +CC="zig cc -target x86_64-linux-musl" CXX="zig c++ -target x86_64-linux-musl" AR="zig ar" RANLIB="zig ranlib" uname_S="Linux" uname_M="x86_64" C11_ATOMIC=yes USE_JEMALLOC=no USE_SYSTEMD=no ./configure --prefix /usr/x86_64-linux-gnu |
| 175 | +make |
| 176 | +sudo make install |
| 177 | +``` |
| 178 | + |
| 179 | +For CMake project you can use [zig-cross](https://github.com/mrexodia/zig-cross) as a base. |
| 180 | + |
| 181 | +### Multithreading |
| 182 | + |
| 183 | +According to [Quick look at Rosetta on Linux](https://threedots.ovh/blog/2022/06/quick-look-at-rosetta-on-linux/) you might run into issues if the VM is not running in Total Store Ordering (TSO) mode. The solution should be to wrap `rosetta` in a `taskset` command during `update-binfmts`. This was not explored further. |
0 commit comments