【问题标题】:Assembly code for __rdtsc() in -O0 vs -O3 [duplicate]-O0 与 -O3 中 __rdtsc() 的汇编代码 [重复]
【发布时间】:2022-01-19 05:11:40
【问题描述】:

我有以下代码:

#include <x86intrin.h>

int main() {
    return __rdtsc();
}

我尝试在我的机器(Intel i7-6700 CPU)和objdump上编译

g++ -Wall test_tsc.cpp -o test_tsc -march=native -mtune=native -O0 -std=c++20
objdump -M intel -d test_tsc > test_tsc.O0

然后在test_tsc.O0:

0000000000401122 <main>:
  401122:   55                      push   rbp
  401123:   48 89 e5                mov    rbp,rsp
  401126:   0f 31                   rdtsc  
  401128:   48 c1 e2 20             shl    rdx,0x20
  40112c:   48 09 d0                or     rax,rdx
  40112f:   90                      nop
  401130:   5d                      pop    rbp
  401131:   c3                      ret    
  401132:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
  401139:   00 00 00 
  40113c:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]

push rbpmov rbp,rsp 做什么?似乎它们是为了保存堆栈指针,但实际上并没有函数调用。如果g++认为__rdtsc()是一个函数调用,那么后面还会有call这样的东西吗?

谢谢。

【问题讨论】:

  • 由于各种原因,函数prologue/epilogue经常被无条件发出。
  • 用 -O2 编译它,你会得到 rdst 后跟 ret (这是你所期望的)。如果您编译非优化调试版本(就像您在此处所做的那样),编译器将通过将寄存器值复制到已知内存位置(然后调试器能够轻松访问)来“优化”代码。结果是一堆毫无意义的mov。只需使用 -O2 或 -O3。
  • 因为你使用了-O0,当然-fno-omit-frame-pointer是默认的。 RBP 帧指针设置/拆卸即使在空函数中也会发生(与叶函数可能仍忽略帧指针的 clang 不同)。 godbolt.org/z/cEPGssYac。这不是“用于保存堆栈指针”,您无法有效地保存/恢复堆栈上的堆栈指针。

标签: c++ c assembly x86-64


【解决方案1】:

rbp 是基指针,而不是堆栈指针。基指针在调试过程中用于回溯,但实际运行时不需要。

它是通过函数调用保存的,因此使用-O3 只会生成预期的程序集:

main:
        rdtsc
        salq    $32, %rdx
        orq     %rdx, %rax
        ret

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 2021-07-31
    • 1970-01-01
    • 2015-03-02
    相关资源
    最近更新 更多