在内存加载一节中实际上已经使用了内存存储指令了,内存存储指令将寄存器的值存储到内存中。
同样,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》