Search code examples
rustsgx

How do I always include a Rust dependency when linking?


I am trying to use the Fortanix SGX framework to run libdvdcss in an enclave, but having problems with the linker.

I created a simple FFI wrapper around libdvdcss which works fine when executing it normally on Linux (without SGX and with libdvdcss installed globally). It does not work when I run it with the target x86_64-fortanix-unknown-sgx as specified on the Getting started page, because the linker complains about many missing symbols, especially about malloc etc.

From what I understand, the issue is that there is no libc in SGX, therefore I need to include rs-libc manually, which is basically a libc to use in SGX. The rs-libc crate contains C, ASM and also some Rust code (mostly for malloc). Thus my Cargo.toml:

[dependencies]
rs-libc = "0.2.3"

I found out that is not sufficient and that I have to provide the following build.rs to manually tell the linker to link the libc.a from the rs-libc crate as well.

pub fn main() {
    println!("cargo:rustc-link-search=/home/me/dev/libdvdcss/.libs");  // Will be changed later
    println!("cargo:rustc-link-lib=static=dvdcss");
    println!("cargo:rustc-link-lib=static=c");
}

This fixes some of the errors with strlen etc. not being found, but not for malloc and free. I think the problem is that they are not compiled from a C source file, but instead in alloc.rs. I've also seen that this source file is compiled to a Rust library in target/x86_64-fortanix-unknown-sgx/debug/deps/librs_libc-04111db022dd517f.rlib and contains the symbols:

rs_libc-04111db022dd517f.rs_libc.53f0fd72-cgu.5.rcgu.o:
0000000000000000 T calloc
0000000000000000 T free
0000000000000000 W __llvm_lvi_thunk_r11
0000000000000000 T malloc
0000000000000000 T realloc
0000000000000000 V __rustc_debug_gdb_scripts_section__
                 U _ZN3std3sys3sgx5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$12alloc_zeroed17ha722ea369ab2dac9E
                 U _ZN3std3sys3sgx5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$5alloc17h561d825df0f2dfa8E
                 U _ZN3std3sys3sgx5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$7dealloc17hbbda0b3d0a1f9d67E
                 U _ZN3std3sys3sgx5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$7realloc17hf76d62802e46847bE
                 U _ZN4core3ptr4read17hc3470c4a404ff082E
                 U _ZN4core3ptr5write17ha0bb4d6cbfed535eE
                 U _ZN4core5alloc6layout6Layout25from_size_align_unchecked17h074422ae6f6459f7E
                 U _ZN4core9panicking5panic17hde9db97a7382bd28E

Unfortunately, this file does not seem to be included in the final linker command. I think this is because no usages of this library are found in my Rust application and thus it is optimized out.

Is there a way to include it nonetheless?


Solution

  • Adding an extern crate rs_libc; to your crate's root should do the trick. It is mandatory that a dependency declared with extern crate must be given to the linker. In rust 2018 and above, an appropriate declaration is implicitly added to your crate by the compiler if and only if you use one or more of that crate's symbols (rust 2015 requires the extern crate be added explicitly). See the section in the rust reference for more information.