5

我正在尝试了解一些有关 LLVM IR 的知识,尤其是 rustc 输出的内容。即使是一个非常简单的案例,我也遇到了一些麻烦。

我将以下内容放在源文件中simple.rs

fn main() {
    let x = 7u32;
    let y = x + 2;
}

并运行rustc --emit llvm-ir simple.rs以获取文件simple.ll,其中包含

; ModuleID = 'simple.cgu-0.rs'
source_filename = "simple.cgu-0.rs"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: uwtable
define internal void @_ZN6simple4main17h8ac50d7470339b75E() unnamed_addr #0 {
start:
  br label %bb1

bb1:                                              ; preds = %start
  ret void
}

define i64 @main(i64, i8**) unnamed_addr {
top:
  %2 = call i64 @_ZN3std2rt10lang_start17ha09816a4e25587eaE(void ()* @_ZN6simple4main17h8ac50d7470339b75E, i64 %0, i8** %1)
  ret i64 %2
}

declare i64 @_ZN3std2rt10lang_start17ha09816a4e25587eaE(void ()*, i64, i8**) unnamed_addr

attributes #0 = { uwtable }

!llvm.module.flags = !{!0}

!0 = !{i32 1, !"PIE Level", i32 2}

然后我尝试使用命令运行它

lli-3.9 -load ~/.multirust/toolchains/nightly-x86_64-unknown-linux-gnu/lib/libstd-35ad9950c7e5074b.so simple.ll

但我收到错误消息

LLVM ERROR: Invalid type for first argument of main() supplied

我可以对此进行最小复制,如下所示:我制作了一个名为 的文件s2.ll,其中包含

define i32 @main(i64, i8**) {
    ret i32 42
}

并运行lli-3.9 s2.ll给出相同的错误消息。但是,如果我将内容更改s2.ll

define i32 @main(i32, i8**) {
    ret i32 42
}

(即我已经更改了argcin main 的类型)然后lli-3.9 s2.ll运行,并echo $?显示它确实返回了42

我不认为我应该i64显式地传递 - 我的参数列表或 C 字符串应该被放入内存中的某个地方,并且指针和长度main自动传递给,对吗?因此,我认为我在调用的方式上做错了lli——但我不知道是什么。

4

1 回答 1

5

#[start]Rust 将其入口点(用属性标记的函数,默认情况下lang_start是标准库中的函数)标记为采用 argc 类型的参数isize这是一个错误,因为它应该具有 C int 的类型,因此在 64 位平台上它应该是 32 位,但isize它是 64 位。但是,由于 64 位调用约定的工作方式,这恰好仍然可以正常工作。返回类型也存在同样的问题。

对此的修复已于 2017-10-01 提交,并且应该存在于 Rust 1.22 中。

lli显然更严格地检查类型main是它给出错误的原因。但是,如果您改用llc它,它应该可以正常工作。

要获得正确的签名,您可以通过在模块顶部main取消默认,并提供您自己的标记为. 但请注意,这将跳过标准库的初始化。main#![no_main]main#[no_mangle]

#![no_main]

#[no_mangle]
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
    0
}

也可以看看:

于 2017-08-24T11:10:05.427 回答