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

news2025/4/4 1:33:17

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

同样,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.coloradmin.cn/o/482373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python多元线性回归预测模型实验完整版

多元线性回归预测模型 实验目的 通过多元线性回归预测模型&#xff0c;掌握预测模型的建立和应用方法&#xff0c;了解线性回归模型的基本原理 实验内容 多元线性回归预测模型 实验步骤和过程 (1)第一步&#xff1a;学习多元线性回归预测模型相关知识。 一元线性回归模型…

高级数据结构专题

1.树状数组 设计二分&#xff0c;二叉树&#xff0c;位运算&#xff0c;前缀和等思想 lowbit x & -x 功能&#xff1a;找到x的二进制数的最后一个1 1.1 树状数组模板 def lowbit(x):return x &-x def add (x,d):while(x < n) :tree[x] dxlowbit(x) def sum(x):an…

零基础学会 Java,这是你需要按照学习的步骤,加油,新加入的你

学习 Java 需要遵循一定的步骤&#xff0c;首先需要学习计算机基础知识&#xff0c;例如算法、数据结构、计算机组成原理等。如果没有相关背景知识&#xff0c;可以参加计算机相关课程进行学习。其次是学习编程基础知识&#xff0c;例如控制流、变量、函数等&#xff0c;你可以…

详解c++---list模拟实现

目录标题 list的准备工作构造函数push_backlist迭代器beginendinserteraseclearconst迭代器list迭代器区间构造swap现代拷贝构造函数现代赋值重载sizeempty->重载 list的准备工作 首先我们知道list是一个带头双向链表&#xff0c;他的数据就会存储在一个一个的节点里面&…

Python基础合集 练习22 (错误与异常处理语句2)

‘’’ try: 语句块 except: 语句块2 else ‘’’ class Mobe1(): def init(self) -> None: pass def mob1(self):while True:try:num int(input(请输入一个数: ))result 50 / numprint(result)print(50/{0}{1}.format(num, result))except (ZeroDivisionError, ValueEr…

时代浪潮已经袭来 AI人工智能频频爆火 ChatGPT改变行业未来

目录 1 人工智能的发展 1.1人工智能发展历程 1.1.1 人工智能的起源 1.1.2 人工智能发展的起起伏伏 1.1.3 人工智能多元化 2 什么是ChatGPT 2.1 ChatGPT的主要功能 2.2ChatGPT对企业的多种优势 2.3 不必担心ChatGPT带来的焦虑 3 人工智能对行业未来的影响 3.1 人工智…

UG NX二次开发(C++)-建模-根据UFun创建的Tag_t转换为Body

文章目录 1、前言2、用UF_MODL_create_block1创建一个块3、将Tag_t转换为Body出现错误3、解决方法4、结论 1、前言 经常采用UG NX二次开发&#xff08;NXOpen C#&#xff09;&#xff08;UG NX二次开发&#xff08;C#&#xff09;专栏&#xff09;&#xff0c;在用UFun创建一个…

【Git 入门教程】第十节、Git的常见问题

Git是一个强大的版本控制系统&#xff0c;它可以帮助开发者管理和协调代码库。然而&#xff0c;初学者使用Git时可能会遇到一些问题。本文将列举一些常见的问题&#xff0c;并提供相应的解决方案。 1. Git无法识别文件权限 在使用Git时&#xff0c;有时候你可能会遇到类似于“…

异构无线传感器网络路由算法研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 ​无线传感器网络(Wireless Sensor Networks, WSN)是一种新型的融合传感器、计算机、通信等多学科的信息获取和处理技术的网络,…

Ubuntu下跑通 nnUNet v2

网上关于nnUNet运行的教程大部分是针对nnUNet v1的。但由于nnUNet v2已经推出&#xff0c;而且相对于v1有了很大的更新。所以个人只能啃nnUNet的英文文档参考在Windows上实现nnU-Net v2的环境配置_netv2_无聊的程序猿的博客-CSDN博客 实现了代码的复现。 1.System requirement…

树与图的存储-邻接表与邻接矩阵-深度广度遍历

全部代码 全部代码在github acwing 上 正在更新 https://github.com/stolendance/acwing 图论 欢迎star与fork 树与图的存储 无论是树 还是无向图 都可以看成有向图 有向图可以采用邻接矩阵与邻接表进行存储 邻接矩阵 邻接矩阵 采用矩阵存储,graph[i][j] 代表i到j边的权重…

Python学习15:恺撒密码 B(python123)

描述 恺撒密码是古罗马凯撒大帝用来对军事情报进行加解密的算法&#xff0c;它采用了替换方法对信息中的每一个英文字符循环替换为字母表序列中该字符后面的第三个字符&#xff0c;即&#xff0c;字母表的对应关系如下&#xff1a;‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪…

Markdown编辑器快捷方式

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Linux安装离线版MySql客户端

本文采用rpm安装方式。 下载文件&#xff1a; mysql-community-libs-5.7.41-1.el7.x86_64 mysql-community-common-5.7.41-1.el7.x86_64 mysql-community-client-5.7.41-1.el7.x86_64 本文件可以在MYSQL官网进行下载 MySQL :: Download MySQL Community Server (Archive…

C语言入门篇——文件操作篇

目录 1、为什么使用文件 2、什么是文件 2.1程序文件 2.2数据文件 2.3文件名 3、文件的打开和关闭 3.1文件指针 3.2文件的打开和关闭 4、文件的顺序读写 5、文件的随机读写 5.1fseek 5.2ftell 5.3rewind 6、文本文件和二进制文件 7、文件读取结束的判定 8、文件…

玩转肺癌目标检测数据集Lung-PET-CT-Dx ——④转换成PASCAL VOC格式数据集

文章目录 关于PASCAL VOC数据集目录结构 ①创建VOC数据集的几个相关目录XML文件的形式 ②读取dcm文件与xml文件的配对关系③创建VOC格式数据集④创建训练、验证集 本文所用代码见文末Github链接。 关于PASCAL VOC数据集 pascal voc数据集是关于计算机视觉&#xff0c;业内广泛…

【五一创作】Pytroch nn.Unfold() 与 nn.Fold()图码详解

文章目录 Unfold()与Fold()的用途nn.Unfold()Unfold()与Fold() 变化模式图解 nn.Fold()单通道 滑动窗口无重叠模拟图片数据&#xff08;b,3,9,9&#xff09;&#xff0c;通道数 C 为3&#xff0c;滑动窗口无重叠。单通道 滑动窗口有重叠。 卷积等价于&#xff1a;Unfold Matri…

Hadoop 2:MapReduce

理解MapReduce思想 MapReduce的思想核心是“先分再合&#xff0c;分而治之”。 所谓“分而治之”就是把一个复杂的问题&#xff0c;按照一定的“分解”方法分为等价的规模较小的若干部分&#xff0c;然后逐个解决&#xff0c;分别找出各部分的结果&#xff0c;然后把各部分的结…

从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针

目录 1. 面向对象 1.1 类的引入 1.2 class 关键字 2. 类的访问限定符及封装 2.1 访问限定符 2.2 封装 2.2.2 封装的本质 3. 类的作用域和实例化 3.1 类定义的两种方式 3.2 类的作用域 3.3 类的实例化 3.3.1 声明和定义的区别 4. 类对象模型 4.1 计算类的存储大小…

Java开发者在Windows环境安装各类开发工具汇总

Java开发者在Windows环境安装各类开发工具汇总 前言Java JDK下载配置 Tomcat下载配置 Maven下载配置配置仓库 Nginx下载启动关闭 MySQL下载配置my.ini初始化MySQL数据文件安装MySQL服务启动MySQL登录MySQL重置登录密码 NodeJs下载安装与验证配置NPM Git下载配置git配置ssh免密登…