Search code examples
rustllvm-irbitcode

Generating Rust executable from LLVM bitcode


How can I generate an executable of an application written in Rust that was compiled into LLVM-IR bitcode?

If I try to compile the .bc file with rustc it tells me stream did not contain valid UTF-8 and I can't seem to figure out if there is a specific option in rustc for this.

Basically I want to achieve this: program.rs -> program.bc -> program. Where program is the final executable. What steps should I make to achieve this?


Solution

  • Starting with this source code:

    fn main() {
        println!("Hello, world!");
    }
    

    You can create LLVM intermediate representation (IR) or bitcode (BC):

    # IR in hello.ll
    rustc hello.rs --emit=llvm-ir
    # BC in hello.bc
    rustc hello.rs --emit=llvm-bc
    

    These files can then be further processed by LLVM to produce assembly or an object file:

    # Assembly in hello.s
    llc hello.bc
    # Object in hello.o
    llc hello.bc --filetype=obj
    

    Then you need to link the files to produce an executable. This requires linking to the Rust standard libraries. The path is platform- and version-dependent:

    cc -L/path/to/stage2/lib/rustlib/x86_64-apple-darwin/lib/ -lstd-f4a73f2c70e583e1 -o hello2 hello.o
    

    You can then run the program:

    DYLD_LIBRARY_PATH=/path/to/stage2/lib/rustlib/x86_64-apple-darwin/lib/ ./hello2
    

    This answer has macOS specific solutions, but the general concepts should be extendable to Linux and Windows. The implementation will differ slightly for Linux and probably greatly for Windows. Notably, I'm using DYLD_LIBRARY_PATH as I've dynamically linked to the Rust standard library which isn't in my usual library search path.

    Note that LLVM IR and BC files don't have the strongest forward / backward compatibility guarantees. This means that you need to use a version of llc that is compatible with the version of rustc you are using. For this answer, I used an llc that was produced by my local Rust development build:

    % rustc --version --verbose
    rustc 1.53.0 (53cb7b09b 2021-06-17)
    binary: rustc
    commit-hash: 53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b
    commit-date: 2021-06-17
    host: x86_64-apple-darwin
    release: 1.53.0
    LLVM version: 12.0.1
    
    % llc --version
    LLVM (http://llvm.org/):
      LLVM version 12.0.1-rust-dev
      Optimized build.
      Default target: x86_64-apple-darwin20.5.0
      Host CPU: skylake
    

    See also: