微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM 过程调用标准

ARM 过程调用标准

时间:11-10 来源:互联网 点击:
上不符合 APCS 的精神,那么将不允许来自你的编译器的代码与来自其他编译器的代码连接在一起。典型的,使用 C 语言的惯例。
  • 前 4 个整数实参(或者更少!)被装载到 a1 - a4。
  • 前 4 个浮点实参(或者更少!)被装载到 f0 - f3。
  • 其他任何实参(如果有的话)存储在内存中,用进入函数时紧接在 sp 的值上面的字来指向。换句话说,其余的参数被压入栈顶。所以要想简单。最好定义接受 4 个或更少的参数的函数。

 

函数退出

通过把返回连接值传送到程序计数器中来退出函数,并且:
  • 如果函数返回一个小于等于一个字大小的值,则把这个值放置到 a1 中。
  • 如果函数返回一个浮点值,则把它放入 f0 中。
  • sp、fp、sl、v1-v6、和 f4-f7 应当被恢复(如果被改动了)为包含在进入函数时它所持有的值。
    我测试了故意的破坏寄存器,而结果是(经常在程序完全不同的部分)出现不希望的和奇异的故障。
  • ip、lr、a2-a4、f1-f3 和入栈的这些实参可以被破坏。
在 32 位模式下,不需要对 PSR 标志进行跨越函数调用的保护。在 26 位模式下必须这样,并通过传送 lr 到 pc 中(MOVS、或 LDMFD xxx^)来暗中恢复。必须从 lr 重新装载 N、Z、C 和 V,跨越函数保护这些标志不是足够的。

建立栈回溯结构

对于一个简单函数(固定个数的参数,不可重入),你可以用下列指令建立一个栈回溯结构:
function_name_labelMOV     ip, spSTMFD   sp!, {fp,ip,lr,pc}SUB     fp, ip, #4
这个片段(来自上述编译后的程序)是最基本的形式。如果你要破坏其他不可破坏的寄存器,则你应该在这个 STMFD 指令中包含它们。

下一个任务是检查栈空间。如果不需要很多空间(小于 256 字节)则你可以使用:

CMPS    sp, slBLLT    |x$stack_overflow|这是 C 版本 4.00 处理溢出的方式。在以后的版本中,你要调用 |__rt_stkovf_split_small|。

接着做你自己的事情...

通过下面的指令完成退出:

LDMEA   fp, {fp,sp,pc}^
还有,如果你入栈了其他寄存器,则也在这里重新装载它们。选择这个简单的 LDM 退出机制的原因是它比分支到一个特殊的函数退出处理器(handler)更容易和更合理。

用在回溯中的对这个协议的一个扩展是把函数名字嵌入到代码中。紧靠在函数(和MOV ip, sp)的前面的应该是:

DCD     &ff0000xx
这里的‘xx’是函数名字符串的长度(包括填充和终结符)。这个字符串是字对齐、尾部填充的,并且应当被直接放置在 DCD &ff....的前面。

所以一个完整的栈回溯代码应当是:

DCB     "my_function_name", 0, 0, 0, 0DCD     &ff000010my_function_nameMOV     ip, spSTMFD   sp!, {fp, ip, lr, pc}SUB     fp, ip, #4CMPS    sp, sl                    ; 如果你不使用栈BLLT    |x$stack_overflow|        ; 则可以省略...处理...LDMEA   fp, {fp, sp, pc}^
要使它遵从 32-bit 体系,只须简单的省略最后一个指令的‘^’。注意你不能在一个编译的 26-bit 代码中使用这个代码。实际上,你可以去除它,但这不是我愿意打赌的事情。

如果你不使用栈,并且你不需要保存任何寄存器,并且你不调用任何东西,则没有必要设置 APCS 块(但在调试阶段对跟踪问题仍是有用的)。在这种情况下你可以:

my_simple_function...处理...MOVS    pc, lr
(再次,对 32 位 APCS 使用 MOV 而不是 MOVS,但是不要冒险与 26 位代码连接)。

 

APCS 标准

总的来说,有多个版本的 APCS (实际上是 16 个)。我们只关心在 RISC OS 上可能遇到的。

APCS-A
就是 APCS-Arthur;由早期的 Arthur 所定义。它已经被废弃,原因是它有不同的寄存器定义(对于熟练的 RISC OS 程序员它是某种异类)。它用于在 USR 模式下运行的 Arthur 应用程序。不应该使用它。

  • sl = R13, fp = R10, ip = R11, sp = R12, lr = R14, pc = R15。
  • PRM (p4-411) 中说“用r12作为sp,而不是在体系上更自然的r13,是历史性的并先于 Arthur 和 RISC OS 二者。”
  • 栈是分段的并可按需要来扩展。
  • 26-bit 程序计数器。
  • 不在 FP 寄存器中传递浮点实参。
  • 不可重入。标志必须被恢复。

APCS-R
就是 APCS-RISC OS。用于 RISC OS 应用程序在 USR 模式下进行操作;或在 SVC 模式下的模块/处理程序。

  • sl = R10, fp = R11, ip = R12, sp = R13, lr = R14, pc = R15。
  • 它是唯一的最通用的 APCS 版本。因为所有编译的 C 程序都使用 APCS-R。
  • 显式的栈限制检查。
  • 26-bit 程序计数器。
  • 不在 FP 寄存器中传递浮点实参。
  • 不可重入。标志必须被恢复。

APCS-U
就是 APCS-Unix,Acorn 的 RISCiX 使用它。它用于 RISCiX 应用程序(USR 模式)或内核(SVC 模式)。

  • sl = R10, fp

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top