如何获取函数的返回地址?

Eli*_*tto 26 llvm rust

我正在编写一个Rust库,其中包含LLVM SanitizerCoverage的回调的实现。这些回调可用于跟踪已检测程序的执行。

产生跟踪的一种常见方法是打印每个执行的基本块的地址。但是,为此,必须检索call调用回调的指令的地址。LLVM提供的C ++示例依赖于编译器内在函数__builtin_return_address(0)来获取此信息。

extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
  if (!*guard) return;
  void *PC = __builtin_return_address(0);
  printf("guard: %p %x PC %p\n", guard, *guard, PC);
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试在Rust中重现相同的功能,但是显然没有等效于__builtin_return_address。我发现的唯一参考来自旧版本的Rust,但是所描述的功能不再可用。该函数如下:

pub unsafe extern "rust-intrinsic" fn return_address() -> *const u8

我当前的骇客解决方案涉及在我的箱子中包含一个C文件,其中包含以下功能:

void* get_return_address() {
  return __builtin_return_address(1);
}
Run Code Online (Sandbox Code Playgroud)

如果我从Rust函数调用它,我就能获得Rust函数本身的返回地址。但是,此解决方案需要编译我的Rust代码-C force-frame-pointers=yes才能正常工作,因为C编译器固有的功能依赖于帧指针的存在。

最后,是否有更直接的方法来获取Rust中当前函数的返回地址?

编辑:return_address GitHub问题中讨论了内部函数的删除。

编辑2:进一步的测试表明,backtrace板条箱能够正确提取当前函数的返回地址,从而避免了我之前描述的黑客行为。幸得鸣叫。

该解决方案的问题是,仅需要当前函数的返回地址时,生成完整回溯的开销。另外,板条箱使用C库提取回溯。这看起来像应该在纯Rust中完成的事情。

编辑3:编译器内部函数__builtin_return_address(0)生成对LLVM内部函数的调用llvm.returnaddress。相应的文档可以在这里找到。

Mau*_*ser 2

我找不到任何关于此的官方文档,但通过在存储库中询问rust-lang发现:您可以链接到 LLVM 内在函数,例如llvm.returnaddress,只需几行代码:

extern {
    #[link_name = "llvm.returnaddress"]
    fn return_address() -> *const u8;
}

fn foo() {
    println!("I was called by {:X}", return_address());
}
Run Code Online (Sandbox Code Playgroud)

LLVM 内在函数llvm.addressofreturnaddress也可能很有趣。