C symbol visibility in static archives

2019-07-16 09:17发布

I have files foo.c bar.c and baz.c, plus wrapper code myfn.c defining a function myfn() that uses code and data from those other files.

I would like to create something like an object file or archive, myfn.o or libmyfn.a, so that myfn() can be made available to other projects without also exporting a load of symbols from {foo,bar,baz}.o as well.

What's the right way to do that in Linux/gcc? Thanks.


Update: I've found one way of doing it. I should've emphasised originally that this was about static archives, not DSOs. Anyway, the recipe:

  1. #define PUBLIC __attribute__ ((visibility("default"))) then mark myfn() as PUBLIC in myfn.c. Don't mark anything else PUBLIC.

  2. Compile objects with gcc -c foo.c bar.c baz.c myfn.c -fvisibility=hidden, which marks everything as hidden except for myfn().

  3. Create a convenience archive using ld's partial-linking switch: ld -r foo.o bar.o baz.o myfn.o -o libmyfn.a

  4. Localise everything that wasn't PUBLIC like so: objcopy --localize-hidden libmyfn.a

  5. Now nm says myfn is the only global symbol in libmyfn.a and subsequent linking into other programs works just fine: gcc -o main main.c -L. -lmyfn (here, the program calls myfn(); if it tried to call foo() then compilation would fail).

If I use ar instead of ld -r in step 3 then compilation fails in step 5: I guess ar hasn't linked foo etc to myfn, and no longer can once those functions are localised, whereas ld -r resolves the link before it gets localised-away.

I'd welcome any response that confirms this is the "right" way, or describes a slicker way of achieving the same.

3条回答
成全新的幸福
2楼-- · 2019-07-16 09:37

Unfortunately, C linkage for globals is all-or-nothing, in the sense that the globals of all modules would be available in libmyfn.a's final list of external symbols.

gcc tool chain offers an extension that lets you hide symbols from outside users, while making them available to other translation units in your library:

foo.h:

void foo();

foo.c:

void foo() __attribute__ ((visibility ("hidden")));

myfn.h:

void myfn();

myfn.c:

#include <stdio.h>
#include "foo.h"

void myfn() {
    printf("calling foo...\n");
    foo();
    printf("calling foo again...\n");
    foo();
}

For portability, you would probably benefit from making a macro for __attribute__ ((visibility ("hidden"))), and placing it in a conditional compilation block conditioned on gcc.

In addition, Linux offers a utility called strip, which lets you remove some of the symbols from compiled object files. Options -N and -K let you identify individual symbols that you want to keep or remove.

查看更多
该账号已被封号
3楼-- · 2019-07-16 09:44

Suppose myfn.c has function myfun() which you want to use in other three files foo.c, bar.c & baz.c

Now create a shared library from code in myfn.c viz libmyf.a

Use this function call myfun() in other three files. Declare function as extern in these files. Now you can create object code of these thee files and link the libmyf.a at linking phase.

Refer to following link for using shared libraries.

http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html

查看更多
▲ chillily
4楼-- · 2019-07-16 10:00

Start with this to build a static library

gcc -c -O2 foo.c bar.c baz.c myfn.c
ar av libmyfunctions.a foo.o bar.o baz.o myfn.o

Compile and link with other programs like:

gcc -O2 program.c -lmyfunctions -o myprogram

Now your libmyfunctions.a will ultimately have extra stuff from the source that isn't required by the code in myfn.c But the linker should do a reasonable job of removing this when it creates the final program.

查看更多
登录 后发表回答