MDK环境的ARM汇编中内存对齐与对ADR Rd,{PC}+n形式的理解
来源:互联网 发布:编程什么意思 编辑:程序博客网 时间:2024/05/24 03:23
在使用ARM汇编的过程中,经常因内存对齐的问题,引发各种奇怪的错误,
以及在使用MDK环境编写Cortex-M3的汇编语言时
ADR Rd,label汇编成一条与PC有关的指令,并表现为如下形式:
ADR Rd,{PC}+n ;其中n的取值不是2,就是4
这经常让人产生疑惑,因为不知道{PC}到底是一种什么样的表达。
现在,通过一段测试代码,来看看内存对齐是如何引发错误的,以及通过它的反汇编,说明{PC}的性质。
代码如下:
上述代码将会产生两个错误:
User\base.s(22): error: A1867E: Immediate 0x00000006 out of range for this operation. Permitted values are multiples of 4 from 0x00000000 to 0x000003FF
User\base.s(23): error: A1875E: Register Rn must be from R0 to R7 in this instruction
这两个错误其实就是一个错误,都是非对齐访问引起的。
首先,对于ADR和LDR与标号有关的内存访问,在不加.W后缀的情况下,都只能汇编成16位的Thumb指令。
因此,22行与23行的两条指令都是16位的。由于他们的标号都会汇编成PC与相对于PC的偏移量构成。
由于16位编码的原因,偏移量由8位表示,且根据规定,只能是0~1020之间4的倍数。
显然,22行的指令地址为0x08000014,而标号SUM的地址为0x0800001E,相差为10
(考虑到指令流水线,PC的值相差10-4=6,ADR R2,SUM将用指令ADD R2,PC,#6代替,显然6不能被4整除),
因此无法生成相对于PC的ADD指令,编译器报告错误:立即数0x00000006超出该操作的范围。允许的值是0x00000000到0x000003FF间4的倍数
23行的指令地址为0x08000016,与标号SUM的地址0x0800001E相差为8,这样看来是能被4整除的,但是怎么也报错?
其实,这就是内存对齐的问题了。执行时,取出PC,先将它字对齐,这样0x08000016就变成了0x08000014,实际上还是与SUM像差10(考虑到流水线机制,PC值相差6)
这样,LDR R3,SUM将使用LDR R3,[PC,#6]代替,该指令编码如下:
LDR Rt ,[PC,#<imm8>]
编译器从低位到高位编码指令,8位立即数<imm8>要求是0~1020间4的倍数,显然,指令中的立即数6不合法!
由于LDR指令有两种编码格式,编译器尝试第二种格式。
这种编码格式如下:
LDR Rt,[Rn,#imm5]
编译器从低位到高位编码指令,我们看到,Rt与Rn只有3位的编码,这意味着,它们只能在R0~R7之间选择。
首先,该指令的Rt选择了R3,而Rn确是PC(R15),超过了允许范围,汇编至此停止,编译器报告错误:该指令的寄存器Rn必须在R0到R7之间
解决的办法很简答,在这两条指令后加一条NOP指令(半字),使指令与标号SUM的PC值相差增加2,由6变为8,能被4整除!
正确代码如下:
现在,来关注反汇编窗口
结合ADR指令的16位编码格式:
ADR Rd ,<label> 即 ADD Rd ,PC,#<imm8>
分析红色框中的机器码:
A201:1010001000000001 编码中imm8=1,指令中<imm8>=4*imm8=4
A200:1010001000000000 编码中imm8=0,指令中<imm8>=4*imm8=0
A202:1010001000000010 编码中imm8=2,指令中<imm8>=4*imm8=8
我们得知:这三条指令分别解释为:
ADD R2,PC,#4ADD R2,PC,#0ADD R2,PC,#8考虑到指令流水线机制,将上述三条加法指令计算的结果都加上4,非字对齐结果按字对齐,就得到存入R2中数据的值,也就是反汇编窗口中@符号后面的值。
仔细分析反汇编窗口中的三条指令:
ADR r2,{pc}+4ADR r2,{pc}+2ADR r2,{pc}+4可以发现,其实{PC}就是表示PC的当前值(没有采取任何对齐操作)
而后面加的数字,是有规律的
当指令在字对齐边界上时,如在地址0x08000010和地址0x08000014处,该数字是4
而在半字对齐边界上时,如在地址0x08000012处,该数字是2
这个数字的目的在于将PC补成字对齐的,而且已经考虑到了指令流水线对PC的影响,之后再与8位的立即数相加!直接得到结果。
我们来看彩色框中的四个部分,分别是{PC}的值,立即数<imm8>的编码值,{PC}之后的数字,和r2中的结果
分析如下:
r2 = {pc} + 4*imm8 + 4 = 0x08000010 + 4*1 + 4 =0x08000018
r2 = {pc} + 4*imm8 + 2 = 0x08000012 + 4*0 + 2 = 0x08000014
r2 = {pc} + 4*imm8 + 4 = 0x08000014 + 4*2 + 4 = 0x08000020
最后:代码窗口中第21行的指令
LDR R2,{PC}+2不同于反汇编窗口中的表达,它是一条伪指令,表示将PC的当前值+2载入到R2中。
该伪指令后面的数字不受限制,即可以是
LDR R2,{PC}+n ;n是寻址范围内的任意值对于反汇编窗口或汇编源文件中出现的,形如:
LDR R2,{PC}-n的指令,参照上述是+的两种情况对应分析。
- MDK环境的ARM汇编中内存对齐与对ADR Rd,{PC}+n形式的理解
- ARM汇编中ldr与adr的区别
- ARM汇编中ldr与adr的区别
- ARM汇编中ldr与adr的区别
- ARM汇编中ldr与adr的区别(转)
- ARM汇编中ldr与adr的区别(转)
- ARM汇编中ldr与adr的区别
- ARM汇编中LDR和ADR的区别
- 关于在ARM中(MDK下)C与汇编混合编程的问题
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- 字母重排
- 如何异步调用Visual C#函数How to call a Visual C# method asynchronously
- hdu 4849 Wow! Such City!(dijstra)
- 推荐算法之基于物品的协同过滤算法
- 1379: [Baltic2001]Postman
- MDK环境的ARM汇编中内存对齐与对ADR Rd,{PC}+n形式的理解
- 【android】app测试工具
- 安装windows phone 8开发环境
- POJ 2485 Highways
- 初探linux子系统集之led子系统(一)
- 南邮ACM 1015 最大公约数和最小公倍数 JAVA解法
- poj 2411 状态压缩(矩形铺砖)
- 解决Win8/8.1无法正确识别USB3.0的问题
- 设计模式之组合模式解决文件目录OJ问题(百练OJ【ps:白练】2775:文件结构“图”)