zoukankan      html  css  js  c++  java
  • 从机器码理解RIP 相对寻址

    本作品采用知识共享署名 4.0 国际许可协议进行许可。转载联系作者并保留声明头部与原文链接https://luzeshu.com/blog/rip-relative-addressing
    本博客同步在 http://www.cnblogs.com/papertree/p/6298763.html


    1. 情景

    在调试linux-3.0.0内核源码过程中,碰到一处lea指令,略有疑问。

    代码如下(路径linux/arch/x86/boot/compressed/head_64.S):

    249 /*
    250  * Copy the compressed kernel to the end of our buffer
    251  * where decompression in place becomes safe.
    252  */
    253     pushq   %rsi
    254     leaq    (_bss-8)(%rip), %rsi
    255     leaq    (_bss-8)(%rbx), %rdi
    256     movq    $_bss /* - $startup_32 */, %rcx
    257     shrq    $3, %rcx
    258     std
    259     rep movsq
    260     cld
    261     popq    %rsi
    

    下图1-1是调试过程中的CPU上下文:

    图1-1

    从“mov rcx,0x243e80”中可以看到,_bss的值为0x243e80的,这是_bss这个symbol在进行汇编时,其所在的section内的偏移位置。
    从“lea rdi,[rbx+0x243e78]”中可以看到,加到%rbx的值是_bss-8,这跟汇编源代码是一致的。
    而从“lea rsi,[rip+0x243c30]” 中可以看到,加到%rip的偏移值并不是_bss-8 的值。

    先说明一点,这个section是加载在0x1000000的内存位置,所以0x1000241这条指令,相对于所在section的起始偏移是0x241。

    那么,上面的0x243c30这个值,是由(_bss-8)再减去0x248(下一条指令相对于section的起始偏移值)而得来。

    那么,前后两条看起来十分相似的汇编代码为什么有这样的区别呢?



    2. RIP的特殊性以及PIC(位置无关代码)

    因为RIP寄存器存放着当前指令的地址,所以有它的特殊性。
    比如上面的%rip + displacement,其中displacement存放的如果是_bss这个symbol与该指令的“距离值”,那么不管这段代码所在的section装载到哪个位置,都可以通过这个计算,访问到_bss实际装载的位置。

    比如section装载在0x1000000,那么指令的%rip为0x1000241,_bss的值为0x1243c30。
    而如果装载在0x5000000,那么指令的%rip为0x5000241,_bss的值为0x5243c30。
    那么如果displacement存放的是_bss与指令之间的距离值,那么不管实际加载到哪个位置,都可以访问到实际的_bss位置。

    这里解释了上面的问题 —— 这两条相似汇编代码的区别,正好利用rip的特殊性,实现了PIC的功能。
    但是,还是有疑问。这里的解释仅仅是解释了displacement为什么有“距离值”和“实际值”两种情况,这里的区别似乎只是停留在汇编层面,因为gas汇编器就可以这样实现,当发现base register是%rip,那么displacement就使用_bss与当前指令的下一条指令的“距离值”,而当base register是其他寄存器时,displacement就等于_bss自身的值。
    而汇编成机器码之后,displacement的值已经由汇编器计算好了,CPU在执行的时候,%rip + displacement 和 %rbx + displacement不是一样的模式吗?

    在搜索资料的时候,发现RIP相对寻址这个概念,这并不是一个汇编器的概念,而是CPU的,所以,既然把%rip + displacement这种寻址模式单独拿出来,那么还是会有差别的。
    此外,在维基上看到的,RIP相对寻址是在x86-64加进去的:

    http://wiki.osdev.org/X86-64_Instruction_Encoding#16-bit_addressing

    RIP/EIP-relative addressing
    Addressing in x86-64 can be relative to the current instruction pointer value. This is indicated with the RIP (64-bit) and EIP (32-bit) instruction pointer registers, which are not otherwise exposed to the program and may not exist physically. RIP-relative addressing allows object files to be location independent.



    3. RIP相对寻址

    那么为了进一步从CPU层面解释%rip + displacement和%rbx + displacement这两种寻址模式的区别,需要来看一下CPU如何解释机器代码。
    下面是从《Intel 64 and IA-32 Architectures Software Developer's Manual》截取的几张图:

    图3-1

    这张图展示了一条机器码指令的结构,下面结合实际指令解释一下。
    首先,在上面图1-1的例子中,查看一下两条lea指令所在的内存数据:

    gdb$ x /14xb 0x1000241
    0x1000241:      0x48    0x8d    0x35    0x30    0x3c    0x24    0x00    0x48
    0x1000249:      0x8d    0xbb    0x78    0x3e    0x24    0x00
    

    这里两条指令分别7个字节。
    其中0x48是Prefixs,0x8d是lea指令的opcode,0x35和0xbb分别是两条指令的ModR/M,这里面没有SIB(下面解释),剩下的0x243c80和0x243e78就是两条指令的Displacement了。

    Instruction Prefixs可以有很多种,上面的wiki链接也解释得很全了。这里的0x48是一种64位长模式特有的REX Prefix。对于REX Prefix的解释见下图3-2和3-3,其中高4位0100是固定的,低四位分别作为指令其他部分的扩展位。下面再进行解释。
    那么上面的0x48,即为0100 1000,即W位为1,R X B 三个位都为0。

    ModR/M 可以划分成3个field,高2位mod,中间3位reg,低3位r/m。例子中的0x35即为(00 110 101),还有0xbb即为(10 111 011),图3-4给出了一份助记表,可以找到0x35的坐标位(disp32,ESI),还有0xbb的坐标为([EBX]+disp32, EDI)。
    看回例子中的“lea rsi,[rip+disp]” 和“lea rdi, [rbx]+disp”,rip作为base register和其他通用寄存器的区别在这里。但是,我也不知道该说这特不特殊了,全部是0和1之间的差别。

    SIB在这两条指令中没有,答案可以从图3-4的NOTES.1中看到,当ModR/M中的mod域和R/M域为某些特定组合时,才存在SIB字节。

    再看会刚刚的REX Prefix的R X B三个位,如何做其他部分的扩展在上面的wiki链接中挺全面。这里截了其中一个图作为解释性说明,见图3-5,当其中的B位为0时,ModR/M的r/m域是符合图3-4的,但是当B位为1时,r/m域选择的寄存器变成了从R8、R9...这些扩展寄存器中选择了。

    图3-2

    图3-3

    图3-4

    图3-5
  • 相关阅读:
    算法--将Excel列索引转换成默认标识
    Java参考资料-中文API
    java编程规范
    POI-根据Cell获取对应的String类型值
    将Excel中读取的科学计数法表示的Double数据转换为对应的字符串
    Android进程间通信之LocalSocket通信
    Android进程间通信之socket通信
    android用讯飞实现TTS语音合成 实现中文版
    Android Junit测试框架
    java interface的两个经典用法
  • 原文地址:https://www.cnblogs.com/papertree/p/6298763.html
Copyright © 2011-2022 走看看