MacOS Arm64 汇编 part 4 - MacOS Arm64 Assembly part 4

  • Interacting with C
  • Call C functions & Call a assmebly function from C
  • Inline assembly in C

Using printf in asm

首先我们来实现由汇编到 C 语言函数的调用,其中最常用的一个就是 printf

1
2
3
4
5
6
7
8
9
10
11
12
13
.global _start
.align 4
_start:
adr x0, ptfStr
ldr x1, =0x114514
stp x1, xzr, [sp, #-16]!
bl _printf
add sp, sp, #16
mov x0, #0
mov x16, #1
svc #0x80

ptfStr: .asciz "hello %x\n"

由于 sp 严格 16-bytes align,因此就算只有 8 bytes,我们也采用 16 bytes 的栈指针偏移,printfclang 语法下需要加下划线,第一个参数采用 X0 传递,而后续参数均采用压栈方式来传递,需要注意的一点是参数栈需要调用者自行释放

Using asm function in C

使用汇编中的函数也比较简单,extern 声明一下就行

add.s
1
2
3
4
5
.global _add
.align 4
_add:
add x0, x0, x1
ret
add.c
1
2
3
4
5
6
#include <stdio.h>
extern int add(long a, long b);
int main() {
printf("%d + %d = %d\n", 1, 1, add(1, 1));
return 0;
}

Packaging Our Code

Static Library

通过 ar 命令实现静态链接库的打包

1
ar -cvq libadd.a add.o

在与 C 一同编译时

1
clang -o add2 add.c libadd.a

Embedding Assembly Code Inside C Code

我们仍可以在 C 语言中使用汇编

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main() {
long long a, b, res;
a = b = 0x4;
asm("add x0, %1, %2\n"
"mov %0, x0\n"
: "=r"(res)
: "r"(a), "r"(b)
: "r0");
printf("%lld + %lld = %lld\n", a, b, res);
return 0;
}

其中前两行是加法计算以及结果拷贝到输出寄存器,实际可以移步到到位,通过 \n 分隔两行汇编代码。

  • 1st : 用于指定输出变量,寄存器默认编号为 %0
  • 2nd : 用于指定输入变量,寄存器默认编号从 %1 开始依次递增,逗号分隔两个输入
  • 3rd : 用于说明使用的(破坏掉的)寄存器列表,逗号分隔