Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make weak linking work with GCC?

Tags:

c

gcc

linker

weak

People also ask

How do you use weak attributes?

The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.

What is __ weak in C?

If a developer closely looks at framework and library files, they may come across functions that have __weak in front of them. The weak symbol is a special linker symbol that denotes a function that can be overridden during link time.

What is Pragma weak?

#pragma weak name1 [= name2 ] Use weak to define a weak global symbol. This pragma is used mainly in source files for building libraries. The linker does not warn you if it cannot resolve a weak symbol.

What is strong and weak symbols in C?

A weak symbol denotes a specially annotated symbol during linking of Executable and Linkable Format (ELF) object files. By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name.


I just looked into this and thought some others might be interested in my findings.

Weak linking with weak_import really only works well with dynamic libraries. You can get it to work with static linking (by specifying -undefined dynamic_lookup as suggested above) but this isn't such a hot idea. It means that no undefined symbols will be detected until runtime. This is something I would avoid in production code, personally.

Here is a Mac OS X Terminal session showing how to make it work:

Here is f.c

int f(int n)
{
    return n * 7;
}

Here is whatnof.c

#include <stdio.h>
#include <stdlib.h>

extern int f (int) __attribute__((weak_import));

int main() {
    if(f == NULL)
        printf("what, no f?\n");
    else
        printf("f(8) is %d\n", f(8));
    exit(0);
}

Make a dynamic library from f.c:

$ cc -dynamiclib -o f.dylib f.c

Compile and link against the dynamic lib, list dynamic libs.

$ cc -o whatnof whatnof.c f.dylib
$ otool -L whatnof
whatnof:
       f.dylib (compatibility version 0.0.0, current version 0.0.0)
       /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

Run whatnof to see what happens:

$ whatnof
f(8) is 56

Now replace f.dylib with an empty library (no symbols):

$ mv f.dylib f.dylib.real
$ touch null.c
$ cc -dynamiclib -o f.dylib null.c

Run same whatnof to see what happens:

$ whatnof
what, no f?

The basic idea (or "use case") for weak_import is that it lets you link against a set of dynamic (shared) libraries, but then run the same code against earlier versions of the same libraries. You can check functions against NULL to see if they're supported in the particular dynamic library that the code is currently running against. This seems to be part of the basic development model supported by Xcode. I hope this example is useful; it has helped put my mind at ease about this part of the Xcode design.


Add -Wl,-flat_namespace,-undefined,dynamic_lookup to the gcc compiler line that you use to do the final link.


Minimal runnable Linux example

main.c

#include <stdio.h>

int my_weak_var __attribute__((weak)) = 1;

int main(void) {
    printf("%d\n", my_weak_var);
}

notmain.c

int my_weak_var = 2;

Compile and run with both objects:

gcc -c -std=c99 -Wall -Wextra -pedantic -o main.o main.c
gcc -c -std=c99 -Wall -Wextra -pedantic -o notmain.o notmain.c
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.o notmain.o
./main.out

Output:

2

Compile and run without notmain.o:

gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.o
./main.out

Output:

1

GitHub upstream.

So we see that if given on notmain.o, then the non-weak symbol takes precedence as expected.

We can analyze the ELF object file symbols with:

nm main.o notmain.o

which gives:

main.o:
                 U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
0000000000000000 V my_weak_var
                 U printf

notmain.o:
0000000000000000 D my_weak_var

and then:

man nm

contains:

The symbol type. At least the following types are used; others are, as well, depending on the object file format. If lowercase, the symbol is usually local; if uppercase, the symbol is global (external). There are however a few lowercase symbols that are shown for special global symbols ("u", "v" and "w").

"D"
"d" The symbol is in the initialized data section.

"V"
"v" The symbol is a weak object. When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked and the symbol is not defined, the value of the weak symbol becomes zero with no error. On some systems, uppercase indicates that a default value has been specified.

If dealing with .a static libraries however, you might have to use -Wl,--whole-archive as explained at: How to make gcc link strong symbol in static library to overwrite weak symbol?

Weak symbols can also be left undefined, which in Binutils leads to "platform specific behaviour", see: GCC behavior for unresolved weak functions

Tested on Ubuntu 18.10, GCC 8.2.0.


You need to set the MACOSX_DEPLOYMENT_TARGET variable to 10.2 or later. See Apple's documentation and their technote on weak linking.


From the gcc doc manual:

weak

The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.

which means that an object is legitimated to overwrite a weak symbol (defined in another object/library) without getting errors at link time. What is unclear is whether you are linking the library with the weak symbol or not. It's seems that both you have not defined the symbol and the library is not properly linked.