Fernichter
Fernichter

Reputation: 56

Statically linking BFD in Rust throws an error

I'm new to using C in Rust and im currently trying to use BFD to build a Binary-Loader. Using bindgen to generate the Rust bindings worked great.

In my build.rs I've used:

println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/");

and

println!("cargo:rustc-link-lib=static=bfd");

This fails with several undefined reference to 'filename_cmp' like errors.

However: When linking dynamically (println!("cargo:rustc-link-lib=bfd");) everything works just fine.

What am I missing?

I've made sure that libbfd.a is present in /usr/lib/x86_64-linux-gnu/.

Upvotes: 1

Views: 104

Answers (1)

Mike Kinghan
Mike Kinghan

Reputation: 61417

I wanted to learn how to use C-Libraries in Rust

In that case, you made a very unlucky choice. libbfd is a rare exception to the rule of that the shared verion of a library and the static version define the same symbols (and leave the same symbols undefined). libbfd.a does not define all of the symbols that libbfd.so defines, and filename_cmp is one the deficit.

See:

$ nm -D /usr/lib/x86_64-linux-gnu/libbfd.so | grep filename_cmp
0000000000109930 T filename_cmp

There it is in libbfd.so. T = defined in text section.

And:

$ nm /usr/lib/x86_64-linux-gnu/libbfd.a | grep filename_cmp
                 U filename_cmp
                 U filename_cmp
                 U filename_cmp
                 

There are nothing but undefined references in members of libbfd.a.

The symbols that are missing from libbfd.a v. libbfd.so are defined in libiberty. libiberty itself is a decommissioned GNU package. That would explain why the definitions it provides to libbfd have been statically linked into the libbfd.so - which is a system runtime - but maintainers evidently haven't got around to decoupling libbfd.a. I don't know why. In Ubuntu, the libbfd shared library is packaged in with libbinutils; a runtime package libiberty does not exist but the development package libiberty-dev does and it installs libiberty.a.

Anyhow, that means that a program you can successfully link dynamically against libbfd by itself will fail to link against it statically by itself. You have to install the libiberty development package and append libiberty to the linkage. Here's a relevant demonstration:

$ cat main.c
#include <stdio.h>

extern int filename_cmp (const char *s1, const char *s2);
int main(void)
{
    if (filename_cmp("filename_cmp.c","FilenameCmp.c")) {
        puts("Not equal");
    } else {
        puts("Equal");
    }
    return 0;
}

Default dynamic linkage against libbfd:

$ gcc -o prog main.c -lbfd
$ ./prog
Not equal

Now statically:

$ gcc -o prog main.c -Wl,-Bstatic -lbfd -Wl,-Bdynamic
/usr/bin/ld: /tmp/ccOy7HDt.o: in function `main':
main.c:(.text+0x1d): undefined reference to `filename_cmp'
collect2: error: ld returned 1 exit status

And now statically with -liberty appended:

$ gcc -o prog main.c -Wl,-Bstatic -lbfd -liberty -Wl,-Bdynamic
$ ./prog
Not equal

Upvotes: 0

Related Questions