Как принудительно установить связь с более старой libc `fcntl` вместо` fcntl64`? - PullRequest
6 голосов
/ 20 октября 2019

Кажется, GLIBC 2.28 (выпущен в августе 2018 г.) сделал довольно агрессивное изменение в fcntl. Определение было изменено в <fcntl.h>, чтобы больше не быть внешней функцией, , а #define в fcntl64 .

В результате вы компилируете свой код в системе с этимglibc - если он вообще использует fcntl () - результирующий двоичный файл не будет выполняться в системе до августа 2018 года. Это влияет на самые разные приложения ... страница руководства по fcntl ()показывает, что это точка входа для небольшого множества подфункций:

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

Было бы хорошо, если бы вы могли сообщить компоновщику, какую конкретную версию функции GLIBC вы хотели. Но самым близким, что я нашел, был этот трюк, описанный в ответе на другой пост:

Ответ на «Связывание со старой версией символа в файле .so»

Этонемного сложнее. fcntl - это переменная без vffcntl, который принимает va_list. В таких ситуациях вы не можете переслать вызов функции с переменным числом . : - (

Когда у кого-то есть стабильный код с преднамеренно низкими зависимостями, это пустяк для его сборки на текущей Ubuntu ... тогда и когда исполняемый файл отказывается запускаться на другой Ubuntu, выпущенной только годом ранее(почти до дня). Какие средства есть для этого?

Ответы [ 2 ]

4 голосов
/ 20 октября 2019

Какие средства есть для этого?

Тот факт, что у GLIBC не было пути к #define USE_FCNTL_NOT_FCNTL64, говорит о многом. Правильно это или нет, большинство создателей наборов инструментов OS +, похоже, решили, что нацеливание бинарных файлов для более старых версий их систем с более новой не является высокоприоритетным. машина вокруг самой старой OS + toolchain, которая строит ваш проект. Используйте это, чтобы создавать двоичные файлы всякий раз, когда вы думаете, что двоичный файл будет работать в старой системе.

Но ...

  • Если вы считаете, что ваши использования находятся в подмножестве fcntl ()вызовы, на которые не влияет изменение размера смещения (то есть вы не используете блокировки диапазона байтов)
  • ИЛИ готовы проверить ваш код на случаи смещения для использования обратно-совместимого определения структуры
  • И не боятся вуду

... тогда продолжайте читать.

Имя отличается, и fcntl является вариативным без vffcntl, который принимаетva_list. В таких ситуациях вы не можете переслать вызов функции с переменными значениями.

... затем, чтобы применить упомянутый трюк обёртывания , вы должны проходить построчно через fcntl() в документации по интерфейсу, распакуйте variadic, как это было бы, и затем вызовите упакованную версию с новым вызовом variadic.

К счастью, это не так уж сложно (fcntl принимает 0 или 1 аргумент с документированными типами),Чтобы попытаться спасти кого-то еще, вот код для этого. Обязательно передайте компоновщик - wrap = fcntl64 ( -Wl, - wrap = fcntl64 , если не вызываете ld напрямую):

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 () показывает, что это точка входа для небольшой вселенной подфункций

... и это, вероятно, должно быть уроком для людей: избегайте создания таких функций "кухонной раковины"через вариадное насилие.

2 голосов
/ 20 октября 2019

Как принудительно установить связь со старой библиотекой fcntl вместо fcntl64?

Компилировать со старой версией libc. Period.

Поскольку glibc не совместим с последующими версиями , он только обратно совместим :

Библиотека GNU C разработана длябыть обратно совместимой , переносимой и высокопроизводительной библиотекой ISO C. Он направлен на соблюдение всех соответствующих стандартов, включая ISO C11, POSIX.1-2008 и IEEE 754-2008.

Без каких-либо гарантий прямой совместимости, вы не знаете, что еще выигралоне работает должным образом .

...