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

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

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 内存访问指令——内存存储指令相关推荐

  1. ARM指令寻址方式之: 内存访问指令寻址

    4.2  内存访问指令寻址 根据内存访问指令的分类,内存访问指令的寻址方式可以分为以下几种. ① 字及无符号字节的Load/Store指令的寻址方式. ② 杂类Load/Store指令的寻址方式. ③ ...

  2. 内存模型 linux,内存模型 - STM32F4 编程手册学习_Linux编程_Linux公社-Linux系统门户网站...

    STM32F4编程手册学习2_内存模型 1. 内存映射 MCU将资源映射到一段固定的4GB可寻址内存上,如下图所示. 内存映射将内存分为几块区域,每一块区域都有一个定义的内存类型,一些区域还有一些附加 ...

  3. 我的模型有多快?——深度学习网络模型的运算复杂度、空间占用和内存访问情况计算...

    向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx 端午情浓,粽飘香 免费领取  定制珍贵品牌香粽 实物见下图,领取方式见本文末. 深度网络的计算 ...

  4. 【自己动手写CPU】加载存储指令的实现

    目标 修改之前一直做测试的sopc,为其添加数据RAM,测试一般加载指令的实现,加入特殊加载存储指令. 探讨由于加载指令引起的load相关问题,给出OpenMIPS的解决方法,验证解决效果. 加载存储 ...

  5. 深入Golang内存管理(三) 内存对齐篇

    Go struct 内存对齐 举个例子 type S struct {a boolb int32c int8d int64e byte } 上面的struct S,占用多大的内存? 首先我们按照每个成 ...

  6. thumb指令和arm指令

    参考https://www.embedded.com/introduction-to-arm-thumb/ 一.为什么一个芯片需要thumb和arm两套指令集 许多复杂的功能在复杂指令集(CISC)处 ...

  7. 【ARMv8 编程】A64 内存访问指令——内存加载指令

    与所有先前的 ARM 处理器一样,ARMv8 架构是一种加载/存储架构.这意味着没有数据处理指令直接对内存中的数据进行操作.数据必须首先被加载到寄存器中,修改,然后存储到内存中.该程序必须指定地址.要 ...

  8. ARMv7和ARMv8中关于内存访问的汇编指令总结对比

    ARMv7和ARMv8中关于内存访问的汇编指令总结对比 文章目录 ARMv7和ARMv8中关于内存访问的汇编指令总结对比 前言 ARMv7下的内存访问指令 寻址模式 多加载/存储 ARMv8下的内存访 ...

  9. 0x00000000指令引用的内存不能为written_变量和内存访问

    计算机世界有一个常识--所有的数据和指令必须经由内存才能进入CPU的寄存器进而被CPU使用,那么我们程序操作的主战场就是内存,内存操作也就顺理成章成为了程序中最高频的操作. 为了节目的效果,我们先来看 ...

最新文章

  1. struts2之配置文件struts.xml详解
  2. 付睿:对新事物的追寻之旅 | 优秀毕业生专访
  3. web怎么用代码创造表格_Python新工具:用三行代码提取PDF表格数据
  4. 前端技巧:谷歌浏览器的font boosting[Text Autosizer]
  5. import 别名_es6模块 import, export 知识点小结
  6. 总是想逃避不想去面对(又是发牢骚的一天)
  7. multi task训练torch_Multi-task Learning的三个小知识
  8. 渡虎谷告诉你CSS的结构和规则
  9. 漫画:给女朋友介绍什么是 “元宇宙” ?
  10. python读取raw图片文件_python读取raw binary图片并提取统计信息的实例
  11. linux 防御***
  12. iterator remove_Iterator与fast-fail机制
  13. 每个java小应用程序必须是,每个Java小应用程序必须定义为()。 A.Applet类或JApplet类的子类B.JFrame类的子类...
  14. 数字孪生技术协助信息物理系统构建数字化城市
  15. 好有成就感。。。又编了一个扫雷
  16. Hadoop高可用安装
  17. 数字孪生智慧制造生产线项目实施方案,平台认知与概念
  18. 隐私集合求交(PSI)协议研究综述
  19. VL53L0X 底层思路整理(1)
  20. CRC32加密算法原理

热门文章

  1. unity小白之 unpack the Prefab instance解压缩预制件实例
  2. 基于UML模型的NGN业务安全分析
  3. 《Go语言圣经练习题》
  4. 该如何训练好深度学习模型?
  5. Linux 安装字体库 中文字体
  6. LR、CR纽扣电池对照表
  7. 项目实训(十)引入mudule后System.loadLibrary失败天坑
  8. NFT潮鞋AR互动零基础教程来啦!
  9. 微信小程序之画布绘制并管理多张图片
  10. 01 | 论文「外审」到底看什么?