Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LLVM produced by rustc gives error about argument type of main when run with lli

Tags:

rust

llvm

lli

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.

like image 966
Harry Braviner Avatar asked Aug 24 '17 06:08

Harry Braviner


1 Answers

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:

  • documentation about lang_items and disabling main
  • Tracking issue for #[start] feature, where some people mention isize not being correct.
like image 106
interjay Avatar answered Nov 19 '22 08:11

interjay