MinGW下C++链接pe-parse库报undefined reference错误如何解决
问题背景
开发PE加壳工具需要PE文件解析能力,选择使用C++ pe-parse库,按照官方指引完成库编译构建后,尝试将其链接到简单测试文件时出现链接错误。
测试代码src/main.cpp内容如下:
#include <pe-parse/parse.h> int main(int ac, char **av) { peparse::parsed_pe *p = peparse::ParsePEFromFile(av[0]); return 0; }
项目目录结构:
. ├── src │ main.cpp ├── lib │ pe-parse.lib ├── bin │ pe-parse.dll └── include └ pe-parse nt-headers.h parse.h to_string.h
环境信息:
- 使用x64版本MinGW,标识为
x86_64-w64-mingw32 - 构建得到的
pe-parse.dll与pe-parse.lib均为pei-x86-64架构,架构匹配
执行的编译命令:
g++ -Wall -Wextra .\src\main.cpp -I.\include\ -L.\bin\ -lpe-parse
报错信息:
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\gz\AppData\Local\Temp\ccxml3rK.o:packer.cpp:(.text+0x1f): undefined reference to `peparse::ParsePEFromFile(char const*)' collect2.exe: error: ld returned 1 exit status
已排查情况:
- 用
nm工具查看pe-parse.lib可检索到目标符号,pe-parse.dll中未查询到对应符号 - 尝试将编译参数中的
-L.\bin\替换为-L.\lib\,问题仍然存在 - 判断
pe-parse.lib是对应DLL的导入库,需要配合DLL完成链接,但始终未找到正确的链接配置方式
根因分析
该问题核心是ABI与库格式不兼容:
- 你持有的
pe-parse.lib大概率是MSVC编译器生成的导入库,MinGW的GCC链接器无法直接兼容MSVC格式的C符号修饰规则——MSVC和GCC的C符号名修饰规则完全不同,即使CPU架构一致,链接器也无法识别匹配对应符号。 - 你在DLL中未查询到对应符号,说明编译pe-parse时要么没有正确配置符号导出规则,要么查询DLL导出符号的工具/方式不对。
解决方案
按优先级选择以下任意一种方案即可:
方案1:用当前MinGW环境重新编译pe-parse(最稳定,推荐)
不要使用MSVC编译产出的.lib和.dll,直接用项目当前使用的同版本MinGW编译pe-parse,从根源消除ABI不兼容问题:
- 进入pe-parse源码目录,在MinGW终端下执行cmake构建,开启动态库编译:
cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON cmake --build build - 构建完成后,将产出文件按原有目录结构放置:
- 头文件放入
include/pe-parse/目录 - MinGW格式导入库
libpe-parse.dll.a放入lib/目录(注意不是MSVC格式的.lib文件) - 动态库
pe-parse.dll放入bin/目录
- 头文件放入
- 调整编译命令,指定正确的链接路径:
注意:MinGW链接时会自动识别带g++ -Wall -Wextra .\src\main.cpp -I.\include -L.\lib -lpe-parselib前缀的库文件,-lpe-parse参数会自动匹配libpe-parse.dll.a,不需要手动写全库文件名 - 编译完成后,将
bin目录下的pe-parse.dll放到生成的可执行文件同目录即可正常运行。
方案2:基于现有DLL手动生成MinGW兼容导入库
如果不想重新编译pe-parse,可以基于已有的DLL生成MinGW可用的导入库:
- 先确认DLL确实导出了目标符号,执行
objdump -p pe-parse.dll | grep ParsePEFromFile查看,如果能查到导出记录再执行后续步骤;如果查不到,说明原有DLL编译本身存在问题,必须重新编译库。 - 生成DLL对应的导出定义文件:
执行后会在当前目录生成gendef pe-parse.dllpe-parse.def文件,记录DLL所有导出符号。 - 基于def文件生成MinGW格式的导入库:
dlltool -d pe-parse.def -l libpe-parse.dll.a - 将生成的
libpe-parse.dll.a放到lib/目录,使用方案1中的编译命令重新编译即可。
方案3:静态链接pe-parse
如果不想额外携带DLL依赖,可以编译静态版本的pe-parse:编译时将cmake参数BUILD_SHARED_LIBS设为OFF,构建完成后会生成libpe-parse.a静态库,链接时直接指定该静态库路径即可,运行时不需要依赖DLL。
注意事项
- 禁止混用MSVC和MinGW编译的C++动态/静态库,二者除了符号修饰规则不兼容,对象内存布局、异常处理逻辑也存在差异,即使勉强链接成功,运行时也大概率出现崩溃问题。
- 注意GCC链接参数顺序:库链接参数
-lpe-parse要放在源文件参数之后,GCC链接器按从左到右顺序解析符号,库参数放前面会出现符号解析失败的问题。
内容的提问来源于stack exchange,提问作者gz6876
相关产品推荐
相关产品推荐

