【ARMv8 编程】A64 内存访问指令——内存存储指令

news/2024/11/23 13:36:10/

在内存加载一节中实际上已经使用了内存存储指令了,内存存储指令将寄存器的值存储到内存中。

同样,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 的例子。

  1. 新建 src_arr、dst_arr 数组,并初始化为 0。
  2. 给 src_arr 赋初值,将 long long int* 指针转为 char*,为了后续内联汇编加载存储(笔者环境实测:如果不这样赋值 STR 指令无法正常写入内存)。
  3. 经过内联汇编代码运行,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 处继续执行。
  4. 继续打印一次 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”字段中编码,它可以具有以下值:

extendoption
UXTW010
LSL011
SXTW110
SXTX111

<amount> 是索引移位量,仅当 <extend> 不是 LSL 时才可选。在允许可选的地方,它默认为 #0。它在“S”字段中编码。

对于 32 位变体,它可以具有以下值:

amountS
#00
#21

对于 64 位变体,它可以具有以下值:

amountS
#00
#31

下面是使用 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”字段中编码。 它可以具有以下值:

extendoption
UXTW010
SXTW110
SXTX111

<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”字段中编码。可以具有以下值:

extendoption
UXTW010
LSL011
SXTW110
SXTX111

<amount> 索引移位量,仅当 <extend> 不是 LSL 时可选。在允许可选的地方,它默认为 #0。它在“S”字段中编码。可以具有以下值:

extendoption
#00
#11

下面是使用 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》


http://www.ppmy.cn/news/59583.html

相关文章

英语中宾语从句的概念及其用法,例句(不断更新)

宾语从句 宾语从句是一个从句&#xff0c;它在句子中充当宾语。也就是说&#xff0c;宾语从句其实就是从句在整个复杂句中做宾语而已。 宾语是谓语动词或某些介词所需的成分&#xff0c;用来回答“谁”或“什么”的问题。宾语从句起到与名词相似的作用&#xff0c;作为整个句子…

五面阿里Java岗,从小公司到阿里的面经总结

​​​​​​​ 面试 笔试常见的问题 面试常见的问题下面给的面试题基本都有。 1 手写代码&#xff1a;手写代码一般会考单例、排序、线程、消费者生产者 排序。 2 写SQL很常考察group by、内连接和外连接 2.面试1-5面总结 1&#xff09;让你自我介绍 2&#xff09;做两道算法…

《基于深度学习模型的非接触式面部视频记录技术用于心房颤动的检测》阅读笔记

目录 一、论文摘要 二、论文十问 Q1: 论文试图解决什么问题&#xff1f; Q2: 这是否是一个新的问题&#xff1f; Q3: 这篇文章要验证一个什么科学假设&#xff1f; Q4: 有哪些相关研究&#xff1f;如何归类&#xff1f;谁是这一课题在领域内值得关注的研究员&#xff1f; …

题目:16版.饲养员喂养动物

1、实验要求 本实验要求&#xff1a;本实验以饲养员喂养老虎为业务背景&#xff0c;体验“函数重载”的价值。 1-1. 业务说明&#xff1a; 1-1.1. 本实验以动物园饲养员喂养动物为业务背景&#xff1b; 1-1.2. 动物园的饲养员最多管理三只老虎&#xff1b; 1-1.3. 饲养员可以一…

更轻更好用的蓝牙耳机,日常佩戴更舒适,QCY Crossky Link体验

平时为了方便接打电话&#xff0c;我经常会戴上一副蓝牙耳机&#xff0c;不过戴久了入耳式的耳机&#xff0c;总感觉不舒服&#xff0c;上个月我看到一款设计很新颖的开放式耳机&#xff0c;来自我之前用过的一个国产品牌&#xff0c;最近到手后试了试&#xff0c;感觉质量不错…

想回西安

五一假期结束了&#xff0c;开始营业总结下跟读者们的交流。 特别感谢大家让我在自己的技术号里面写一些和生活相关的事情&#xff0c;现在正常营业&#xff0c;回复下读者的问题。 问题 发哥&#xff0c;我现在有个疑惑能麻烦帮我解答下嘛。 我已经工作一年多了&#xff0c;但…

【2023 年第十三届 MathorCup 高校数学建模挑战赛】 B 题 城市轨道交通列车时刻表优化问题 42页论文及代码

相关信息 &#xff08;1&#xff09;建模思路 【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 详细建模过程解析及代码实现 【2023 年第十三届 MathorCup 高校数学建模挑战赛】 B 题 城市轨道交通列车时刻表优化问题 详细建…

2023年房地产抵押贷款研究报告

第一章 概述 房地产抵押贷款是一种以房地产为抵押品的贷款形式&#xff0c;包括个人和企业两种情况。个人房地产抵押贷款是指个人将名下房产作为抵押品向银行或其他金融机构申请贷款&#xff0c;而企业房地产抵押贷款则是指企业将自己名下的商业房产作为抵押品向金融机构申请贷…