如何强制链接到较早的libc fcntl而不是fcntl64`?

问题描述 投票:2回答:2

[似乎GLIBC 2.28 (released August 2018)对fcntl进行了相当激进的更改。 <fcntl.h>中的定义已更改为不再是but a #define to fcntl64的外部函数。

结果是,如果您使用此glibc在系统上编译代码-如果它使用fcntl()完全-生成的二进制文件将不会在2018年8月之前在系统上执行。各种各样的应用... fcntl()的手册页显示,这是一小部分子功能的入口:

#define

如果您可以告诉链接器您想要的GLIBC函数的特定版本,那将很好。但是我发现最接近的是在另一篇文章的答案中描述的这个技巧:

https://linux.die.net/man/2/fcntl

这有点复杂。 Answer to "Linking against older symbol version in a .so file"是可变参数的,没有带va_list的fcntl。在这种情况下vffcntl。 :-(

[如果一个程序具有稳定的代码且具有较低的依赖关系,那么就可以将其构建在当前的Ubuntu上了……然后让可执行文件拒绝在仅一年前(即一天)发布的另一个Ubuntu上运行。一个人有什么追索权?

c ld variadic-functions glibc fcntl
2个回答
1
投票

名称不同,并且fcntl是可变参数,而没有带va_list的vffcntl。在这种情况下,您将无法转发可变参数函数的调用。

因此,要应用you cannot forward an invocation of a variadic function,您必须逐行浏览fcntl()的接口文档,解压缩可变参数,然后使用新的可变参数调用来调用包装的版本。

幸运的是,这种情况并不难(fcntl接受0或1个文档类型的参数)。为了避免给其他人带来麻烦,请使用以下代码。确保将-wrap = fcntl64传递给链接器(如果不直接调用ld,则传递给-Wl,-wrap = fcntl64):

the wrapping trick mentioned

请注意,根据您实际构建的版本,如果其中某些标志段不可用,则可能必须#ifdef。

这会影响各种各样的应用程序... fcntl()的手册页显示它是一小部分子功能的入口点

...这应该是对人们的一个教训:避免通过各种各样的滥用来创建这样的“厨房水槽”功能。

一个人有什么追索权?

[GLIBC无法实现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) { // // File descriptor flags // case F_GETFD: goto takes_void; case F_SETFD: goto takes_int; // File status flags // case F_GETFL: goto takes_void; case F_SETFL: goto takes_int; // File byte range locking, not held across fork() or clone() // case F_SETLK: goto takes_flock_ptr; case F_SETLKW: goto takes_flock_ptr; case F_GETLK: goto takes_flock_ptr; // File byte range locking, held across fork()/clone() -- Not POSIX // case F_OFD_SETLK: goto takes_flock_ptr; case F_OFD_SETLKW: goto takes_flock_ptr; case F_OFD_GETLK: goto takes_flock_ptr; // Managing I/O availability signals // 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; // Notified when process tries to open or truncate file (Linux 2.4+) // case F_SETLEASE: goto takes_int; case F_GETLEASE: goto takes_void; // File and directory change notification // case F_NOTIFY: goto takes_int; // Changing pipe capacity (Linux 2.6.35+) // case F_SETPIPE_SZ: goto takes_int; case F_GETPIPE_SZ: goto takes_void; // File sealing (Linux 3.17+) // case F_ADD_SEALS: goto takes_int; case F_GET_SEALS: goto takes_void; // File read/write hints (Linux 4.13+) // 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: result = fcntl64(fd, cmd, va_arg(va, struct flock*)); va_end(va); return result; 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; } 的事实说明了很多。不管是对是错,大多数OS +工具链制造商似乎已经决定,从较新的版本开始针对其系统旧版本的二进制文件并不是优先考虑的事情。

另一个替代方法-在其他线程上也提到过-是使虚拟机位于用于构建项目的最旧的OS +工具链附近。只要您认为二进制文件将在旧系统上运行,就可以使用该文件来生成二进制文件。


0
投票

如何强制链接到较早的libc #define USE_FCNTL_NOT_FCNTL64而不是fcntl

© www.soinside.com 2019 - 2024. All rights reserved.