对此有何救济措施?
GLIBC没有一种定义“#define USE_FCNTL_NOT_FCNTL64”的方法,这说明了很多问题。无论对错如何,大多数操作系统和工具链制造商似乎已经决定,从新版本的系统针对旧版本的二进制文件不是高优先级。
最简单的方法是保留一个虚拟机,用于构建项目的最旧版本的操作系统和工具链。每当您认为该二进制文件将在旧系统上运行时使用它来生成二进制文件。
但是...
如果您相信您的用途属于不受偏移量大小更改影响的fcntl() 调用子集(也就是说,您不使用字节范围锁定)
或者愿意审核代码以使用向后兼容的结构定义
并且不害怕巫术
...那么请继续阅读。
变量名不同,而fcntl是一种变参函数,没有接受va_list的vffcntl。在这种情况下,您无法转发变参函数的调用。
因此,要应用
提到的包装技巧,您必须逐行查看fcntl() 的接口文档,并解包变参函数,然后使用新的变参调用调用包装版本。
幸运的是,这不是一个很难的情况(fcntl函数需要0或1个参数,并有文档类型)。为了尝试帮助其他人节省一些麻烦,这里提供了相关代码。请确保将--wrap=fcntl64传递给链接器(如果不直接调用ld,则为-Wl,--wrap=fcntl64):
asm (".symver fcntl64, fcntl@GLIBC_2.2.5");
extern "C" int __wrap_fcntl64(int fd, int cmd, ...)
{
int result;
va_list va;
va_start(va, cmd);
switch (cmd) {
case F_GETFD: goto takes_void;
case F_SETFD: goto takes_int;
case F_GETFL: goto takes_void;
case F_SETFL: goto takes_int;
case F_SETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_SETLKW: goto takes_flock_ptr_INCOMPATIBLE;
case F_GETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_OFD_SETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_OFD_SETLKW: goto takes_flock_ptr_INCOMPATIBLE;
case F_OFD_GETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_GETOWN: goto takes_void;
case F_SETOWN: goto takes_int;
case F_GETOWN_EX: goto takes_f_owner_ex_ptr;
case F_SETOWN_EX: goto takes_f_owner_ex_ptr;
case F_GETSIG: goto takes_void;
case F_SETSIG: goto takes_int;
case F_SETLEASE: goto takes_int;
case F_GETLEASE: goto takes_void;
case F_NOTIFY: goto takes_int;
case F_SETPIPE_SZ: goto takes_int;
case F_GETPIPE_SZ: goto takes_void;
case F_ADD_SEALS: goto takes_int;
case F_GET_SEALS: goto takes_void;
case F_GET_RW_HINT: goto takes_uint64_t_ptr;
case F_SET_RW_HINT: goto takes_uint64_t_ptr;
case F_GET_FILE_RW_HINT: goto takes_uint64_t_ptr;
case F_SET_FILE_RW_HINT: goto takes_uint64_t_ptr;
default:
fprintf(stderr, "fcntl64 workaround got unknown F_XXX constant")
}
takes_void:
va_end(va);
return fcntl64(fd, cmd);
takes_int:
result = fcntl64(fd, cmd, va_arg(va, int));
va_end(va);
return result;
takes_flock_ptr_INCOMPATIBLE:
fprintf(stderr, "fcntl64 hack can't use glibc flock directly");
exit(1);
takes_f_owner_ex_ptr:
result = fcntl64(fd, cmd, va_arg(va, struct f_owner_ex*));
va_end(va);
return result;
takes_uint64_t_ptr:
result = fcntl64(fd, cmd, va_arg(va, uint64_t*));
va_end(va);
return result;
}
请注意,根据实际构建的版本,如果它们不可用,则可能必须#ifdef掉其中一些标志部分。
这影响相当多的应用程序... fcntl()的手册页面显示它是小宇宙子函数的入口点
...这应该对人们来说是一个教训:避免通过变参滥用创建这样的“厨房水槽”函数。