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].
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.
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.
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).
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.
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.
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).
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