我正在搜索 UnreachableInst 在哪里被翻译成 _abort 调用。
下面是故事。
我目前正在尝试让 Rust 可用于 Renesas RL78 目标。 为此,我从 Renesas 的开源工具中获取了 LLVM 源代码,并将其用作 rustc 编译器的后端。
首先,我编写了只有 main 函数的代码。 这段代码编译没有错误,并且就我查看二进制内容而言没有问题。
请注意,这是部分代码,实际代码具有
#![no_main]
等属性和恐慌处理程序等基本组件。
#[no_mangle]
pub unsafe extern "C" fn main() -> ! {
loop {}
}
但是,如果我像 cortex-m crate 那样编写并使用
#[entry]
proc 宏,则会出现以下错误。
#[rl78_macros::entry]
fn main() -> ! {
loop {}
}
lld: error: undefined symbol: _abort
>>> referenced by main.rs:26 (src/main.rs:26)
>>> /home/vmuser/Documents/renesas/renesas-program/target/rl78/debug/deps/renesas_program-916d6430e40e98ae.3a31hiwjtkbq95rf.rcgu.o:(_main)
我添加了虚拟中止函数并将
.plt
部分添加到链接器脚本中,因为链接器也需要它。
我重试编译,成功了。
我调查了二进制文件,发现 _abort 调用放在 rust main 调用之后,如下所示。
00000085 _main:
85: fc 81 00 00 call !!__ZN15renesas_program11__rl78_main17h608e5bb48d9d4215E
89: fd 80 00 call !_abort
我也调查了llvm ir rustc生成的,有unreachable的语句。
define dso_local void @main() unnamed_addr addrspace(2) #0 !dbg !183 {
start:
; call renesas_program::__rl78_main
call addrspace(2) void @_ZN15renesas_program11__rl78_main17h608e5bb48d9d4215E() #4, !dbg !184
unreachable, !dbg !184
}
在 rustc 生成的目标文件中,已经插入了 _abort 调用。 这就是为什么,我怀疑 LLVM 将 Unreachable 翻译为 abort 调用,而 Linker 和 Rustc 没有做任何事情。
00000000 _main:
0: fc 00 00 00 call !!0x0
4: fd 00 00 call !0x0
就像我上面所说的,这个 LLVM 是 Renesas RL78 的 LLVM 10 的定制版本, 所以这个问题可能来自自定义,但我无法从原始和自定义的差异中找到原因。
我知道这是学习llvm内部最好、最好的机会,所以我目前正在学习它。 不过我也想知道问题出在哪里。
请告诉我有什么问题
可能不会。
每个 LLVM 基本块都必须以终止符指令结束,
unreachable
就是其中之一,并且经常检查并无情地执行该要求。另一方面,A call
不是终止符。因此,创建 abort() 调用的代码通常会在 call
后面加上 unreachable
。
SelectionDAGBuilder::visitUnreachable
是 UnreachableInst
变成 ISD::TRAP
的地方。 SelectionDAGLegalize::ConvertNodeToLibcall
是 ISD::TRAP
降低为 abort() 的地方。