首页
社区
课程
招聘
[翻译]ARM汇编简介(三)内存指令-加载和存储 (下)
发表于: 2018-6-19 16:19 9360

[翻译]ARM汇编简介(三)内存指令-加载和存储 (下)

2018-6-19 16:19
9360

本文是内存指令-加载和存储的下篇,接上文https://bbs.pediy.com/thread-228602.htm继续翻译

The first STR operation uses the offset address mode and stores the value found in R2 at the memory location calculated from [r1, r2, LSL#2], which means that it takes the value in R1 as a base (in this case, R1 contains the memory address of var2), then it takes the value in R2 (0x3), and shifts it left by 2. The picture below is an attempt to visualize how the memory location is calculated with [r1, r2, LSL#2]. 

第一个STR操作(str r2, [r1, r2, LSL#2] )使用偏移寻址模式,并将在R2中找到的值作为地址,取出里面的值存储在:[R1,R2,LSL #2 ]计算出的内存地址指向的内存空间中,这意味着它将R1中的值用作基址(此时R1包含了var2变量的内存地址),然后它取出R2(0x3)中的值向左移动两位,把这个值作为偏移量。下面的图片将[R1,R2,LSL×2 ]计算内存地址的方法可视化了。


The second STR operation uses the pre-indexed address mode. This means, it performs the same action as the previous operation, with the difference that it updates the base register R1 with the calculated memory address afterwards. In other words, it will first store the value found at the memory address R1 (0x1009c) + the offset left shifted by #2 (0x03 LSL#2 = 0xC) = 0x100a8, and update R1 with 0x100a8.

第二个操作 STR (str r2, [r1, r2, LSL#2]!)使用先索引地址模式。这意味着,它执行与先前操作相同的动作,不同之处在于,用随后计算出的内存地址更新了基址寄存器R1。换言之,它首先将存储器地址R1(0x1009C)加上偏移:将R1向左偏移2位(0x03 LSL×2=0xC ,这是偏移量)得到0x100A8,将 0x100A8 作为地址,取出里面的值给R2,以及用0x100A8更新R1。


The last LDR operation ( ldr r3, [r1], r2)uses the post-indexed address mode. This means, it loads the value at the memory address found in R1 (0x100a8) into register R3, then updates the base register R1 with the value calculated with r2, LSL#2. In other words, R1 gets updated with the value R1 (0x100a8) + the offset R2 (0x3) left shifted by #2 (0xC) = 0x100b4.

最后一个LDR运算使用后索引寻址模式。意思是说,将R1里的数(0x100a8)作为地址,取出该地址空间里的值并将它载入寄存器R3,然后,用r2, LSL#2计算所得的结果更新基址寄存器R1。换言之,使用R1的值(0x100a8),加上偏移R2(0x3)左移两位得到的值( 0xC ),等于0x100b4,用0x100b4更新R1


Remember the three offset modes in LDR/STR:记住 LDR/STR用到的三种偏移模式


1.offset mode uses an immediate as offset 用立即数作为偏移的偏移模式

     ldr   r3, [r1, #4]

2.offset mode uses a register as offset 用寄存器的值作为偏移的偏移模式

     ldr   r3, [r1, r2]

3.offset mode uses a scaled register as offset  用移位寄存器的值作为偏移的偏移模式

     ldr   r3, [r1, r2, LSL#2]


How to remember the different address modes in LDR/STR:如何记住 LDR/STR中的不同寻址模式:


If there is a !, it’s prefix address mode 如果有一个!,就是先寻址模式

ldr   r3, [r1, #4]!

ldr   r3, [r1, r2]!

ldr   r3, [r1, r2, LSL#2]!


If the base register is in brackets by itself, it’s postfix address mode 如果方括号里只有基址寄存器它自己,就是后寻址模式

ldr   r3, [r1], #4

ldr   r3, [r1], r2

ldr   r3, [r1], r2, LSL#2


Anything else is offset address mode. 其他的都是偏移寻址模式

ldr   r3, [r1, #4]

ldr   r3, [r1, r2]

ldr   r3, [r1, r2, LSL#2]

Loading immediate values in a register on ARM is not as straightforward as it is on x86. There are restrictions on which immediate values you can use. What these restrictions are and how to deal with them isn’t the most exciting part of ARM assembly, but bear with me, this is just for your understanding and there are tricks you can use to bypass these restrictions (hint: LDR).

将立即数载入ARM寄存器不像在x86上那样简单。我们能使用的立即数是有限制的。 这些限制是什么,如何处理它们并不是ARM汇编中最令人兴奋的部分,但请耐心听我说,这只是为了让你透彻的理解。另外还有一些窍门可以用来绕过这些限制(提示:LDR)。


We know that each ARM instruction is 32 bit long, and all instructions are conditional. There are 16 condition codes which we can use and one condition code takes up 4 bits of the instruction. Then we need 2 bits for the destination register. 2 bits for the first operand register, and 1 bit for the set-status flag, plus an assorted number of bits for other matters like the actual opcodes. The point here is, that after assigning bits to instruction-type, registers, and other fields, there are only 12 bits left for immediate values, which will only allow for 4096 different values.

我们知道,每一条ARM指令都有32位的长度,所有的指令都是由条件的。我们可以使用16种条件指令,每种条件指令占4位。接着我们需要2位用于表示目标寄存器,再用2位表示第一操作数,1位用于设置状态标志位,再加上其他情况要用到的一个分类数(比如实际的操作码)。这里的关键问题是,给指令类型。寄存器和其他字段分配字节空间后,留给立即数的只剩下12位了,12位只允许表示4096个不同的数值


This means that the ARM instruction is only able to use a limited range of immediate values with MOV directly.  If a number can’t be used directly, it must be split into parts and pieced together from multiple smaller numbers.

这意味在直接调用MOV指令只能使用取值范围受到限制的立即数。如果不直接使用数字,就必须把它分成多个部分,用多个比原数小的数字拼在一起使用。


But there is more. Instead of taking the 12 bits for a single integer, those 12 bits are split into an 8 bit number (n) being able to load any 8-bit value in the range of 0-255, and a 4 bit rotation field (r) being a right rotate in steps of 2 between 0 and 30. This means that the full immediate value v is given by the formula: v = n ror 2*r. In other words, the only valid immediate values are rotated bytes (values that can be reduced to a byte rotated by an even number).

但这还没结束。我们并没有把12位全部用于组成一个单独的整数,而是将12位分成8位数字(n)和4位循环移位字段(r)两部分,8位数字的取值范围是0-255, 而4位用于构成循环移位数(r),第二步的整体的范围是0和30之间。意思是说,一个完整的立即数V由如下公式决定:v=n ror 2*r。换言之,唯一有效的立即数是循环字节数(通过移动偶数个位可以减少到一个字节)

(译者注:这里翻译的不太好,建议配合原文看下面作者给的实际例子认真理解)


Here are some examples of valid and invalid immediate values:下面是几个合规的和不合规的立即数

This has the consequence that it is not possible to load a full 32 bit address in one go. We can bypass this restrictions by using one of the following two options:

这导致无法一次性加载一个完整的32位地址。我们可以通过使用以下两个选项之一来绕过这些限制:


1.Construct a larger value out of smaller parts 用较小的数字组成更大的数字

     1.Instead of using MOV  r0, #511   不使用 MOV  r0, #511

     2.Split 511 into two parts: MOV r0, #256, and ADD r0, #255    将511分成两部分, MOV r0, #256, 以及 ADD r0, #255


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

最后于 2018-6-20 09:26 被r0Cat编辑 ,原因:
收藏
免费 2
支持
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  junkboy   +5.00 2018/06/19
最新回复 (3)
雪    币: 1382
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
谢谢分享!~
2018-6-20 00:34
0
雪    币: 209
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
寻址模式:后索引模式。将R2的值作为地址取出里面的值,应该是r1把
2018-12-4 11:40
0
雪    币: 209
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
将r1里的值作为地址取出里面的值并将这个值存入寄存器r2  应该是存入r3把
最后于 2018-12-4 11:43 被lyxhh编辑 ,原因:
2018-12-4 11:42
0
游客
登录 | 注册 方可回帖
返回
//