首页
社区
课程
招聘
[翻译]]ARM汇编简介(四)载入/存储多个值,入栈和出栈
发表于: 2018-6-28 16:36 4984

[翻译]]ARM汇编简介(四)载入/存储多个值,入栈和出栈

2018-6-28 16:36
4984

最近心情不错,抓紧时间继续学习并翻译~https://azeria-labs.com/arm-conditional-execution-and-branching-part-5/

Sometimes it is more efficient to load (or store) multiple values at once. For that purpose we use LDM (load multiple) and STM (store multiple). These instructions have variations which basically differ only by the way the initial address is accessed. This is the code we will use in this section. We will go through each instruction step by step. 

有时,一次性加载(或存储)多个值更有效率。因此,我们需要使用LDM(载入多个值)和STM(存储多个值)。这些指令基于起始地址的不同,有不同的形式。下面是我们将在本节中将会使用的代码。我们将一步一步地完成每一个指令。


We use ADR instruction (lazy approach) to get the address of the 4th(words[3]) element into the R0. We point to the middle of the words array because we will be operating forwards and backwards from there.

我们使用ADR指令(偷懒的办法)将数组第四部分(word[3])的地址传送给R0。我们用R0指向word数组的中间位置,所以我们可以从这开始向前或者向后移动指针。


R0 now contains the address of word[3], which in this case is 0x80B8. This means, our array starts at the address of word[0]: 0x80AC (0x80B8 –  0xC).

现在R0里包含了word[3]的地址,这里是0x80B8。这意味着数组首地址,也是word[0]的地址为:0x80AC (0x80B8 –  0xC)


We prepare R1 and R2 with the addresses of the first (array_buff[0]) and third (array_buff[2]) elements of the array_buff array. Once the addresses are obtained, we can start operating on them. 

我们用 array_buff数组的第一个( (array_buff[0] )和第三个元素( array_buff[2] )的地址来分别填充R1和R2。一旦地址被获取,我们就能操作他们了

After executing the two instructions above, R1 and R2 contain the addresses of array_buff[0] and array_buff[2].

执行完上面的两条命令后,R1,R2中分别包含了 array_buff[0]的地址和 array_buff[2]的地址

The next instruction uses LDM to load two word values from the memory pointed by R0. So because we made R0 point to words[3] element earlier, the words[3] value goes to R4 and the words[4] value goes to R5.

下面一条指令(ldm r0, {r4,r5})使用LDM指令,将R0指向的内存中,取两个字的数据出来。由于之前我们让R0指向了word[3],因此 word[3]的值会被存入R4, word[4]的会被存入R5

We loaded multiple (2 data blocks) with one command, which set R4 = 0x00000003 and R5 = 0x00000004.

也就是说,使用一条指令加载了多个数据(2个数据块),并将R4设置为0x00000003 ,R5设置为 0x00000004

So far so good. Now let’s perform the STM instruction to store multiple values to memory. The STM instruction in our code takes values (0x3 and 0x4) from registers R4 and R5 and stores these values to a memory location specified by R1. We previously set the R1 to point to the first array_buff element so after this operation the array_buff[0] = 0x00000003 and array_buff[1] = 0x00000004. If not specified otherwise, the LDM and STM opperate on a step of a word (32 bits = 4 byte).

到目前为止还不错。现在,让我们使用STM指令将多个值写入内存。STM指令将R4,R5寄存器的值0x3和0x4存入R1指向的内存空间中。由于之前我们让R1指向 array_buff的第一个元素,所以指令执行后 array_buff[0] = 0x00000003 ,array_buff[1] = 0x00000004。如果没有特别说明,LDM和STM指令操作的基本单位是一个字(32位等于4个字节)

The values 0x3 and 0x4 should now be stored at the memory address 0x100D0 and 0x100D4. The following instruction inspects two words of memory at the address 0x000100D0.

现在,0x3和0x4分别被存储在0x100D0和0x100D4指向的内存空间。下条指令检查了从0x000100D0开始的两个字长度的内存中存储了什么值。

As mentioned before, LDM and STM have variations. The type of variation is defined by the suffix of the instruction. Suffixes used in the example are: -IA (increase after), -IB (increase before), -DA (decrease after), -DB (decrease before). These variations differ by the way how they access the memory specified by the first operand (the register storing the source or destination address). In practice, LDM is the same as LDMIA, which means that the address for the next element to be loaded is increased after each load. In this way we get a sequential (forward) data loading from the memory address specified by the first operand (register storing the source address).

之前说过,LDM和STM有多种不同的使用形式。具体是哪一种使用形式由指令的后缀所决定。这个示例列出了后缀的几种形式:-IA (之后增加), -IB (之前增加), -DA (之后减少), -DB (之前减少)。这么多种类型,他们之间是如何区分的呢?由指令的第一个字段:运算指令规定了访问内存的方式(寄存器作为源地址还是目标地址)。实际上,由于LDM和LDMIA作用相同,所以每次载入完成后,地址指针会自己增加,从而指向下一个被载入的元素。用这种方法可以从某内存地址中获取( 前向 )序列化的数据,并载入寄存器,

After executing the two instructions above, the registers R4-R6 and the memory addresses 0x000100D0, 0x000100D4, and 0x000100D8 contain the values 0x3, 0x4, and 0x5.

执行完上面的两条指令后,寄存器R4-R6分别包含了 0x3,0x4,0x5 ,内存地址 0x000100D0, 0x000100D4,和 0x000100D8中也包含了0x3,0x4,0x5

The LDMIB instruction first increases the source address by 4 bytes (one word value) and then performs the first load. In this way we still have a sequential (forward) loading of data, but the first element is with a 4 byte offset from the source address. That’s why in our example the first element to be loaded from the memory into the R4 by LDMIB instruction is 0x00000004 (the words[4]) and not the 0x00000003 (words[3]) as pointed by the R0.

LDMIB指令先将源地址增加4字节(一个字),然后开始载入数据。该方法仍能让我们载入一串前向数据,但第一个数据的起始地址相较源地址有4个字节的偏移。这就是为什么我们用LDMIB指令将内存中的第一个元素载入R4后,R4是0x04(word[4]),而不是R0指向的0x3(word[3])

After executing the two instructions above, the registers R4-R6 and the memory addresses 0x100D4, 0x100D8, and 0x100DC contain the values 0x4, 0x5, and 0x6.

执行完上面两条指令后,寄存器R4-R6存储了0x4,0x5,0x6, 0x100D4, 0x100D8, 和0x100DC也存储了 0x4,0x5,0x6。

When we use the LDMDA instruction everything starts to operate backwards. R0 points to words[3]. When loading starts we move backwards and load the words[3], words[2] and words[1] into R6, R5, R4. Yes, registers are also loaded backwards. So after the instruction finishes R6 = 0x00000003, R5 = 0x00000002, R4 = 0x00000001. The logic here is that we move backwards because we Decrement the source address AFTER each load. The backward registry loading happens because with every load we decrement the memory address and thus decrement the registry number to keep up with the logic that higher memory addresses relate to higher registry number. Check out the LDMIA (or LDM) example, we loaded lower registry first because the source address was lower, and then loaded the higher registry because the source address increased.

使用LDMDA向相反方向执行运算(译者注:ldmda r0, {r4-r6}       /* words[3] -> r6 = 0x03; words[2] -> r5 = 0x02; words[1] -> r4 = 0x01 */)。R0指向word[3],载入操作开始后,我们向后将 words[3], words[2]和words[1]载入R6, R5, R4。是的你没有看错,连寄存器都是反着被载入的。所以指令将 R6赋值为0x00000003, R5赋值为0x00000002, R4赋值为0x00000001。这里的逻辑是,每次载入操作完成后向后减少内存地址所以是反向赋值。寄存器之所以也是反向载入的是由于我们减少了内存地址,所以对应的寄存器的编号值也跟着下降,因为它需要遵循更高的内存地址关联了更高的寄存器编号这一逻辑。回头检查一下 LDMIA (或是 LDM)那个例子(译者注:ldmia r0, {r4-r6} /* words[3] -> r4 = 0x03, words[4] -> r5 = 0x04; words[5] -> r6 = 0x05;  */ ),我们先载入编号更低的寄存器,因为源地址更低。然后载入到编号更高的寄存器,因为源地址增加了。


Load multiple, decrement after:

载入值,之后降低地址(译者注:建议不要纠结字面含义,建议对照代码理解)


Registers R4, R5, and R6 after execution:

R4,R5,R6的变化:


Load multiple, decrement before:

先降低地址,再载入多个值 (译者注:建议不要纠结字面含义,建议对照代码理解)


Registers R4, R5, and R6 after execution:

R4,R5,R6的变化


Store multiple, decrement after.

存储值,之后降低地址 (译者注:建议不要纠结字面含义,建议对照代码理解)


Memory addresses of array_buff[2], array_buff[1], and array_buff[0] after execution:

观察 array_buff[2], array_buff[1], 和 array_buff[0]执行后的改变


Store multiple, decrement before:

先给地址指针减4,再一边赋值一边降序


Memory addresses of array_buff[1] and array_buff[0] after execution:

观察一下 array_buff[1]和array_buff[0]执行后的结果


There is a memory location within the process called Stack. The Stack Pointer (SP) is a register which, under normal circumstances, will always point to an address wihin the Stack’s memory region. Applications often use Stack for temporary data storage. And As mentioned before, ARM uses a Load/Store model for memory access, which means that the instructions LDR / STR or their derivatives (LDM.. /STM..) are used for memory operations. In x86, we use PUSH and POP to load and store from and onto the Stack. In ARM, we can use these two instructions too:

进程中有使用一块内存区域叫堆栈。堆栈指针(SP)是一个寄存器,在正常情况下,它总是指向栈内存区域中的一个地址。应用程序通常使用堆栈进行临时数据存储。之前提过,ARM使用加载/存储模型进行内存访问,这意味着指令LDR/STR或它们的派生指令(LDM.../STM...)用于内存操作。在x86中,我们使用PUSH和POP从堆栈中加载和存储。在ARM中,我们也可以使用这两个指令:


When we PUSH something onto the Full Descending (more about Stack differences inPart 7: Stack and Functions) stack the following happens:

当我们把数据压入降序分布的栈区(详见第7部分:栈和函数)后会发生:


1.First, the address in SP gets DECREASED by 4.

首先,SP寄存器里的地址值减4


2.Second, information gets stored to the new address pointed by SP.


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2018-6-29 10:54 被r0Cat编辑 ,原因:
收藏
免费 1
支持
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  junkboy   +5.00 2018/06/28
最新回复 (4)
雪    币: 344
活跃值: (314)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
顶个
2018-6-28 16:56
0
雪    币: 7012
活跃值: (4222)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2018-6-28 18:29
0
雪    币: 11716
活跃值: (133)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
看完啦  谢谢翻译  希望楼主心情一直好  等下一集~
2018-6-28 21:35
0
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
5
junkboy 看完啦 谢谢翻译 希望楼主心情一直好 等下一集~
感谢JB大神的鼎力支持,出手果然不同凡响,感谢感谢
2018-6-28 23:02
0
游客
登录 | 注册 方可回帖
返回
//