.data
array_buff:
.word 0x00000000 /* array_buff[0] */
.word 0x00000000 /* array_buff[1] */
.word 0x00000000 /* array_buff[2]. This element has a relative address of array_buff+8 */
.word 0x00000000 /* array_buff[3] */
.word 0x00000000 /* array_buff[4] */
.text
.global _start
_start:
adr r0, words+12 /* address of words[3] -> r0 */
ldr r1, array_buff_bridge /* address of array_buff[0] -> r1 */
ldr r2, array_buff_bridge+4 /* address of array_buff[2] -> r2 */
ldm r0, {r4,r5} /* words[3] -> r4 = 0x03; words[4] -> r5 = 0x04 */
stm r1, {r4,r5} /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04 */
ldmia r0, {r4-r6} /* words[3] -> r4 = 0x03, words[4] -> r5 = 0x04; words[5] -> r6 = 0x05; */
stmia r1, {r4-r6} /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04; r6 -> array_buff[2] = 0x05 */
ldmib r0, {r4-r6} /* words[4] -> r4 = 0x04; words[5] -> r5 = 0x05; words[6] -> r6 = 0x06 */
stmib r1, {r4-r6} /* r4 -> array_buff[1] = 0x04; r5 -> array_buff[2] = 0x05; r6 -> array_buff[3] = 0x06 */
ldmda r0, {r4-r6} /* words[3] -> r6 = 0x03; words[2] -> r5 = 0x02; words[1] -> r4 = 0x01 */
ldmdb r0, {r4-r6} /* words[2] -> r6 = 0x02; words[1] -> r5 = 0x01; words[0] -> r4 = 0x00 */
stmda r2, {r4-r6} /* r6 -> array_buff[2] = 0x02; r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00 */
stmdb r2, {r4-r5} /* r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00; */
bx lr
words:
.word 0x00000000 /* words[0] */
.word 0x00000001 /* words[1] */
.word 0x00000002 /* words[2] */
.word 0x00000003 /* words[3] */
.word 0x00000004 /* words[4] */
.word 0x00000005 /* words[5] */
.word 0x00000006 /* words[6] */
array_buff_bridge:
.word array_buff /* address of array_buff, or in other words - array_buff[0] */
.word array_buff+8 /* address of array_buff[2] */
开始调试上面的代码gdb ldr
下断点
break _start
运行
run //运行到断点处
x/i $pc
:查看接下来反汇编指令(60是10进制数,转成16进制为3c)
0x10074 <_start>: add r0, pc, #60 ; 0x3c
使用i r pc
查询到 的pc当前存储的值为0x10074
pc 0x10074 0x10074 <_start>
也就是说下一条指令是用0x100b0
=(0x10074+0x3c),赋值给r0,但是实际并不是,执行下面的单步执行
,执行完第一条指令,使用i r r0
发现结果为0x100b8
r0 0x100b8 65720
为什么结果会比计算的值多8呢?
参考:什么时候PC+8,PC+4,PC-4,PC-8
[图片上传失败...(image-cefda3-1543372618746)]
需要知道的点:
1、每条指令执行有三个流程:取指、译码、执行
2、当第一条汇编指令取指完成后,紧接着就是第二条指令的取指,然后第三条...如此嵌套
3、取指
完成后,PC就指向了第二条指令,此时PC=PC+4
所以可以知道:第一条指令执行的时候,也是第三条指令的取指的时候,即PC=PC+8
单步执行
nexti/ni //步入
stepi/si //步过
adr r0, words+12
:将words+12处的内存地址获取并存到r0。
words+12->0x00000003(这个地址存储的值),
i r r0 //获取r0寄存器数据:0x100b8
x/3w 0x100b8 //十六进制,字类型查看0x100b8和其之后的两个地址的数据
结果:0x100b8 <words+12>: 3 4 5
ldm r0, {r4, r5}
ldm 源,目的寄存器
:r0的值为内存地址,其指向的值附给r4,r0+4指向的值给r5
r0: 寄存其中的值
r0 0x100b8 0x100b8
内存地址指向的值
x/w 0x100b8 >> 3
x/w 0x100bc >> 4
stm r1, {r4, r5}
stm 目的地址,{源寄存器}
:将寄存器中的值,放入目的地址指向的位置处
执行前:
$r1 : 0x000200d0
$r4 : 0x3
$r5 : 0x4
x/2w 0x100d0 (0x000100d0指向的值>>0x0; 0x000100d4>>0x0)
执行后si
:
x/2w 0x200d0
结果为:0x200d0: 0x3 0x4
ldmia、stmia
-IA(之后递增)
:ldm 和 ldmia是相同的,每次加载下一条指令,源地址都会增加4字节(一个字的值)
,stmia也一样
ldmia r0, {r4-r6} /* r0 -> r4 = 0x03, r0+4 -> r5 = 0x04; r0+8 -> r6 = 0x05; */
stmia r1, {r4-r6} /* r4 -> r1 = 0x03; r5 -> r1+4 = 0x04; r6 -> r1+8 = 0x05 */
ldmib、stmib
-IB(之前递增)
:在加载下一条指令之前增加4字节(一个字的值)
ldmia r0, {r4-r6} /* r0 -> r0+4 = 0x03, r0+8 -> r5 = 0x04; r0+12 -> r6 = 0x05; */
stmia r1, {r4-r6} /* r4 -> r1+4 = 0x03; r5 -> r1+8 = 0x04; r6 -> r1+12 = 0x05 */
LDMDA、STMDA:递减情况下,目的寄存器是先赋值给后面,同样从源寄存器中取指时也是先从后面取值
-DA(之后递减)
ldmda r0, {r4-r6} /* r0 -> r6 = 0x03; r0-4 -> r5 = 0x02; r0-8 -> r4 = 0x01 */
stmda r2, {r4-r6} /* r6 -> array_buff[2] = 0x02; r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00 */
LDMDB、STMDB
-DB(之前递减)
ldmdb r0, {r4-r6} /* r0-4 -> r6 = 0x02; r0-8 -> r5 = 0x01; r0-12 -> r4 = 0x00 */
stmdb r2, {r4-r5} /* r5 -> r2-4 = 0x01; r4 -> r2-8 = 0x00; */
PUSH AND POP
知识点PUSH
:
- SP-4
- 数据存储到SP指向的新地址处
POP
:
- SP的值先存储到某个寄存器中
- SP+4
实例
.text
.global _start
_start:
mov r0, #3
mov r1, #4
push {r0, r1}
pop {r2, r3}
stmdb sp!, {r0, r1}
ldmia sp!, {r4, r5}
bkpt
汇编后:
0x10054 <_start+0> mov r0, #3
0x10058 <_start+4> mov r1, #4
-> 0x1005c <_start+8> push {r0, r1}
0x10060 <_start+12> pop {r2, r3}
0x10064 <_start+16> push {r0, r1}
0x10068 <_start+20> pop {r4, r5}
0x1006c <_start+24> bkpt 0x0000
- push:先从后面压入堆栈
0x1005c <_start+8> push {r0, r1} //r0=3;r1=4
堆栈信息:
0xbefff2a8|+0x0000: 0x00000003 <-$sp
0xbefff2ac|+0x0004: 0x00000004
- pop:先赋值给前面的寄存器
0x10060 <_start+12> pop {r2, r3}
寄存器信息
$r2 : 0x3
$r3 : 0x4
-
stmdb sp!
就是push
-
ldmia sp!
就是pop