You copied the Doc URL to your clipboard.

About weak references and definitions

Weak references and definitions provide additional flexibility in the way the linker includes various functions and variables in a build. These references are typically to library functions.

Weak references

If the linker cannot resolve normal, non-weak, references to symbols included in the link, 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, the section it is resolved to 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.

Function or variable declarations in C source files can be marked with the __weak qualifier. As with extern, this qualifier tells the compiler that a function or variable is declared in another source file. Because the definition of this function or variable might not be available to the compiler, it creates a weak reference to be resolved by the linker.

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 is strongly referenced 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

A function definition, or an exported label in assembler, can also be marked as weak, as can a variable definition. In this case, a weak symbol definition is created in the object file.

A weak definition can be used 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 due to 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. Weak references can be used 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 --split_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().

  • The linker feedback mechanism, --feedback, records init_foo() as being unused during the link step. This causes the compiler to place init_foo() into its own section during subsequent compilations, so that it can be removed.

  • The compiler directive #pragma arm section also instructs the compiler to generate a separate ELF section for some functions.

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:

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

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


  IMPORT init_foo WEAK
  AREA init, CODE, readonly
    BL init_foo
    ;Rest of code

Example of a weak definition

A simple or dummy implementation of a function can be provided as a weak definition. This enables you to built 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.