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.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.