Чи буде виконуваний Linux, зібраний на одному «ароматі» Linux, працювати на іншому?


59

Чи буде виконується невелика, надзвичайно проста програма, така як наведена нижче, що складається на одному ароматі Linux, з іншим смаком? Або його потрібно було б перекомпілювати?

Чи має значення архітектура машини у такому випадку?

int main()
{
  return (99);
}

2
Дякуємо всім за видатні відповіді! Я дізнався набагато більше, ніж передбачав. Я зробив код штучно простим, щоб він залежав від якомога меншої кількості бібліотек; але я справді мав це сказати на передовій. Більшість моїх кодувань на C ++ на різних платформах включали розробку за допомогою інструмента Microsoft, наприклад Visual Studio, а потім перенесення коду до * nix-системи та перекомпіляція.
JCDeen

4
Багато аспектів і міркувань, висловлених тут, мене вразили! Я щиро бажаю, щоб я міг вибрати декілька як відповідь. Ще раз дякую всім! З повагою.
JCDeen

2
Android також є операційною системою на базі Linux. Однак, пощастило, запустивши будь-який код, складений glibcтам, або навпаки. Зрозуміло, це не зовсім неможливо .
undercat

2
Для максимальної сумісності інструменту командного рядка ви можете використовувати uClibc, musl або dietlibc замість glibc і статично зв’язувати свій 32-розрядний виконуваний файл ( gcc -m32 -static). Роблячи це, будь-який i386 або amd64 Linux зможе запустити виконуваний файл.
пт

10
Вам слід повернутись 42 ! :)
Homunculus Reticulli

Відповіді:


49

Це залежить. Щось, складене для IA-32 (32-бітний Intel), може працювати на amd64, оскільки Linux для Intel зберігає зворотну сумісність із 32-бітними програмами (із встановленим відповідним програмним забезпеченням). Ось ваша codeкомпільована в 32-розрядна система RedHat 7.3 (близько 2002 р., Gcc версія 2,96), а потім двійковий файл скопійований на 64-бітну систему Centos 7.4 (близько 2017 року) та запуск її:

-bash-4.2$ file code
code: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.2.5, not stripped
-bash-4.2$ ./code
-bash: ./code: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
-bash-4.2$ sudo yum -y install glibc.i686
...
-bash-4.2$ ./code ; echo $?
99

Старовинні RedHat 7.3 до Centos 7.4 (фактично RedHat Enterprise Linux 7.4) залишаються в тій же «дистрибутивної» сім’ї, тому, швидше за все, матимуть кращу портативність, ніж переходити з якогось випадкового «Linux з нуля», встановленого з 2002 року, до якогось іншого випадкового дистрибутива Linux у 2018 році .

Щось компільоване для amd64 не працюватиме на 32-бітних випусках Linux (старе обладнання не знає про нове обладнання). Це справедливо і для нового програмного забезпечення, складеного в сучасних системах, призначених для роботи на старих старих речах, оскільки бібліотеки та навіть системні виклики можуть бути не портативними назад, тому можуть знадобитися хитрощі компіляції, або отримання старого компілятора тощо, або, можливо, замість цього складання за старою системою. (Це хороший привід для збереження віртуальних машин давніх давніх речей.)

Архітектура має значення; amd64 (або IA-32) сильно відрізняється від ARM або MIPS, тому бінарний з одного з них не очікується працювати на іншому. На рівні Аассамблеі mainчастина вашого коду на IA-32 компілює через gcc -S code.cдо

main:
    pushl %ebp
    movl %esp,%ebp
    movl $99,%eax
    popl %ebp
    ret

з якою може працювати система amd64 (в системі Linux - OpenBSD на відміну від amd64 не підтримує 32-бітні бінарні файли; зворотна сумісність із старими арками дає зловмисникам махнути кімнатою, наприклад, CVE-2014-8866 та друзями). Тим часом система MIPS з великим ендіаномmain замість цього компілює:

main:
        .frame  $fp,8,$31
        .mask   0x40000000,-4
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        addiu   $sp,$sp,-8
        sw      $fp,4($sp)
        move    $fp,$sp
        li      $2,99
        move    $sp,$fp
        lw      $fp,4($sp)
        addiu   $sp,$sp,8
        j       $31
        nop

який процесор Intel не матиме уявлення, що робити, і аналогічно для збірки Intel на MIPS.

Можливо, ви можете використовувати QEMU або інший емулятор для запуску іноземного коду (можливо, дуже, дуже повільно).

Однак! Ваш код дуже простий код, тому у вас буде менше проблем з переносом, ніж будь-що інше; програми, як правило, використовують бібліотеки, які змінювалися з часом (glibc, openssl, ...); для них може знадобитися також встановити старіші версії різних бібліотек (наприклад, RedHat зазвичай кладе "compat" десь у назві пакета для такої)

compat-glibc.x86_64                     1:2.12-4.el7.centos

або, можливо, переживайте про зміни ABI (бінарний інтерфейс програми) для старих речей, які використовують glibc, або останніх змін через C ++ 11 або інших C ++ випусків. Можна також компілювати статичні (значно збільшуючи бінарний розмір на диску), щоб спробувати уникнути проблем із бібліотекою, хоча від того, чи робив це якийсь старий бінарний файл, залежить від того, чи використовував старий дистрибутив Linux більшість всього динамічного (RedHat: так) чи ні. З іншого боку, такі речі patchelfможуть перенаправляти динамічні (ELF, але, мабуть, не a.outформатування) бінарні файли для використання інших бібліотек.

Однак! Вміти запускати програму - це одне, а насправді робити щось корисне з нею інше. У старих 32-розрядних бінарних файлів Intel можуть виникнути проблеми із безпекою, якщо вони залежать від версії OpenSSL, яка має якусь жахливу і непідтримувану проблему безпеки, або програма взагалі не зможе домовитись із сучасними веб-серверами (як сучасний сервери відхиляють старі протоколи та шифри старої програми), або протокол SSH версії 1 більше не підтримується, або ...


14
По-перше, абзац: ні, Intel називає це "Intel 64" (ці дні, переглядаючи деякі інші назви раніше). IA-64 посилається на Itanium, не що-небудь сумісне з x86.
варення

1
@hobbs дякую, я замінив ці посилання на amd64; Я залишу назву речей у відділі маркетингу Intel.
thrig

3
чому б не згадати статичне сполучення?
квітня

2
Змінюються не лише бібліотечні ABI, але з часом розширюється інтерфейс системного виклику ядра. Зауважте for GNU/Linux 2.6.32(або таке) у висновку file /usr/bin/ls.
Чарльз Даффі

1
@Wilbert Ви, мабуть, пропустили, що тріг посилався на Red Hat Linux, який відрізняється від Red Hat Enterprise Linux.
Боб

68

Коротше кажучи: якщо ви збираєте скомпільований двійковий файл з одного хоста на інший, використовуючи ту саму (або сумісну) архітектуру , можливо, ви будете чудово переносити його в інший дистрибутив . Однак зі збільшенням складності коду збільшується ймовірність зв’язання з бібліотекою, яка не встановлена; встановлено в іншому місці; або встановлений у іншій версії, збільшується. Візьмемо, наприклад, свій код, для якого lddповідомляються про наступні залежності при компіляції gcc -o exit-test exit-test.cна (похідному від Debian) хості Ubuntu Linux:

$ ldd exit-test
    linux-gate.so.1 =>  (0xb7748000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757b000)
    /lib/ld-linux.so.2 (0x8005a000)

Очевидно, що цей двійковий файл не запуститься, якщо я перейду його до, скажімо, Mac ( ./exit-test: cannot execute binary file: Exec format error). Спробуємо перенести його у вікно RHEL:

$ ./exit-test
-bash: ./exit-test: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory

О Боже. Чому це може бути?

$ ls /lib/ld-l* # reference the `ldd` output above
ls: cannot access /lib/ld-l*: No such file or directory

Навіть для цього випадку використання вилочного навантажувача не вдалося через відсутність спільних бібліотек.

Однак якщо я компілюю його gcc -static exit-test-static exit-test.c, перенесення його до системи без бібліотек працює чудово. За рахунок, звичайно, дискового простору:

$ ls -l ./exit-test{,-static}
-rwxr-xr-x  1 username  groupname    7312 Jan 29 14:18 ./exit-test
-rwxr-xr-x  1 username  groupname  728228 Jan 29 14:27 ./exit-test-static

Іншим життєздатним рішенням було б встановлення необхідних бібліотек на новому хості.

Як і для багатьох речей у Всесвіті U&L, це кішка з багатьма шкурами, дві з яких викладені вище.


4
Дійсно, я забув про статичні бінарні файли. Деякі виробники застосовують статичні бінарні файли, а деякі автори шкідливих програм також покращують бінарну сумісність між версіями Linux тієї самої архітектури
Rui F Ribeiro

8
Навантажувач ...?
користувач253751

2
@immibis Я думаю, що це означає копіювання даних (виконуваних файлів) з одного середовища (дистрибутива) в інше, де дані не призначені для середовища призначення.
wjandrea

13
Ваш приклад Linux, на жаль, є штучним, і ілюструє ваш погляд на архітектуру, а не на дистрибутиві: ви створили 32-розрядний бінарний файл на Debian і намагалися запустити його на 64-бітному RHEL; це різні архітектури ... Бінарні файли однакової архітектури з такою малою залежністю від бібліотеки можуть бути скопійовані просто чудово.
Стівен Кітт

7
@MSalters Я не кажу, що це нерозумно, я кажу, що це поганий приклад, враховуючи те, що DopeGhoti намагається зробити (ви не можете копіювати бінарні файли з одного дистрибутива в інший - що неправильно). Звичайно, 64-бітний Linux в Intel також підтримує 32-бітні виконувані файли з відповідною інфраструктурою. Достовірним прикладом у цьому випадку IMO буде побудова amd64бінарного файлу та запуск його на інший amd64дистрибутив, або побудова i386бінарного файлу та запуск його на інший i386дистрибутив.
Стівен Кітт

25

Додаючи до відмінних відповідей @thrig та @DopeGhoti: Unix або Unix-подібні ОС, включаючи Linux, традиційно завжди розроблялися та вирівнювалися більше для портативності вихідного коду, ніж двійкових файлів.

Якщо у вас немає нічого специфічного для апаратного забезпечення або є простим джерелом, як у вашому прикладі, ви можете без проблем пересувати його між майже будь-якою версією Linux або архітектурою як вихідним кодом , доки на серверах призначення встановлені пакети розробки C , необхідні бібліотеки та встановлені відповідні бібліотеки розвитку.

Що стосується перенесення більш досконалого коду зі старих версій Linux, віддалених за часом, або більш конкретних програм, таких як модулі ядра для різних версій ядра, можливо, вам доведеться адаптувати та змінювати вихідний код для обліку застарілих бібліотек / API / ABI.


19

За замовчуванням ви майже напевно зіткнетесь із проблемами із зовнішніми бібліотеками. Деякі з інших відповідей детальніше описують ці проблеми, тому я не буду дублювати їх роботу.

Однак ви можете скласти багато програм - навіть нетривіальні - для перенесення між системами Linux. Ключовим є інструментарій, який називається Linux Standard Base . LSB призначений для створення тільки цих типів портативних додатків. Створіть програму для LSB v5.0, і вона запуститься в будь-якому іншому середовищі Linux (тієї ж архітектури), що реалізує LSB v5.0. Кілька дистрибутивів Linux сумісні з LSB, а інші включають набори інструментів / бібліотек LSB як встановлений пакет. Якщо ви будуєте свою програму за допомогою інструментів LSB (наприклад, lsbccобгортки для gcc) та посилаєтесь на версію бібліотек LSB, ви створите портативний додаток.


і qemuви можете навіть запускати програми, складені для різних архітектур, (не висока ефективність, але ви можете запускати їх)
Jasen

1
Я навіть не знав про інструментарій Linux Standard Base, тож дякую! Я почав працювати з C / C ++ дуже давно, тому значна частина інформації в цих відповідях для мене нова. І дуже корисно.
JCDeen

1
У статті Вікіпедії сказано, що Debian і Ubuntu не застосовують LSB (і не мають наміру цього робити.)
BlackJack

2
@ BlackJack. Сам дистрибутив не реалізує 100% його як частину основної ОС, але ви можете встановити бібліотеки та набори сумісності LSB як додаткові пакети. Я використовував Ubuntu (наприклад) для створення LSB-сумісних програм, які потім працювали на Suse та Centos, вам потрібно apt-get installлише кілька пакетів.
бта

10

Може бути.

До речей, які мають тенденцію його порушувати, належать.

  1. Різні архітектури. Очевидно, що абсолютно різні архітектури не працюватимуть (якщо у вас є щось на зразок користувальницького режиму qemu з binfmt_misc, але це навряд чи нормальна конфігурація). Бінарні файли x86 можуть працювати на amd64, але лише за наявності 32-бітних бібліотек.
  2. Бібліотечні версії. Якщо soversion неправильна, вона взагалі не знайде бібліотеку. Якщо soversion однакова, але двійковий файл побудований на основі нової версії бібліотеки, ніж вона працює, тоді вона може не завантажуватися через нові символи або нові версії символів. Зокрема, glibc є великим користувачем версій символів, тому бінарні файли, побудовані на основі новішого glibc, дуже ймовірно, не зможуть зістарити зі старшим glibc.

Якщо ви не користуєтесь будь-якими бібліотеками, що швидко змінюються, уникайте змін архітектури та будуйте найдавніший дистрибутив, на який хочете націлитись, у вас є шанс зробити одну бінарну роботу на багатьох дистрибутивах.


4

На додаток до деяких речей, про які було сказано раніше, відбулися деякі зміни у форматі виконуваних файлів. Здебільшого linux використовує ELF, але старіші версії використовуються a.out або COFF.

Початок wikihole:

https://en.wikipedia.org/wiki/Comppare_of_executable_file_formats

Можливо, є спосіб отримати старіші версії для запуску новіших форматів, але я особисто ніколи не заглядав у це.


На сьогоднішній день "старший" дуже старий.
plugwash
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.