上一篇文章 iOS汇编入门教程 中介绍了汇编在iOS开发中的应用以及ARM汇编基础知识,本文将介绍在C或Objective-C构成的工程中如何嵌入汇编代码。html
在调试ARM汇编时,Xcode的Build对象必须为真机,若是对象为模拟器则是x86汇编。ios
在函数中能够直接插入汇编代码来影响函数的运行逻辑,使用的语法为编译指令__asm__
,注意插入汇编有可能会被编译器忽略,所以须要加入__volatile__
修饰符保证汇编代码有效。函数
下面给出一个简单的例子,假如咱们要实现一个将数值翻一倍的简单函数。post
int double_num(int num) {
return num * 2;
}
复制代码
下面咱们采用内联汇编的形式实现将num的值翻倍的操做。ui
int double_num(int num) {
__asm__ __volatile__(
"lsl x0, x0, 1\n"
"str x0, [sp, #12]\n"
);
return num;
}
复制代码
lsl为左移指令,x0中存储的为入参num的值,因为该函数未发起对其余函数的调用,因此没必要保护现场,只有一个int类型入参,须要4byte,因为ARM64下sp寻址时必须按照16byte对齐,因此该函数的调用栈大小为16byte,因此num变量会存储在高地址的sp+12~sp+16
区域,所以在函数返回时会从sp+12
处取出,咱们经过str
指令将翻倍以后的数值存储在对应区域便可。spa
在上面的例子中,为了将计算后的值做为返回值,咱们采用了静态计算变量地址的方式,这里咱们换用另外一种方式,将汇编的计算结果直接存储在C变量中,如下面的函数为例,将输入的值翻倍数次。调试
int double_num_times(int num, int times) {
int ret;
__asm__ __volatile__(
"lsl x0, x0, x1\n"
"mov %0, x0"
: "=r" (ret)
:
:
);
return ret;
}
复制代码
这里的x0中存储的是num,x1存储的是times,可见从C到汇编的通讯是很是天然的;可见汇编的后三行使用了三个冒号,这是内联汇编与C通讯的语法,其中第一行为输出指令,第二行为输入指令,第三行为更改的变量列表。对于汇编到C的赋值,只须要在第一行声明"=r" (变量标识符)
,在汇编执行完毕后会将%0寄存器(其实是使用x8, x9寄存器来模拟的,常与临时值寄存器x12配合使用,使用%0可能会污染x8和x9)的值保存在变量标识符内,若是有多个变量须要赋值,可使用%1, %2以此类推,有关内联汇编输入输出的基本语法能够看这篇文章。code
注意: 因为C++有特殊的name mangling规则,该方法仅适用于Ccdn
除了嵌入式内联汇编外,咱们还可使用汇编文件来直接定义函数,在Xcode中新建文件时,选择Other组中的汇编文件,便可建立一个汇编文件并将其添加到工程的编译单元中。 htm
咱们采用纯汇编来实现一下上面的double_num_times
函数,在汇编文件中写入以下代码。
; example.s
.section __TEXT,__text,regular,pure_instructions
.ios_version_min 11, 2
.p2align 2
.global _double_num_times_asm
_double_num_times_asm:
lsl x0, x0, x1
ret
复制代码
第一行为段的固定写法,段的定义将在后续的教程中详细介绍,第四行将符号引出到全局,从第五行开始定义了符号_double_num_times_asm
的功能逻辑,这里的下划线是根据C语言的name mangling规则命名的,符号将被映射为C语言的全局函数符号double_num_times_asm
,这里因为_double_num_times_asm
没有调用到其余符号,所以不须要处理x29和x30的暂存。
经过上述的汇编代码,咱们已经完成了函数定义,只须要经过一个头文件声明一下函数便可。
// example.h
int double_num_times_asm(int num, int times);
复制代码
引入头文件后,便可正常使用函数。
在Xcode中嵌入汇编代码主要依赖了C语言支持经过__asm__
引入汇编代码的功能,而直接使用汇编实现函数逻辑则是至关于手动帮助编译器完成了生成汇编代码的过程,经过嵌入汇编能够从更大程度上把握程序的运行。