ARM 过程调用标准
时间:11-10
来源:互联网
点击:
,来反向跟踪调用的函数。
回溯结构是:
地址高端保存代码指针 [fp] fp 指向这里返回 lr 值 [fp, #-4] 返回 sp 值 [fp, #-8] 返回 fp 值 [fp, #-12] 指向下一个结构 [保存的 sl][保存的 v6] [保存的 v5] [保存的 v4] [保存的 v3] [保存的 v2][保存的 v1][保存的 a4][保存的 a3][保存的 a2][保存的 a1][保存的 f7] 三个字[保存的 f6] 三个字[保存的 f5] 三个字[保存的 f4] 三个字地址低端
这个结构包含 4 至 27 个字,在方括号中的是可选的值。如果它们存在,则必须按给定的次序存在(例如,在内存中保存的 a3 下面可以是保存的 f4,但 a2-f5 则不能存在)。浮点值按‘内部格式’存储并占用三个字(12 字节)。
fp 寄存器指向当前执行的函数的栈回溯结构。返回 fp 值应当是零,或者是指向由调用了这个当前函数的函数建立的栈回溯结构的一个指针。而这个结构中的返回 fp 值是指向调用了调用了这个当前函数的函数的函数的栈回溯结构的一个指针;并以此类推直到第一个函数。
在函数退出的时候,把返回连接值、返回 sp 值、和返回 fp 值装载到 pc、sp、和 fp 中。
#include所以,我们可以检查 fp 并参看给函数‘two’的结构,它指向给函数‘one’的结构,它指向给‘main’的结构,它指向零来终结。在这种方式下,我们可以反向追溯整个程序并 确定我们是如何到达当前的崩溃点的。值得指出‘zero’函数,因为它已经被执行并退出了,此时我们正在做它后面的打印,所以它曾经在回溯结构中,但现在 不在了。值得指出的还有对于给定代码不太可能总是生成象上面那样的一个 APCS 结构。原因是不调用任何其他函数的函数不要求完全的 APCS 头部。void one(void);void two(void);void zero(void);int main(void){one();return 0;}void one(void){zero();two();return;}void two(void){printf("main...one...two/n");return;}void zero(void){return;}当它在屏幕上输出消息的时候,APCS 回溯结构将是:fp ----> two_structurereturn linkreturn spreturn fp ----> one_structure... return linkreturn spreturn fp ----> main_structure... return linkreturn spreturn fp ----> 0...
为了更细致的理解,下面是代码是 Norcroft C v4.00 为上述代码生成的...
AREA |C$code|, CODE, READONLYIMPORT |__main||x$codeseg|B |__main|DCB &6d,&61,&69,&6eDCB &00,&00,&00,&00DCD &ff000008IMPORT |x$stack_overflow|EXPORT oneEXPORT mainmainMOV ip, spSTMFD sp!, {fp,ip,lr,pc}SUB fp, ip, #4CMPS sp, slBLLT |x$stack_overflow|BL oneMOV a1, #0LDMEA fp, {fp,sp,pc}^DCB &6f,&6e,&65,&00DCD &ff000004EXPORT zeroEXPORT twooneMOV ip, spSTMFD sp!, {fp,ip,lr,pc}SUB fp, ip, #4CMPS sp, slBLLT |x$stack_overflow|BL zeroLDMEA fp, {fp,sp,lr}B twoIMPORT |_printf|twoADD a1, pc, #L000060-.-8B |_printf|L000060DCB &6d,&61,&69,&6eDCB &2e,&2e,&2e,&6fDCB &6e,&65,&2e,&2eDCB &2e,&74,&77,&6fDCB &0a,&00,&00,&00zeroMOVS pc, lrAREA |C$data||x$dataseg|END这个例子不遵从 32 为体系。APCS-32 规定只是简单的说明了标志不需要被保存。所以删除 LDM 的‘^’后缀,并在函数 zero 中删除 MOVS 的‘S’后缀。则代码就与遵从 32-bit 的编译器生成的一样了。
保存代码指针包含这条设置回溯结构的指令(STMFD ...)的地址再加上 12 字节。记住,对于 26-bit 代码,你需要去除其中的 PSR 来得到实际的代码地址。
现在我们查看刚进入函数的时候:
- pc总是包含下一个要被执行的指令的位置。
- lr(总是)包含着退出时要装载到pc中的值。在 26-bit 位代码中它还包含着 PSR。
- sp指向当前的栈块(chunk)限制,或它的上面。这是用于复制临时数据、寄存器和类似的东西到其中的地方。在 RISC OS 下,你有可选择的至少 256 字节来扩展它。
- fp要么是零,要么指向回溯结构的最当前的部分。
- 函数实参布置成(下面)描述的那样。
实际参数APCS 没有定义记录、数组、和类似的格局。这样语言可以自由的定义如何进行这些活动。但是,如果你自己的实现实际
ARM过程调用标 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)