What are practical applications of weak linking?

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?


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.


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.


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.

链接地址: http://www.djcxy.com/p/73030.html

上一篇: 派生类中的成员new / delete重载有用吗?

下一篇: 弱链接的实际应用是什么?