I'm trying to learn a little about the LLVM IR, particularly what exactly rustc outputs. I'm having a little bit of trouble running even a very simple case.
I put the following in a source file simple.rs
:
fn main() {
let x = 7u32;
let y = x + 2;
}
and run rustc --emit llvm-ir simple.rs
to get the file simple.ll
, containing
; 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}
I then try to run this with the command
lli-3.9 -load ~/.multirust/toolchains/nightly-x86_64-unknown-linux-gnu/lib/libstd-35ad9950c7e5074b.so simple.ll
but I get the error message
LLVM ERROR: Invalid type for first argument of main() supplied
I'm able to make a minimal reproduction of this as follows: I make a file called s2.ll
, containing
define i32 @main(i64, i8**) {
ret i32 42
}
and running lli-3.9 s2.ll
gives the same error message. But if I change the contents of s2.ll
to
define i32 @main(i32, i8**) {
ret i32 42
}
(i.e. I've changed the type of argc
in main) then lli-3.9 s2.ll
runs, and echo $?
reveals that it did indeed return 42
.
I don't think I should have to pass in the i64
explicitly - my argument list or C strings should be put into memory somewhere and the pointer and length passed to main
automatically, right? Therefore I assume that I'm doing something wrong in the way in invoke lli
- but I have no idea what.
Rust marks its entry point (the function marked with #[start]
attribute, by default the function lang_start
in the standard library) as taking an argc parameter of type isize
. This is a bug because it should have the type of a C int, so it should be 32 bits on a 64-bit platform, but isize
is 64 bits. However, due to the way 64-bit calling conventions work, this happens to still work correctly. The same issue also exists for the return type.
A fix for this has been committed on 2017-10-01 and should be present in Rust 1.22.
lli
is apparently more strict about checking the type of main
which is why it gives the error. But if you use llc
instead, it should work correctly.
To get the correct main
signature, you can cancel the default main
by putting #![no_main]
at the top of the module, and provide your own main
marked with #[no_mangle]
. But note that this will skip the standard library's initialization.
#![no_main]
#[no_mangle]
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
0
}
See also:
lang_items
and disabling main
#[start]
feature, where some people mention isize
not being correct.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With