【问题标题】:Inline assembly with "jmp 0f" or "b 0f" at the beginning以“jmp 0f”或“b 0f”开头的内联汇编
【发布时间】:2013-03-25 21:06:46
【问题描述】:

更新

将汇编的第二行更改为实际使用的助记符 (mflr),并在底部添加了更多信息。


我遇到了一些代码(使用 gcc),类似于以下(意译):

#define SOME_MACRO( someVar ) \
do {                          \
  __asm__ (                   \
    "    b 0f\n"              \
    "0:  mflr %0\n"           \
    : "=r"( someVar )         \
  );                          \
} while(0)

...b 指令 (ppc) 是一个简短的 jmp,mflr 正在获取“链接寄存器”的内容——这在某些方面类似于程序计数器。对于英特尔代码,我也看到过这种情况(参见this 问题中接受的答案)。

分支充当无操作...我的问题:这有什么目的?

我猜它与分支预测有关,但到目前为止,我只发现人们在搜索时使用这个成语的代码。


看来我在分支预测猜测上错了。 mflr 抓取链接寄存器的内容。

所以,我的问题归结为:为什么需要分支。

【问题讨论】:

  • 会不会刷新指令预取队列?
  • 有些目的是在somethingelse。这样的代码可用于instrumentation(调试/运行时跟踪)。例如,在 x86 中,asm("call 0f\n0: pop %0\n" : "=r"(pc)) 是一种检索程序计数器 IP 的方法(请注意,这在 64 位模式下是不安全的)。在 ARM(和 64 位 x86)上,该方法还经常用于在代码中嵌入常量,用于与 PC 相关的负载。是否对分支预测/流水线产生影响取决于 CPU,因此通常不能说“这就是它的用途”。
  • @FrankH。我花了更多时间查看代码;这是我没有只见树木不见森林的一个很好的例子。你的分析很到位; somethingelse 正在获取程序计数器并将其存储在 %0 中。
  • 如果您不介意将您的回复作为答案发布,我会接受。

标签: assembly pipeline branch-prediction


【解决方案1】:

像这样有趣的代码往往发生在somethingelse。此类代码的一些已知用途是:

  • 运行时状态检索;例如在 x86 中,
    __asm__("call 0f\n0: pop %0\n" : "=r"(pc))
    是一种检索程序计数器的方法(IP 寄存器 - 这是隐藏的,不能直接访问,因此 call 将其推送到堆栈这一事实用于检索它)。
    请注意,由于 红色区域,在 64 位模式下的叶子函数中使用它是不安全的 - 请参阅 Inline assembly that clobbers the red zone。在 x86_64 上执行此操作的正确方法是
    asm("lea 0f(%%rip), %0\n0:\n" : "=r"(pc))
    它利用了在 64 位模式下可以进行 PC 相对寻址这一事实。
  • instrumentation(调试/运行时跟踪),例如通过在其中放置跟踪代码/NOP 插槽,运行时的跟踪实用程序可以修改以动态挂钩代码。 Solaris DTrace 使用此类技术。
  • 在 ARM(和 64 位 x86)上,该方法还用于在代码中嵌入常量,用于与 PC 相关的负载。

像这样的无条件分支是否会导致分支预测未命中惩罚或其他类型的停顿非常依赖于 CPU。

【讨论】:

  • 你想推测一下为什么需要这个分支吗?
  • 我挖掘了 ppc 指令集...b 不会改变链接寄存器,但bl 会。所以,我现在有三种可能的解释:1) 分支产生了一些不明显的副作用,2) 他们希望 PC 在b 0f 之前执行代码——这就引出了一个问题,为什么b 0f完全...和 ​​3) 这段代码的编写者希望 b 0f 更新 LR,因此代码没有按照他们的预期进行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多