在iOS中如何使用汇编语言

时间:2021-02-01 01:05:28

本文将系统地介绍如何利用XCode在iOS设备上使用汇编语言。


一、创建汇编源文件:


在你的XCode项目中存放源文件的目录下鼠标(或触控板)右键,选择New File。然后在左侧的iOS那栏里选择Other,在右边你会看到Assembly File,选中它,然后命名,以.s作为后缀。



二、编写汇编代码:
 

然后可以尝试以下代码:

/*
* arm7.asm
* Test
*
* Created by Zenny Chen on 4/24/10.
* Copyright 2010 GreenGames Studio. All rights reserved.
*/

.text
.align 4
.globl _my_arm_test
.globl _my_thumb_test


.arm

_my_arm_test:

vdup.32 q0, r0
qadd8 r0, r1, r2
add r0, r0, LSL #2
bx lr


.thumb
.thumb_func _my_thumb_test

_my_thumb_test:

movw r1, #1001
rev16 r0, r1
bx lr


这里要注意的是Apple所采用的ARM汇编器遵循GNU Assembler规范。其中,我们可以看到,汇编文件里的注释可以采用C语言标准的注释方式,也可以用C++标准的//注释方式。

.text表示代码正文部分。

.align根据不同的汇编器会有不同的行为,像这里的.align4可能表示4字节对齐,也可能表示16字节对齐。

GAS规范中表示,可以用.global或.globl来标注全局函数。在Apple的Assembler中仅支持.globl。函数名前要加下划线。

.arm表示后面的函数中的指令都是arm指令。而.thumb表示后面函数中的指令都是thumb或thumb-2指令。其中,如果一个函数是用thumb写的,那么必须用.thumb_func修饰,否则连接器在连接符号时会有问题。

上述代码中,_my_arm_test分别使用了一条NEON指令,一条ARMv6指令和两条ARMv5TE指令。而_my_thumb_test中则分别使用了一条ARMv7 Thumb-2指令、一条ARMv6指令和一条ARMv5TE指令。

另外,Apple LLVM汇编器中的条件预处理与C语言用的也几乎一样。可以使用#if、#else、#endif、#ifdef、#ifndef、#elif等等。另外,在架构标识上也统一使用了标准的架构标识符,比如:__i386__表示x86处理器架构;__x86_64__表示64位的x86处理器;__arm__表示ARM架构的处理器;__arm64__表示64位ARM架构处理器。下面给出一个示例代码:

.text
.align
2

.globl _MyASMTest


#if defined(__i386__) || defined(__x86_64__)

_MyASMTest:
xor %eax, %eax
ret

#elif defined(__arm__)

_MyASMTest:
eor r1, r0, r0
bx lr

#elif defined(__arm64__)

_MyASMTest:
eor x1, x0, x0
ret

#endif

如果要查看当前架构下的所有子架构所预定义的宏,那么可以使用以下控制台命令:

clang -arch arm64 -E -dM - < /dev/null

这将输出当前所有arm64架构下预定义的宏。

 

三、在C/C++或Objective C/C++中调用汇编函数


如何在你的C/C++源文件中调用汇编写的函数呢?其实这跟调用普通的C函数一样。

extern int my_arm_test(int a, int b, int c);
extern int my_thumb_test(int a, int b);


void my_test(void)
{
printf("ARM value: %d\n", my_arm_test(10, 20, 30));
printf("Thumb value: %d\n", my_thumb_test(10, 20));
}

 
我们可以看到,这里函数名前的下划线没有了。这里不需要,而且也不能加下划线。 
 

由于当前Apple的ARM汇编器尚未完全支持Thumb-2指令集,像.w后缀就全都没有支持。但Apple LLVM3.0和LLVM-GCC支持。因此我们可以采用在C/C++中以内联汇编的方式来写。详细请参考——在LLVM的C语言编译器中内联纯汇编函数的注意事项。而Xcode4.5之后,Thumb-2已经支持得非常良好了。现在Xcode自带的汇编器还不支持Thumb-EE,不过它已经成为过时的指令集了,我们也无需深入研究,呵呵。


Apple LLVM 5.1开始,对ARMv7、VFPv4以及ARM64都已经完整支持了。下面再进一步介绍iOS中ARMv7以及ARM64下的ABI:

ARMv7中,对于通用寄存器,自己写的过程中需要保护R4、R5、R6、R7、R8、R9、R10、R11以及R14寄存器;NEON寄存器需要保存Q4、Q5、Q6、Q7寄存器。

ARM64模式下,通用寄存器X18、X30不能被使用。而需要被自己写的过程所保护的是:X19、X20、X21、X22、X23、X24、X25、X26、X27、X28、X29寄存器;而SIMD寄存器需要保护的是V8、V9、V10、V11、V12、V13、V14、V15。