Generating Rust executable from LLVM bitcode - rust

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?

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?

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

Related

Providing compiler flags to Rust build for the MSVC toolchain

I am looking to enable compiler options for Rust applications built on Windows using the MSVC toolchain. I see that rustc provides the option "-C llvm-args" to provide flags to the LLVM toolchain but I don't see such an option for MSVC. Does this support currently exist for rustc or cargo?
Rustc is the Rust compiler and it relies on the LLVM backends for actual code generation on all platforms. So if you need to pass arguments to the backend, you can use -C llvm-args on Windows like in other platforms.
The distinction between the MSVC toolchain or the MINGW toolchain mostly concerns the linker. Options can be passed to the linker with -C link-arg or -C link-args on all platforms, although of course in this case the available options will depend on the targeted toolchain.

Emscripten Clang produce ELF 64-bit executabel and wasm binary cross compiler targets

I have a prepared a minimal Cmake project containing one cpp file which represent the main and one cpp file which represent the shared library, that prints basically hello world.
https://github.com/courteous/wasmELF.git
The target is to compile this miniaml code with emscripten/clang only and produce
1) one WebAssembly (wasm) binary module version 0x1 (MVP)
2) one ELF 64-bit LSB
without clearing the cmake build directory and rebuilding it again.
Currently i can successfully produce them bought by running the commands
emconfigure cmake ../ -DCMAKE_BUILD_TYPE=WASM
make
and
cmake ../ -DCMAKE_BUILD_TYPE=Linux
make
However the problem is that in order to do that i need to compile the first one with Clang the to remove the build and then to do a second compilation with GCC. I would like Emscripten/Clang to produce them bought instead. I do not want to delete the build directory since the compilation times is taking too long. (Well not in this Project but imagine if the project was much larger)
What i see is that emscripten/clang selects always a target "wasm32-unknown-emscripten"
clang++ -target wasm32-unknown-emscripten
and if i understand that correctly the target should change
I do see that the project is producing LLVM IR bitcode since i have send the flag "flto"
i.e.
file TestSharedClass.cpp.o
TestSharedClass.cpp.o: LLVM IR bitcode
and in the CMakeLists.txt
set(CMAKE_CXX_FLAGS "-flto")
x86_64-unknown-linux-gnu is a supported target by emscripten/Clang
~/Projects/emscripten/emsdk/upstream/bin$ ./llc --version
LLVM (http://llvm.org/):
LLVM version 11.0.0git
Optimized build with assertions.
Default target: x86_64-unknown-linux-gnu
Host CPU: haswell
Registered Targets:
wasm32 - WebAssembly 32-bit
wasm64 - WebAssembly 64-bit
x86 - 32-bit X86: Pentium-Pro and above
x86-64 - 64-bit X86: EM64T and AMD64
In cmake i do have
SET(TARGET x86_64-unknown-linux-gnu)
however when i run
emconfigure cmake ../ -DCMAKE_BUILD_TYPE=Linux
make
i get mainTestFile.js and mainTestFile.wasm instead of ELF 64-bitcode.
what i am doing wrong here. How to tell clang to product once ELF and once wasm from the same code run without having to clear the build directory. This should be possible since clang is producing LLVM IR bitcode. Or do i understand that wrong?
https://github.com/emscripten-core/emscripten/issues/10361
OK that seems to not be possible i.e. the reply from the dev on github states that emcc or emmake can not be used with another target other then wasm32-unknown-emscripten.

How do I link libgcc statically in rust

I am trying to compile a Rust program with statically linked libgcc.
The program is meant to run in initramfs in a restricted environment and is compiled for different platforms (arm, x86_64).
Currently my only solution is to compile against musl which produces a statically linked binary.
Unfortunately this adds a bit of complexity to the build process - I have not found a way to cross-compile for arm-musl on x86 and I have extra installation requirements (musl-gcc).
I have tried to add this:
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "target-feature=+crt-static", "-C", "link-args=-static-libgcc"]
...to .cargo/config, but as far as I understand +crt-static only works on Windows, and -static-libgcc showed no effect either.

How to build the Rust compiler to use a custom fork of LLVM?

AMD released an optimized version of the LLVM toolchain named AOCC. Rust uses LLVM as the native code generator. Is it possible to use this LLVM instead of the fork from the Rust team?
As of Rust 1ad094, when configuring Rust, you can pass various LLVM-related options:
./configure --help | grep -i llvm
--enable-llvm-static-stdcpp statically link to libstdc++ for LLVM
--enable-llvm-link-shared prefer shared linking to LLVM (llvm-config --link-shared)
--enable-llvm-version-check check if the LLVM version is supported, build anyway
--enable-ninja build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)
--enable-emscripten compile the emscripten backend as well as LLVM
--enable-optimize-llvm build optimized LLVM
--enable-llvm-assertions build LLVM with assertions
--enable-llvm-release-debuginfo build LLVM with debugger metadata
--llvm-root=VAL set LLVM root
--experimental-targets=VAL experimental LLVM targets to build
--build=VAL GNUs ./configure syntax LLVM build triple
--host=VAL GNUs ./configure syntax LLVM host triples
--target=VAL GNUs ./configure syntax LLVM target triples
If the version of LLVM in the fork you want to use is compatible with the version of LLVM that Rust needs, then you should just be able to use --llvm-root=

Can gcc produce binary for Arm without cross compilation

Can we configure gcc running on intel x64 architecture to produce binary for ARM chip by just passing some flags to gcc and not using a cross compiler.
Short: Nope
Compiler:
gcc is not a native crosscompiler, the target architecture has to be specified at the time you compile gcc. (Some exceptions apply, as for example x86 and x86_64 can be supported at the same time)
clang would be a native crosscompiler, and you can generate code for arm by passing -target=arm-linux-gnu, but you still cant produce binaries, as you need a linker and a C-library too. Means you can run clang -target=arm-linux-gnu -c <your file> and compile C/C++ Code (will likely need to point it to your C/C++ include paths) - but you cant build binaries.
Rest of the toolchain:
You need a fitting linker and toolchain too, both are specific to the architecture and OS you want to run at.
Possible solutions:
Get a fitting toolchain, or compile your own. For arm linux you have for ex. CrossToolchains if you are on debian, for barebones you can get a crosscompiler from codesourcery.
Since you were very vague, its not possible to give you a clearer answer

Resources