Linker Scripts#

pw_build: Integrations for Bazel, GN, and CMake

pw_build provides utilities for working with linker scripts in embedded projects. If using the GN or Bazel build systems you can preprocess your linker script using the C preprocessor with the pw_linker_script rules.

Linker Script Helpers#

PW_MUST_PLACE#

PW_MUST_PLACE(isection)#

PW_MUST_PLACE is a macro intended for use in linker scripts to ensure inputs are non-zero sized.

Say you want to place a specific object file into a particular section. You can reference it by file path like:

SECTIONS
{
  .special_code
  {
    */src/path/libspecial_code.a:*.o
  }
}

This works but is fragile as it will silently break if the filename or path changes. Use PW_MUST_PLACE to get a linker assertion if the input is empty.

#include "pw_build/must_place.ld.h"

SECTIONS
{
  .special_code
  {
    PW_MUST_PLACE(*/src/path/libspecial_code.a:*.o)
  }
}

If the wildcard match fails PW_MUST_PLACE will generate an error telling you which input had no symbols.

Error: No symbols found in pattern below
*/src/path/libspecial_code.a:*.o

This could be because you had a typo, the path changed, or the symbols were dropped due to linker section garbage collection.In the latter case, you can choose to add KEEP() around your input to prevent garbage collection.

LinkerSymbol#

template<class T = uintptr_t>
class LinkerSymbol#

Represents a symbol provided by the linker, i.e. via a linker script.

LinkerSymbol objects are used with linker-provided symbols that don’t have storage (which is common), and only provide a value e.g.

MY_LINKER_VARIABLE = 42

LinkerSymbol objects are not actual variables (do not have storage) and thus cannot be created; they can only be used with an extern "C" declaration. The purpose is to communicate values from the linker script to C++ code.

Example:

#include "pw_build/linker_symbol.h"

extern "C" pw::LinkerSymbol<uint32_t> MY_LINKER_VARIABLE;

uint32_t GetMyLinkerVariable() {
  return MY_LINKER_VARIABLE.value();
}
Template Parameters:

T – The type of the value communicated by the linker, defaulting to uintptr_t. Must be an integral or enum type, no larger than uintptr_t.

Public Functions

inline T value() const#

Gets the value of this linker symbol, converted to the specified type.

Note

LinkerSymbol does not support, and is not necessary for, symbols that communicate a pointer value (i.e. an address). For those, simply define an extern variable of the pointed-to type, e.g.:

extern "C" uint32_t PTR_SYM;

LinkerSymbol is superior to the traditional extern uint8_t FOO; (uint32_t)&FOO method because it catches subtle errors:

  • Missing extern specifier:

    error: use of deleted function 'pw::build::LinkerSymbol::LinkerSymbol()'
    | LinkerSymbol oops;
    |              ^~~~
    
  • Missing & operator:

    error: invalid cast from type 'pw::build::LinkerSymbol' to type 'uint32_t' {aka 'long unsigned int'}
    |  uint32_t val = (uint32_t)FOO_SYM;
    |                 ^~~~~~~~~~~~~~~~~