• 沉淀的梦想
    2019-10-12
    没太看懂文稿中的"leaq L_.str(%rip), %rdi"里面的"L_.str(%rip)"的含义,能再解释一下吗?

    作者回复: 就是一个间接内存访问。基数是%rip,也就是指令寄存器中的值,也就是leaq这行代码的下一行代码的地址。L_.str会被汇编器算出一个直接数来,比如0x20,也就是32个字节。这行指令就等价于:0x20(%rip)。
    0x20是什么意思?就是这个字符串常量的地址与%rip值的差。这种寻址方式叫做rip相对寻址。因为代码区在下面,静态数据区在上面,所以静态数据的地址一定大于指令的地址。在这里,是多0x20个字节,也就是32个字节。
    为什么要这么麻烦呢?为什么不使用这个字符串的确定地址呢?这主要是为了让程序代码更加位置无关。在使用动态库之类的场景的时候有好处。

    另外,lea这个指令除了获取地址以外,还有一个“奇怪”的用法,它可以用计算地址的方法,实际上对寄存器的值同时完成加法和乘法的计算,相当于一个三元计算,并且只使用一个时钟周期。比如:lea 0x20(,%eax,2) %eax,本来是用来算一个地址,结果被用来一次性的做了一个乘法和一个加法计算。

    提供3篇文章作为参考:
    https://stackoverflow.com/questions/40329260/why-is-the-address-of-static-variables-relative-to-the-instruction-pointer

    https://stackoverflow.com/questions/3250277/how-to-use-rip-relative-addressing-in-a-64-bit-assembly-program

    https://zhuanlan.zhihu.com/p/58774036

    
     2
  • 权华
    2019-11-12
    刚刚的问题,xorl %eax, %eax,将返回值置为0。

    作者回复: 对的。

    
    
  • 权华
    2019-11-12
    leaq L_.str(%rip), %rdi
    leaq L_.str.1(%rip), %rsi
    xorl %eax, %eax
    callq _printf
    xorl %eax, %eax

    宫老师你好,这是文章前面的汇编代码的一部分,我不明白 xorl %eax, %eax 这两行代码,它的作用是什么?为什么没有给寄存器 eax 就直接 xorl 操作了。
    展开

    作者回复: 修昂党羽给eax赋值为0,但用xorl使用的时钟周期更少。

    
    
  • 不的
    2019-10-23
    老师,为啥要设计成区分调用者、被调用者保护的寄存器,统一被调用者或者调用者保护,有啥问题么

    作者回复: 这里有一个效率的问题。

    如果全部都是调用者保护,那么其实你调用的对象根本不会破坏你的寄存器,你也要保护起来,那就增加了成本,对于逻辑比较简单的被调用者,是用不到几个寄存器的。

    如果全部都是被调用者保护,也是一样的逻辑。如果调用者用了很少几个寄存器,被调用者却要保护很多,也不划算。

    所以最优的方法,其实是比较中庸主义的。我觉得这可以用概率的方法做比较严谨的证明。

    
    
  • 沉淀的梦想
    2019-10-14
    看了老师的回答与讲解"RIP相对寻址"的文章,但是还是不太理解:%rip存储的是下一条要执行的代码的地址,他存储值应该在不停地变,所以他和静态数据的偏移应该也在不停地变,为什么这里的偏移(L_.str)看起来是个常量啊?

    作者回复: 对的。
    如果你在不同的代码里调用使用L_.str(%rip),前面的L_.str对应的立即数是不同的。这个计算工作是由汇编器来算,不影响我们编程的效率。

    
    
  • 峰
    2019-10-12
    感受是写了一大坨,天都黑了,还没写完。。。

    作者回复: 就是搬砖的工作太多,创造性的工作太少:-)

    
    
我们在线,来聊聊吧