ARM反汇编的指令、寄存器含义及作用、堆栈方式

Source:http://blog.csdn.net/mmdj2008/article/details/6381524

                 http://general.blog.51cto.com/927298/657803/

http://blog.csdn.net/ssdsafsdsd/article/details/8686229

http://blog.csdn.net/qianlong4526888/article/details/7719675

当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack);

当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。

同时,根据堆栈的生成方式,又可以分为递增堆栈(Ascending Stack)和递减堆栈(DecendingStack)。

当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。

 

这样就有四种类型的堆栈工作方式,ARM 微处理器支持这四种类型的堆栈工作方式,

即:

 ◎ Full descending 满递减堆栈——FD 堆栈首部是高地址,堆栈向低地址增长。栈指针总是指向堆栈最后一个元素(最后一个元素是最后压入的数据)。 ARM-Thumb过程调用标准和ARM、Thumb C/C++ 编译器总是使用Full descending 类型堆栈。

 ◎ Full ascending 满递增堆栈——FA 堆栈首部是低地址,堆栈向高地址增长。栈指针总是指向堆栈最后一个元素(最后一个元素是最后压入的数据)。

◎ Empty descending 空递减堆栈——ED 堆栈首部是高地址,堆栈向低地址增长。栈指针总是指向下一个将要放入数据的空位置。

◎ Empty ascending 空递增堆栈——EA 堆栈首部是低地址,堆栈向高地址增长。栈指针总是指向下一个将要放入数据的空位置。

 

       在ARM中,一般是满堆栈,堆栈生长方向是从上向下递减的(51相反为递增),在操作系统的一直过程中,与CPU相关部分的一直肯定会涉及到堆栈生长方向的定义。

      在ARM中我们定义如下:

       #define OS_STK_GROWTH 1 //从上向下递减 UCOS51中相同的定义如下:

       #define OS_STK_GROWTH 0 //从下向上递增

      一直对arm 的堆栈操作有很多疑惑,这几天终于没有客户来烦了,拿出书来研究了一下,发现原来理解上有误区。这里写一些读书笔记,算是帮自己记录一下吧。

     arm堆栈的组织结构是 满栈降 的形式,满栈即sp是要停留在最后一个进栈元素,降:就是堆栈的增长方向是从高地址向低地址发展。 arm对于堆栈的操作一般采用 LDMFD(pop)和STMFD (push) 两个命令。 以前困惑的就是STMFD 命令 对于操作数 是按照什么顺序压栈的 

    比如:STMFD sp!{R0-R5,LR} 进栈顺序是:

                         高地址(1方式) LR R5 R4 ``````` R0 <-sp 低地址

                         高地址(2方式) R0 R1 ``` R5 LR <-sp 低地址

 

现在通过下表,可以轻松的解决这个问题:
寻址方式 说明 pop =LDM push =STM
FA 递增满 LDMFA LDMDA STMFA STMIB
FD 递减满 LDMFD LDMIA STMFD STMDB
EA 递增空 LDMEA LDMDB STMEA STMIA
ED 递减空 LDMED LDMIB STMED STMDA

 

可以轻松的解决这个问题: 寻址方式说明 pop =LDM push =STM FA 递增满 LDMFA LDMDA STMFA STMIB FD 递减满 LDMFD LDMIA STMFD STMDB EA 递增空 LDMEA LDMDB STMEA STMIA ED 递减空 LDMED LDMIB STMED STMDA 按照图表,可知 STMFD对应的是STMDB,根据arm指令手册,可知STMDB入栈顺序是(1方式) 而LDMFD对应的是LDMIA,这样这两个操作就可以成功配对



先看个例子:

void test2(int a,int b,int c)

int k=a,j=b,m=c;

}
GCC反汇编:
00000064 <test2>:
mov     ip, sp                  //IP=SP;保存SP
stmdb   sp!, {fp, ip, lr, pc}   //先对SP减4,再对fp,ip,lr,pc压栈。---------1
sub     fp, ip, #4      ; 0x4   //fp=ip-4;此时fp指向栈里面的“fp”
sub     sp, sp, #24     ; 0x18 //分配空间
str     r0, [fp, #-28]          //
str     r1, [fp, #-32]          //
str     r2, [fp, #-36]          //参数压栈
ldr     r3, [fp, #-28]          //
str     r3, [fp, #-24]          //
ldr     r3, [fp, #-32]          //
str     r3, [fp, #-20]          //
ldr     r3, [fp, #-36]          //
str     r3, [fp, #-16]          //
sub     sp, fp, #12     ; 0xc   //sp=fp-12;此时sp指向栈里面的lr
ldmia   sp, {fp, sp, pc}        //弹栈pc=lr,sp=ip,fp=fp。然后地址加4---------1

汇编基础:
stmdb   sp!, {fp, ip, lr, pc} //sp=sp-4,sp=pc;先压PC
                              //sp=sp-4,sp=lr;再压lr
                              //sp=sp-4,sp=ip;再压ip
                              //sp=sp-4,sp=fp;再压fp
ldmia   sp, {fp, sp, pc}      //和stmdb成对使用,
                              //fp=sp,sp=sp+4;先弹fp
                              //sp=sp,sp=sp+4;先弹sp,此处的弹出不会影响sp,因为ldmia是一个机器周期执行完的。
                              //pc=sp,sp=sp+4;先弹pc
LDRH          R0, [R13, #0xC] //加载无符号半字数据,即低16位
LDRB          R0, [R13, #0x4] //加载一字节数据,即低8位。

注意:R11=fp;R12=ip;R13=SP;R14=LR;R15=PC;R0,R1,R2用于传递参数和存放函数返回值。
注意;低地址的寄存器被压入低地址内存中,也就是说如果向下增长,高地址寄存器先压,向上增长测试低地址先压。 
注意:根据“ARM-thumb 过程调用标准”:
1, r0-r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。---如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。
2, r4-r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。
3, r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。

4,寄存器 r13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
5,寄存器 r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复

6,寄存器 r15 是程序计数器 PC。它不能用于任何其它用途。

7,在中断程序中,所有的寄存器都必须保护,编译器会自动保护R4~R11,所以一般你自己只要在程序的开头
sub lr,lr,#4
stmfd sp!,{r0-r3,r12,lr};保护R0~R3,R12,LR就可以了,除非你用汇编人为的去改变R4~R11的值。(具体去看UCOS os_cpu_a.S中的IRQ中断的代码)

补充:

寄存器名字
Reg # APCS 意义
R0 a1 工作寄存器
R1 a2 "
R2 a3 "
R3 a4 "
R4 v1 必须保护
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 v6 "
R10 sl 栈限制
R11 fp 桢指针
R12 ip 
R13 sp 栈指针
R14 lr 连接寄存器
R15 pc 程序计数器

回溯结构

寄存器 fp (桢指针)应当是零或者是指向栈回溯结构的列表中的最后一个结构,提供了一种追溯程序的方式,来反向跟踪调用的函数。

回溯结构是:

地址高端

   保存代码指针        [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]                          三个字

pc 总是包含下一个要被执行的指令的位置。 
lr (总是)包含着退出时要装载到 pc 中的值。在 26-bit 位代码中它还包含着 PSR。 
sp 指向当前的栈块(chunk)限制,或它的上面。这是用于复制临时数据、寄存器和类似的东西到其中的地方。在 RISC OS 下,你有可选择的至少 256 字节来扩展它。 
fp 要么是零,要么指向回溯结构的最当前的部分。





  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
原作者:宛城布衣。 本文件已移除PDF签名,如内容有误,欢迎大家指正。 目录 前言 i 目录 I ARM7TDMI(-S)指令集及汇编1 ARM 处理器寻址方式2 寄存器寻址2 立即寻址2 寄存器偏移寻址2 寄存器间接寻址3 基址寻址3 多寄存器寻址4 堆栈寻址4 块拷贝寻址5 相对寻址5 指令集介绍7 ARM 指令集7 指令格式7 第 2 个操作数7 #immed_8r 7 Rm8 Rm,shift8 条件码9 ARM 存储器访问指令 11 LDR 和 STR 11 LDM 和 STM14 SWP 17 ARM 数据处理指令19 数据传送指令20 MOV 20 MVN 20 算术逻辑运算指令20 ADD 20 SUB21 RSB 21 ADC 21 SBC 21 RSC 22 AND 22 ORR22 EOR22 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII BIC 23 第 I 页常用 ARM 指令集及汇编 Ver:1010 比较指令23 CMP 23 CMN23 TST24 TEQ24 乘法指令25 MUL25 MLA25 UMULL25 UMLAL26 SMULL 26 SMLAL 26 ARM 跳转指令27 B27 BL27 BX 27 ARM 协处理器指令28 CDP28 LDC29 STC 29 MCR30 MRC30 ARM 杂项指令31 SWI 31 MRS 32 MSR 33 ARM指令34 ADR 35 ADRL35 LDR36 NOP37 Thumb 指令集39 Thumb 指令集与 ARM 指令集的区别 39 Thumb 存储器访问指令 40 LDR 和 STR 41 PUSH 和 POP 43 LDMIA 和 STMIA 43 Thumb 数据处理指令 45 数据传送指令46 MOV 46 MVN 46 NEG47 算术逻辑运算指令47 ADD 47 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 第 II 页常用 ARM 指令集及汇编 Ver:1010 SUB48 ADC 49 SBC 49 MUL50 AND 50 ORR50 EOR51 BIC 51 ASR51 LSL52 LSR 52 ROR53 比较指令53 CMP 53 CMN54 TST54 Thumb 跳转指令 55 B 55 BL55 BX 55 Thumb 杂项指令 56 SWI 56 Thumb 伪指令 57 ADR 57 LDR57 NOP58 伪指令59 符号定义伪指令59 GBLA、GBLL、GBLS 59 LCLA、LCLL、LCLS60 SETA、SETL、SETS 61 RLIST61 CN 62 CP62 DN、SN62 FN63 数据定义伪指令63 LTORG64 MAP64 FIELD 65 SPACE66 DCB 66 DCD 和 DCDU67 DCDO 67 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 第 III 页常用 ARM 指令集及汇编 Ver:1010 DCFD 和 DCFDU68 DCFS 和 DCFSU68 DCI69 DCQ 和 DCQU69 DCW 和 DCWU 70 报告伪指令70 ASSERT 70 INFO 71 OPT 71 TTL 和 SUBT 72 汇编控制伪指令73 IF、ELSE 和 ENDIF73 MACRO 和 MEND 74 WHIL 和 WEND 75 杂项伪指令76 ALIGN 77 AREA78 CODE16 和 CODE32 79 END 80 ENTRY80 EQU 81 EXPORT 和 GLOBAL 81 IMPORT 和 EXTERN 82 GET 和 INCLUDE 83 INCBIN83 KEEP83 NOFP 84 REQUIRE 84 PEQUIRE8 和 PRESERVE8 84 RN 84 ROUT85 ARM指令86 ADR 86 ADRL86 LDR86

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值