【ARMv8 编程】A64 内存访问指令——内存存储指令
在内存加载一节中实际上已经使用了内存存储指令了,内存存储指令将寄存器的值存储到内存中。
同样,Store 指令的一般形式如下:
STR Rn, <addr>
还有 unscaled-offset 偏移形式,例如 STUR<type>
。 程序员通常不需要明确使用 STUR 形式,因为大多数汇编器可以根据使用的偏移量选择合适的版本。
要存储的大小可能小于寄存器。可以通过向 STR 添加 B 或 H 后缀来指定它。在这种情况下,存储的总是寄存器的最低有效部分。
1 STR(立即数)
存储寄存器(立即数)指令将寄存器中的一个字或一个双字存储到内存中。用于存储的地址是根据基址寄存器和立即偏移量计算得出的。它具有 3 种类型的编码:Post-index、Pre-index 和 Unsigned offset。
Post-index
32-bit (size == 10)
STR <Wt>, [<Xn|SP>], #<simm>
64-bit (size == 11)
STR <Xt>, [<Xn|SP>], #<simm>
Pre-index
32-bit (size == 10)
STR <Wt>, [<Xn|SP>, #<simm>]!
64-bit (size == 11)
STR <Xt>, [<Xn|SP>, #<simm>]!
Unsigned offset
32-bit (size == 10)
STR <Wt>, [<Xn|SP>{, #<pimm>}]
64-bit (size == 11)
STR <Xt>, [<Xn|SP>{, #<pimm>}]
<Wt>
是要传输的通用寄存器的 32 位名称,在“Rt”字段中编码。
<Xt>
是要传输的通用寄存器的 64 位名称,在“Rt”字段中编码。
<Xn|SP>
是通用基址寄存器或堆栈指针的 64 位名称,在“Rn”字段中编码。
<simm>
是带符号的立即字节偏移量,在 -256 到 255 的范围内,在“imm9”字段中编码。
<pimm>
是可选的正立即字节偏移量。对于 32 位变体:是 0 到 16380 范围内 4 的倍数,默认为 0 并在“imm12”字段中编码为 <pimm>/4
;对于 64 位变体:是 0 到 32760 范围内 8 的倍数,默认为 0 并在“imm12”字段中编码为 <pimm>/8
。
STR(立即数)Post-index
下面是使用 STR(立即数)Post-index 的例子。
- 新建 src_arr、dst_arr 数组,并初始化为 0。
- 给 src_arr 赋初值,将 long long int* 指针转为 char*,为了后续内联汇编加载存储(笔者环境实测:如果不这样赋值 STR 指令无法正常写入内存)。
- 经过内联汇编代码运行,
MOV X3, %x[len]
先将数组长度 len 移动到 X3 寄存器,接着 1 是标签,LDR X2, [%x[src]], #8
将 src_arr 数组的前 8 个字节加载到 X2 寄存器,接着 Post-index(也就是地址加 8 写回,下次读取起点已经加 8)。STR X2, [%x[dst]], #8
会将刚刚 X2 寄存器的值写入 dst_arr 内存中,同样 Post-index(也就是地址加 8 写回,下次写入起点已经加 8)。SUBS X3, X3, #1
将 X3 每次都减去 1,SUBS 会设置条件标志,后面B.GT 1b
判断当 SUBS 设置条件标志 Z = 1 时,就不满足跳转到标签 1 处执行的条件,也就退出了内联汇编代码,否则跳转到标签 1 处继续执行。 - 继续打印一次 dst_arr 数组,查看内部值,此时和 src_arr 内的值保持一致,说明 LDR 和 STR 都生效了。
long long int len = 10;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for(int i = 0; i < len; i++){src_arr[i] = 0x0101010101010101 * (i + 1);LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for(int i = 0; i < len; i++){LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""1:\n""LDR X2, [%x[src]], #8\n""STR X2, [%x[dst]], #8\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for(int i = 0; i < len; i++){LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
运行结果如下:
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[0]=0x101010101010101
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[1]=0x202020202020202
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[2]=0x303030303030303
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[3]=0x404040404040404
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[4]=0x505050505050505
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[5]=0x606060606060606
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[6]=0x707070707070707
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[7]=0x808080808080808
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[8]=0x909090909090909
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: src_arr[9]=0xa0a0a0a0a0a0a0a
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: =============================
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[3]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[4]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[5]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[6]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[7]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[8]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[9]=0x0
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[0]=0x101010101010101
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[1]=0x202020202020202
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[2]=0x303030303030303
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[3]=0x404040404040404
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[4]=0x505050505050505
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[5]=0x606060606060606
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[6]=0x707070707070707
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[7]=0x808080808080808
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[8]=0x909090909090909
2023-04-30 15:05:47.973 20725-20725/com.example.myapplication D/native-armv8a: dst_arr[9]=0xa0a0a0a0a0a0a0a
STR(立即数)Pre-index
下面是使用 STR(立即数)Pre-index 的例子。
将 STR(立即数)Post-index 的例程略做修改,首先将 STR 指令改为 STR X2, [%x[dst], #8]!
,表示地址前置自增 8(地址先加 8 后再向其存储数据),接着为了防止 dst 地址越界,引入了 SUB X3, X3, #1
指令,再进入 1 标签循环之前就执行 SUB X3, X3, #1
指令。
long long int len = 10;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0101010101010101 * (i + 1);LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""SUB X3, X3, #1\n""1:\n""LDR X2, [%x[src]], #8\n""STR X2, [%x[dst], #8]!\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
运行结果如下:
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[0]=0x101010101010101
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[1]=0x202020202020202
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[2]=0x303030303030303
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[3]=0x404040404040404
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[4]=0x505050505050505
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[5]=0x606060606060606
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[6]=0x707070707070707
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[7]=0x808080808080808
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[8]=0x909090909090909
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: src_arr[9]=0xa0a0a0a0a0a0a0a
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: =============================
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[3]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[4]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[5]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[6]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[7]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[8]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[9]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[1]=0x101010101010101
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[2]=0x202020202020202
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[3]=0x303030303030303
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[4]=0x404040404040404
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[5]=0x505050505050505
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[6]=0x606060606060606
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[7]=0x707070707070707
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[8]=0x808080808080808
2023-04-30 07:46:45.133 29892-29892/com.example.myapplication D/native-armv8a: dst_arr[9]=0x909090909090909
STR(立即数)Unsigned offset
下面是使用 STR(立即数)Unsigned offset 的例子。
Unsigned offset 代表存储的位置一直是固定无符号偏移量。将上面的例程 STR(立即数)Pre-index 中 STR 指令改为 STR X2, [%x[dst], #8]
,也就是去掉后面的感叹号。
long long int len = 10;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0101010101010101 * (i + 1);LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""1:\n""LDR X2, [%x[src]], #8\n""STR X2, [%x[dst], #8]\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
dst_arr[1] 被修改了,实际上每次循环都会被修改,但最终被保留最后一次修改覆盖的值(0xa0a0a0a0a0a0a0a)。运行结果如下:
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[0]=0x101010101010101
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[1]=0x202020202020202
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[2]=0x303030303030303
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[3]=0x404040404040404
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[4]=0x505050505050505
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[5]=0x606060606060606
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[6]=0x707070707070707
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[7]=0x808080808080808
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[8]=0x909090909090909
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: src_arr[9]=0xa0a0a0a0a0a0a0a
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: =============================
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[3]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[4]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[5]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[6]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[7]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[8]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[9]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[1]=0xa0a0a0a0a0a0a0a
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[3]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[4]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[5]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[6]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[7]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[8]=0x0
2023-04-30 07:56:04.949 32260-32260/com.example.myapplication D/native-armv8a: dst_arr[9]=0x0
2 STR(寄存器)
STR(寄存器)指令根据基址寄存器值和偏移寄存器值计算地址,并将 32 位字或 64 位双字存储到寄存器中计算出的地址。
32-bit (size == 10)
STR <Wt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]
64-bit (size == 11)
STR <Xt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]
<Wt>
是要传输的通用寄存器的 32 位名称,在“Rt”字段中编码。
<Xt>
是要传输的通用寄存器的 64 位名称,在“Rt”字段中编码。
<Xn|SP>
是通用基址寄存器或堆栈指针的 64 位名称,在“Rn”字段中编码。
<Wm>
当 option<0>
设置为 0 时,是通用索引寄存器的 32 位名称,编码在“Rm”字段中。
<Xm>
当 option<0>
设置为 1 时,是通用索引寄存器的 64 位名称,编码在“Rm”字段中。
<extend>
是索引扩展/移位说明符,默认为 LSL,当省略<amount>
时,LSL 选项必须省略。在“option”字段中编码,它可以具有以下值:
extend | option |
---|---|
UXTW | 010 |
LSL | 011 |
SXTW | 110 |
SXTX | 111 |
<amount>
是索引移位量,仅当 <extend>
不是 LSL 时才可选。在允许可选的地方,它默认为 #0。它在“S”字段中编码。
对于 32 位变体,它可以具有以下值:
amount | S |
---|---|
#0 | 0 |
#2 | 1 |
对于 64 位变体,它可以具有以下值:
amount | S |
---|---|
#0 | 0 |
#3 | 1 |
下面是使用 STR(寄存器)指令的例子。
long long int len = 3;long long int x = 0x100;auto *y_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {y_arr[i] = 0x0102030410203040 * (i + 1);LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);}char *y = (char *) y_arr;asm volatile("MOV X3, #1\n""STR %x[x], [%x[y] ,X3, LSL#3]\n":[x] "+r"(x),[y] "+r"(y):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);}delete[] y_arr;
STR %x[x], [%x[y] ,X3, LSL#3]
首先计算需要存储地址的位置,将 X3 寄存器的值左移 3 位,也就是乘以 8,接着将这个偏移应用到 y 地址指向的数组,所以最终将 y + 8 的位置写入 x 的值,也就是将 0x100 写到 y_arr[1]。
运行结果如下:
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: y_arr[0]=0x102030410203040
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: y_arr[1]=0x204060820406080
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090c0
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: y_arr[0]=0x102030410203040
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: y_arr[1]=0x100
2023-04-30 15:25:07.509 31693-31693/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090c0
3 STRB(立即数)
存储寄存器字节(立即数)指令将 32 位寄存器的最低有效字节存储到内存中。用于存储的地址是根据基址寄存器和立即偏移量计算得出的。
Post-index
STRB <Wt>, [<Xn|SP>], #<simm>
Pre-index
STRB <Wt>, [<Xn|SP>, #<simm>]!
Unsigned offset
STRB <Wt>, [<Xn|SP>{, #<pimm>}]
<Wt>
是要传输的通用寄存器的 32 位名称,在“Rt”字段中编码。
<Xn|SP>
是通用基址寄存器或堆栈指针的 64 位名称,在“Rn”字段中编码。
<simm>
是带符号的立即字节偏移量,在 -256 到 255 的范围内,在“imm9”字段中编码。
<pimm>
是可选的正立即字节偏移量,范围为 0 到 4095,默认为 0 并在“imm12”字段中编码。
STRB(立即数)Post-index
下面是使用 STRB(立即数)Post-index 的例子。
long long int len = 3;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0102030420304050 * (i + 1);LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""1:\n""LDR X2, [%x[src]], #8\n""STRB W2, [%x[dst]], #8\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
STRB W2, [%x[dst]], #8
指令将 W2 寄存器的最低有效字节存储到了 dst 指向的内存(每次存储后地址加 8)。
运行结果如下:
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030420304050
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608406080a0
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c6090c0f0
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: =============================
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: dst_arr[0]=0x50
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: dst_arr[1]=0xa0
2023-04-30 16:07:12.384 17806-17806/com.example.myapplication D/native-armv8a: dst_arr[2]=0xf0
STRB(立即数)Pre-index
下面是使用 STRB(立即数)Pre-index 的例子。
long long int len = 3;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0102030420304050 * (i + 1);LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""SUB X3, X3, #1\n""1:\n""LDR X2, [%x[src]], #8\n""STRB W2, [%x[dst], #8]!\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
STRB W2, [%x[dst], #8]!
先将 dst 对应的地址加 8 并保存地址,然后再去将 W2 寄存器的最低有效字节存储到这个地址。
运行结果如下:
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030420304050
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608406080a0
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c6090c0f0
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: =============================
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: dst_arr[1]=0x50
2023-04-30 16:11:24.444 20155-20155/com.example.myapplication D/native-armv8a: dst_arr[2]=0xa0
STRB(立即数)Unsigned offset
下面是使用 STRB(立即数)Unsigned offset 的例子。
long long int len = 3;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0102030420304050 * (i + 1);LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""1:\n""LDR X2, [%x[src]], #8\n""STRB W2, [%x[dst], #8]\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
STRB W2, [%x[dst], #8]
每轮循环修改的地址都是固定的,最后一轮将 0xf0 覆盖到 dst_arr[1] 最低有效字节。
运行结果如下:
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030420304050
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608406080a0
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c6090c0f0
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: =============================
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: dst_arr[1]=0xf0
2023-04-30 16:14:02.492 21418-21418/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
4 STRB(寄存器)
存储寄存器字节(寄存器)指令根据基址寄存器值和偏移寄存器值计算地址,并将 32 位寄存器中的一个字节存储到计算出的地址中。
扩展寄存器变体(option != 011)
STRB <Wt>, [<Xn|SP>, (<Wm>|<Xm>), <extend> {<amount>}]
移位寄存器变体(option == 011)
STRB <Wt>, [<Xn|SP>, <Xm>{, LSL <amount>}]
<Wt>
是要传输的通用寄存器的 32 位名称,在“Rt”字段中编码。
<Xn|SP>
是通用基址寄存器或堆栈指针的 64 位名称,在“Rn”字段中编码。
<Wm>
当 option<0>
设置为 0 时,是通用索引寄存器的 32 位名称,编码在“Rm”字段中。
<Xm>
当 option<0>
设置为 1 时,是通用索引寄存器的 64 位名称,编码在“Rm”字段中。
<extend>
是索引扩展说明符,在“option”字段中编码。 它可以具有以下值:
extend | option |
---|---|
UXTW | 010 |
SXTW | 110 |
SXTX | 111 |
<amount>
是索引移位量,必须是 #0,如果省略则在“S”中编码为 0,如果存在则编码为 1。
下面是使用 STRB(寄存器)指令的例子。
long long int len = 3;long long int x = 0xff;auto *y_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {y_arr[i] = 0x0102030410203040 * (i + 1);LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);}char *y = (char *) y_arr;asm volatile("MOV X3, #1\n""STRB %w[x], [%x[y] ,X3, LSL#0]\n":[x] "+r"(x),[y] "+r"(y):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);}delete[] y_arr;
STRB %w[x], [%x[y] ,X3, LSL#0]
首先计算需要存储地址的位置,将 X3 寄存器的值左移 0 位,也就是没变化,所以最终将 y + 1 的位置写入 0xff 这个字节,也就是将 y_arr[0] 中的第二个低位字节(小端)写成 0xff。
运行结果如下:
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: y_arr[0]=0x102030410203040
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: y_arr[1]=0x204060820406080
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090c0
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: y_arr[0]=0x10203041020ff40
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: y_arr[1]=0x204060820406080
2023-04-30 19:11:18.654 4947-4947/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090c0
5 STRH(立即数)
存储寄存器半字(立即数)指令将 32 位寄存器的最低有效半字存储到内存中。用于存储的地址是根据基址寄存器和立即偏移量计算得出的。
Post-index
STRH <Wt>, [<Xn|SP>], #<simm>
Pre-index
STRH <Wt>, [<Xn|SP>, #<simm>]!
Unsigned offset
STRH <Wt>, [<Xn|SP>{, #<pimm>}]
<Wt>
是要传输的通用寄存器的 32 位名称,在“Rt”字段中编码。
<Xn|SP>
是通用基址寄存器或堆栈指针的 64 位名称,在“Rn”字段中编码。
<simm>
是带符号的立即字节偏移量,在 -256 到 255 的范围内,在“imm9”字段中编码。
<pimm>
是可选的正立即字节偏移量,是 0 到 8190 范围内 2 的倍数,默认为 0 并在“imm12”字段中编码为 <pimm>/2
。
STRH(立即数)Post-index
下面是使用 STRH(立即数)Post-index 的例子。
long long int len = 3;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0102030420304050 * (i + 1);dst_arr[i] = -1;LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""1:\n""LDR X2, [%x[src]], #8\n""STRH W2, [%x[dst]], #8\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
STRH W2, [%x[dst]], #8
将 dst_arr 每个元素的低 16 位替换为 W2 寄存器的低 16 位。
运行结果如下:
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030420304050
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608406080a0
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c6090c0f0
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: =============================
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: dst_arr[0]=0xffffffffffffffff
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: dst_arr[1]=0xffffffffffffffff
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: dst_arr[2]=0xffffffffffffffff
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: dst_arr[0]=0xffffffffffff4050
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: dst_arr[1]=0xffffffffffff80a0
2023-04-30 19:30:00.743 31159-31159/com.example.myapplication D/native-armv8a: dst_arr[2]=0xffffffffffffc0f0
STRH(立即数)Pre-index
下面是使用 STRH(立即数)Pre-index 的例子。
long long int len = 3;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0102030420304050 * (i + 1);dst_arr[i] = -1;LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""SUB X3, X3, #1\n""1:\n""LDR X2, [%x[src]], #8\n""STRH W2, [%x[dst], #8]!\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
STRH W2, [%x[dst], #8]!
存储元素前先进行地址加 8。
运行结果如下:
2023-05-01 07:06:43.040 31331-31331/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-05-01 07:06:43.040 31331-31331/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030420304050
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608406080a0
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c6090c0f0
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: =============================
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: dst_arr[0]=0xffffffffffffffff
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: dst_arr[1]=0xffffffffffffffff
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: dst_arr[2]=0xffffffffffffffff
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: -----------------------------
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: dst_arr[0]=0xffffffffffffffff
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: dst_arr[1]=0xffffffffffff4050
2023-05-01 07:06:43.041 31331-31331/com.example.myapplication D/native-armv8a: dst_arr[2]=0xffffffffffff80a0
STRH(立即数)Unsigned offset
下面是使用 STRH(立即数)Unsigned offset 的例子。将上面的例子 STRH(立即数)Pre-index 稍做修改(即去掉感叹号)。
long long int len = 3;auto *src_arr = new long long int[len]{0};auto *dst_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {src_arr[i] = 0x0102030420304050 * (i + 1);dst_arr[i] = -1;LOGD("src_arr[%d]=0x%llx", i, src_arr[i]);}LOGD("=============================");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}char *src = (char *) src_arr;char *dst = (char *) dst_arr;asm volatile("MOV X3, %x[len]\n""SUB X3, X3, #1\n""1:\n""LDR X2, [%x[src]], #8\n""STRH W2, [%x[dst], #8]\n""SUBS X3, X3, #1\n""B.GT 1b\n":[len] "+r"(len),[src] "+r"(src),[dst] "+r"(dst):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("dst_arr[%d]=0x%llx", i, dst_arr[i]);}delete[] src_arr;delete[] dst_arr;
STRH W2, [%x[dst], #8]
每次写入的位置均为 dst + 8,最终 0x80a0 得以保留。
运行结果如下:
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030420304050
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608406080a0
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c6090c0f0
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: =============================
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: dst_arr[0]=0xffffffffffffffff
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: dst_arr[1]=0xffffffffffffffff
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: dst_arr[2]=0xffffffffffffffff
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: -----------------------------
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: dst_arr[0]=0xffffffffffffffff
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: dst_arr[1]=0xffffffffffff80a0
2023-05-01 07:16:57.305 2657-2657/com.example.myapplication D/native-armv8a: dst_arr[2]=0xffffffffffffffff
6 STRH(寄存器)
Store Register Halfword(寄存器)指令根据基址寄存器值和偏移寄存器值计算地址,并将来自 32 位寄存器的半字存储到计算出的地址。
STRH <Wt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]
<Wt>
是要传输的通用寄存器的 32 位名称,在“Rt”字段中编码。
<Xn|SP>
是通用基址寄存器或堆栈指针的 64 位名称,在“Rn”字段中编码。
<Wm>
当 option<0>
设置为 0 时,是通用索引寄存器的 32 位名称,编码在“Rm”字段中。
<Xm>
当 option<0>
设置为 1 时,是通用索引寄存器的 64 位名称,编码在“Rm”字段中。
<extend>
是索引扩展/移位说明符,默认为 LSL,当 <amount>
被省略时,必须省略 LSL 选项。在“option”字段中编码。可以具有以下值:
extend | option |
---|---|
UXTW | 010 |
LSL | 011 |
SXTW | 110 |
SXTX | 111 |
<amount>
索引移位量,仅当 <extend>
不是 LSL 时可选。在允许可选的地方,它默认为 #0。它在“S”字段中编码。可以具有以下值:
extend | option |
---|---|
#0 | 0 |
#1 | 1 |
下面是使用 STRH(寄存器)指令的例子。
long long int len = 3;long long int x = 0xff;auto *y_arr = new long long int[len]{0};LOGD("+++++++++++++++++++++++++++++");for (int i = 0; i < len; i++) {y_arr[i] = 0x0102030410203040 * (i + 1);LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);}char *y = (char *) y_arr;asm volatile("MOV X3, #1\n""STRH %w[x], [%x[y] ,X3, LSL#1]\n":[x] "+r"(x),[y] "+r"(y):: "cc", "memory");LOGD("-----------------------------");for (int i = 0; i < len; i++) {LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);}delete[] y_arr;
STRH %w[x], [%x[y] ,X3, LSL#1]
首先计算地址偏移量,即 X3 的值左移 1 位,也就是 1 * 2 = 2,最终即为 y + 2 的位置写入一个半字(16 位);然后从 x 的值分配的寄存器取出最低 16 位写入。
运行结果如下:
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: y_arr[0]=0x102030410203040
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: y_arr[1]=0x204060820406080
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090c0
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: -----------------------------
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: y_arr[0]=0x102030400ff3040
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: y_arr[1]=0x204060820406080
2023-05-01 07:30:16.344 5961-5961/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090c0
参考资料
1.《ARMv8-A-Programmer-Guide》
2.《Arm® A64 Instruction Set Architecture Armv8, for Armv8-A architecture profile》
【ARMv8 编程】A64 内存访问指令——内存存储指令相关推荐
- ARM指令寻址方式之: 内存访问指令寻址
4.2 内存访问指令寻址 根据内存访问指令的分类,内存访问指令的寻址方式可以分为以下几种. ① 字及无符号字节的Load/Store指令的寻址方式. ② 杂类Load/Store指令的寻址方式. ③ ...
- 内存模型 linux,内存模型 - STM32F4 编程手册学习_Linux编程_Linux公社-Linux系统门户网站...
STM32F4编程手册学习2_内存模型 1. 内存映射 MCU将资源映射到一段固定的4GB可寻址内存上,如下图所示. 内存映射将内存分为几块区域,每一块区域都有一个定义的内存类型,一些区域还有一些附加 ...
- 我的模型有多快?——深度学习网络模型的运算复杂度、空间占用和内存访问情况计算...
向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程 公众号:datayx 端午情浓,粽飘香 免费领取 定制珍贵品牌香粽 实物见下图,领取方式见本文末. 深度网络的计算 ...
- 【自己动手写CPU】加载存储指令的实现
目标 修改之前一直做测试的sopc,为其添加数据RAM,测试一般加载指令的实现,加入特殊加载存储指令. 探讨由于加载指令引起的load相关问题,给出OpenMIPS的解决方法,验证解决效果. 加载存储 ...
- 深入Golang内存管理(三) 内存对齐篇
Go struct 内存对齐 举个例子 type S struct {a boolb int32c int8d int64e byte } 上面的struct S,占用多大的内存? 首先我们按照每个成 ...
- thumb指令和arm指令
参考https://www.embedded.com/introduction-to-arm-thumb/ 一.为什么一个芯片需要thumb和arm两套指令集 许多复杂的功能在复杂指令集(CISC)处 ...
- 【ARMv8 编程】A64 内存访问指令——内存加载指令
与所有先前的 ARM 处理器一样,ARMv8 架构是一种加载/存储架构.这意味着没有数据处理指令直接对内存中的数据进行操作.数据必须首先被加载到寄存器中,修改,然后存储到内存中.该程序必须指定地址.要 ...
- ARMv7和ARMv8中关于内存访问的汇编指令总结对比
ARMv7和ARMv8中关于内存访问的汇编指令总结对比 文章目录 ARMv7和ARMv8中关于内存访问的汇编指令总结对比 前言 ARMv7下的内存访问指令 寻址模式 多加载/存储 ARMv8下的内存访 ...
- 0x00000000指令引用的内存不能为written_变量和内存访问
计算机世界有一个常识--所有的数据和指令必须经由内存才能进入CPU的寄存器进而被CPU使用,那么我们程序操作的主战场就是内存,内存操作也就顺理成章成为了程序中最高频的操作. 为了节目的效果,我们先来看 ...
最新文章
- struts2之配置文件struts.xml详解
- 付睿:对新事物的追寻之旅 | 优秀毕业生专访
- web怎么用代码创造表格_Python新工具:用三行代码提取PDF表格数据
- 前端技巧:谷歌浏览器的font boosting[Text Autosizer]
- import 别名_es6模块 import, export 知识点小结
- 总是想逃避不想去面对(又是发牢骚的一天)
- multi task训练torch_Multi-task Learning的三个小知识
- 渡虎谷告诉你CSS的结构和规则
- 漫画:给女朋友介绍什么是 “元宇宙” ?
- python读取raw图片文件_python读取raw binary图片并提取统计信息的实例
- linux 防御***
- iterator remove_Iterator与fast-fail机制
- 每个java小应用程序必须是,每个Java小应用程序必须定义为()。 A.Applet类或JApplet类的子类B.JFrame类的子类...
- 数字孪生技术协助信息物理系统构建数字化城市
- 好有成就感。。。又编了一个扫雷
- Hadoop高可用安装
- 数字孪生智慧制造生产线项目实施方案,平台认知与概念
- 隐私集合求交(PSI)协议研究综述
- VL53L0X 底层思路整理(1)
- CRC32加密算法原理