欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

ARM 汇编基础速成4:ARM汇编内存访问相关指令

来源:本站整理 作者:佚名 时间:2017-07-11 TAG: 我要投稿

ARM使用加载-存储模式控制对内存的访问,这意味着只有加载/存储(LDR或者STR)才能访问内存。尽管X86中允许很多指令直接操作在内存中的数据,但ARM中依然要求在操作数据前,必须先从内存中将数据取出来。这就意味着如果要增加一个32位的在内存中的值,需要做三种类型的操作(加载,加一,存储)将数据从内存中取到寄存器,对寄存器中的值加一,再将结果放回到内存中。
为了解释ARM架构中的加载和存储机制,我们准备了一个基础的例子以及附加在这个基础例子上的三种不同的对内存地址的便宜访问形式。每个例子除了STR/LDR的偏移模式不同外,其余的都一样。而且这个例子很简单,最佳的实践方式是用GDB去调试这段汇编代码。
第一种偏移形式:立即数作为偏移
地址模式:用作偏移
地址模式:前向索引
地址模式:后向索引
第二种偏移形式:寄存器作为偏移
地址模式:用作偏移
地址模式:前向索引
地址模式:后向索引
第三种偏移形式:寄存器缩放值作为偏移
地址模式:用作偏移
地址模式:前向索引
地址模式:后向索引
基础样例代码
通常,LDR被用来从内存中加载数据到寄存器,STR被用作将寄存器的值存放到内存中。

LDR R2, [R0]   @ [R0] - 数据源地址来自于R0指向的内存地址
@ LDR操作:从R0指向的地址中取值放到R2中
STR R2, [R1]   @ [R1] - 目的地址来自于R1在内存中指向的地址
@ STR操作:将R2中的值放到R1指向的地址中
样例程序的汇编代码及解释如下:
.data          /* 数据段是在内存中动态创建的,所以它的在内存中的地址不可预测*/
var1: .word 3  /* 内存中的第一个变量 */
var2: .word 4  /* 内存中的第二个变量 */
.text          /* 代码段开始 */
.global _start
_start:
    ldr r0, adr_var1  @ 将存放var1值的地址adr_var1加载到寄存器R0中
    ldr r1, adr_var2  @ 将存放var2值的地址adr_var2加载到寄存器R1中
    ldr r2, [r0]      @ 将R0所指向地址中存放的0x3加载到寄存器R2中 
    str r2, [r1]      @ 将R2中的值0x3存放到R1做指向的地址
    bkpt            
adr_var1: .word var1  /* var1的地址助记符 */
adr_var2: .word var2  /* var2的地址助记符 */
在底部我们有我们的文字标识池(在代码段中用来存储常量,字符串,或者偏移等的内存,可以通过位置无关的方式引用),分别用adr_var1和adr_var2存储着变量var1和var2的内存地址(var1和var2的值在数据段定义)。第一条LDR指令将变量var1的地址加载到寄存器R0。第二条LDR指令同样将var2的地址加载到寄存器R1。之后我们将存储在R0指向的内存地址中的值加载到R2,最后将R2中的值存储到R1指向的内存地址中。
当我们加载数据到寄存器时,方括号“[]”意味着:将其中的值当做内存地址,并取这个内存地址中的值加载到对应寄存器。
当我们存储数据到内存时,方括号“[]”意味着:将其中的值当做内存地址,并向这个内存地址所指向的位置存入对应的值。
听者好像有些抽象,所以再来看看这个动画吧:

同样的再来看看的这段代码在调试器中的样子。
gef> disassemble _start
Dump of assembler code for function _start:
 0x00008074 :      ldr  r0, [pc, #12]   ; 0x8088
 0x00008078 :      ldr  r1, [pc, #12]   ; 0x808c
 0x0000807c :      ldr  r2, [r0]
 0x00008080 :     str  r2, [r1]
 0x00008084 :     bx   lr
End of assembler dump.
可以看到此时的反汇编代码和我们编写的汇编代码有出入了。前两个LDR操作的源寄存器被改成了[pc,#12]。这种操作叫做PC相对地址。因为我们在汇编代码中使用的只是数据的标签,所以在编译时候编译器帮我们计算出来了与我们想访问的文字标识池的相对便宜,即PC+12。你也可以看汇编代码中手动计算验证这个偏移是正确的,以adr_var1为例,执行到8074时,其当前有效PC与数据段还有三个四字节的距离,所以要加12。关于PC相对取址我们接下来还会接着介绍。
PS:如果你对这里的PC的地址有疑问,可以看外面第二篇关于程序执行时PC的值的说明,PC是指向当前执行指令之后第二条指令所在位置的,在32位ARM模式下是当前执行位置加偏移值8,在Thumb模式下是加偏移值4。这也是与X86架构PC的区别之所在。

第一种偏移形式:立即数作偏移
STR    Ra, [Rb, imm]
LDR    Ra, [Rc, imm]
在这段汇编代码中,我们使用立即数作为偏移量。这个立即数被用来与一个寄存器中存放的地址做加减操作(下面例子中的R1),以访问对应地址偏移处的数据。
.data
var1: .word 3
var2: .word 4
.text
.global _start
_start:
    ldr r0, adr_var1  @ 将存放var1值的地址adr_var1加载到寄存器R0中

[1] [2] [3] [4]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载