How to cross-compile from a Linux host to FreeBSD6

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.

The libc cratw defaults to the FreeBSD 11 ABI: https://github.com/rust-lang/libc/blob/28ab9b9e7bd04a5c5aca3f4d78583214f63d4002/build.rs#L70 Looks like the only way it can be configured is through the presence of the freebsd-version command which prints the FreeBSD version of the host system. Libstd itself also uses a specific version of the FreeBSD ABI. I'm not sure which version though. Changing that one requires recompiling the standard library.