首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何强制连接到较老的libc ` `fcntl`‘而不是“fcntl64”?

如何强制连接到较老的libc ` `fcntl`‘而不是“fcntl64”?
EN

Stack Overflow用户
提问于 2019-10-20 12:23:54
回答 2查看 3.9K关注 0票数 14

GLIBC 2.28 (2018年8月发布)似乎对fcntl做了相当积极的修改。该定义在<fcntl.h>中被更改为不再是外部函数转到fcntl64

其结果是,如果您用这个glibc在一个系统上编译代码--如果它使用fcntl() --那么从2018年8月开始,生成的二进制文件将不会在系统上执行。这会影响到fcntl()的各种applications...the手册页面,显示它是一个小的子函数域的入口点:

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

如果你能告诉链接者你想要的GLIBC函数的具体版本,那就太好了。但我发现的最接近的方法是在对另一篇文章的回答中描述的这个技巧:

回答“链接到.so文件中的旧符号版本”

这有点复杂。fcntl是可变的,没有接受va_list的vffcntl。在这种情况下,不能转发对变量函数的调用。。:-(

如果一个人有稳定的代码,并且依赖度低,那么在当前的Ubuntu...then上构建它,并让可执行的代码拒绝在仅仅一年前发布的另一个Ubuntu上运行(几乎是一天),这是一种失败。一个人对此有什么追索权?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-20 12:23:54

一个人对此有什么追索权?

GLIBC没有办法实现#define USE_FCNTL_NOT_FCNTL64这一事实说明了很多问题。不管是对是错,大多数OS+toolchain制造商似乎都认为,将较旧版本的二进制文件与较新版本的二进制文件作为目标并不是一个高度优先事项。

最小阻力的途径是在构建项目的最古老的OS+toolchain周围保留一个虚拟机。每当您认为二进制文件将在旧系统上运行时,就使用它来生成二进制文件。

但是..。

  • 如果您认为您的用法位于fcntl()调用的子集中,则不受偏移量大小更改的影响(也就是说,您不使用字节范围锁)
  • 或者愿意检查代码中的偏移量情况,以使用向后兼容的结构定义。
  • 也不怕巫毒

...then继续阅读。

名称是不同的,fcntl是可变的,没有接受va_list的vffcntl。在这种情况下,您不能转发对变量函数的调用。

要应用...then,您必须逐行遍历fcntl()的接口文档,按原样解压变量,然后使用新的变量调用调用包装版本。

幸运的是,这不是那么困难的情况(fcntl使用0或1个有文档类型的参数)。为了给其他人省点麻烦,下面是代码。确保将--wrap=fcntl64传递给链接器(如果不直接调用ld,则为--Wl,--Wl=fcntl64):

代码语言:javascript
复制
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_INCOMPATIBLE;
      case F_SETLKW: goto takes_flock_ptr_INCOMPATIBLE;
      case F_GETLK: goto takes_flock_ptr_INCOMPATIBLE;

      // File byte range locking, held across fork()/clone() -- Not POSIX
      //
      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;

      // 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_INCOMPATIBLE:
    //
    // !!! This is the breaking case: the size of the flock
    // structure changed to accommodate larger files.  If you
    // need this, you'll have to define a compatibility struct
    // with the older glibc and make your own entry point using it,
    // then call fcntl64() with it directly (bear in mind that has
    // been remapped to the old fcntl())
    // 
    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()的各种applications...the手册页面,显示它是子函数的一个小宇宙的入口点。

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

票数 13
EN

Stack Overflow用户

发布于 2019-10-20 13:34:22

如何强制连接到较早的libc fcntl而不是fcntl64

针对较早版本的libc进行编译。句号。

因为glibc不是前向兼容,所以它只是向后兼容

GNU库设计为向后兼容的、可移植的和高性能的ISO库。它的目标是遵循所有相关标准,包括国际标准化组织C11、POSIX.1-2008和IEEE754-2008。

如果没有任何前向兼容性的保证,您就不知道还有什么不能正常工作。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58472958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档