Calling Assembly from Swift
Introduction
I’ve recently read a book called Learn to Program with Assembly by Jonathan Bartlett. The book introduces assembly language as well as syscalls, stack, memory, etc. At the end of the book author shows how modern programming language features, such as object-oriented programming, work at the assembly level. I highly recommend this book for all developers.
So as I’m an iOS developer, I wondered – can we call assembly from Swift? Let’s try!
Disclaimer
⚠️ Don’t do this in production code, since assembly has
Writing assembly
For simplicity let’s write an app for adding integers. Sum calculation (the main logic for our app) will be written in assembly.
.globl _sum_numbers
.text
# rdi register contains x
# rsi register contains y
_sumnumbers:
mov %rdi, %rax
add %rsi, %rax
ret
Here we define the global sum_numbers
function to use it outside. And place the function body in the text segment of our program. In my experience, you need to start a function name with an underscore, but Swift won't take it into account. As I understand, it's so because of historical reasons.
According to the calling convention, the function takes arguments in registers. The first argument in rdi
, second – rsi
. On the first line, we move the first argument from rdi
to rax
register. Then add rsi
to rax
and store the result in rax
, since it is used to return the function’s result. At the end, we call return.
Calling assembly
Now let’s go to Swift code and try to call sum_numbers
somehow. We know, that function already exists in our binary. All we have to do is declare the function for the compiler. Swift doesn’t allow that, but Objective-C does!
We need to create a header file and declare sum_numbers
function. Next, create a bridging header to transfer the header file to Swift.
// sum.h
int64_t sum_numbers(int64_t, int64_t);
// ConsoleApp-Bridging-Header.h
#import "sum.h"
We are done! Now we can call our function, written on assembly, from Swift.
print(sum_numbers(10, 100)) // 110
print(sum_numbers(-100, 20)) // -80