APCS (ARM 过程调用标准) 编写安全的 32-bit 代码的基本规则 IEEE 浮点指令 汇编器伪指令 指令快速查找 ARM 指令格式 寄存器和处理器模式 ARM 处理器有二十七个寄存器,其中一些是在一定条件下使用的,所以一次只能使用十六 个... 寄存器 0 到寄存器 7 是通用寄存器并可以用做任何目的.不象 80x86 处理器那样 要求特定寄存器被用做栈访问,或者象 6502 那样把数学计算的结果放置到一个累 加器中,ARM 处理器在寄存器使用上是高度灵活的. 寄存器 8 到 12 是通用寄存器,但是在切换到 FIQ 模式的时候,使用它们的影子 (shadow)寄存器. 寄存器 13 典型的用做 OS 栈指针,但可被用做一个通用寄存器.这是一个操作系 统问题,不是一个处理器问题,所以如果你不使用栈,只要你以后恢复它,你可以 在你的代码中自由的占用(corrupt)它.每个处理器模式都有这个寄存器的影子寄存 器. 寄存器 14 专职持有返回点的地址以便于写子例程.当你执行带连接的分支的时候, 把返回地址存储到 R14 中.同样在程序第一次运行的时候,把退出地址保存在 R14 中.R14 的所有实例必须被保存到其他寄存器中(不是实际上有效)或一个栈中.这 个寄存器在各个处理器模式下都有影子寄存器.一旦已经保存了连接地址,这个寄 存器就可以用做通用寄存器了. 寄存器 15 是程序计数器.它除了持有指示程序当前使用的地址的二十六位数之外, 还持有处理器的状态. 为更清晰一些... 提供下列图表: User 模式 SVC 模式 IRQ 模式 FIQ 模式 APCS R0 ------- R0 ------- R0 ------- R0 a1 R1 ------- R1 ------- R1 ------- R1 a2 R2 ------- R2 ------- R2 ------- R2 a3 R3 ------- R3 ------- R3 ------- R3 a4 R4 ------- R4 ------- R4 ------- R4 v1 R5 ------- R5 ------- R5 ------- R5 v2 R6 ------- R6 ------- R6 ------- R6 v3 R7 ------- R7 ------- R7 ------- R7 v4 R8 ------- R8 ------- R8 ----R8_fiq v5 R9 ------- R9 ------- R9 ----R9_fiq v6 R10 ------ R10 ------ R10 --R10_fiq sl R11 ------ R11 ------ R11 --R11_fiq fp R12 ------ R12 ------ R12 --R12_fiq ip R13 ---R13_svc ---R13_irq --R13_fiq sp R14 ---R14_svc ---R14_irq --R14_fiq lr ------------- R15 / PC ------------- pc 最右侧的列是 APCS 代码使用的名字,关于 APCS 的详情参见这里. 程序计数器构造如下: 位 31 30 29 28 27 26 25------------2 1 0 N Z C V I F 程 序 计 数 器 S1 S0 对 R15 的详细解释,请参见 psr.html. 下面是你想知道的"模式",比如上面提及的"FIQ"模式. 用户模式,运行应用程序的普通模式.限制你的内存访问并且你不能直接读取硬件 设备.
超级用户模式(SVC 模式),主要用于 SWI(软件中断)和 OS(操作系统).这个模式有 额外的特权,允许你进一步控制计算机.例如,你必须进入超级用户模式来读取一 个插件(podule).这不能在用户模式下完成.
中断模式(IRQ 模式),用来处理发起中断的外设.这个模式也是有特权的.导致 IRQ 的设备有键盘, VSync (在发生屏幕刷新的时候),IOC 定时器,串行口,硬盘,软 盘,等等...
快速中断模式(FIQ 模式),用来处理发起快速中断的外设.这个模式是有特权的. 导致 FIQ 的设备有处理数据的软盘,串行端口(比如在 82C71x 机器上的 A5000) 和 Econet.
IRQ 和 FIQ 之间的区别是对于 FIQ 你必须尽快处理你事情并离开这个模式.IRQ 可以被 FIQ 所中断但 IRQ 不能中断 FIQ.为了使 FIQ 更快,所以有更多的影子寄存器.FIQ 不能 调用 SWI.FIQ 还必须禁用中断.如果一个 FIQ 例程必须重新启用中断,则它太慢了并应 该是 IRQ 而不是 FIQ. APCS,ARM 过程调用标准(ARM Procedure Call Standard),提供了紧凑的编写例程的一种机制,定义的例程可以与其他例程交织在一起。最显著的一点是对这些例程来自哪里没有明确的限制。它们可以编译自 C、 Pascal、也可以是用汇编语言写成的。 APCS 定义了:
对寄存器使用的限制。 使用栈的惯例。 在函数调用之间传递/返回参数。 可以被‘回溯’的基于栈的结构的格式,用来提供从失败点到程序入口的函数(和给予的参数)的列表。 APCS 不一个单一的给定标准,而是一系列类似但在特定条件下有所区别的标准。例如,APCS-R (用于 RISC OS)规定在函数进入时设置的标志必须在函数退出时复位。在 32 位标准下,并不是总能知道进入标志的(没有 USR_CPSR),所以你不需要恢复它们。如你所预料的那样,在不同版本间没有相容性。希望恢复标志的代码在它们未被恢复的时候可能会表现失常...
如果你开发一个基于 ARM 的系统,不要求你去实现 APCS。但建议你实现它,因为它不难实现,且可以使你获得各种利益。但是,如果要写用来与编译后的 C 连接的汇编代码,则必须使用 APCS。编译器期望特定的条件,在你的加入(add-in)代码中必须得到满足。一个好例子是 APCS 定义 a1 到 a4 可以被破坏,而 v1 到 v6 必须被保护。现在我确信你正在挠头并自言自语“a 是什么? v 是什么?”。所以首先介绍 APCS-R 寄存器定义...
|