1.加载指令(PC相对地址)
ADR: 加载PC相对地址的label地址,范围+/- 1MB;
ADRP: 加载PC相对地址,label地址,并且4KB对齐,范围+/- 4GB;
/* others inst */
.align 3
.global my_test_data
my_test_data:
.dword 0x12345678abcdeeff
.global adrp_test
adrp_test:
adr x0, my_test_data
adrp x1, my_test_data //4KB align
add x2, x1,#:lo12:my_test_data
ldr x3, [x2] //get val
ldr x4,=my_test_data //get addr
ldr x5, my_test_data //get value
adrp x6, init_pg_dir //get addr
ldr x7, =init_pg_dir //get addr
ret
运行结果如下图:
LDR和ADRP区别
LDR伪指令:加载的是链接地址(虚拟地址)
ADRP指令:加载的是当前运行地址的PC值+label的offset,即label的当前运行地址(物理地址)
在link脚本,将链接地址改成0xffff000000080000,重新执行上面程序;
注:当程序链接地址不等于运行地址时,用如下命令加载符号表,否则无法单步调试;
add-symbol-file xxx.elf 0x80030 -s .text.boot 0x80000 -s .rodata 0x80758
0x80030:text段的起始地址;
0x80000:text.boot段的起始地址;
0x80758:只读数据段的起始地址;
可通过aarch64-linux-gnu-readelf -S xxx.elf来查看各个段的地址
程序启动:看到PC值:
重新运行测试程序,结果如下:
2. 内存独占加载和访问指令
ldxr xd, [xn|sp] //独占的读取xn或sp地址的内容到xd寄存器
stxr wd, xt, [xn|sp] //独占的把xt内容写入到xn或sp指向的地址
//wd为0, 表示成功;wd = 1,表示不成功
Linux内核常用来实现atomic访问;
spinlock机制可以简单易用ldxr和lstxr指令实现;
.align 3
.global my_data2
my_data2:
.dword 0x0
.global my_atomic_write
my_atomic_write:
adr x6, my_data2;
1:
ldxr x2, [x6];
orr x2,x2,x0;
stxr w3, x2, [x6]
cbnz w3, 1b
mov x0,x2
ret
3.异常处理指令
svc:系统调用指令
hvc:虚拟化系统调用指令
smc:安全监控系统调用指令
4. 系统寄存器访问指令
指令 | 描述 |
---|---|
MRS | 读取系统寄存器到通用寄存器 |
MSR | 写系统寄存器 |
5.内存屏障指令
指令名 | 功能描述 |
---|---|
DMB | 数据存储器隔离。DMB 指令保证:指令前后的,内存访问指令的执行循序 ; 不保证: 内存访问指令在内存屏障指令之前完成; |
DSB | 数据同步隔离。比 DMB 严格: 任何指令都要等DSB前面的存储访问完成 |
ISB | 指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。 |