我正在尝试使用dlopen和dlsym动态加载统计信息功能。stat系列的功能包装在相应的功能__xstat
,__xstat64
中。
按照以下代码片段,在以32位模式编译时可以编译并工作(出于示例目的,包含sys/stat.h
以获取统计信息结构)
#include <iostream>
#include <dlfcn.h>
#include <sys/stat.h>
typedef int (*xstat_f) (int __ver, const char *__filename, struct stat *__stat_buf);
int main()
{
auto* h = dlopen("libc.so.6", RTLD_LAZY);
if(!h)
{
return 1; // invalid handle
}
auto f = (xstat_f)dlsym(h, "__xstat");
if(!f)
{
return 1; // invalid handle
}
struct stat s = {};
const auto r = f(3, "/tmp", &s);
if (r != 0)
{
perror("stat");
return errno;
}
return 0;
}
g++ main.cpp -o main -ldl -m32
在64位计算机上没有-m32
开关的可执行文件编译,将返回EINVAL(无效参数)。
原因是什么?
还进行了最低限度的测试
#include <iostream>
#include <sys/stat.h>
int main(){
struct stat s;
const auto x = stat("/tmp", &s);
if(x != 0) return errno;
return 0;
}
并在32位和64位可执行文件上使用objdump -T
,都显示stat
被解析为__xstat
,因此我使用的是正确的符号。我也尝试过__xstat/__xstat64
,struct stat/stat64
的组合,结果相同。
__ xstat声明如下:
int __xstat(int ver, const char *path, (struct stat *stat_buf))
在文档参数ver中的描述类似于ver shall be 3 or the behavior of these functions is undefined
,这并不完全正确,因为在源代码中,_STAT_VER_LINUX
的定义如下:
#ifndef __x86_64__
# define _STAT_VER_LINUX 3
#else
# define _STAT_VER_LINUX 1
#endif
这就是为什么对64位的__xstat
调用失败的原因,应该将参数ver
设置为1,而将32位编译的参数设置为3。