Могут ли 32-разрядные исполняемые файлы LINUX 2.6 надежно работать на машинах с LINUX 3.2?

Предполагая, что 32-битная поддержка была загружена в данную 64-битную установку LINUX:

  • Может ли 32-разрядный исполняемый файл LINUX 2.6 надежно работать на машинах с LINUX 3.2? (да, перефразируя название) Очевидно, нет!

  • Какие ограничения накладываются на 32-битные программы (с точки зрения каких программ, а не с точки зрения ограничений 4 ГБ и т. д.)?

  • Есть ли конкретный маркерный файл, исполняемый файл, системный вызов, который можно проверить, чтобы определить это заранее, чтобы скрипт мог сообщить пользователю, что система настроена неправильно? Затем я мог бы написать сценарий, скажем, «canirunhere», который мог бы сделать это очевидным для пользователя, а не просто получить какой-то причудливый сбой FLOATING POINT EXCEPTION.

    • Trying to run the program (within the script) and see if it crashes is not an option, as the program could just be doing a divide-by-zero!

Предыстория:

У меня есть 32-битная бинарная сборка для 2.6 LINUX, которая демонстрирует классическую трассировку стека несовместимости (см. ниже). Он работает на НЕКОТОРЫХ машинах, таких как x86_64 Linux 3.2 (в данном случае 3.2.0-8), но не на других, таких как AMD64 Linux 3.2 (в данном случае 3.2.44-3).

Необходимая информация:

Программа умирает в самом динамическом загрузчике. Вот биты информации «file» и «uname -a»:

Файл:
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), not stripped

НЕфункциональная система:
3.2.44-3.2.0.3.1-amd64-10846333 #1 SMP Wed May 29 13:08:01 UTC 2013 x86_64 GNU/Linux

ФУНКЦИОНАЛЬНАЯ система, x86_64 VM под управлением Ubuntu:
3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 17:37:58 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Обратите внимание, что система Ubuntu изначально не поддерживала 32-разрядные программы, поэтому Мне пришлось следовать инструкциям по ссылке (теперь, к сожалению, мертвой) в этом предыдущем вопросе. (нажмите здесь) Я не могу выполнить ту же задачу на неработающей машине, хотя отсутствие ошибки "файл не найден" означает, что 32-битная поддержка теоретически есть.

Трассировка стека:
Program received signal SIGFPE, Arithmetic exception. 0xf7feb876 in do_lookup_x () from /lib/ld-linux.so.2 (gdb) where #0 0xf7feb876 in do_lookup_x () from /lib/ld-linux.so.2 #1 0xf7febc07 in _dl_lookup_symbol_x () from /lib/ld-linux.so.2 #2 0xf7fed251 in _dl_relocate_object () from /lib/ld-linux.so.2 #3 0xf7fe7108 in dl_main () from /lib/ld-linux.so.2 #4 0xf7ff58f1 in _dl_sysdep_start () from /lib/ld-linux.so.2 #5 0xf7fe3c33 in _dl_start () from /lib/ld-linux.so.2 #6 0xf7fe3817 in _start () from /lib/ld-linux.so.2

Вывод strace: по предложению респондента, вот вывод strace (это не та же самая программа, поэтому адреса будут немного отличаться), что подтверждает, что она находится в динамической загрузке, надеюсь, поможет сузить причину.

strace ./porgram execve("./program", ["./program"...], [/* 63 vars */]) = 0 brk(0) = 0x80ea000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf77c5000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=47552, ...}) = 0 mmap2(NULL, 47552, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf77b9000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\222"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1265332, ...}) = 0 mmap2(NULL, 1275268, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7681000 mmap2(0xf77b2000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x130) = 0xf77b2000 mmap2(0xf77b6000, 9604, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf77b6000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7680000 set_thread_area({entry_number:-1 -> 12, base_addr:0xf76806b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 --- SIGFPE (Floating point exception) @ 0 (0) ---


person Mark Gerolimatos    schedule 13.03.2014    source источник
comment
Попробуйте strace казнить.   -  person Basile Starynkevitch    schedule 14.03.2014
comment
Спасибо за предложение, это слишком большой результат, чтобы разместить его здесь, мы добавим его к информации выше.   -  person Mark Gerolimatos    schedule 14.03.2014
comment
Марк Джеролиматос, можешь ли ты запустить ldd для своего 32-битного двоичного файла? Какой была старая 32-битная Linux (какая версия Ubuntu)? Вы должны использовать статически связанное программное обеспечение, если более новые 64-разрядные версии Linux не имеют той же версии 32-разрядной glibc...   -  person osgx    schedule 14.03.2014


Ответы (2)


Предполагая, что 32-битная поддержка была загружена в данную 64-битную установку LINUX

В основном да, ядро ​​должно поддерживать старые бинарные файлы, но в вашем случае программа была скомпонована динамически, поэтому ей нужна конкретная версия glibc и всех других динамических библиотек.

Вы можете попробовать распаковать полный старый 32-битный дистрибутив в какую-нибудь подпапку, затем сделать chroot в нее, а затем запустить свою программу внутри chroot.

Кроме того, проверьте ldd вывод вашего бинарника (это может не сработать, если бинарник был собран с очень старой glibc, потому что есть программа ld.so aka ld-linux.so.2 для загрузки динамических бинарников и реализации ldd).

Был один пример SIGFPE в do_lookup_x (вы можете найти его в Google: SIGFPE, арифметическое исключение. do_lookup_x):

Исключение с плавающей запятой (SIGFPE) в 'int main(){ return(0); }' @ stackoverflow.com

Поддержка секции хеширования GNU была добавлена ​​в glibc примерно в 2006 году, а основные дистрибутивы начали использовать только хэш GNU примерно в 2007 или 2008 году. Glibc вашего Centrino датируется 2003 годом, что предшествует хэшированию GNU.

Если ld.so не понимает хэш GNU, он попытается вместо этого использовать старый раздел хэша ELF, который пуст. В частности, я подозреваю, что ваш сбой происходит в этой строке в elf/do-lookup.h:

 for (symidx = map->l_buckets[hash % map->l_nbuckets];

Поскольку компоновщик, по-видимому, не понимает хэши GNU, l_nbuckets будет равен 0, что приведет к сбою.

Таким образом, ваш FPE может возникнуть из-за той же несовместимости между glibc в более старых 32-разрядных версиях Linux и 32-разрядной glibc в некоторых более новых дистрибутивах.

person osgx    schedule 14.03.2014
comment
readelf покажет вам внутренности динамически подключаемой программы без ld.so из того же glibc. - person osgx; 14.03.2014
comment
Спасибо вам за отличную информацию! Все еще прохожу через это. По иронии судьбы, readelf была программой, которую я запускал для создания трассировки стека (очевидно, кросс-компилированная версия :) ) - person Mark Gerolimatos; 14.03.2014
comment
В вашем вопросе трассировка стека взята из gdb. objdump — это другая программа от binutils для проверки внутренностей ELF. - person osgx; 14.03.2014
comment
Нет, я имел в виду, что сгенерировал трассировку стека, запустив 32-битную версию READELF в GDB :-) - person Mark Gerolimatos; 14.03.2014
comment
Этот ответ правильно угадывает причину FPE, но не то, что с этим делать. Для этого вы также можете прочитать мой ответ. - person Employed Russian; 16.03.2014
comment
Занятый русский, Есть небольшая задача: найти правильный 32-битный дистрибутив, распаковать его и запустить программу в chroot. Это вариант, когда целевое приложение трудно пересобрать (например, без исходников). - person osgx; 16.03.2014

Как правильно указано в другом ответе, ваша проблема не имеет ничего общего с версиями ядра.

Скорее всего, glibc на вашей целевой (нефункциональной) машине слишком стар.

Обычно результат сборки на более новой системе glibc и запуска на более старой приводит к ошибке динамического компоновщика GLIBC_2.x version not found (required by ...), но в этом случае происходит сбой еще до того, как вы дойдете до этой точки.

Теперь, если вы сможете пересобрать приложение с помощью -Wl,--hash-style=sysv, вы решите проблему SIGFPE и в итоге получите либо работающее приложение (что маловероятно), либо ошибку GLIBC_2.x not found (весьма вероятно).

Этот ответ показывает, как это можно обойти.

Примечание: большинство систем UNIX поддерживают обратную совместимость (старые бинарные файлы продолжают работать в более новых системах), но не прямую совместимость (бинарные файлы, созданные на более новых машинах, работают на более старых).

person Employed Russian    schedule 16.03.2014
comment
Большое спасибо за информацию. Вывод LDD действительно показывает, что libc программы выше, чем libc, работающей на неисправной машине. - person Mark Gerolimatos; 18.03.2014