使用ld的--wrap参数包装close、stat等C标准文件函数失败如何解决
问题原因
你遇到的问题是GNU C库(glibc)的文件类API特殊封装机制导致的:
- socket、send这类网络函数在glibc中是直接导出的独立符号,编译时不会做隐式替换,因此你直接对函数名做
--wrap即可生效。 - 而open、close、stat、fstat这类文件操作函数,glibc默认开启了大文件支持(LFS),编译阶段会通过头文件的宏定义,把代码中写的
fstat自动替换为fstat64或者内部实现符号_fxstat,最终二进制里根本没有对fstat符号的引用,所以你针对fstat的wrap配置自然无法命中。你在GDB中看到的调用路径fstat() → fstat64() → _fxstat()也正好验证了这一点。
解决方法
方法1:直接wrap二进制中实际引用的符号
这是兼容性最好、不影响业务功能的方案:
- 先确认你的二进制中实际调用的文件类函数符号名,你可以用
nm 目标文件或者objdump -x 目标文件 | grep 函数名查看,从你给出的GDB日志来看,你需要额外wrap的符号包括fstat64、_fxstat、open64、__xstat,如果close也出现同样问题就同理新增对应符号。 - 修改你的LDFLAGS,新增对应的wrap参数:
LDFLAGS="-Wl,--wrap=socket,--wrap=bind,--wrap=accept,--wrap=send,--wrap=recv,--wrap=select,--wrap=close,--wrap=stat,--wrap=fstat,--wrap=fstat64,--wrap=_fxstat,--wrap=open64,--wrap=__xstat -static-libgcc -L/path/to/my/wrap/library"
- 编写对应符号的包装函数,注意要匹配glibc内部函数的原型,比如
_fxstat的原型多了一个版本号参数:
// 原来的fstat包装可以保留,建议补充对应64位和内部符号的包装 int __wrap_fstat(int fd, struct stat *statbuf) { return 0; } int __wrap_fstat64(int fd, struct stat64 *statbuf) { return 0; } int __wrap__fxstat(int ver, int fd, struct stat *statbuf) { return 0; }
方法2:关闭glibc的大文件支持
如果你不需要处理超过2G的大文件,可以在编译参数中加入宏定义关闭LFS,让glibc不做函数名隐式替换:
修改你的CFLAGS,新增-D_FILE_OFFSET_BITS=32:
CFLAGS="-g --static -D_FILE_OFFSET_BITS=32"
这种方案不需要修改wrap配置和包装函数,原来针对fstat、open的wrap即可直接生效,但要注意业务是否依赖大文件操作能力。
内容的提问来源于stack exchange,提问作者ballsmahoney
相关产品推荐
相关产品推荐

