zoukankan      html  css  js  c++  java
  • CSAPP读书随笔之一:为什么汇编器会将call指令中的引用的初始值设置为-4

      CSAPP,即《深入理解计算机系统:程序员视角》第三版,是一本好书,但读起来确需要具备相当的基本功。而且,有的表述(中译文)还不太直白。

      比如,第463页提到,(对于32位系统)为什么汇编器会将call指令中的引用的初始值设置为-4。其后解释语焉不详。结合文中对代码计算公式的展开:

                *refptr = (unsigned) (ADDR(r.symbol) + *refptr - refaddr)

                           = (unsigned) (0x80483c8        + (-4)     - 0x80483bb)

                           = (unsigned) (0x9)

    依然一头雾水。

      其实,这里只要反过来推算,就很好理解了。下图是重定向完成后的内存映象:

    0x80483b4    .text

    ...

    0x80483ba    call 80483c8<swap>    ; e8 09 00 00 00

                                                                 ▲

                                              0x80483bb --↗

    0x80483bf    (下一条指令)

    ...

    0x80483c8    swap()

    ...

      有题如下:

      已知:.text节重定位于0x80483b4,相应地call调用则位于0x80483ba,而swap()函数重定位于0x80483c8。

      求:重定位后,call指令的操作码(即书中所谓“重定位引用”)应当是几?(亦即swap函数相对于call指令执行时PC的偏移是多少?)

      首先说答案,swap函数相对于call指令执行时PC的偏移是0x9,即call指令的完整机器码是 e8 09 00 00 00。

      为什么呢?因为当执行call指令时,PC值已是下一条指令的地址即0x80483bf。为了完成call调用,要把PC值加上call的操作数,结果作为新的PC值。也就是 0x80483bf + 0x9 = 0x80483c8,正好是swap()函数的地址。

      接下来说说,call指令中的引用的初始值-4是做什么用的。我把前面的公式变形:

                *refptr = (unsigned) (ADDR(r.symbol) + *refptr - refaddr)

                          = (unsigned) (ADDR(r.symbol) + (*refptr - refaddr))

                          = (unsigned) (0x80483c8        + (-4      - 0x80483bb))

                          = (unsigned) (0x80483c8        -0x80483bf)

                          = (unsigned) (0x9)

      可以看到,-4就是为了从call指令中操作数本身的地址转换为下一指令的地址而设置的。对于32位机器来说,call指令长5字节,操作码1个字节,而操作数正好占4字节。call指令位于0x80483ba,操作数位于0x80483bb,再过4字节就正好是下一条指令的地址。

      那为什么用-4而不是+4呢?其实很简单,这和链接程序采用的计算公式有关。

      

  • 相关阅读:
    poi管道流的导入导出
    Mysql导入数据库的方法
    MySQL数据库指定字符集
    eclipse 的操作
    Mysql的操作
    第十周作业
    第九周作业
    第八周作业
    第七周作业
    第六周作业
  • 原文地址:https://www.cnblogs.com/xxfcz/p/6115435.html
Copyright © 2011-2022 走看看