新网站制作市场,答题小程序开发教程,做网站需要平台,商场设计网站LOAD/STORE MULTIPLE 有时一次加载#xff08;或存储#xff09;多个值更有效。为此#xff0c;我们使用LDM#xff08;加载多个#xff09;和STM#xff08;存储多个#xff09;。这些指令有一些变化#xff0c;基本上只在访问初始地址的方式上有所不同。这是…LOAD/STORE MULTIPLE 有时一次加载或存储多个值更有效。为此我们使用LDM加载多个和STM存储多个。这些指令有一些变化基本上只在访问初始地址的方式上有所不同。这是我们将在本节中使用的代码。我们将一步一步地研究每一条指令。
.dataarray_buff:.word 0x00000000 /* array_buff[0] */.word 0x00000000 /* array_buff[1] */.word 0x00000000 /* array_buff[2]. This element has a relative address of array_buff8 */.word 0x00000000 /* array_buff[3] */.word 0x00000000 /* array_buff[4] */.text
.global _start_start:adr r0, words12 /* address of words[3] - r0 */ldr r1, array_buff_bridge /* address of array_buff[0] - r1 */ldr r2, array_buff_bridge4 /* 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 lrwords:.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_buff8 /* address of array_buff[2] */ 在开始之前请记住.字指的是32位4字节的数据内存块。这对于理解抵消非常重要。因此该程序由.data部分组成我们在其中分配一个包含5个元素的空数组array_buff。我们将使用它作为存储数据的可写内存位置。.text部分包含我们的代码以及内存操作指令和一个只读数据池其中包含两个标签一个用于具有7个元素的数组另一个用于“桥接”.text和.data部分以便我们可以访问.data部分中的array_buff。
adr r0, words12 /* address of words[3] - r0 */ 我们使用ADR指令惰性方法将第4个单词[3]元素的地址获取到R0中。我们指向单词数组的中间因为我们将从那里向前和向后操作。
gef break _start
gef run
gef nexti R0现在包含字[3]的地址在本例中为0x80B8。这意味着我们的数组从字[0]的地址开始0x80AC0x80B8–0xC。
gef x/7w 0x00080AC
0x80ac words: 0x00000000 0x00000001 0x00000002 0x00000003
0x80bc words16: 0x00000004 0x00000005 0x00000006 我们用array_buff数组的第一个array_buff[0]和第三个array_buff[2]元素的地址来准备R1和R2。一旦获得地址我们就可以开始对其进行操作。
ldr r1, array_buff_bridge /* address of array_buff[0] - r1 */
ldr r2, array_buff_bridge4 /* address of array_buff[2] - r2 */ 在执行上述两条指令后R1和R2包含array_buff[0]和array_bufp[2]的地址。
gef info register r1 r2
r1 0x100d0 65744
r2 0x100d8 65752 下一条指令使用LDM从R0指向的内存中加载两个字值。因此因为我们早些时候让R0指向单词[3]元素单词[3]值变为R4单词[4]值变为R5。
ldm r0, {r4,r5} /* words[3] - r4 0x03; words[4] - r5 0x04 */ 我们用一个命令加载了多个2个数据块该命令设置R40x00000003和R50x00000004。
gef info registers r4 r5
r4 0x3 3
r5 0x4 4 到目前为止还不错。现在让我们执行STM指令将多个值存储到内存中。我们代码中的STM指令从寄存器R4和R5获取值0x3和0x4并将这些值存储到R1指定的内存位置。我们之前将R1设置为指向第一个array_buff元素因此在该操作之后array_buff[0]0x00000003array_baff[1]0x00000004。如果未另行指定LDM和STM在字的一个步长上运算32位4字节。
stm r1, {r4,r5} /* r4 - array_buff[0] 0x03; r5 - array_buff[1] 0x04 */ 值0x3和0x4现在应该存储在存储器地址0x100D0和0x100D4处。以下指令检查地址0x000100D0处的两个存储器字。
gef x/2w 0x000100D0
0x100d0 array_buff: 0x3 0x4 如前所述LDM和STM有变化。变体的类型由指令的后缀定义。示例中使用的后缀为-IA在之后增加、-IB在之前增加、-DA在后面减少、-DB在前面减少。这些变体访问第一个操作数指定的内存存储源或目标地址的寄存器的方式不同。在实践中LDM与LDMIA相同这意味着要加载的下一个元素的地址在每次加载后都会增加。通过这种方式我们从第一个操作数指定的内存地址存储源地址的寄存器获得顺序正向数据加载。
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 */ 在执行上述两条指令之后寄存器R4-R6和存储器地址0x000100D0、0x000100D4和0x000100D8包含值0x3、0x4和0x5。
gef x/3w 0x100D4
0x100d4 array_buff4: 0x00000004 0x00000005 0x00000006
gef info register r4 r5 r6
r4 0x4 4
r5 0x5 5
r6 0x6 6 当我们使用LDMDA指令时一切都开始向后操作。R0指向单词[3]。当加载开始时我们向后移动并将单词[3]、单词[2]和单词[1]加载到R6、R5、R4中。是的寄存器也是向后加载的。因此在指令完成后R60x00000003R50x00000002R40x00000001。这里的逻辑是我们向后移动因为我们在每次加载后递减源地址。发生反向注册表加载是因为每次加载时我们都会减少内存地址从而减少注册表编号以跟上内存地址越高注册表编号越高的逻辑。查看LDMIA或LDM示例我们首先加载较低的注册表因为源地址较低然后加载较高的注册表原因是源地址增加。
加载倍数在以下时间后递减
ldmda r0, {r4-r6} /* words[3] - r6 0x03; words[2] - r5 0x02; words[1] - r4 0x01 */
执行后的寄存器R4、R5和R6
gef info register r4 r5 r6
r4 0x1 1
r5 0x2 2
r6 0x3 3
存储倍数之后递减。
stmda r2, {r4-r6} /* r6 - array_buff[2] 0x02; r5 - array_buff[1] 0x01; r4 - array_buff[0] 0x00 */
array_buff[2]、array_buff[1]、array_bbuff[0]执行后的内存地址
gef x/3w 0x100D0
0x100d0 array_buff: 0x00000000 0x00000001 0x00000002
存储倍数递减之前
stmdb r2, {r4-r5} /* r5 - array_buff[1] 0x01; r4 - array_buff[0] 0x00; */
array_buff[1]和array_bufp[0]执行后的内存地址
gef x/2w 0x100D0
0x100d0 array_buff: 0x00000000 0x00000001
PUSH AND POP 进程中有一个名为Stack的内存位置。堆栈指针SP是一个寄存器在正常情况下它总是指向堆栈内存区域中的地址。应用程序经常使用Stack进行临时数据存储。如前所述ARM使用加载/存储模型进行内存访问这意味着指令LDR/STR或其衍生物LDM../STM..用于内存操作。在x86中我们使用PUSH和POP从堆栈加载和存储。在ARM中我们也可以使用以下两条指令
当我们把一些东西推到Full Descending第7部分堆栈和函数中关于堆栈差异的更多信息堆栈上时会发生以下情况
首先SP中的地址减少4。其次信息被存储到SP指向的新地址
当我们从堆栈中弹出某个东西时会发生以下情况 当前SP地址处的值被加载到某个寄存器中 SP中的地址增加4。
在以下示例中我们同时使用PUSH/POP和LDMIA/STMDB
.text
.global _start_start:mov r0, #3mov r1, #4push {r0, r1}pop {r2, r3}stmdb sp!, {r0, r1}ldmia sp!, {r4, r5}bkpt
让我们来看看这个代码的反汇编。
azerialabs:~$ as pushpop.s -o pushpop.o
azerialabs:~$ ld pushpop.o -o pushpop
azerialabs:~$ objdump -D pushpop
pushpop: file format elf32-littlearmDisassembly of section .text:00008054 _start:8054: e3a00003 mov r0, #38058: e3a01004 mov r1, #4805c: e92d0003 push {r0, r1}8060: e8bd000c pop {r2, r3}8064: e92d0003 push {r0, r1}8068: e8bd0030 pop {r4, r5}806c: e1200070 bkpt 0x0000 正如您所看到的我们的LDMIA和STMDB指令被转换为PUSH和POP。这是因为PUSH是STMDB-sp的同义词reglist和POP是LDMIA sp的同义词reglist请参阅ARM手册
让我们在GDB中运行此代码。
gef break _start
gef run
gef nexti 2
[...]
gef x/w $sp
0xbefff7e0: 0x00000001 运行前两条指令后我们快速检查了SP指向的内存地址和值。下一条PUSH指令应将SP减少8并将R1和R0的值按顺序存储到堆栈中。
gef nexti
[...] ----- Stack -----
0xbefff7d8|0x00: 0x3 - $sp
0xbefff7dc|0x04: 0x4
0xbefff7e0|0x08: 0x1
[...]
gef x/w $sp
0xbefff7d8: 0x00000003 接下来这两个值0x3和0x4从堆栈弹出到寄存器中使得R20x3和R30x4。SP增加8:
gef nexti
gef info register r2 r3
r2 0x3 3
r3 0x4 4
gef x/w $sp
0xbefff7e0: 0x00000001