福州中小企业网站制作,天元建设集团有限公司 伊永成,电脑软件界面设计,做打折网站如何前言这篇主要介绍arm64程序调用规则#xff0c;详细分析了程序调用过程中#xff0c;参数是如何传递的。Android、iOS、Linux等基本遵循这些规则#xff0c;但是各个操作系统平台也有小部分自己特定的规则。下一篇#xff0c;我将介绍iOS平台的特定规则。术语介绍术语意义A…前言这篇主要介绍arm64程序调用规则详细分析了程序调用过程中参数是如何传递的。Android、iOS、Linux等基本遵循这些规则但是各个操作系统平台也有小部分自己特定的规则。下一篇我将介绍iOS平台的特定规则。术语介绍术语意义A32在ARMv7架构中使用32位固定长度指令的ARM指令集。A64AArch64可用时的指令集。AAPCS64AArch64程序调用标准。(PCSProcedure Call Standard)AArch32ARMv8中的32位通用寄存器兼容ARMv7-A。AArch64ARMv8中的64位通用寄存器ABI(Application Binary Interface)汇编接口规范跟执行环境相关比如Linux ABI说的是Linux环境下的汇编接口规范ARM-based基于ARMFloating point根据上下文有这三种意思(1)遵循IEEE 754 2008的浮点运算; (2)ARMv8浮点指令集; (3)一个被ARMv8浮点指令集和ARMv8 SIMD指令集共享的寄存器组。Q-o-IQuality of ImplementationSIMDSingle Instruction Multiple Data 一条指令操作多个数据T32T32使用可变16bit和32bitRoutine, subroutineRoutine调用者subroutine被调用者Procedure没有返回值的函数Function有返回值的函数PIC, PIDPosition-independent code, position-independent data.Program state指程序内存和寄存器的值Caller- saved register调用者在调用函数之前保存寄存器(一般入栈)函数返回后恢复寄存器(一般出栈)Callee-saved register被调用者(函数内部)在起始地方保存寄存器在结束时恢复寄存器NGRN(The Next General-purpose Register Number )可以理解为记录r0-r7(见下文寄存器)使用个数参数传递前设为0每放一个参数进入寄存器(整型寄存器)值加1。当等于8时候说明r0-r7寄存器使用完了再有参数只能放入内存了。NSRN (The Next SIMD and Floating-point Register Number)同上记录v0-v7使用个数NSAA (The next stacked argument address)记录参数放入内存参数传递前设为SP所以内存中参数范围应该是 sp~NSAA。详细见下文参数传递数据类型和对齐基本数据类型Type ClassMachine TypeBytesizeNaturalAlignment(bytes)IntegralUnsigned byte11Signed byte11Unsigned half-word22Signed half-word22Unsigned word44Signed word44Unsigneddouble-word88Signed double-word88Unsigned quad-word1616Signed quad-word1616Floating PointHalf precision22Single precision44Doubleprecision88Quad precision1616Short vector64-bit vector88128-bit vector1616PointerData pointer88Code pointer88程序调用规则寄存器arm64有两种寄存器处理整型和指针的寄存器通用寄存器和AAPCS64用法寄存器别名意义SPStack Pointer:栈指针r30LRLink Register:在调用函数时候保存下一条要执行指令的地址。r29FPFrame Pointer:保存函数栈的基地址。r19...r28Callee-saved registers(含义见上面术语解释)r18平台寄存器有特定平台解释其用法。如果平台未把其做特殊用途可当做临时寄存器使用。(iOS平台保留的寄存器应用不可使用)r17IP1The second intra-procedure-call temporary register (can be used by call veneers and PLT code); at other times may be used as a temporary register.r16IP0The first intra-procedure-call scratch register (can be used by call veneers and PLT code); at other times may be used as a temporary register.r9...r15临时寄存器r8在一些情况下返回值是通过r8返回的r0...r7r0-r7在函数调用过程中传递参数和返回值NZCV状态寄存器N(Negative)负数 Z(Zero) 零 C(Carry) 进位 V(Overflow) 溢出arm64有31个通用整型寄存器r0-r30。当使用64bits时候命名x0-x30使用32bits时命名w0-w30。当寄存器在此程序调用标准中具有固定角色时使用大写。SIMD 和 Floating-Point寄存器ARM64有32个寄存器v0-v31用于处理SIMD和浮点运算。长度不同称谓也不同bhsdq分别代表byte(8位)half(16位)single(32位)double(64位)quad(128位)。v0-v7在函数调用过程中传递参数和返回值v8-v15 是Callee-saved registers(见术语解释)且是保存前64bits(更大的位数调用者负责保存)v0-v7, v16-v31不需要保存或者调用者保存。进程、内存、栈一个进程的内存可分为5类代码区。只能被进程读不可些。可写静态数据。只读静态数据。堆。栈。可写静态数据可以细分为初始化零初始化和未初始化数据。 除了栈之外其它4类内存不需要占用连续的内存。 进程必须具有一些代码和栈其它3类不是必须有。堆是由进程管理的内存区域 通常用于创建动态数据对象。内存地址地址空间包括一个或多个不相交的区域。 区域不能跨越零地址但是可以从零开始。标记寻址(tagged addressing)的使用是特定平台解释的。 当禁用标记寻址时指针的所有64位都被传递到地址转换系统。 启用标记寻址时为了进行地址转换将忽略指针的前八位。注意此tagged addressing非iOS里的Tagged Pointer。栈栈是连续的内存空间可用于存储局部变量和参数传递(用于传递参数的寄存器不够用时候)。栈地址是从高到低栈的地址保存在SP中。栈使用限制Stack-limit SP stack-base进程只能访问这个范围内的栈空间[SP, stack-base – 1]SP mod 16 0函数调用A64指令集包含函数调用指令BL和BLR。执行BLPC(program counter)顺序的下一个值也就是返回地址(函数调用完成返回要执行指令的地址)存放到LR中将跳转地址传给PC。BLR跟BL类似只不过PC的值是从寄存器中读取。参数传递参数可通过r0-r7、v0-v7栈来传递如果参数个数不多且参数可放进寄存器那仅用寄存器传递参数。可变参数可变参数可分为命名参数(已声明的)和匿名参数(可选的参数)。当可变参数的函数调用时候没有可选参数时候(只有已声明的参数)调用过程和固定参数的函数一样的。参数传递规则参数传递从概念上可以分为2阶段从源语言参数类型到机器类型的映射(不同源语言映射规则不同)整理机器类型生成最终参数列表参数传递过程分为3个阶段阶段A – 初始化(在开始处理参数之前该阶段仅执行一次)NGRN 0 (NGRN意义见术语)NSRN 0 (NSRN意义见术语)NSAA SP(NSAA意义见术语)阶段B - 预填充和扩展参数 (把参数列表中的每一个参数去匹配下面规则第一个被匹配到的规则应用到该参数上。)如果参数类型是复合类型调用者和被调用者都不能确定其大小则将参数复制到内存中并将参数替换为指向该内存的指针。 (C / C 语言中没有这样的类型其它语言存在。)如果参数是HFA或HVA类型则参数不修改。如果参数是大于16个字节的复合类型调用者申请一个内存将参数复制到内存里去并将参数替换为指向该内存的指针。如果参数是复合类型则参数的大小向上舍入为最接近8个字节的倍数。(例如参数大小为9字节修改为16字节)阶段C- 把参数放到寄存器或栈里 (参数列表中的每个参数将依次应用以下规则直到参数放到寄存器或栈里此参数处理完成然后再从参数列表中取参数。注 将参数分配给寄存器时寄存器中未使用的位的值不确定。 将参数分配给栈时未填充字节的值不确定。)(1) 如果参数是half(16bit)single(16bit)double(32bit)或quad(64bit)浮点数或Short Vector Type并且NSRN小于8则将参数放入寄存器v[NSRN]的最低有效位。 NSRN增加1。 此参数处理完成。(2) 如果参数是HFA(homogeneous floating-point aggregate)或HVA(homogeneous short vector aggregate)类型且NSRN (HFA或HVA成员个数) ≤ 8则每个成员依次放入SIMD and Floating-point 寄存器NSRNNSRN HFA或HVA成员个数。此参数处理完成。(3) 如果参数是HFA(homogeneous floating-point aggregate)或HVA(homogeneous short vector aggregate)类型但是NSRN已经等于8(说明v0-v7被使用完毕)。则参数的大小向上舍入为最接近8个字节的倍数。(例如参数大小为9字节修改为16字节)(4) 如果参数是HFA(homogeneous floating-point aggregate)、HVA(homogeneous short vector aggregate)、quad(64bit)浮点数或Short Vector TypeNSAA NSAAmax(8, 参数自然对齐大小)。(5) 如果参数是half(16bit)single(16bit)浮点数参数扩展到8字节(放入最低有效位其余bits值不确定)(6) 如果参数是HFA(homogeneous floating-point aggregate)、HVA(homogeneous short vector aggregate)、half(16bit)single(16bit)double(32bit)或quad(64bit)浮点数或Short Vector Type参数copy到内存NSAANSAAsize(参数)。此参数处理完成。(7) 如果参数是整型或指针类型、size(参数)8字节且NGRN小于8则参数复制到x[NGRN]中的最低有效位。 NGRN增加1。 此参数处理完成。(8) 如果参数对齐后16字节NGRN向上取偶数。(例如NGRN为2那值保持不变假如NGRN为3则取4。 注iOS ABI没有这个规则)(9) 如果参数是整型对齐后16字节且NGRN小于7则把参数复制到x[NGRN] 和 x[NGRN1]x[NGRN]是低位。NGRN NGRN 2。 此参数处理完成。(10) 如果参数是复合类型且参数可以完全放进x寄存器(8-NGRN 参数字节大小/8)。从x[NGRN]依次放入参数(低位开始)。未填充的bits的值不确定。NGRN NGRN 此参数用掉的寄存器个数。此参数处理完成。(11) NGRN设为8。(12) NSAA NSAAmax(8, 参数自然对齐大小)。(13) 如果参数是复合类型参数copy到内存NSAANSAAsize(参数)。此参数处理完成。(14) 如果参数小于8字节参数设置为8字节大小高位bits值不确定。(15) 参数copy到内存NSAANSAAsize(参数)。此参数处理完成。从上面规则可以得到经验处理完参数列表中所有的参数后调用者一定知道传递参数用了多少栈空间。(NSAA - SP)浮点数和short vector types通过v寄存器和栈传递不会通过r寄存器传递。(除非是小复合类型的成员)寄存器和栈中参数未填充满的部分的值不可确定。函数返回结果函数返回方式取决于返回结果的类型。如果返回是类型T如下void func(T arg)复制代码arg值通过寄存器(组)传递返回的结果也是通过相同的寄存器(组)返回。2. 调用者申请内存(内存大小足够放入返回结果且是内存对齐的)将内存地址放入x8中传递给子函数子函数运行时候可以更新x8指向内存的内容从而将结果返回。结语假如文章有不对地方欢迎大家留言指出或者给我发邮件(wu_k_kfoxmail.com)。引用--EOF-- 转载请保留链接谢谢