我们先来看下,如果在C代码中两个定义如下,一个数组和一个结构体。
int a[100]; struct my_struct { char f0; int f1; } b;
|
在32位ARM汇编中的定义如下:
|
结构体my_struct实际是5个字节,但是这里定义了8个自己,因为是4字节对齐的,多出的3个自己就是Padding,填充用。
我们看个完整的例子。
ARM32为例。
.data
.balign 4
a: .skip 400
.balign 4
b: .skip 8
.text
.global main
main:
ldr r1, addr_of_a /* r1 ← &a */
mov r2, #0 /* r2 ← 0 */
loop:
cmp r2, #100 /* 检查索引是否达到100了*/
beq end /* 到达100则结束*/
add r3, r1, r2, LSL #2 /* r3 ← r1 + (r2*4) ,获取数组中各项地址*/
str r2, [r3] /* *r3 ← r2 ,将索引复制给数组各项*/
add r2, r2, #1 /* r2 ← r2 + 1 ,索引自加1*/
b loop /* 循环开始处*/
end:
bx lr
addr_of_a: .word a
as -g -o array.o array.s
gcc -o array array.o
上面这段代码完成了如下C代码片段:
for (i = 0; i < 100; i++)
a[i] = i;
上面的模式操作有些过时。
在获取数组地址的时候可以使用ARM提供的索引方法。
[Rsource1, +#immediate]或者
[Rsource1, -#immediate]
寄存器方法:
[Rsource1, +Rsource2] 或者
[Rsource1, -Rsource2]
综合的方法:
[Rsource1, +Rsource2, shift_operation #immediate]或者
[Rsource1, -Rsource2, shift_operation #immediate]
|
执行前后r1是没有变化的。
以上这些的话不会自动更新索引,因为是要循环100次的,每次操作完需要更新索引。
[Rsource1], #+immediate 或者
[Rsource1], #-immediate
循环片段可以改成如下:
loop:
cmp r2, #100 /*检查索引是否达到100了*/
beq end /*到达100则结束
str r2, [r1], #4 /* *r1 ← r2 then r1 ← r1 + 4 */
add r2, r2, #1 /* r2 ← r2 + 1 ,自加*/
b loop /* Go to the beginning of the loop */
end:
[Rsource1], +Rsource2或者
[Rsource1], -Rsource2
再或者
[Rsource1], +Rsource2, shift_operation #immediate 或
[Rsource1], -Rsource2, shift_operation #immediate
这些操作是执行后再跟新索引的。
我们看下执行前跟新索引的操作。命令如下,区别是加了一个!号。
[Rsource1, #+immediate]!或
[Rsource1, #-immediate]!
代码小片段如下:
|
此外还有:
[Rsource1, +Rsource2]! 或
[Rsource1, +Rsource2]!
或者
[Rsource1, +Rsource2, shift_operation #immediate]!或
[Rsource1, -Rsource2, shift_operation #immediate]!
几个命令的差异卡看上去比较小,主要是注意感叹号和中括号。
使用如上这些可以轻松获取的结构体中的某个变量便宜。
例如C语法中的:
b.f1 = b.f1 + 7;
其中b是结构体如下:
struct my_struct
{
char f0;
int f1;
} b;
可以通过如下代码片段实现,r1是结构体的基地址:
|