Emulating Ubuntu Server X86_64 on macOS ARM64
Table of Contents
ARM processors are becoming more ubiquitous thanks to the introduction of Apple Silicon and Qualcomm Snapdragon. These new processors offer great performance, silent operation, and all-day battery life. On the other hand, not all software is ported to this new architecture, so there could be cases when we need to run or program x86_64 devices.
To solve this problem, we have several tools at our disposal. In this post, let’s explore one solution to emulate and run x86_64 software.
What we need#
- An ARM64 machine. In our case, any Apple Silicon Mac would suffice.
- UTM App.
- Any x86_64 OS ISO. In our case, we’re installing Ubuntu Server 24.10.
Installing UTM#
The piece of software that will be doing the work for us is called UTM. This is a macOS app that uses QEMU under the hood for virtualization and emulation.
We can get this software from their website or directly from the macOS App Store. I find the former option the best.
Choose the option that best suits your needs.
Creating the emulated Virtual Machine#
Once we have UTM installed, let’s download the ISO of the operating system we want to emulate. In our case, Ubuntu Server 24.10.
Next, let’s open UTM and click on Create a New Virtual Machine
. Here, we just need to select emulation, select the downloaded ISO, and configure the virtualized hardware. The process is quite straightforward.
In the last screen, you can view the summary of the VM. If this looks good to you, press Create and start the VM on the main UTM window.
This will start the normal installation of the selected OS using the provided ISO.
It’s a good idea to install OpenSSH for Ubuntu Server.
Configuring SSH#
Once we are logged into our VM, we can start configuring SSH. This will allow us to access our VM from our host OS and connect via VSCode to start programming.
First, we need to create our SSH key. For that, we can follow the GitHub tutorial here.
Once we have the SSH key ready, we need a way to add it to our VM. For this, we are going to use scp
.
- On VM, get the IP address using
ip a
. The IP should look similar toinet 192.168.1.10/24
(we don’t need the/24
part). - On macOS terminal, copy the public key using
pbcopy < ~/.ssh/id_ed25519.pub
. - On macOS terminal, create the
authorized_keys
file with the SSH public key usingcat ~/.ssh/id_ed25519.pub >> ~/authorized_keys
(you can modify the location of the file to your needs). - On macOS terminal, copy the file to the VM using
scp authorized_keys username@yvm_ip_address:~/.ssh/
. - On macOS terminal, test the SSH connection using
ssh username@vm_ip_address
.
If your VM doesn’t have OpenSSL installed, run the following inside your VM
sudo apt update && sudo apt install openssh-server && sudo systemctl start ssh && sudo systemctl enable ssh && sudo systemctl status ssh
. This will install SSH, run it, enable it on startup, and check its current status.
Coding an ASM example with VSCode#
Now it’s time to do some x86_64 ASM to verify that our system is working properly.
- Open VSCode and click on the lower left blue icon
><
. - Select
+ Add New SSH Host...
and add your VM host parameters using this structuressh username@vm_ip_address
. - Select the configuration file to save your new host (the first option is okay).
- Once the host is added, click on
Connect
. (On macOS, you may need to give VSCode permission to access the network, allow it, and press retry). - Wait for the VSCode server to install on the VM.
Now that everything is ready, let’s make a hello world!
Open VSCode integrated terminal (CMD + BACKTICK) and create a new file called hello.asm
(use touch hello.asm
to create the file and code hello.asm
to open the file on VSCode) with the following content:
section .data
msg db 'Hello, World!', 0xA ; Message to print with newline
len equ $ - msg ; Length of the message
section .text
global _start ; Entry point for the program
_start:
mov rax, 1 ; sys_write system call (1)
mov rdi, 1 ; File descriptor (stdout)
mov rsi, msg ; Address of the message
mov rdx, len ; Length of the message
syscall ; Make the system call
mov rax, 60 ; sys_exit system call (60)
xor rdi, rdi ; Exit code 0
syscall ; Make the system call
Before continuing, install the assembler using sudo apt install nasm
.
Now let’s run the program!
# Assembling the code
nasm -f elf64 hello.asm -o hello.o
# Linking the code
ld hello.o -o hello
# Running the code
./hello
If all went well, you should see on the integrated terminal the text Hello, World!
. Congratulations, your emulated x86_64 system is working correctly!
Conclusion#
ARM processors have revolutionized the computing landscape with their efficiency, performance, and battery life, making them an excellent choice for modern devices. However, their growing adoption doesn’t eliminate the need to run or develop software for the x86_64 architecture. With tools like UTM, we can easily emulate x86_64 systems on ARM-based devices, such as Apple Silicon Macs.
This post guided you through the process of setting up UTM, creating a virtual machine, configuring SSH, and even running an x86_64 assembly program. By following these steps, you’ve not only learned how to emulate a different architecture but also created a functional environment for programming and development.
The flexibility of emulation tools bridges the gap between architectures, ensuring that developers can maintain productivity regardless of the hardware they are using. This workflow demonstrates how we can adapt to and leverage the best of both ARM and x86_64 worlds. Happy coding!