Cross Compiling Rust (Notes)

I’ve been fiddling with cross compiling Rust to our ARM-64 platforms. I’m hitting a wall because Rust elfs require the system loader and C libs. I’m writing these notes to document what I’ve found so far. Would like to come back and discover how to build a static ARM-64 executable. Started here: https://github.com/japaric/rust-cross

Step 1. Install Rust. https://www.rust-lang.org/tools/install

Step2. Install a C cross compiler. Rust uses the C linker.

% sudo apt install gcc-aarch64-linux-gnu 
or 
% sudo dnf install gcc-aarch64-linux-gnu

Step 3. Add the cross compiler targets to Rust.

rustup target add aarch64-unknown-linux-gnu
rustup target add aarch64-unknown-linux-musl

Step 4. Add to the cargo config

…marvin:hello-rust% cat ~/.cargo/config
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-gcc"

Step 5. Create a simple new project.

cargo new --bin hello-rust
cd hello-rust

Step 6. Build

cross build --target aarch64-unknown-linux-gnu

Now examining the final executable, I’m finding it requires the glibc loader and libraries. We’re using uClibc because historical reasons.

% file ./target/aarch64-unknown-linux-gnu/debug/hello-rust
./target/aarch64-unknown-linux-gnu/debug/hello-rust: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=f62e92025124bc8018570c700b6e5faeecfdd671, for GNU/Linux 3.7.0, with debug_info, not stripped
% readelf -a ./target/aarch64-unknown-linux-gnu/debug/hello-rust
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x0000000000000230 0x0000000000000230 R 0x8
INTERP 0x0000000000000270 0x0000000000000270 0x0000000000000270
0x000000000000001b 0x000000000000001b R 0x1
[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
[snip]
Dynamic section at offset 0x3aac8 contains 30 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]

I tried the Rust musl cross compiler but hit a wall with some compile errors around, I think, hard/soft floats. The musl cross compiler I found here: https://toolchains.bootlin.com/releases_aarch64.html

There are notes explaining musl can be static linked. https://github.com/japaric/rust-cross#how-do-i-compile-a-fully-statically-linked-rust-binaries

I should google those errors. Found:

https://github.com/rust-lang/rust/issues/46651

Looks like it might be fixed but not in a released Rust? Need to investigate further.

Update: Installed the nightly build and voila! static link musl elf.

% rustup toolchain install nightly
% rustup default nightly-x86_64-unknown-linux-gnu
% cross build --target aarch64-unknown-linux-musl
% file ./target/aarch64-unknown-linux-musl/debug/hello-rust
./target/aarch64-unknown-linux-musl/debug/hello-rust: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, with debug_info, not stripped

Copied the resulting elf to my firmware. IT WORKS! It’s big, but it works.

/var/tmp # ls -l hello-rust
 -rwxr--r--    1 root     root       3878608 Oct 26 12:55 hello-rust*
 /var/tmp # ./hello-rust
 Hello, world!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s