Hello everyone,
I want to cross compile the rust code from Linux host to FreeBSD6 platform. It seems cross compile to FreeBSD12 is ok. But, for FreeBSD6, I faced linker error.
I went through the following steps.
Build the GCC Cross Compiler
In order to cross compile to FreeBSD6, I've built cross GCC compiler.
user@user-virtual-machine:~/rust/app$ ls -l /usr/local/x86_64-pc-freebsd6/bin
total 134644
-rwxr-xr-x 1 root root 6515632 Aug 10 11:09 x86_64-pc-freebsd6-addr2line
-rwxr-xr-x 1 root root 6699400 Aug 10 11:09 x86_64-pc-freebsd6-ar
-rwxr-xr-x 1 root root 8974488 Aug 10 11:09 x86_64-pc-freebsd6-as
-rwxr-xr-x 2 root root 3684360 Aug 10 11:22 x86_64-pc-freebsd6-c++
-rwxr-xr-x 1 root root 6463800 Aug 10 11:09 x86_64-pc-freebsd6-c++filt
-rwxr-xr-x 1 root root 3681240 Aug 10 11:22 x86_64-pc-freebsd6-cpp
-rwxr-xr-x 1 root root 126360 Aug 10 11:09 x86_64-pc-freebsd6-elfedit
-rwxr-xr-x 2 root root 3684360 Aug 10 11:22 x86_64-pc-freebsd6-g++
-rwxr-xr-x 2 root root 3679160 Aug 10 11:22 x86_64-pc-freebsd6-gcc
-rwxr-xr-x 2 root root 3679160 Aug 10 11:22 x86_64-pc-freebsd6-gcc-6.4.0
-rwxr-xr-x 1 root root 143184 Aug 10 11:22 x86_64-pc-freebsd6-gcc-ar
-rwxr-xr-x 1 root root 143104 Aug 10 11:22 x86_64-pc-freebsd6-gcc-nm
-rwxr-xr-x 1 root root 143120 Aug 10 11:22 x86_64-pc-freebsd6-gcc-ranlib
-rwxr-xr-x 1 root root 2600376 Aug 10 11:22 x86_64-pc-freebsd6-gcov
-rwxr-xr-x 1 root root 2261592 Aug 10 11:22 x86_64-pc-freebsd6-gcov-dump
-rwxr-xr-x 1 root root 2388088 Aug 10 11:22 x86_64-pc-freebsd6-gcov-tool
-rwxr-xr-x 1 root root 7068408 Aug 10 11:09 x86_64-pc-freebsd6-gprof
-rwxr-xr-x 2 root root 9939816 Aug 10 11:09 x86_64-pc-freebsd6-ld
-rwxr-xr-x 2 root root 9939816 Aug 10 11:09 x86_64-pc-freebsd6-ld.bfd
-rwxr-xr-x 1 root root 6584944 Aug 10 11:09 x86_64-pc-freebsd6-nm
-rwxr-xr-x 1 root root 7288264 Aug 10 11:09 x86_64-pc-freebsd6-objcopy
-rwxr-xr-x 1 root root 10821920 Aug 10 11:09 x86_64-pc-freebsd6-objdump
-rwxr-xr-x 1 root root 6699432 Aug 10 11:09 x86_64-pc-freebsd6-ranlib
-rwxr-xr-x 1 root root 4296624 Aug 10 11:09 x86_64-pc-freebsd6-readelf
-rwxr-xr-x 1 root root 6510640 Aug 10 11:09 x86_64-pc-freebsd6-size
-rwxr-xr-x 1 root root 6518600 Aug 10 11:09 x86_64-pc-freebsd6-strings
-rwxr-xr-x 1 root root 7288256 Aug 10 11:09 x86_64-pc-freebsd6-strip
Copying FreeBSD6 Shared Objects
And, I copied every shared object and archive files from the FreeBSD6 to Linux host to link with my compiled binary.
Writing Target specification json
Next, I wrote target specification json file.
{
"abi-return-struct-as-int": true,
"arch": "x86",
"cpu": "pentium4",
"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128",
"default-dwarf-version": 2,
"dynamic-linking": true,
"has-rpath": true,
"llvm-target": "i686-unknown-freebsd6.3",
"max-atomic-width": 64,
"os": "freebsd",
"position-independent-executables": true,
"panic-strategy": "abort",
"linker-flavor": "gcc",
"linker": "/usr/local/x86_64-pc-freebsd6/bin/x86_64-pc-freebsd6-gcc",
"pre-link-args": {
"gcc": [
"-m32"
]
},
"post-link-args": {
"gcc": [
"-m32",
"-L/usr/local/x86_64-pc-freebsd6/lib -lgcc_s -lstdc++ -lc",
"-B/usr/local/x86_64-pc-freebsd6/lib",
"--verbose"
]
},
"relro-level": "full",
"stack-probes": {
"kind": "inline-or-call",
"min-llvm-version-for-inline": [
16,
0,
0
]
},
"target-family": [
"unix"
],
"target-pointer-width": "32"
}
I saved this json to i686-unknown-freebsd6.json
.
Building
My final build command is following.
$ cargo build -Z build-std=core,std,panic_abort --target=i686-unknown-freebsd6.json
The building results is linker error.
9: undefined reference to `stat@FBSD_1.0'
collect2: error: ld returned 1 exit status
GNU ld (GNU Binutils) 2.39
Supported emulations:
elf_x86_64_fbsd
elf_i386_fbsd
elf_x86_64
elf_i386
elf_iamcu
Notice that the stat
and fstat
functions link to stat@FBSD_1.0
and fstat@FBSD_1.0
. This appears to be related to FreeBSD symbol versioning.
Use custom libc
I did some research and realized that libc is a C interface, where stat
defines a link to stat@FBSD_1.0
, so I changed libc
locally and then changed Cargo to use it.
[package]
name = "app"
version = "0.1.0"
edition = "2018"
[dependencies]
libc = "0.3.2"
[patch.crates-io]
libc = { path = "/home/user/rust/libc" }
But the build result is same.
I'm not sure what direction to go with my research here, as I have limited experience with RUST, and would appreciate some advice.