31

Using special compiler commands a symbol can be declared weak. According to Wikipedia:

a weak symbol is a symbol definition in an object file or dynamic library that may be overridden by other symbol definitions

In what scenarios or for what applications do you need weak symbols? What are typical use cases?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Bernhard Kausler
  • 5,119
  • 3
  • 32
  • 36

5 Answers5

24

In embedded development, when you have for instance a vector of interrupt pointers, it's very handy to be able to use weak linking to get default handlers for interrupts you're not interested in.

This works by defining an empty handler (once), then introducing one new properly-named symbol for each interrupt pointer that you need, which is weakly linked to the default handler.

The vector is then filled with these symbols, which will all point at the same actual code, until you decide to implement one of them using the same (proper) name, then your code "overpowers" the weak link, causing a pointer to your code to be installed in the interrupt table.

This is often implemented in some mixture of C and assembly, but using C pseudocode we might have something like:

static void placeholder_isr(void)
{
}

/* Introduce properly-named function pointers, with weak linking.
 * NOTE: This syntax is completely fictional as far as I know.
*/
void (*timer1_isr)() = placeholder_isr __attribute("weak linking");
void (*timer2_isr)() = placeholder_isr __attribute("weak linking");
void (*usart1_isr)() = placeholder_isr __attribute("weak linking");
void (*usart2_isr)() = placeholder_isr __attribute("weak linking");
void (*dma1_isr)() = placeholder_isr __attribute("weak linking");
void (*dma1_isr)() = placeholder_isr __attribute("weak linking");

/* Declare the table of interrupt handlers. */
static void (*isr_table)[] = {
  timer1_isr,
  timer2_isr,
  usart1_isr,
  usart2_isr,
  dma1_isr,
  dma2_isr,
} __attribute("isr vector"); /* Attribute to place it where it needs to go. */

Then you can just implement your own function when needed:

void timer1_isr(void)
{
  /* Handler ISR from timer1. */
}

without having to change anything else, it "just works". As long as your name is the one that the above "support code" expects, of course.

unwind
  • 391,730
  • 64
  • 469
  • 606
23

One use of weak linking is implementing the replaceable functions in the C++ standard. Namely:

void *operator new(std::size_t);
void *operator new(std::size_t, std::nothrow_t const &) noexcept;
void *operator new[](std::size_t);
void *operator new[](std::size_t, const std::nothrow_t&) noexcept;
void operator delete(void *) noexcept;
void operator delete(void *, std::nothrow_t const &) noexcept;
void operator delete[](void *) noexcept;
void operator delete[](void *, std::nothrow_t const &) noexcept;

These are functions which must be provided by the implementation, but if a program implements them then the program's implementation replaces or overrides the implementation's version. This is easily implemented via weak linkage.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • 1
    @BernhardKausler provides some related SO questions that might give more insight: [Why would one replace default new and delete operators?](http://stackoverflow.com/questions/7149461/why-would-one-replace-default-new-and-delete-operators) [How to properly replace global new & delete operators](http://stackoverflow.com/questions/8186018/how-to-properly-replace-global-new-delete-operators) [How should I write ISO C++ Standard conformant custom new and delete operators?](http://stackoverflow.com/questions/7194127/how-should-i-write-iso-c-standard-conformant-custom-new-and-delete-operators) – bames53 Mar 21 '13 at 15:03
9

The typical and every day use case is inline and template functions.

For example this part of code when compiled with g++ -shared -fPIC:

extern void a();

inline void foo() { a(); }

void bar() { foo(); }
void baz() { foo(); }

Would have symbols bar and baz marked as T (normal) by nm and foo would be marked as W - weak.

(i.e. mn -C ./a.out)

Rationale:

inline functions and templates may be defined in headers and usually defined multiple times in different parts of sources and finally only one remains active.

If it would be not marked as Weak it would be collision of multiple "foo" symbols or the compiler would not be able to disable inlining

mtk
  • 542
  • 5
  • 9
Artyom
  • 31,019
  • 21
  • 127
  • 215
7

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.

The weak attribute example:

weak.c

extern void foo() __attribute__((weak));

int main() {
if (foo) foo();
} 

foo.c

void foo() {
printf("in foo.\n");
} 

strong.c

extern void foo() ;

int main() {
if (foo) foo();
} 

Compiling

$ cc weak.c // Compiles OK
$ cc strong.c // undefined reference to `foo'

When the "foo" is declared to be weak, its definition can be omitted, or replaced by different libraries, featuring kind of "link-time binding". The linker will fill in 0 for undefined weak symbols.

masoud
  • 55,379
  • 16
  • 141
  • 208
5

You generally use weak linking when you want to be able to override a function definition in another part of your code. This is typically the case in libraries that specify e.g. a default error handler that you can override with a custom function if you use the library.

fuz
  • 88,405
  • 25
  • 200
  • 352