You copied the Doc URL to your clipboard.

Weak references and definitions

Weak references and definitions provide additional flexibility in the way the linker includes various functions and variables in a build.

Weak references and definitions are typically used in connection with library functions.

Weak references

If the linker cannot resolve normal, non-weak, references to symbols from the content loaded so far, it attempts to do so by finding the symbol in a library:

  • If it is unable to find such a reference, the linker reports an error.

  • If such a reference is resolved, a section that is reachable from an entry point by at least one non-weak reference is marked as used. This ensures the section is not removed by the linker as an unused section. Each non-weak reference must be resolved by exactly one definition. If there are multiple definitions, the linker reports an error.

Symbols can be given weak binding by the compiler and assembler.

The linker does not load an object from a library to resolve a weak reference. It is able to resolve the weak reference only if the definition is included in the image for other reasons. The weak reference does not cause the linker to mark the section containing the definition as used, so it might be removed by the linker as unused. The definition might already exist in the image for several reasons:

  • The symbol has a non-weak reference from somewhere else in the code.

  • The symbol definition exists in the same ELF section as a symbol definition that is included for any of these reasons.

  • The symbol definition is in a section that has been specified using --keep, or contains an ENTRY point.

  • The symbol definition is in an object file included in the link and the --no_remove option is used. The object file is not referenced from a library unless that object file within the library is explicitly included on the linker command-line.

In summary, a weak reference is resolved if the definition is already included in the image, but it does not determine if that definition is included.

An unresolved weak function call is replaced with either:

  • A no-operation instruction, NOP.

  • A branch with link instruction, BL, to the following instruction. That is, the function call just does not happen.

Weak definitions

You can mark a function or variable definition as weak in a source file. A weak symbol definition is then present in the created object file.

You can use a weak definition to resolve any reference to that symbol in the same way as a normal definition. However, if another non-weak definition of that symbol exists in the build, the linker uses that definition instead of the weak definition, and does not produce an error because of multiply-defined symbols.

Example of a weak reference

A library contains a function foo(), that is called in some builds of an application but not in others. If it is used, init_foo() must be called first. You can use weak references to automate the call to init_foo().

The library can define init_foo() and foo() in the same ELF section. The application initialization code must call init_foo() weakly. If the application includes foo() for any reason, it also includes init_foo() and this is called from the initialization code. In any builds that do not include foo(), the call to init_foo() is removed by the linker.

Typically, the code for multiple functions defined within a single source file is placed into a single ELF section by the compiler. However, certain build options might alter this behavior, so you must use them with caution if your build is relying on the grouping of files into ELF sections. The compiler command-line option -ffunction-sections results in each function being placed in its own section. In this example, compiling the library with this option results in foo() and init_foo() being placed in separate sections. Therefore init_foo() is not automatically included in the build due to a call to foo().

In this example, there is no need to rebuild the initialization code between builds that include foo() and do not include foo(). There is also no possibility of accidentally building an application with a version of the initialization code that does not call init_foo(), and other parts of the application that call foo().

An example of foo.c source code that is typically built into a library is:

void init_foo()
    // Some initialization code
void foo()
     // A function that is included in some builds
     // and requires init_foo() to be called first.

An example of init.c is:

__attribute__((weak)) void init_foo(void);
int main(void)
    //  Rest of code that may make calls to foo() directly or indirectly.

An example of a weak reference generated by the assembler is:

    bl      init_foo
    // Rest of code

    .weak   init_foo

Example of a weak definition

You can provide a simple or dummy implementation of a function as a weak definition. This enables you to build software with defined behavior without having to provide a full implementation of the function. It also enables you to provide a full implementation for some builds if required.