【问题标题】:Silent symbol collision?无声符号碰撞?
【发布时间】:2021-06-14 09:30:01
【问题描述】:

之前在 Raspberry Stackexchange 上发过,因离题而关闭,所以我来了。

下面的程序用gcc main.c -lpigpio -lpthread -Wall -Wextra 编译干净。我使用的是 gcc 8.3.0(交叉编译器或普通编译器不会改变任何东西)。

// main.c
#include <stdio.h>
#include <pigpio.h>

void listen() {
        printf("hi from listen\n");
}

int main() {
        gpioInitialise();
        printf("hi from main\n");
        gpioTerminate();
        return 0;
}

没有警告,但程序会愉快地打印

hi from listen
hi from main

原因似乎是gpioInitialise() 试图从&lt;sys/sockets.h&gt; here 调用listen(2),而是从main.c 调用函数。当然,这不起作用并导致 pigpio 库中的错误消息:

xxxx-xx-xx xx:xx:xx pthSocketThread: setsockopt() fail, closing socket -1
xxxx-xx-xx xx:xx:xx pthSocketThread: accept failed (Bad file descriptor)

问题:为什么 gcc 链接一个具有完全不同签名的函数而不抛出任何错误?我知道static,但我想了解这一点并从中学习。肯定不会像listen(2) 不被声明为静态那么简单吧?

【问题讨论】:

  • 与 C++ 不同,外部 C 库中没有函数原型签名信息。

标签: c gcc static linker


【解决方案1】:

链接器允许您插入这样的符号以用于调试、分析等目的。不幸的是,在链接阶段,打字信息通常不可用,因此链接器无法执行任何健全性检查来验证预期和实际签名是否匹配。有人可能会争辩说,使用-g 这将是可能的,但没有人关心实现这一点(尽管这可能是一个不错的家庭项目)。

Static 会对您的情况有所帮助,因为它会阻止 listen 被导出并阻止 libc 的 listen 被覆盖。

附带说明,在 ELF 系统 (Linux) 上,情况变得更糟,因为它们允许运行时符号插入(即库在程序启动时竞争谁赢得符号名称)。这通常通过static-fvisiblity=hidden 解决(不幸的是许多库do not use them)。

【讨论】:

    猜你喜欢
    • 2022-01-19
    • 2014-09-21
    • 2016-06-01
    • 2016-09-29
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多