Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 920
Leonardo Marques Avatar asked May 24 '16 14:05

Leonardo Marques


People also ask

What is LLVM Bitcode?

What is commonly known as the LLVM bitcode file format (also, sometimes anachronistically known as bytecode) is actually two things: a bitstream container format and an encoding of LLVM IR into the container format. The bitstream format is an abstract encoding of structured data, very similar to XML in some ways.

Does Rust use LLVM?

Tradeoff #4: LLVM and poor LLVM IR generationrustc uses LLVM to generate code. LLVM can generate very fast code, but it comes at a cost. LLVM is a very big system. In fact, LLVM code makes up the majority of the Rust codebase.

Does Rust use LLVM as backend?

Yes. cargo/rustc use LLVM as a codegen backend by default, and likely will for the foreseeable future. However, there's ongoing work to support using rustc with alternative backends.

Is LLVM Bitcode portable?

LLVM is designed around a language-independent intermediate representation (IR) that serves as a portable, high-level assembly language that can be optimized with a variety of transformations over multiple passes.


2 Answers

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:

  • How stable is the LLVM assembly language?
like image 76
Shepmaster Avatar answered Oct 19 '22 06:10

Shepmaster


It isn't obvious since the LLVM documentation is very obscure, but clang will compile both LLVM IR files (".ll") and bitcode files (".bc"), and link with your system libraries.

On Linux with Rust 1.9:

clang -dynamic-linker /usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d16b8f0e.so  hello.ll -o hello
like image 20
Peter Caven Avatar answered Oct 19 '22 06:10

Peter Caven