【问题标题】:What are practical applications of weak linking?弱链接的实际应用是什么?
【发布时间】:2013-03-09 15:57:27
【问题描述】:

使用特殊的编译器命令可以声明符号According to Wikipedia:

弱符号是目标文件或动态库中的符号定义,可能会被其他符号定义覆盖

在哪些场景或哪些应用中需要弱符号?有哪些典型用例?

【问题讨论】:

标签: c++ c linker


【解决方案1】:

在嵌入式开发中,例如,当您有一个中断指针向量时,能够使用弱链接为您不感兴趣的中断获取默认处理程序非常方便。

这通过定义一个空处理程序(一次),然后为您需要的每个中断指针引入一个新的正确命名的符号来工作,它与默认处理程序弱链接。

然后用这些符号填充向量,这些符号都指向相同的实际代码,直到您决定使用相同(正确)名称实现其中一个,然后您的代码“压倒”弱链接,导致指向要安装在中断表中的代码的指针。

这通常是在 C 和汇编的混合中实现的,但是使用 C 伪代码我们可能会有类似的东西:

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. */

然后你可以在需要的时候实现你自己的功能:

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

无需更改任何其他内容,它“就可以正常工作”。当然,只要您的名字是上述“支持代码”所期望的名字。

【讨论】:

    【解决方案2】:

    弱链接的一个用途是在 C++ 标准中实现 可替换 函数。即:

    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;
    

    这些是必须由实现提供的功能,但如果程序实现了它们,那么程序的实现将替换或覆盖实现的版本。这很容易通过弱链接实现。

    【解决方案3】:

    典型的日常用例是内联和模板函数。

    例如使用g++ -shared -fPIC编译时的这部分代码:

    extern void a();
    
    inline void foo() { a(); }
    
    void bar() { foo(); }
    void baz() { foo(); }
    

    符号 bar 和 baz 将被 nm 标记为 T(正常),而 foo 将被标记为 W - 弱。

    (即mn -C ./a.out

    理由:

    内联函数和模板可以在标题中定义,通常在源的不同部分定义多次,最后只有一个保持活动状态。

    如果它没有被标记为 Weak,那么它将是多个“foo”符号的冲突,或者编译器将无法禁用内联

    【讨论】:

    • 因此,大多数模板函数也会很弱。
    • @MatthieuM。确实,添加到答案中
    【解决方案4】:

    The weak 属性导致声明作为弱声明发出 符号而不是全局。这主要用于定义 可以在用户代码中覆盖的库函数,尽管它可以 也可用于非函数声明。弱符号是 支持 ELF 目标,并且在使用 GNU 汇编器和链接器。

    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();
    } 
    

    编译

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

    当“foo”被声明为弱时,它的定义可以省略, 或被不同的库取代,具有“链接时间 binding"。链接器将为未定义的弱符号填充 0。

    【讨论】:

      【解决方案5】:

      当您希望能够覆盖代码的另一部分中的函数定义时,通常会使用弱链接。这通常是指定例如的库中的情况。如果您使用该库,则可以使用自定义函数覆盖默认错误处理程序。

      【讨论】:

        猜你喜欢
        • 2013-05-31
        • 1970-01-01
        • 2011-01-24
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        • 2011-12-07
        • 2014-09-12
        相关资源
        最近更新 更多