我正在尝试使用一个旧程序(其中只有二进制文件可用),而在使用旧版本glibc的系统上工作时,该程序只会卡在Debian Buster的IO上。有人发现问题与通过https://sourceware.org/bugzilla/show_bug.cgi?id=1190
引入的glibc修复有关。我设法编译了带注释的修复程序的glibc,并使用该glibc运行程序使其正常工作。
系统的glibc显示了上述修订更改的两个功能,因此我认为可以用有效撤消该修订的自己的替换它们:
$ readelf -a /lib/x86_64-linux-gnu/libc.so.6 | grep underflow
1544: 000000000007ed60 86 FUNC GLOBAL DEFAULT 13 _IO_str_underflow@@GLIBC_2.2.5
1597: 0000000000074550 346 FUNC GLOBAL DEFAULT 13 __wunderflow@@GLIBC_2.2.5
1604: 00000000000753d0 1603 FUNC GLOBAL DEFAULT 13 _IO_wfile_underflow@@GLIBC_2.2.5
2152: 000000000007c520 705 FUNC GLOBAL DEFAULT 13 _IO_file_underflow@@GLIBC_2.2.5
2216: 000000000007d420 258 FUNC GLOBAL DEFAULT 13 __underflow@@GLIBC_2.2.5
我也设法用 gdb。
因此,我写了一个小的共享库来拦截已更改的功能。不幸的是,由于我的替换函数从未调用过,因此无法解决。作为测试,我以相同的方式为fread
和fwrite
添加了替换,并调用了那些。所以我的一般方法是有效的。
更多详细信息:
-该修复程序更改了glibc的_IO_new_file_underflow
和iolib/fileops.c
中的_IO_old_file_underflow
中的两个功能iolib/oldfileops.c
-我编写了两个替换函数,它们撤消了修复程序,然后调用原始函数:
int
_IO_new_file_underflow (FILE *fp)
{
int (*next)(FILE *fp) = dlsym(RTLD_NEXT, "_IO_new_file_underflow");
fprintf(stderr, "%s: called\n", __func__);
if (fp->_flags & _IO_EOF_SEEN)
fp->_flags &= ~_IO_EOF_SEEN;
return next(fp);
}
int
_IO_old_file_underflow (FILE *fp)
{
int (*next)(FILE *fp) = dlsym(RTLD_NEXT, "_IO_old_file_underflow");
fprintf(stderr, "%s: called\n", __func__);
if (fp->_flags & _IO_EOF_SEEN)
fp->_flags &= ~_IO_EOF_SEEN;
return next(fp);
}
gcc -o x.so -shared x.c -ldl -fPIC
LD_PRELOAD=/path/to/x.so faultyprogram
$ readelf -a x.so | grep underflow
8: 000000000000118a 117 FUNC GLOBAL DEFAULT 12 _IO_old_file_underflow
9: 0000000000001115 117 FUNC GLOBAL DEFAULT 12 _IO_new_file_underflow
47: 0000000000001115 117 FUNC GLOBAL DEFAULT 12 _IO_new_file_underflow
50: 000000000000118a 117 FUNC GLOBAL DEFAULT 12 _IO_old_file_underflow
与以上来自系统glibc的输出相反,我的版本缺少符号,因此我还通过链接器版本脚本添加了它们:
$ cat version
VERSION {
GLIBC_2.2.5 {
global: *;
};
$ gcc -o x.so -shared x.c -ldl -fPIC version
$ readelf -a x.so | grep underflow
8: 0000000000001115 117 FUNC GLOBAL DEFAULT 13 _IO_new_file_underflow@@GLIBC_2.2.5
9: 000000000000118a 117 FUNC GLOBAL DEFAULT 13 _IO_old_file_underflow@@GLIBC_2.2.5
48: 0000000000001115 117 FUNC GLOBAL DEFAULT 13 _IO_new_file_underflow
51: 000000000000118a 117 FUNC GLOBAL DEFAULT 13 _IO_old_file_underflow
但这也不起作用。
使用LD_DEBUG=all
在程序上运行ldd我可以看到很多符号,但是链接器没有解决有问题的两个符号。我猜这是因为它们在glibc中被视为某种私有函数。但是,如果是这样,那么为什么在libc.so.6中根本看不到这些符号?
我现在想知道我是否在这里遗漏了一些必要的东西,或者通常不可能实现对所讨论的两个功能的LD_PRELOAD替换。
更新:增加了gdb体验,修正了错字