(1)PC是程序计数器,存储将要执行的指令地址
(2)LR是链接寄存器,是ARM处理器中一个有特殊用途的寄存器,当调用函数时,返回地址即PC的值被保存到LR中(mov lr,pc)。
(3)IR是指令寄存器,用来保存当前正在执行的一条指令。当执行一条指令时,先把它从内存取到数据寄存器(DR)中,然后再传送至IR。
mov r1, #0x53000000 //立即数寻址方式
立即数要求以“#”作前缀,对于十六进制的数,还要求在#后面加上0x或者&。0x大家很好理解。
STR是比较重要的指令了,跟它对应的是LDR。ARM指令集是加载/存储型的,也就是说它只处理在寄存器中的数据。那么对于系统存储器的访问就经常用到STR和LDR了。STR是把寄存器上的数据传输到指定地址的存储器上。LDR就是把数据从存储器传输到寄存器上。
ARM有两种跳转方式。
(1) mov pc <跳转地址〉
这种向程序计数器PC直接写跳转地址,能在4GB连续空间内任意跳转。
(2)通过 B BL BLX BX 可以完成在当前指令向前或者向后32MB的地址空间的跳转(为什么是32MB呢?寄存器是32位的,此时的值是24位有符号数,所以32MB)。
B是最简单的跳转指令。要注意的是,跳转指令的实际值不是绝对地址,而是相对地址——是相对当前PC值的一个偏移量,它的值由汇编器计算得出。
BL非常常用。它在跳转之前会在寄存器LR中保存PC的当前内容。BL的经典用法如下:
bl NEXT ; 跳转到NEXT
……
NEXT
……
mov pc, lr ; 从子程序返回。
在ARM架构下, 数据从内存到CPU之间的移动只能通过LDR/STR指令来完成. 而MOV只能在寄存器之间移动数据,或者把立即数移动到寄存器中
csel w0, w2, w0, gt
csel根据后面的条件决定如何赋值,如果是GT,则w0=w2,否则w0 = w0。
LDR R0, [R1]
这条指令的意思是,将R1中的值作为地址,将地址里面存的值复制给寄存器R0
STR R1,[R0]
这条指令的意思是,将R1里面的值,复制到以R0里面的值作为地址的内存里面。
typedef struct Person {
int id;
int age;
char name[10];
int sex;
} CPerson;
int getId(CPerson person) {
return person.id;
}
int getAge(CPerson person) {
return person.age;
}
int getSex(CPerson person) {
return person.sex;
}
int run(CPerson person, int age) {
if (age<7) {
return 0xffff;
} else if (age < 13) {
return age +1;
} else {
age = getAge(person);
return age;
}
}
int run_1(int x) {
if (x >15) {
return 0xffff;
} else {
return 0x111;
}
}
void test() {
CPerson person ={12, 10, "cm", 1};
run(person, 10);
}
mutian@mutian:~/share/test/test$ cp ~/workspace/NDK/libs/arm64-v8a/libhello-jni.so .
mutian@mutian:~/share/test/test$ ~/soft/android-ndk-r10e/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -S -D libhello-jni.so > x.log
000000000000063c <getId>:
63c: b9400000 ldr w0, [x0]
640: d65f03c0 ret
0000000000000644 <getAge>:
644: b9400400 ldr w0, [x0,#4]
648: d65f03c0 ret
000000000000064c <getSex>:
// 这个方法是全局方法,所以x0是第一个参数
// 结构体按最大的数据类型进行字节对齐,所以sex偏移值是20,而不是18
// 返回值存放在w0中, w0是x0的低32位
64c: b9401400 ldr w0, [x0,#20]
650: d65f03c0 ret
0000000000000654 <run>:
// stack 扩大30 每个方法调用前就已经知道,这个方法需要多大stack
654: d100c3ff sub sp, sp, #0x30
//cmp指令 w1 - 0x6 结果不存储 只更改状态寄存器CPSR中的条件标志位
658: 7100183f cmp w1, #0x6
65c: aa0003e2 mov x2, x0
660: 529fffe0 mov w0, #0xffff // #65535
664: f90003fe str x30, [sp]
668: 5400008c b.gt 678 <run+0x24>
66c: f94003fe ldr x30, [sp]
670: 9100c3ff add sp, sp, #0x30
674: d65f03c0 ret
678: 7100303f cmp w1, #0xc
67c: 11000420 add w0, w1, #0x1
680: 54ffff6d b.le 66c <run+0x18>
684: a9401444 ldp x4, x5, [x2]
688: f9400841 ldr x1, [x2,#16]
68c: 910043e0 add x0, sp, #0x10
690: f90013e1 str x1, [sp,#32]
694: a90117e4 stp x4, x5, [sp,#16]
698: 97ffffeb bl 644 <getAge>
69c: f94003fe ldr x30, [sp]
6a0: 9100c3ff add sp, sp, #0x30
6a4: d65f03c0 ret
00000000000006a8 <run_1>:
6a8: 71003c1f cmp w0, #0xf
6ac: 529fffe1 mov w1, #0xffff // #65535
6b0: 52802220 mov w0, #0x111 // #273
6b4: 1a80c020 csel w0, w1, w0, gt
6b8: d65f03c0 ret