2017-08-24 16 views
5

我想了解一些關於LLVM IR的內容,尤其是什麼rustc輸出。即使是非常簡單的情況,我也會遇到一些麻煩。由rustc生成的LLVM在運行lli時給出了主參數類型的錯誤

我把源文件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 
} 

(即我在主已經改變的argc類型),然後lli-3.9 s2.ll運行,並且echo $?表明,它確實返回42

我不認爲我應該明確地通過i64 - 我的參數列表或C字符串應該放在內存中,指針和長度自動傳遞到main,對吧?因此,我認爲我在調用lli的方式上做錯了事 - 但我不知道是什麼。

回答

5

Rust將其入口點(標有#[start]屬性的功能,默認爲標準庫中的函數lang_start)標記爲採用isize類型的argc參數。 This is a bug,因爲它應該具有C int類型,所以它應該是64位平臺上的32位,但isize是64位。但是,由於64位調用約定的工作方式,這種情況仍然可以正常工作。返回類型也存在同樣的問題。

A fix爲此已在2017-10-01承諾並應存在於Rust 1.22中。

lli明顯更嚴格地檢查main的類型,這就是爲什麼它會給出錯誤。但是,如果您使用llc,它應該正常工作。

爲了得到正確的main簽名,你可以通過把#![no_main]在模塊的頂部取消默認main,並提供標有#[no_mangle]自己main。但請注意,這將跳過標準庫的初始化。

#![no_main] 

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

參見:

相關問題