【已解决】由于链接顺序引起的符号定位未找到问题

本文记录了一次因链接顺序不当导致的符号定位未找到问题。在使用CMake工具构建工程时,作者遇到了libsum.a中sum函数找不到libadd.a中add函数定义的情况。通过调整链接顺序,即将使用到符号的库放在前面,定义符号的库放在后面,成功解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于链接顺序引起的符号定位未找到问题


最近在将我们的工程切换到CMake工具构建,遇到了一个由于链接顺序引起的问题,当时没看出来原因,被困扰了几个小时,特此记录一下。

编译报错类似下面这样,提示在libsum.a库中sum函数找不到add的定义。

/usr/bin/ld: libsum.a(sum.o): in function `sum':
sum.c:(.text+0x1d): undefined reference to `add'
collect2: error: ld returned 1 exit status

怎么会没找到呢?我明明链接了libadd.a呀,难道库有问题。
通过nm命令查看libadd.a中的符号,如下。

add.o:
0000000000000000 T add

有add啊,但是符号值怎么是全0?没有写实现吗?
于是去看源文件,发现其实是有实现的。
那么问题出在哪里呢?

这时候一个声音响起,“会不会是链接顺序不对?”,真可谓一语惊醒梦中人。
马上把libsum.a和libadd.a的链接顺序对换,问题果然解决了。
(其实,当时没想起来这个原因,也是因为在切换CMake之前,这个链接顺序也能通过编译。很奇怪,还需要再深入看看。)

通过报错,基本就可以看出来了,在libsum.a中使用了libadd.a中的符号,那么链接时需要将libsum.a放前面,libadd.a放后面。

这个是由编译器决定的,对于gcc来说,libsum.a放前面,libadd.a放后面,当找不到libsum.a中的符号时,它会在后面的链接库中继续查找。

大家可以自己试试,这里提供源文件和编译命令。
add.h

#ifndef __ADD_H__
#define __ADD_H__

int add(int a, int b);

#endif

add.c

#include "add.h"

int add(int a, int b) {
    return a + b;
}

sum.h

#ifndef __SUM_H__
#define __SUM_H__

int sum(int a, int b);

#endif

sum.c

#include "add.h"
#include "sum.h"

int sum(int a, int b) {
    return add(a, b);
}

main.c

#include "sum.h"
#include <stdio.h>

int main()
{
    int res = sum(2, 3);
    printf("the sum of 2 and 3 = %d\n", res);
    
    return 0;
}
  1. 首先生成add静态库
gcc -c add.c -o add.o
ar -rc libadd.a add.o
  1. 然后生成sum静态库
gcc -c sum.c -o sum.o
ar -rc libsum.a sum.o
  1. 编译main.c(链接顺序不对)
gcc main.c libadd.a libsum.a -o main
### 调用 DLL 时 “无法定位程序输入点于动态链接库” 的原因 当在 VS2019 中开发 C++ 应用并调用外部 DLL 文件时,“无法定位程序输入点于动态链接库”的错误通常表明应用程序尝试加载的函数或符号未存在于指定的 DLL 文件中。此问题可能由以下几个常见因素引起: - **不兼容版本**:使用的 DLL 版本与项目需求不符,可能导致某些函数不存在。 - **缺失依赖项**:目标 DLL 可能还依赖其他 DLL 或资源文件,而这些文件未能正确安装或配置[^1]。 - **导出表损坏**:如果 DLL 文件本身存在损坏或者其导出表被破坏,则可能会引发此类错误。 ### 解决方案概述 针对该类问题的具体解决措施如下所示: #### 方法一:验证 DLL 和项目的匹配性 确认所使用的 DLL 是否适用于当前平台架构 (如 x86 vs. x64),以及它是否支持正在运行的操作系统版本。此外还需核实该项目设置中的编译器选项(例如 /MD 或 /MT),以确保它们同 DLL 编译环境一致[^3]。 #### 方法二:检查是否存在必要的依赖关系 利用工具如 Dependency Walker 来扫描目标 DLL 并识别任何缺少的依赖项。一旦发现有丢失的依赖库,请下载相应组件并将它们放置到适当位置以便访问[^2]。 #### 方法三:重新生成或替换有问题的 DLL 如果有权限获取源码的话,建议重新构建所需的 DLL;如果没有办法获得最新版则考虑寻找官方发布的更新包来替代旧版本。 #### 方法四:调整加载顺序或其他高级技术 有时可以通过修改应用启动方式改变模块装载次序从而绕过冲突情况下的失败情形。另外也可以探索延迟载入等更复杂的编程技巧作为备选策略之一。 以下是通过代码实现的一个简单例子展示如何安全地加载 DLL: ```cpp #include <windows.h> #include <iostream> typedef void (*MyFunctionType)(); int main() { HMODULE hModule = LoadLibrary(L"path_to_your_dll.dll"); if (!hModule) { std::cerr << "Failed to load DLL." << std::endl; return EXIT_FAILURE; } MyFunctionType myFunction = reinterpret_cast<MyFunctionType>(GetProcAddress(hModule, "YourExportedFunctionName")); if (!myFunction) { FreeLibrary(hModule); std::cerr << "Could not find function in DLL." << std::endl; return EXIT_FAILURE; } // Call the loaded function. myFunction(); FreeLibrary(hModule); } ``` 上述示例展示了基本流程——先加载库再检索特定地址最后执行操作前释放资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wingrez

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值