10

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?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Leonardo Marques
  • 3,721
  • 7
  • 36
  • 50
  • 1
    `rustc` is the Rust compiler, it doesn't compile other input formats. Why not use LLVM's `llc` or equivalent if you have the bitcode? – Shepmaster May 24 '16 at 14:26
  • That was my initial guess but I'm not very familiar with llc and only found this: -filetype - Choose a file type (not all types are supported by all targets): =asm - Emit an assembly ('.s') file =obj - Emit a native object ('.o') file =null - Emit nothing, for performance testing. None of them seemed what I was looking for. – Leonardo Marques May 24 '16 at 14:29

2 Answers2

6

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:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • What is the DYLD_LIBRARY_PATH=/path/to/stage2/lib/rustlib/x86_64-apple-darwin/lib/ for? – Leonardo Marques May 24 '16 at 15:34
  • 1
    @LeonardoMarques When I linked the object files with the standard library, it used dynamic linking. Since the Rust standard library isn't in my default library search path, I have to inform the dynamic linker where to find it at program execution time. You could build a static binary instead (which is a bit tricky for me on OS X, so I skipped it) or if the standard library was in the search path the runtime linker would know where to find it. – Shepmaster May 24 '16 at 15:38
  • isn't -lstd-2f39a9bd suposed to have a .dylib extension? Why is it tricky to build a static binary? – Leonardo Marques May 24 '16 at 15:51
  • 1
    @LeonardoMarques that's just how the `-l` flag works. It prepends a `lib` and adds `.dylib` (or `.so`, or whatever is appropriate for the platform). – Shepmaster May 24 '16 at 15:53
  • Why is it tricky to build a static binary? (I'm also working on MacOSX) – Leonardo Marques May 24 '16 at 15:57
  • 1
    @LeonardoMarques ["Apple does not support statically linked binaries on Mac OS X"](https://developer.apple.com/library/mac/qa/qa1118/_index.html). Also see [Creating static Mac OS X C build](http://stackoverflow.com/q/5259249/155423). Stack Overflow has lots of these details fleshed out. :-) – Shepmaster May 24 '16 at 16:01
  • @Shepmaster I get an error when I try to replicate your commands (`llc hello.bc`). ```llc: error: llc: hello.bc: error: Unknown attribute kind (61) (Producer: 'LLVM11.0.0-rust-1.49.0-stable' Reader: 'LLVM 7.1.0')``` – rambi Jul 14 '21 at 09:27
  • @rambi as the error message states, LLVM 7.1.0 cannot read data from LLVM 11.0.0. You will need to match the versions. – Shepmaster Jul 14 '21 at 14:56
  • thanks ! I saw this helpfull post to: https://stackoverflow.com/questions/15836430/how-stable-is-the-llvm-assembly-language – rambi Jul 14 '21 at 15:59
5

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