国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

這篇具有很好參考價值的文章主要介紹了【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

與所有先前的 ARM 處理器一樣,ARMv8 架構(gòu)是一種加載/存儲架構(gòu)。這意味著沒有數(shù)據(jù)處理指令直接對內(nèi)存中的數(shù)據(jù)進(jìn)行操作。數(shù)據(jù)必須首先被加載到寄存器中,修改,然后存儲到內(nèi)存中。該程序必須指定地址、要傳輸?shù)臄?shù)據(jù)大小以及源或目標(biāo)寄存器。有額外的加載和存儲指令提供更多選項,例如非臨時加載/存儲、加載/存儲獨占和獲取/釋放。

Load 指令的一般形式如下:

LDR Rt, <addr>

對于加載到整數(shù)寄存器中的指令,可以選擇要加載的大小。例如,要加載小于指定寄存器值的大小,請將以下后綴之一附加到 LDR 指令:

  • LDRB(8 位,零擴(kuò)展)
  • LDRSB(8 位,符號擴(kuò)展)
  • LDRH(16 位,零擴(kuò)展)
  • LDRSH(16 位,符號擴(kuò)展)
  • LDRSW(32 位,符號擴(kuò)展)

下面是 LDRSB 和 LDRB 加載示例圖:

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

還有 unscaled-offset 的偏移形式,例如 LDUR<type>。 程序員通常不需要顯式使用 LDUR 形式,因為大多數(shù)匯編器可以根據(jù)使用的偏移量選擇合適的版本。

我們不需要指定 X 寄存器的零擴(kuò)展加載,因為寫入 W 寄存器實際上是零擴(kuò)展到整個寄存器寬度。

下面是在 Android 平臺 Log 打印使用的代碼,下面 Demo 代碼中會使用到。

#define LOG_TAG "NativeCore"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

1 LDR(立即數(shù))

LDR 指令加載寄存器(立即偏移量)。它有 3 種類型編碼:后索引(Post-index)、前索引(Pre-index)和無符號偏移(Unsigned offset)。

Post-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (size = 10)

LDR <Wt>, [<Xn|SP>], #<simm>

64-bit (size = 11)

LDR <Xt>, [<Xn|SP>], #<simm>

Pre-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (size = 10)

LDR <Wt>, [<Xn|SP>, #<simm>]!

64-bit (size = 11)

LDR <Xt>, [<Xn|SP>, #<simm>]!

Unsigned offset

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (size = 10)

LDR <Wt>, [<Xn|SP>{, #<pimm>}]

64-bit (size = 11)

LDR <Xt>, [<Xn|SP>{, #<pimm>}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,編碼在“Rt”字段中。

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<simm> 是帶符號的立即字節(jié)偏移量,在 -256 到 255 的范圍內(nèi),在“imm9”字段中編碼。

<pimm> 是可選的正立即字節(jié)偏移量。對于 32 位變體:是 0 到 16380 范圍內(nèi) 4 的倍數(shù),默認(rèn)為 0 并在“imm12”字段中編碼為 <pimm>/4。對于 64 位變體:是 0 到 32760 范圍內(nèi) 8 的倍數(shù),默認(rèn)為 0 并在“imm12”字段中編碼為 <pimm>/8。

LDR 指令 Post-index

下面是使用 LDR 指令 Post-index 的例子。

  1. 新建 src_arr、dst_arr 數(shù)組,并初始化為 0。
  2. 給 src_arr 賦初值,將 long long int* 指針轉(zhuǎn)為 char*,為了后續(xù)內(nèi)聯(lián)匯編加載(筆者環(huán)境實測:如果不這樣賦值 STR 指令無法正常寫入內(nèi)存)。
  3. 經(jīng)過內(nèi)聯(lián)匯編代碼運行,MOV X3, %x[len] 先將數(shù)組長度 len 移動到 X3 寄存器,接著 1 是標(biāo)簽,LDR X2, [%x[src]], #8 將 src_arr 數(shù)組的前 8 個字節(jié)加載到 X2 寄存器,接著 Post-index(也就是地址加 8 寫回,下次讀取起點已經(jīng)加 8)。STR X2, [%x[dst]], #8 會將剛剛 X2 寄存器的值寫入 dst_arr 內(nèi)存中,同樣 Post-index(也就是地址加 8 寫回,下次寫入起點已經(jīng)加 8)。SUBS X3, X3, #1 將 X3 每次都減去 1,SUBS 會設(shè)置條件標(biāo)志,后面 B.GT 1b 判斷當(dāng) SUBS 設(shè)置條件標(biāo)志 Z = 1 時,就不滿足跳轉(zhuǎn)到標(biāo)簽 1 處執(zhí)行的條件,也就退出了內(nèi)聯(lián)匯編代碼,否則跳轉(zhuǎn)到標(biāo)簽 1 處繼續(xù)執(zhí)行。
  4. 繼續(xù)打印一次 dst_arr 數(shù)組,查看內(nèi)部值,此時和 src_arr 內(nèi)的值保持一致,說明 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;
        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;

下面是運行結(jié)果,首先打印出 src_arr 和 dst_arr 的值,此處知道 dst_arr 已經(jīng)清零。后面一次 dst_arr 打印,則是經(jīng)過了內(nèi)聯(lián)匯編代碼。

    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[0]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[1]=0x101010101010101
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[2]=0x202020202020202
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[3]=0x303030303030303
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[4]=0x404040404040404
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[5]=0x505050505050505
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[6]=0x606060606060606
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[7]=0x707070707070707
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[8]=0x808080808080808
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: src_arr[9]=0x909090909090909
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: =============================
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[3]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[4]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[5]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[6]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[7]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[8]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[9]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: -----------------------------
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[1]=0x101010101010101
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[2]=0x202020202020202
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[3]=0x303030303030303
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[4]=0x404040404040404
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[5]=0x505050505050505
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[6]=0x606060606060606
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[7]=0x707070707070707
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[8]=0x808080808080808
    2023-04-13 18:46:34.838 11692-11801/com.demo.myapplication D/NativeCore: dst_arr[9]=0x909090909090909

LDR 指令 Pre-index

下面是使用 LDR 指令 Pre-index 的例子,也就是 index 提前加 8 的意思。將程序稍做修改,因為 index 提前加 8,為了防止發(fā)生內(nèi)存讀取越界,因此引入 SUB X3, X3, #1 先減 1,其次 LDR 指令也換為了 Pre-index 的格式 LDR X2, [%x[src], #8]!,地址先加 8 再去讀取內(nèi)存中的值到寄存器 X2。

    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;
        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;

運行結(jié)果如下:

    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[0]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[1]=0x101010101010101
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[2]=0x202020202020202
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[3]=0x303030303030303
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[4]=0x404040404040404
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[5]=0x505050505050505
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[6]=0x606060606060606
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[7]=0x707070707070707
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[8]=0x808080808080808
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: src_arr[9]=0x909090909090909
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: =============================
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[3]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[4]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[5]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[6]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[7]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[8]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[9]=0x0
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: -----------------------------
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[0]=0x101010101010101
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[1]=0x202020202020202
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[2]=0x303030303030303
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[3]=0x404040404040404
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[4]=0x505050505050505
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[5]=0x606060606060606
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[6]=0x707070707070707
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[7]=0x808080808080808
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[8]=0x909090909090909
    2023-04-13 19:22:58.314 19791-19862/com.demo.myapplication D/NativeCore: dst_arr[9]=0x0

LDR 指令 Unsigned offset

下面是使用 LDR 指令 Unsigned offset 的例子,也就是每次從這個 offset(無符號數(shù))讀取。

    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;
        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;

運行結(jié)果如下:

    2023-04-14 08:05:08.059 7157-7305/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[0]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[1]=0x101010101010101
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[2]=0x202020202020202
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[3]=0x303030303030303
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[4]=0x404040404040404
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[5]=0x505050505050505
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[6]=0x606060606060606
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[7]=0x707070707070707
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[8]=0x808080808080808
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: src_arr[9]=0x909090909090909
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: =============================
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[3]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[4]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[5]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[6]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[7]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[8]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[9]=0x0
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: -----------------------------
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[0]=0x101010101010101
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[1]=0x101010101010101
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[2]=0x101010101010101
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[3]=0x101010101010101
    2023-04-14 08:05:08.060 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[4]=0x101010101010101
    2023-04-14 08:05:08.061 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[5]=0x101010101010101
    2023-04-14 08:05:08.061 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[6]=0x101010101010101
    2023-04-14 08:05:08.061 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[7]=0x101010101010101
    2023-04-14 08:05:08.061 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[8]=0x101010101010101
    2023-04-14 08:05:08.061 7157-7305/com.demo.myapplication D/NativeCore: dst_arr[9]=0x101010101010101

2 LDR(literal)

LDR(文字)指令根據(jù) PC 值和立即偏移量計算地址,從內(nèi)存加載一個字,并將其寫入寄存器。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc = 00)

LDR <Wt>, <label>

64-bit (opc = 01)

LDR <Xt>, <label>

<Wt> 是要加載的通用寄存器的 32 位名稱,編碼在“Rt”字段中。

<Xt> 是要加載的通用寄存器的 64 位名稱,編碼在“Rt”字段中。

<label> 是要從中加載數(shù)據(jù)的程序標(biāo)簽。它與該指令地址的偏移量在 +/-1MB 范圍內(nèi),編碼為“imm19”乘以 4。

下面是使用 LDR(literal) 指令的例子。

    long long int x = 0;

    asm volatile(
        "LDR X2, abc\n"
        "MOV %x[x], X2\n"
        "abc:\n"
        "MOV X2, #0\n"
        "MOV X2, #1\n"
        "MOV X2, #2\n"
    :[x] "+r"(x)
    :
    : "cc", "memory");

執(zhí)行 LDR X2, abc 將 abc 標(biāo)簽根據(jù) PC 值和立即偏移量計算地址,將這個地址的內(nèi)容加載到寄存器。此時 x 的值打印出來它固定為 0xd2800022d2800002,它是什么呢?實際就是 MOV X2, #0MOV X2, #1 這兩條指令。每條指令都編碼為 32 位。

溫習(xí)一下 MOV (wide immediate)

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-StgTzt7P-1682724688018)(https://note.youdao.com/yws/res/112016/WEBRESOURCE199789001157b11eae15547fb4c87e34)]

0xd2800022d2800002 的二進(jìn)制為 0b1 10 100101 00 0000000000000001 00010 1 10 100101 00 0000000000000000 00010(實際上這些位都是連續(xù)的,為了方便解讀指令編碼做了一些空白),0b1 10 100101 00 0000000000000001 00010 正好是 MOV X2, #1 的指令編碼,而 0b1 10 100101 00 0000000000000000 00010則是 MOV X2, #0 的指令編碼。

再來用 IDA 工具反編譯一下這段代碼:

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

我們可以清晰看到 MOV X2, #2 這條指令,卻看不到它上面的另外兩條 MOV (wide immediate) 指令,因為它們編碼在 0xd2800022d2800002 內(nèi)了。 并且 LDR X2, abc 替換成了 LDR X2, =0xD2800022D2800002,這和我們的運行結(jié)果完全一致。

3 LDR(寄存器)

LDR(寄存器)指令根據(jù)基址寄存器值和偏移寄存器值計算地址,從內(nèi)存中加載一個字,并將其寫入寄存器。偏移寄存器值可以選擇性地移位和擴(kuò)展。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (size = 10)

LDR <Wt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]

64-bit (size = 11)

LDR <Xt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<Wm> 當(dāng) option<0> 設(shè)置為 0 時,是通用索引寄存器的 32 位名稱,編碼在“Rm”字段中。

<Xm> 當(dāng) option<0> 設(shè)置為 1 時,是通用索引寄存器的 64 位名稱,編碼在“Rm”字段中。

<extend> 是索引擴(kuò)展/移位說明符,默認(rèn)為 LSL,當(dāng)省略 <amount> 時,LSL 選項必須省略。在“option”字段中編碼。它可以具有以下值:

<extend> option 編碼
UXTW 010
LSL 011
SXTW 110
SXTX 111

<amount> 是索引移位量。僅當(dāng) <extend> 不是 LSL 時才可選。在允許可選的地方,它默認(rèn)為 #0。

對于 32 位變體:它在“S”字段中編碼可以具有以下值:

<amount> S 編碼
#0 0
#2 1

對于 64 位變體:它在“S”字段中編碼可以具有以下值:

<amount> S 編碼
#0 0
#3 1

下面是使用 LDR(寄存器)指令的例子。

    long long int len = 3;
    
    long long int x = 0;
    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"
        "LDR %x[x], [%x[y] ,X3, LSL#3]\n"
    :[x] "+r"(x),
     [y] "+r"(y)
    :
    : "cc", "memory");
    
    LOGD("-----------------------------");
    LOGD("x=0x%llx", x);
    
    delete[] y_arr;

運行結(jié)果如下:

    2023-04-15 21:14:22.007 20790-20790/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
    2023-04-15 21:14:22.007 20790-20790/com.example.myapplication D/native-armv8a: y_arr[0]=0x102030410203040
    2023-04-15 21:14:22.007 20790-20790/com.example.myapplication D/native-armv8a: y_arr[1]=0x204060820406080
    2023-04-15 21:14:22.007 20790-20790/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090c0
    2023-04-15 21:14:22.007 20790-20790/com.example.myapplication D/native-armv8a: -----------------------------
    2023-04-15 21:14:22.007 20790-20790/com.example.myapplication D/native-armv8a: x=0x204060820406080

執(zhí)行 LDR %x[x], [%x[y] ,X3, LSL#3],首先經(jīng)過 MOV X3, #1 指令后 X3 的值為 1,在 X3 索引寄存器上邏輯左移 3 位,也就是 1 * 8 = 8,最終在 y_arr(%x[y] 內(nèi)裝載的實際上就是 y_arr 數(shù)組的基址) 上準(zhǔn)備加載的索引就是 8,也就將 8 ~ 15 這些索引指向的字節(jié)加載到 %x[x] 寄存器,所以最終 x 的值為 0x204060820406080(和 y_arr 中第二個值是相同的)。

4 LDRB(立即數(shù))

加載寄存器字節(jié)(立即數(shù))指令從內(nèi)存中加載一個字節(jié),對其進(jìn)行零擴(kuò)展,并將結(jié)果寫入寄存器。用于加載的地址是根據(jù)基址寄存器和立即偏移量計算得出的。

Post-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRB <Wt>, [<Xn|SP>], #<simm>

Pre-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRB <Wt>, [<Xn|SP>, #<simm>]!

Unsigned offset

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRB <Wt>, [<Xn|SP>{, #<pimm>}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<simm> 是帶符號的立即字節(jié)偏移量,在 -256 到 255 的范圍內(nèi),在“imm9”字段中編碼。

<pimm> 是可選的正立即字節(jié)偏移量,范圍為 0 到 4095,默認(rèn)為 0 并在“imm12”字段中編碼。

LDRB(立即數(shù))Post-index

下面是使用 LDRB(立即數(shù))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] = 0x0102030410203040 * (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"
        "LDRB W2, [%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;

從結(jié)果不難知道 LDRB W2, [%x[src]], #8 確實只加載了一個字節(jié)到 W2 寄存器,并把寄存器高位全部清零,這里還能確定的一點是數(shù)據(jù)是按照小端在內(nèi)存中分布的。運行結(jié)果如下:

    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030410203040
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: src_arr[1]=0x204060820406080
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c306090c0
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: =============================
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: -----------------------------
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: dst_arr[0]=0x40
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: dst_arr[1]=0x80
    2023-04-16 15:26:19.658 14573-14573/com.example.myapplication D/native-armv8a: dst_arr[2]=0xc0

LDRB(立即數(shù))Pre-index

下面是使用 LDRB(立即數(shù))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] = 0x0102030410203040 * (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"
        "LDRB W2, [%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;

運行結(jié)果如下:

    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030410203040
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: src_arr[1]=0x204060820406080
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c306090c0
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: =============================
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: -----------------------------
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: dst_arr[0]=0x80
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: dst_arr[1]=0xc0
    2023-04-16 15:37:29.915 19872-19872/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0

LDRB(立即數(shù))Unsigned offset

下面是使用 LDRB(立即數(shù))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] = 0x0102030410203040 * (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"
        "LDRB W2, [%x[src], #6]\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;

運行結(jié)果如下:

    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030410203040
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: src_arr[1]=0x204060820406080
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c306090c0
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: =============================
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: -----------------------------
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: dst_arr[0]=0x2
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: dst_arr[1]=0x2
    2023-04-16 15:43:05.327 24289-24289/com.example.myapplication D/native-armv8a: dst_arr[2]=0x2

5 LDRB(寄存器)

加載寄存器字節(jié)(寄存器)指令根據(jù)基址寄存器值和偏移寄存器值計算地址,從內(nèi)存中加載一個字節(jié),對其進(jìn)行零擴(kuò)展,并將其寫入寄存器。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

Extended register (option != 011)

LDRB <Wt>, [<Xn|SP>, (<Wm>|<Xm>), <extend> {<amount>}]

Shifted register (option = 011)

LDRB <Wt>, [<Xn|SP>, <Xm>{, LSL <amount>}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<Wm> 當(dāng) option<0> 設(shè)置為 0 時,是通用索引寄存器的 32 位名稱,編碼在“Rm”字段中。

<Xm> 當(dāng) option<0> 設(shè)置為 1 時,是通用索引寄存器的 64 位名稱,編碼在“Rm”字段中。

<extend> 是索引擴(kuò)展說明符,在“option”字段中編碼。它可以具有以下值:

<extend> option 編碼
UXTW 010
SXTW 110
SXTX 111

<amount> 是索引移位量,必須是#0,如果省略則在“S”中編碼為0,如果存在則編碼為1。

下面是使用 LDRB(寄存器)指令的例子。

    long long int len = 3;

    long int x = 0;
    auto *y_arr = new long long int[len]{0};

    LOGD("+++++++++++++++++++++++++++++");
    for(int i = 0; i < len; i++){
        y_arr[i] = 0x0102030410203050 * (i + 1);
        LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);
    }

    char* y = (char*)y_arr;

    asm volatile(
    "MOV X3, #16\n"
    "LDRB %w[x], [%x[y] ,X3, LSL#0]\n"
    :[x] "+r"(x),
    [y] "+r"(y)
    :
    : "cc", "memory");

    LOGD("-----------------------------");
    LOGD("x=0x%lx", x);

    delete[] y_arr;

運行結(jié)果如下:

    2023-04-16 16:07:58.615 20132-20132/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
    2023-04-16 16:07:58.615 20132-20132/com.example.myapplication D/native-armv8a: y_arr[0]=0x102030410203050
    2023-04-16 16:07:58.615 20132-20132/com.example.myapplication D/native-armv8a: y_arr[1]=0x2040608204060a0
    2023-04-16 16:07:58.615 20132-20132/com.example.myapplication D/native-armv8a: y_arr[2]=0x306090c306090f0
    2023-04-16 16:07:58.615 20132-20132/com.example.myapplication D/native-armv8a: -----------------------------
    2023-04-16 16:07:58.615 20132-20132/com.example.myapplication D/native-armv8a: x=0xf0

MOV X3, #16 將索引立即數(shù) 16 移動到 X3 寄存器,LDRB %w[x], [%x[y] ,X3, LSL#0] 則首先對索引邏輯左移 0 位,也就是沒變化還是 16,接著就從 16 這個位置加載 y_arr 中的字節(jié),也就是 0xF0,寫入 %w[x],并把寄存器高位清零,所以最終 x 的值就為 0xF0。

6 LDRSB(立即數(shù))

加載寄存器有符號字節(jié)(立即數(shù))指令從內(nèi)存中加載一個字節(jié),將其符號擴(kuò)展為 32 位或 64 位,并將結(jié)果寫入寄存器。用于加載的地址是根據(jù)基址寄存器和立即偏移量計算得出的。

Post-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc = 11)

LDRSB <Wt>, [<Xn|SP>], #<simm>

64-bit (opc = 10)

LDRSB <Xt>, [<Xn|SP>], #<simm>

Pre-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc = 11)

LDRSB <Wt>, [<Xn|SP>, #<simm>]!

64-bit (opc = 10)

LDRSB <Xt>, [<Xn|SP>, #<simm>]!

Unsigned offset

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc = 11)

LDRSB <Wt>, [<Xn|SP>{, #<pimm>}]

64-bit (opc = 10)

LDRSB <Xt>, [<Xn|SP>{, #<pimm>}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<simm> 是帶符號的立即字節(jié)偏移量,在 -256 到 255 的范圍內(nèi),在“imm9”字段中編碼。

<pimm> 是可選的正立即字節(jié)偏移量,范圍為 0 到 4095,默認(rèn)為 0 并在“imm12”字段中編碼。

LDRSB(立即數(shù))Post-index

下面是使用 LDRSB(立即數(shù))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] = 0x0102030410203050 * (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"
        "LDRSB 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 的最后兩個值變?yōu)榱素?fù)數(shù),這就是 LDRSB 補符號位的作用。運行結(jié)果如下:

    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030410203050
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608204060a0
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c306090f0
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: =============================
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: -----------------------------
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: dst_arr[0]=0x50
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: dst_arr[1]=0xffffffffffffffa0
    2023-04-16 20:39:09.486 7564-7564/com.example.myapplication D/native-armv8a: dst_arr[2]=0xfffffffffffffff0

LDRSB(立即數(shù))Pre-index

下面是使用 LDRSB(立即數(shù))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] = 0x0102030410203050 * (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"
        "LDRSB 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;

和 LDRSB(立即數(shù))Post-index 指令的區(qū)別就是 index 前置自增了。運行結(jié)果如下:

2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030410203050
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608204060a0
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c306090f0
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: =============================
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: -----------------------------
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: dst_arr[0]=0xffffffffffffffa0
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: dst_arr[1]=0xfffffffffffffff0
2023-04-16 20:44:15.080 10777-10777/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0

LDRSB(立即數(shù))Unsigned offset

下面是使用 LDRSB(立即數(shù))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] = 0x0102030410203050 * (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"
        "LDRSB X2, [%x[src], #6]\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;

除了加載固定位置的字節(jié)外,由于字節(jié)的符號位為 0,所以沒有出現(xiàn)負(fù)數(shù)的行為!運行結(jié)果如下:

    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: +++++++++++++++++++++++++++++
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: src_arr[0]=0x102030410203050
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: src_arr[1]=0x2040608204060a0
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: src_arr[2]=0x306090c306090f0
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: =============================
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: dst_arr[0]=0x0
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: dst_arr[1]=0x0
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: dst_arr[2]=0x0
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: -----------------------------
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: dst_arr[0]=0x2
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: dst_arr[1]=0x2
    2023-04-16 20:48:49.703 13214-13214/com.example.myapplication D/native-armv8a: dst_arr[2]=0x2

7 LDRSB(寄存器)

加載寄存器有符號字(寄存器)指令根據(jù)基址寄存器值和偏移寄存器值計算地址,從內(nèi)存中加載一個字節(jié),對其進(jìn)行符號擴(kuò)展,并將其寫入寄存器。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit extended register offset (opc = 11 && option != 011)

LDRSB <Wt>, [<Xn|SP>, (<Wm>|<Xm>), <extend> {<amount>}]

32-bit shifted register offset (opc = 11 && option = 011)

LDRSB <Wt>, [<Xn|SP>, <Xm>{, LSL <amount>}]

64-bit extended register offset (opc = 10 && option != 011)

LDRSB <Xt>, [<Xn|SP>, (<Wm>|<Xm>), <extend> {<amount>}]

64-bit shifted register offset (opc = 10 && option = 011)

LDRSB <Xt>, [<Xn|SP>, <Xm>{, LSL <amount>}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<Wm> 當(dāng) option<0> 設(shè)置為 0 時,是通用索引寄存器的 32 位名稱,編碼在“Rm”字段中。

<Xm> 當(dāng) option<0> 設(shè)置為 1 時,是通用索引寄存器的 64 位名稱,編碼在“Rm”字段中。

<extend> 是索引擴(kuò)展說明符,編碼在“option”中:

option <extend>
010 UXTW
110 SXTW
111 SXTX

<amount> 是索引移位量,必須是#0,如果省略則在“S”中編碼為0,如果存在則編碼為1。

下面是使用 LDRSB(寄存器)指令的例子。

    long long int len = 3;

    long int x = 0;
    auto *y_arr = new long long int[len]{0};

    LOGD("+++++++++++++++++++++++++++++");
    for(int i = 0; i < len; i++){
        y_arr[i] = 0x0102030410203050 * (i + 1);
        LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);
    }

    char* y = (char*)y_arr;

    asm volatile(
    "MOV X3, #16\n"
    "LDRSB %w[x], [%x[y] ,X3, LSL#0]\n"
    :[x] "+r"(x),
    [y] "+r"(y)
    :
    : "cc", "memory");

    LOGD("-----------------------------");
    LOGD("x=0x%lx", x);

    delete[] y_arr;

我們看到和 LDRB(寄存器)指令的區(qū)別是對符號位的處理。運行結(jié)果如下:

2023-04-17 08:13:44.105 12670-12733/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-17 08:13:44.105 12670-12733/com.demo.myapplication D/NativeCore: y_arr[0]=0x102030410203050
2023-04-17 08:13:44.105 12670-12733/com.demo.myapplication D/NativeCore: y_arr[1]=0x2040608204060a0
2023-04-17 08:13:44.105 12670-12733/com.demo.myapplication D/NativeCore: y_arr[2]=0x306090c306090f0
2023-04-17 08:13:44.105 12670-12733/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-17 08:13:44.105 12670-12733/com.demo.myapplication D/NativeCore: x=0xfffffff0

8 LDRH(立即數(shù))

加載寄存器半字(立即數(shù))指令從內(nèi)存中加載一個半字,對其進(jìn)行零擴(kuò)展,并將結(jié)果寫入寄存器。用于加載的地址是根據(jù)基址寄存器和立即偏移量計算得出的。

Post-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRH <Wt>, [<Xn|SP>], #<simm>

Pre-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRH <Wt>, [<Xn|SP>, #<simm>]!

Unsigned offset

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRH <Wt>, [<Xn|SP>{, #<pimm>}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<simm> 是帶符號的立即字節(jié)偏移量,在 -256 到 255 的范圍內(nèi),在“imm9”字段中編碼。

<pimm> 是可選的正立即字節(jié)偏移量,是 0 到 8190 范圍內(nèi) 2 的倍數(shù),默認(rèn)為 0 并在“imm12”字段中編碼為 <pimm>/2

LDRH(立即數(shù))Post-index

下面是使用 LDRH(立即數(shù))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] = 0x0102030410203040 * (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"
        "LDRH W2, [%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;

從結(jié)果不難知道 LDRH W2, [%x[src]], #8 確實只加載了兩個字節(jié)(即半字)到 W2 寄存器,并把寄存器高位全部清零。運行結(jié)果如下:

2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: src_arr[0]=0x102030410203040
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: src_arr[1]=0x204060820406080
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: src_arr[2]=0x306090c306090c0
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: =============================
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: dst_arr[0]=0x3040
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: dst_arr[1]=0x6080
2023-04-18 07:47:47.383 15674-15741/com.demo.myapplication D/NativeCore: dst_arr[2]=0x90c0

LDRH(立即數(shù))Pre-index

下面是使用 LDRH(立即數(shù))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] = 0x0102030410203040 * (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"
        "LDRH W2, [%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;

運行結(jié)果如下:

2023-04-18 07:51:27.771 17090-17178/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 07:51:27.771 17090-17178/com.demo.myapplication D/NativeCore: src_arr[0]=0x102030410203040
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: src_arr[1]=0x204060820406080
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: src_arr[2]=0x306090c306090c0
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: =============================
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: dst_arr[0]=0x6080
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: dst_arr[1]=0x90c0
2023-04-18 07:51:27.772 17090-17178/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0

LDRH(立即數(shù))Unsigned offset

下面是使用 LDRH(立即數(shù))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] = 0x0102030410203040 * (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"
        "LDRH W2, [%x[src], #6]\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;

運行結(jié)果如下:

2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: src_arr[0]=0x102030410203040
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: src_arr[1]=0x204060820406080
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: src_arr[2]=0x306090c306090c0
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: =============================
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: dst_arr[0]=0x102
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: dst_arr[1]=0x102
2023-04-18 07:53:55.745 18154-18224/com.demo.myapplication D/NativeCore: dst_arr[2]=0x102

9 LDRH(寄存器)

加載寄存器半字(寄存器)指令根據(jù)基址寄存器值和偏移寄存器值計算地址,從內(nèi)存中加載一個半字,對其進(jìn)行零擴(kuò)展,并將其寫入寄存器。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRH <Wt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<Wm> 當(dāng) option<0> 設(shè)置為 0 時,是通用索引寄存器的 32 位名稱,編碼在“Rm”字段中。

<Xm> 當(dāng) option<0> 設(shè)置為 1 時,是通用索引寄存器的 64 位名稱,編碼在“Rm”字段中。

<extend> 是索引擴(kuò)展/移位說明符,默認(rèn)為 LSL,當(dāng)省略 <amount> 時,LSL 選項必須省略。 在“option”中編碼:

option <extend>
010 UXTW
011 LSL
110 SXTW
111 SXTX

<amount> 索引移位量,僅當(dāng)<extend>不是 LSL 時可選。在允許可選的地方,它默認(rèn)為#0。 它以“S”編碼:

S <amount>
0 #0
1 #1

下面是使用 LDRH(寄存器)指令的例子。

    long long int len = 3;

    long int x = 0;
    auto *y_arr = new long long int[len]{0};

    LOGD("+++++++++++++++++++++++++++++");
    for(int i = 0; i < len; i++){
        y_arr[i] = 0x0102030410205030 * (i + 1);
        LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);
    }

    char* y = (char*)y_arr;

    asm volatile(
    "MOV X3, #16\n"
    "LDRH %w[x], [%x[y] ,X3, LSL#0]\n"
    :[x] "+r"(x),
    [y] "+r"(y)
    :
    : "cc", "memory");

    LOGD("-----------------------------");
    LOGD("x=0x%lx", x);

    delete[] y_arr;

注意看 LDRH(寄存器)指令的對符號位的處理方式,并沒有擴(kuò)展符號位。運行結(jié)果如下:

2023-04-18 08:03:02.690 19907-20036/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 08:03:02.690 19907-20036/com.demo.myapplication D/NativeCore: y_arr[0]=0x102030410205030
2023-04-18 08:03:02.690 19907-20036/com.demo.myapplication D/NativeCore: y_arr[1]=0x20406082040a060
2023-04-18 08:03:02.690 19907-20036/com.demo.myapplication D/NativeCore: y_arr[2]=0x306090c3060f090
2023-04-18 08:03:02.691 19907-20036/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 08:03:02.691 19907-20036/com.demo.myapplication D/NativeCore: x=0xf090

10 LDRSH(立即數(shù))

加載寄存器帶符號半字(立即數(shù))指令從內(nèi)存中加載半字,將其符號擴(kuò)展為 32 位或 64 位,并將結(jié)果寫入寄存器。用于加載的地址是根據(jù)基址寄存器和立即偏移量計算得出的。

Post-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc == 11)

LDRSH <Wt>, [<Xn|SP>], #<simm>

64-bit (opc == 10)

LDRSH <Xt>, [<Xn|SP>], #<simm>

Pre-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc == 11)

LDRSH <Wt>, [<Xn|SP>, #<simm>]!

64-bit (opc == 10)

LDRSH <Xt>, [<Xn|SP>, #<simm>]!

Unsigned offset

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc == 11)

LDRSH <Wt>, [<Xn|SP>{, #<pimm>}]

64-bit (opc == 10)

LDRSH <Xt>, [<Xn|SP>{, #<pimm>}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<simm> 是帶符號的立即字節(jié)偏移量,在 -256 到 255 的范圍內(nèi),在“imm9”字段中編碼。

<pimm> 是可選的正立即字節(jié)偏移量,是 0 到 8190 范圍內(nèi) 2 的倍數(shù),默認(rèn)為 0 并在“imm12”字段中編碼為 <pimm>/2。

LDRSH(立即數(shù))Post-index

下面是使用 LDRSH(立即數(shù))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] = 0x0102030410203050 * (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"
        "LDRSH 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 的最后一個值變?yōu)榱素?fù)數(shù),這就是 LDRSH 補符號位的作用。運行結(jié)果如下:

2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: src_arr[0]=0x102030410203050
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: src_arr[1]=0x2040608204060a0
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: src_arr[2]=0x306090c306090f0
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: =============================
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: dst_arr[0]=0x3050
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: dst_arr[1]=0x60a0
2023-04-18 08:20:35.778 24768-24851/com.demo.myapplication D/NativeCore: dst_arr[2]=0xffffffffffff90f0

LDRSH(立即數(shù))Pre-index

下面是使用 LDRSH(立即數(shù))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] = 0x0102030410203050 * (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"
        "LDRSH 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;

和 LDRSH(立即數(shù))Post-index 指令的區(qū)別就是 index 前置自增了。運行結(jié)果如下:

2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: src_arr[0]=0x102030410203050
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: src_arr[1]=0x2040608204060a0
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: src_arr[2]=0x306090c306090f0
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: =============================
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: dst_arr[0]=0x60a0
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: dst_arr[1]=0xffffffffffff90f0
2023-04-18 08:22:29.119 25484-25614/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0

LDRSH(立即數(shù))Unsigned offset

下面是使用 LDRSH(立即數(shù))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] = 0x8102030410203050 * (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"
        "LDRSH X2, [%x[src], #6]\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;

除了加載固定位置的半字外,由于半字的符號位為 1,所以進(jìn)行了補 1 操作(符號位擴(kuò)展),運行結(jié)果如下:

2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: src_arr[0]=0x8102030410203050
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: src_arr[1]=0x2040608204060a0
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: src_arr[2]=0x8306090c306090f0
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: =============================
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: dst_arr[0]=0xffffffffffff8102
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: dst_arr[1]=0xffffffffffff8102
2023-04-18 08:25:22.617 27152-27230/com.demo.myapplication D/NativeCore: dst_arr[2]=0xffffffffffff8102

11 LDRSH(寄存器)

加載寄存器帶符號半字(寄存器)指令根據(jù)基址寄存器值和偏移寄存器值計算地址,從內(nèi)存加載半字,對其進(jìn)行符號擴(kuò)展,并將其寫入寄存器。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

32-bit (opc == 11)

LDRSH <Wt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]

64-bit (opc == 10)

LDRSH <Xt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]

<Wt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?32 位名稱,在“Rt”字段中編碼。

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<Wm> 當(dāng) option<0> 設(shè)置為 0 時,是通用索引寄存器的 32 位名稱,編碼在“Rm”字段中。

<Xm> 當(dāng) option<0> 設(shè)置為 1 時,是通用索引寄存器的 64 位名稱,編碼在“Rm”字段中。

<extend> 是索引擴(kuò)展/移位說明符,默認(rèn)為 LSL,當(dāng)省略 <amount> 時,LSL 選項必須省略。 在“option”中編碼:

option <extend>
010 UXTW
011 LSL
110 SXTW
111 SXTX

<amount> 索引移位量,僅當(dāng)<extend>不是 LSL 時可選。在允許可選的地方,它默認(rèn)為#0。 它以“S”編碼:

S <amount>
0 #0
1 #1

下面是使用 LDRSH(寄存器)指令的例子。

    long long int len = 3;

    long int x = 0;
    auto *y_arr = new long long int[len]{0};

    LOGD("+++++++++++++++++++++++++++++");
    for(int i = 0; i < len; i++){
        y_arr[i] = 0x0102030410205030 * (i + 1);
        LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);
    }

    char* y = (char*)y_arr;

    asm volatile(
    "MOV X3, #16\n"
    "LDRSH %w[x], [%x[y] ,X3, LSL#0]\n"
    :[x] "+r"(x),
    [y] "+r"(y)
    :
    : "cc", "memory");

    LOGD("-----------------------------");
    LOGD("x=0x%lx", x);

    delete[] y_arr;

注意看 LDRH(寄存器)指令的對符號位的處理方式,此處擴(kuò)展了符號位。運行結(jié)果如下:

2023-04-18 08:07:02.317 21812-21904/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-18 08:07:02.317 21812-21904/com.demo.myapplication D/NativeCore: y_arr[0]=0x102030410205030
2023-04-18 08:07:02.317 21812-21904/com.demo.myapplication D/NativeCore: y_arr[1]=0x20406082040a060
2023-04-18 08:07:02.317 21812-21904/com.demo.myapplication D/NativeCore: y_arr[2]=0x306090c3060f090
2023-04-18 08:07:02.317 21812-21904/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-18 08:07:02.317 21812-21904/com.demo.myapplication D/NativeCore: x=0xfffff090

12 LDRSW(立即數(shù))

加載寄存器有符號字(立即數(shù))指令從內(nèi)存中加載一個字,將其符號擴(kuò)展為 64 位,并將結(jié)果寫入寄存器。用于加載的地址是根據(jù)基址寄存器和立即偏移量計算得出的。

Post-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRSW <Xt>, [<Xn|SP>], #<simm>

Pre-index

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRSW <Xt>, [<Xn|SP>, #<simm>]!

Unsigned offset

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRSW <Xt>, [<Xn|SP>{, #<pimm>}]

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<simm> 是帶符號的立即字節(jié)偏移量,在 -256 到 255 的范圍內(nèi),在“imm9”字段中編碼。

<pimm> 是可選的正立即字節(jié)偏移量,是 0 到 16380 范圍內(nèi)的 4 的倍數(shù),默認(rèn)為 0 并在“imm12”字段中編碼為 <pimm>/4。

LDRSW(立即數(shù))Post-index

下面是使用 LDRSW(立即數(shù))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] = 0x0102030410203050 * (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"
        "LDRSW 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;

運行結(jié)果如下:

2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: src_arr[0]=0x102030410203050
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: src_arr[1]=0x2040608204060a0
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: src_arr[2]=0x306090c306090f0
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: =============================
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: dst_arr[0]=0x10203050
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: dst_arr[1]=0x204060a0
2023-04-19 07:54:08.461 3256-3487/com.demo.myapplication D/NativeCore: dst_arr[2]=0x306090f0

LDRSW(立即數(shù))Pre-index

下面是使用 LDRSW(立即數(shù))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] = 0x0102030450203050 * (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"
        "LDRSW 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;

運行結(jié)果如下:

2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: src_arr[0]=0x102030450203050
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: src_arr[1]=0x2040608a04060a0
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: src_arr[2]=0x306090cf06090f0
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: =============================
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: dst_arr[0]=0xffffffffa04060a0
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: dst_arr[1]=0xfffffffff06090f0
2023-04-19 07:55:54.196 5861-5962/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0

LDRSW(立即數(shù))Unsigned offset

下面是使用 LDRSW(立即數(shù))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] = 0x8102030410203050 * (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"
        "LDRSW X2, [%x[src], #6]\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;

運行結(jié)果如下:

2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: src_arr[0]=0x8102030410203050
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: src_arr[1]=0x2040608204060a0
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: src_arr[2]=0x8306090c306090f0
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: =============================
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: dst_arr[0]=0x0
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: dst_arr[1]=0x0
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: dst_arr[2]=0x0
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: dst_arr[0]=0x60a08102
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: dst_arr[1]=0x60a08102
2023-04-19 07:58:02.543 7440-7531/com.demo.myapplication D/NativeCore: dst_arr[2]=0x60a08102

13 LDRSW(literal)

加載寄存器有符號字(文字)指令根據(jù) PC 值和立即偏移量計算地址,從內(nèi)存加載一個字,并將其寫入寄存器。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRSW <Xt>, <label>

<Xt> 是要加載的通用寄存器的 64 位名稱,在“Rt”字段中編碼。

<label> 是要從中加載數(shù)據(jù)的程序標(biāo)簽。它與該指令地址的偏移量在 +/-1MB 范圍內(nèi),編碼為“imm19”乘以 4。

下面是使用 LDRSW(literal) 指令的例子。

    long long int x = 0;

    asm volatile(
        "LDRSW X2, abc\n"
        "MOV %x[x], X2\n"
        "abc:\n"
        "MOV X2, #0\n"
        "MOV X2, #1\n"
        "MOV X2, #2\n"
    :[x] "+r"(x)
    :
    : "cc", "memory");

執(zhí)行 LDRSW X2, abc 將 abc 標(biāo)簽根據(jù) PC 值和立即偏移量計算地址,將這個地址的內(nèi)容加載到寄存器。此時 x 的值打印出來它固定為 0xffffffffd2800002,高半部分的字全部被填充為了 1(這是因為 0xd2800002 符號位擴(kuò)展了),0xd2800002 實際就是 MOV X2, #0 這條指令,所以這個地址的內(nèi)容僅包含一條指令,而 LDR(literal) 包含了兩條指令。使用 IDA 反匯編工具可看到 MOV X2, #1MOV X2, #2 的確沒有編碼到這個地址指向的內(nèi)容中。

14 LDRSW(寄存器)

加載寄存器有符號字(寄存器)指令根據(jù)基址寄存器值和偏移寄存器值計算地址,從內(nèi)存中加載一個字,對其進(jìn)行符號擴(kuò)展以形成 64 位值,并將其寫入寄存器。偏移寄存器值可以左移 0 或 2 位。

【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令

LDRSW <Xt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}]

<Xt> 是要傳輸?shù)耐ㄓ眉拇嫫鞯?64 位名稱,在“Rt”字段中編碼。

<Xn|SP> 是通用基址寄存器或堆棧指針的 64 位名稱,在“Rn”字段中編碼。

<Wm> 當(dāng) option<0> 設(shè)置為 0 時,是通用索引寄存器的 32 位名稱,編碼在“Rm”字段中。

<Xm> 當(dāng) option<0> 設(shè)置為 1 時,是通用索引寄存器的 64 位名稱,編碼在“Rm”字段中。

<extend> 是索引擴(kuò)展/移位說明符,默認(rèn)為 LSL,當(dāng)省略 <amount> 時,LSL 選項必須省略。在“option”中編碼:

option <extend>
010 UXTW
011 LSL
110 SXTW
111 SXTX

<amount> 索引移位量,僅當(dāng) <extend> 不是 LSL 時可選。在允許可選的地方,它默認(rèn)為#0。 它以“S”編碼:

S <amount>
0 #0
1 #2

下面是使用 LDRSW(寄存器)指令的例子。

    long long int len = 3;

    long long int x = 0;
    auto *y_arr = new long long int[len]{0};

    LOGD("+++++++++++++++++++++++++++++");
    for(int i = 0; i < len; i++){
        y_arr[i] = 0x0102030450205030 * (i + 1);
        LOGD("y_arr[%d]=0x%llx", i, y_arr[i]);
    }

    char* y = (char*)y_arr;

    asm volatile(
    "MOV X3, #4\n"
    "LDRSW %x[x], [%x[y] ,X3, LSL#2]\n"
    :[x] "+r"(x),
    [y] "+r"(y)
    :
    : "cc", "memory");

    LOGD("-----------------------------");
    LOGD("x=0x%llx", x);

    delete[] y_arr;

LDRSW %x[x], [%x[y] ,X3, LSL#2] 首先將索引寄存器的值邏輯左移 2 位,也就是將 X3 寄存器的值乘以 4,即索引最終的值為 4 * 4 = 16,接著使用索引的值去加載數(shù)組中的一個字,也就是 0xF060F090,擴(kuò)展符號位后就變?yōu)榱?0xFFFFFFFFF060F090,這也是最終 x 的值。運行結(jié)果如下:

2023-04-19 08:34:42.228 27863-27920/com.demo.myapplication D/NativeCore: +++++++++++++++++++++++++++++
2023-04-19 08:34:42.228 27863-27920/com.demo.myapplication D/NativeCore: y_arr[0]=0x102030450205030
2023-04-19 08:34:42.228 27863-27920/com.demo.myapplication D/NativeCore: y_arr[1]=0x2040608a040a060
2023-04-19 08:34:42.228 27863-27920/com.demo.myapplication D/NativeCore: y_arr[2]=0x306090cf060f090
2023-04-19 08:34:42.228 27863-27920/com.demo.myapplication D/NativeCore: -----------------------------
2023-04-19 08:34:42.228 27863-27920/com.demo.myapplication D/NativeCore: x=0xfffffffff060f090

參考資料

1.《ARMv8-A-Programmer-Guide》
2.《Arm? A64 Instruction Set Architecture Armv8, for Armv8-A architecture profile》文章來源地址http://www.zghlxwxcb.cn/news/detail-432385.html

到了這里,關(guān)于【ARMv8 編程】A64 內(nèi)存訪問指令——內(nèi)存加載指令的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【ARMv8 SIMD和浮點指令編程】浮點加減乘除指令——四則運算

    【ARMv8 SIMD和浮點指令編程】浮點加減乘除指令——四則運算

    浮點指令有專門的加減乘除四則運算指令,比如 FADD、FSUB、FMUL、FDIV 等。 1 FADD (scalar) 浮點加法(標(biāo)量)。該指令將兩個源 SIMDFP 寄存器的浮點值相加,并將結(jié)果寫入目標(biāo) SIMDFP 寄存器。 該指令可以產(chǎn)生浮點異常。根據(jù) FPCR 中的設(shè)置,異常會導(dǎo)致在 FPSR 中設(shè)置標(biāo)志,或者生成同

    2024年02月05日
    瀏覽(27)
  • 【ARMv8 SIMD和浮點指令編程】浮點數(shù)據(jù)轉(zhuǎn)換指令——數(shù)據(jù)類型互轉(zhuǎn)必備

    浮點數(shù)據(jù)轉(zhuǎn)換指令包括不同的浮點精度數(shù)之間的轉(zhuǎn)換,還包括整型和浮點數(shù)之間的轉(zhuǎn)化。 在了解數(shù)據(jù)轉(zhuǎn)換指令前,必須學(xué)習(xí) IEEE 754 定義的五種舍入規(guī)則。前兩條規(guī)則舍入到最接近的值,其他的稱為定向舍入: 舍入到最接近的值 Round to nearest, ties to even – rounds to the nearest va

    2024年02月02日
    瀏覽(26)
  • 【ARMv8 SIMD和浮點指令編程】NEON 通用數(shù)據(jù)處理指令——復(fù)制、反轉(zhuǎn)、提取、轉(zhuǎn)置...

    【ARMv8 SIMD和浮點指令編程】NEON 通用數(shù)據(jù)處理指令——復(fù)制、反轉(zhuǎn)、提取、轉(zhuǎn)置...

    NEON 通用數(shù)據(jù)處理指令包括以下指令(不限于): ? DUP 將標(biāo)量復(fù)制到向量的所有向量線。 ? EXT 提取。 ? REV16、REV32、REV64 反轉(zhuǎn)向量中的元素。 ? TBL、TBX 向量表查找。 ? TRN 向量轉(zhuǎn)置。 ? UZP、ZIP 向量交叉存取和反向交叉存取。 1 DUP (element) 將向量元素復(fù)制為向量或標(biāo)量。

    2024年02月07日
    瀏覽(23)
  • ARMv8 匯編指令

    ARMv8 匯編指令

    MOV Xd|SP, Xn|SP MOV Xd|SP, #imm16 常用于寄存器之間的搬移和立即數(shù)搬移, ? 僅僅支持imm16, 0-4096大小范圍的立即數(shù)操作 MRS: 狀態(tài)寄存器 -- 通用寄存器的傳送指令。 MSR: 通用寄存器 -- 狀態(tài)寄存器的傳送指令。 注意:在ARMv7里通過CP15協(xié)處理器方位系統(tǒng)寄存器 還可以訪問PSTATE寄存器一

    2024年04月27日
    瀏覽(42)
  • ARMv8-A 與異常相關(guān)的指令

    ARMv8-A 與異常相關(guān)的指令

    最近一直在學(xué)習(xí) ARMv8-A 的東西,記錄一下與異常相關(guān)的指令。下面的內(nèi)容基于AArch64討論,暫不考慮 AArch32。 與異常生成相關(guān)的指令如下所示。下面主要學(xué)習(xí) SVC 和 HVC 。 1. SVC SVC (Supervisor Call) 產(chǎn)生一個路由到 EL1 的異常,可以調(diào)用系統(tǒng)服務(wù)這些。此時, ESR_ELx.EC = 0x15 。 2. HVC

    2024年02月21日
    瀏覽(24)
  • 樹莓派4b(armv8) 64位系統(tǒng)編譯安裝onnx

    樹莓派4b(armv8) 64位系統(tǒng)編譯安裝onnx

    網(wǎng)上大部分樹莓派安裝onnx的都是基于樹莓派3b的,或者說基于armv7架構(gòu)的。 本文記錄一下如何在最新的樹莓派4b系統(tǒng)(armv8、python3.9)上編譯安裝onnx的過程。 獲取當(dāng)前系統(tǒng)的內(nèi)核版本號及系統(tǒng)名稱 獲取當(dāng)前系統(tǒng)的內(nèi)核版本及系統(tǒng)名稱 可以看到我的cpu版本是armv8 如果是armv7架構(gòu)

    2024年02月05日
    瀏覽(228)
  • 交叉編譯----宿主機(jī)x86 ubuntu 64位-目標(biāo)機(jī)ARMv8 aarch64

    交叉編譯----宿主機(jī)x86 ubuntu 64位-目標(biāo)機(jī)ARMv8 aarch64

    1.交叉編譯是什么,為什么要交叉編譯 編譯:在一個平臺上生成在該平臺上的可執(zhí)行代碼 交叉編譯:在一個平臺上生成在另一個平臺上的可執(zhí)行代碼 交叉編譯的例子:如51單片機(jī)的可執(zhí)行代碼(hex文件)是在集成環(huán)境keil上面編譯完成的,我們只需要將編譯好的可執(zhí)行代碼下

    2024年02月15日
    瀏覽(49)
  • Yocto系列講解[技巧篇]92 - armv8 aarch64兼容armv7 32位程序運行環(huán)境

    Yocto系列講解[技巧篇]92 - armv8 aarch64兼容armv7 32位程序運行環(huán)境

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜歡的盆友歡迎點贊和訂閱! 你的喜歡就是我寫作的動力!

    2024年01月24日
    瀏覽(32)
  • 【ARM Cortex-M 系列 3 番外篇 -- ARMv6, ARMv7, ARMv8, ARMv9 架構(gòu)差異及精簡指令集 與 復(fù)雜指令集 介紹】

    上篇文章:ARM Cortex-M 系列 2.1 – RT-Thread Cortex-M7 異常處理及 hardfault 處理分析 ARM架構(gòu)是一種處理器架構(gòu),全稱為高級精簡指令集計算機(jī)(Advanced RISC Machine)。它是英國ARM公司設(shè)計的一種精簡指令集( RISC )處理器架構(gòu),和復(fù)雜指令集( CISC )處理器架構(gòu)相對。 CISC 與 RISC 差異

    2024年02月08日
    瀏覽(21)
  • ARMv8的異常等級(Exception Level)以及執(zhí)行狀態(tài)(AArch64/AArch32)

    ARMv8的異常等級(Exception Level)以及執(zhí)行狀態(tài)(AArch64/AArch32)

    目錄 1,異常等級(Exception Level) 2,Execution states,執(zhí)行狀態(tài) AArch64的異常等級 AArch32的異常等級: 3,異常等級切換 ?4,執(zhí)行狀態(tài)切換(AArch64 = AArch32) 5,狀態(tài)切換后的寄存器狀態(tài) Registers at AArch32 PSTATE at AArch32 6,指令集的切換:Switching between the instruction sets 在ARMv8中,存在

    2024年02月13日
    瀏覽(31)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包