【问题标题】:How do I find the assembly code for my function in a (release) Rust build?如何在(发布)Rust 构建中找到我的函数的汇编代码?
【发布时间】:2020-05-25 18:45:19
【问题描述】:

Compiler Explorer 似乎能够可靠地找到与函数对应的汇编代码。假设x86_64-unknown-linux-gnu 工具链、常规(无属性)函数并且没有像cargo-asm 这样的额外工具,我自己该怎么做?

我知道要生成程序集,我可以使用rustc's --emit asm flag。有人可能认为找到函数就像在 .s 文件中搜索其名称一样简单,但我发现并非如此。

例如,.s 文件通常甚至没有提及函数名称,在这种情况下,将#[inline(never)] 添加到函数中会有所帮助。其次,找到带有函数名称的标签后,如何确定函数的结束位置?在我的测试箱中,我发现在更下方的.size 指令中再次提到了函数名称——这可能标志着函数的结束吗?或者它可能是函数启动后的第一个retq

假设这个目标是可以实现的,我希望学习:

  • 找到函数的开始和结束的最可靠方法是什么?
  • 获取合适的程序集文件以执行此操作的先决条件是什么?

【问题讨论】:

  • 从技术上讲,.size 可以在任何地方,但它的形式通常是. - foo,其中. 是当前地址,因此它标志着函数的结束。一个函数可能有多个返回指令,因此这不是识别它的可靠方法。
  • source code is available,大概包含了答案。
  • 在 C/C++ 中,编译器必须为不是 static 的函数生成独立定义。即可以从另一个翻译单元调用。我真的不了解 Rust。如果这不是默认设置,那么您可能需要以某种方式将其标记为“全局”或“导出”。这仍然可以让它内联到一些调用者中并进行独立定义,但在其他方面实现与inline(never) 相同的目标

标签: assembly rust x86-64 compiler-explorer


【解决方案1】:

由于没有答案,我做了一些研究,这应该可以解决问题:

  1. 确保在二进制 crate 的情况下由 main() 使用该函数,或者在库 crate 的情况下由 pub 函数使用(或者是 pub 本身)。
  2. 为避免编译器内联您的基准,请将其标记为#[inline(never)]
  3. 搜索函数名,应该会找到开头,如下所示:
    .type   <mangled_name>,@function
<mangled_name>:
    .cfi_startproc
  1. 搜索函数的结尾,标记为:
.Lfunc_end<number>:
    .size   <mangled_name>, .Lfunc_end<number>-<mangled_name>
    .cfi_endproc

这有时可以在 retq 前面,但不可靠。

那些以点开头并且以冒号结尾的行,例如.type,是指令。 GNU 汇编器理解的指令记录在 here 中,--emit asm 的输出应该是 GNU 汇编器的有效输入。

编译器资源管理器和cargo-asm

似乎编译器资源管理器实际上保留了整个文件并且不搜索函数,它只是过滤掉某些行。至少source code 似乎是这样做的。

cargo-asm 似乎专门寻找.cfi_endproc on Linux and Mac, and .seh_endproc on Windows

【讨论】:

  • 对,Compiler Explorer 只是过滤行。当你编译一个只有几个函数的 C++ 源文件时,它工作得很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 1970-01-01
  • 2018-02-06
  • 2019-06-06
  • 2013-02-25
  • 2019-10-01
相关资源
最近更新 更多