关于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>

posted @ 2022-04-21 11:51  怎么可以吃突突  阅读(5160)  评论(0编辑  收藏  举报