關於ARM中的adrp與adr指令


adrp指令

ADRP <Xd>, <label>adrp指令將label的值傳遞給xd寄存器。label的值為pc所在頁基值 + (立即數 * 4096) ,立即數就相當於是頁索引。

此指令一般用於將變量的頁基地址存入寄存器中,下面的代碼是ndk實現的一個JNI接口函數,定義一個全局變量num,JNI接口函數會訪問此全局變量。

jint num = 1;
extern "C" JNIEXPORT jstring JNICALL
stringFromJNI(JNIEnv* env, jobject /* this */) {
    num = 2;
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

將編譯生成的so文件拖進IDA里查看,#0x34000就是對應變量所在頁面基地址,而#0xFD8就是變量對應的頁內偏移。

變量頁面基地址為0x34000, 頁內偏移為0xFD8,所以對應的變量地址為 0x34FD8.
IDA中查看Section發現其在got表中,而got表此0x34FD8存放的是真實num全局變量的地址,會在鏈接器加載程序時重定位修復。

adr和adrl指令

adr是小范圍的地址讀取指令,adrl是中等范圍的地址讀取指令(偽指令)。ADR<c> <Rd>, <label>都是將<label>標簽的值存放到目標寄存器rd中,<label>的值為立即數 * 4 + pc。

對於thumb指令模式而言,adr指令長度為2,低8位為立即數等於0x44,pc值等於0xd64,所以計算結果為0x44 * 4 + 0xd64 = 0xE74,對應的反匯編結果為adr r1, #0xE74

需要注意的是在使用內聯匯編時adr指令給出的是最后一個操作數不是<label>的值,也不是立即數的值,其實際是立即數 * 4的值(相當於是相對於pc的偏移)。例如下面的內聯匯編中 adr r0,0x100 指令中的0x100實際是立即數*4的值。

__asm__ volatile(
    "nop \n\t"
    "nop \n\t"
    "nop \n\t"
    "adr r0,0x100 \n\t"
);

查看反匯編即可看到立即數等於0x40,0x40 * 4等於0x100,adr r0,0x100指令處對應的PC值為0x12A68,0x100 + 0x12A68 = 0x12B68 = <label>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM