gcc використовує терміни "архітектура" для позначення "набору інструкцій" певного процесора, а "target" охоплює комбінацію CPU та архітектури, а також інші змінні, такі як ABI, libc, endian-ness та багато іншого (можливо, включаючи "голий метал"). Типовий компілятор має обмежений набір цільових комбінацій (ймовірно, один ABI, одне сімейство процесорів, але можливо, як 32-, так і 64-розрядні). Перехресний компілятор зазвичай означає або компілятор з ціллю, відмінною від системи, на якій він працює, або такий, що має декілька цілей, або ABI (див. Також це ).
Чи переносять бінарні файли в різних архітектурах процесора?
Загалом, ні. Двійковий код у звичайних термінах - це власний об'єктний код для певної сім'ї процесора чи процесора. Але є декілька випадків, коли вони можуть бути помірно-надто портативними:
- одна архітектура є сукупністю іншої (зазвичай бінарні файли x86 націлені на i386 або i686, а не на останній і найбільший x86, наприклад
-march=core2
)
- одна архітектура забезпечує вроджену емуляцію чи переклад іншої (можливо, ви чули про Crusoe ) або надає сумісні спільні процесори (наприклад, PS2 )
- ОС і підтримка часу виконання мультиархів (наприклад, можливість запускати 32-бітні x86 бінарні файли на x86_64), або зробити VM / JIT безпроблемним (Android за допомогою Dalvik або ART )
- є підтримка "жирних" двійкових файлів, які по суті містять дублікат коду для кожної підтримуваної архітектури
Якщо вам якимось чином вдасться вирішити цю проблему, то інша портативна бінарна проблема з безлічі версій бібліотеки (glibc, на яку я дивлюсь) представить себе. (Більшість вбудованих систем позбавляють вас від конкретної проблеми хоча б.)
Якщо ви ще цього не зробили, зараз прийшов час побігти gcc -dumpspecs
і gcc --target-help
подивитися, що ви проти.
Жирні бінарні продукти мають різні недоліки , але все ще мають потенційне використання ( EFI ).
Однак в інших відповідях відсутня ще два міркування: ELF та інтерпретатор ELF, а також підтримка ядра Linux для довільних бінарних форматів . Я не буду вникати в деталі про двійкові файли або байт-код для нереальних процесорів тут, хоча можна трактувати їх як "рідні" та виконувати Java або компільовані бінарні файли байт-коду Python , такі бінарні файли не залежать від апаратної архітектури (але залежать замість цього про відповідну версію VM, яка в кінцевому рахунку працює нативним бінарним файлом).
Будь-яка сучасна система Linux використовує бінарні файли ELF (технічні деталі в цьому PDF ), у випадку динамічних бінарних файлів ELF ядро відповідає за завантаження зображення в пам'ять, але це завдання '' інтерпретатора '', встановленого в ELF заголовки, щоб зробити важкий підйом. Зазвичай це передбачає наявність усіх залежних динамічних бібліотек (за допомогою розділу "Динамічна", в якому перераховані бібліотеки та деякі інші структури, в яких перераховуються необхідні символи), - але це майже загальний рівень опосередкованого шару.
$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses \
shared libs), stripped
$ readelf -p .interp /bin/ls
String dump of section '.interp':
[ 0] /lib/ld-linux.so.2
( /lib/ld-linux.so.2
це також двійковий код ELF; він не має інтерпретатора і є нативним двійковим кодом.)
Проблема ELF полягає в тому, що заголовок у двійковій ( readelf -h /bin/ls
) позначає його для конкретної архітектури, класу (32- або 64-бітового), ендіанства та ABI ("універсальні" бінарні файли Apple використовують альтернативний бінарний формат Mach-O замість того, що вирішує цю проблему, вона виникла на NextSTEP). Це означає, що виконуваний файл ELF повинен відповідати системі, на якій він повинен працювати. Один випускний люк - це інтерпретатор, це може бути будь-який виконуваний файл (включаючи той, який витягує або відображає конкретні підрозділи архітектури спочатку бінарних файлів і викликає їх), але ви все ще обмежені типом (іми) ELF, який ваша система дозволить запускати . (У FreeBSD є цікавий спосіб обробки файлів ELF Linux , він brandelf
змінює поле ELI ABI.)
Існує (використовуючи binfmt_misc
) підтримку Mach-O на Linux , там є приклад, який показує вам, як створювати та запускати жировий (32- та 64-бітний) двійковий файл. Форки ресурсів / ADS , як це було зроблено на Mac, може бути вирішенням, але жодна рідна файлова система Linux це не підтримує.
Більш-менш те ж саме стосується модулів ядра, .ko
файли також ELF (хоча вони не мають інтерпретатора). У цьому випадку є додатковий шар, який використовує версію ядра ( uname -r
) в шляху пошуку, те, що теоретично можна зробити замість цього в ELF з версією, але я певно підозрюю.
Як було зазначено в іншому місці, Linux не підтримує жирові файли, але існує активний жирово -бінарний проект: FatELF . Це вже багато років , воно ніколи не було інтегровано у стандартне ядро, частково через проблеми, пов'язані з патентом. У цей час йому потрібна підтримка ядра та ланцюжка інструментів. Він не використовує binfmt_misc
підхід, цей побічний крок видає заголовок ELF і дозволяє також використовувати модулі жирового ядра.
- Якщо у мене складено додаток для запуску на 'x86 target, linux OS xyz', чи можу я просто запустити той самий скомпільований бінарний файл на іншій системі 'ARM target, Linux OS Xyz'?
Не з ELF, це не дозволить вам це зробити.
- Якщо вище не відповідає дійсності, єдиний спосіб - отримати вихідний код програми для відновлення / перекомпіляції, використовуючи відповідну ланцюжок інструментів «наприклад, arm-linux-gnueabi»?
Проста відповідь - так. (Складні відповіді включають емуляцію, проміжні подання, перекладачі та JIT; за винятком випадків "пониження" бінарного файлу i686 для використання лише коду i386, вони, мабуть, тут не цікаві, а корекції ABI потенційно такі ж важкі, як і переклад рідного коду. )
- Так само, якщо я маю завантажуваний модуль ядра (драйвер пристрою), який працює на 'x86 target, linux OS версії xyz', чи можу я просто завантажувати / використовувати те саме, що складено .ko на іншій системі 'ARM target, linux OS version xyz' ?
Ні, ELF не дозволить вам це зробити.
- Якщо вище не відповідає дійсності, єдиний спосіб - отримати вихідний код драйвера для відновлення / перекомпіляції, використовуючи відповідну ланцюжок інструментів «наприклад, arm-linux-gnueabi»?
Проста відповідь - так. Я вважаю, що FatELF дозволяє створити .ko
багатопрофільну архітектуру, але в якийсь момент має бути створена бінарна версія для кожної підтримуваної архітектури. Речі, для яких потрібні модулі ядра, часто поставляються з джерелом і будуються за необхідності, наприклад, це робить VirtualBox.
Це вже довга бурхлива відповідь, є лише ще один об’їзд. У ядрі вже вбудована віртуальна машина, хоч і спеціальна: BPM VM, яка використовується для узгодження пакетів. Людський читаний фільтр "хост foo, а не порт 22") компілюється в байт-код, і фільтр пакета ядра виконує його . Новий eBPF призначений не лише для пакетів, але теоретично, що VM-код є портативним у будь-якому сучасному Linux і llvm підтримує його, але з міркувань безпеки він, ймовірно, не підходить ні для чого, крім адміністративних правил.
Тепер, залежно від того, наскільки ви щедрий для визначення бінарного виконуваного файлу, ви можете (ab) використовувати binfmt_misc
для реалізації жирової бінарної підтримки зі скриптом оболонки та ZIP-файлами у форматі контейнера:
#!/bin/bash
name=$1
prog=${1/*\//} # basename
prog=${prog/.woz/} # remove extension
root=/mnt/tmpfs
root=$(TMPDIR= mktemp -d -p ${root} woz.XXXXXX)
shift # drop argv[0], keep other args
arch=$(uname -m) # i686
uname_s=$(uname -s) # Linux
glibc=$(getconf GNU_LIBC_VERSION) # glibc 2.17
glibc=${glibc// /-} # s/ /-/g
# test that "foo.woz" can unzip, and test "foo" is executable
unzip -tqq "$1" && {
unzip -q -o -j -d ${root} "$1" "${arch}/${uname_s}/${glibc}/*"
test -x ${root}/$prog && (
export LD_LIBRARY_PATH="${root}:${LD_LIBRARY_PATH}"
#readlink -f "${root}/${prog}" # for the curious
exec -a "${name}" "${root}/${prog}" "$@"
)
rc=$?
#rm -rf -- "${root}/${prog}" # for the brave
exit $rc
}
Назвіть це "wobbin" і налаштуйте його на кшталт:
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
printf ":%s:%s:%s:%s:%s:%s:%s" \
"woz" "E" "" "woz" "" "/path/to/wozbin" "" > /proc/sys/fs/binfmt_misc/register
Це реєструє .woz
файли з ядром, wozbin
замість цього викликається скрипт з його першим аргументом, встановленим на шлях викликаного .woz
файлу.
Щоб отримати портативний (жирний) .woz
файл, просто створіть test.woz
ZIP-файл із ієрархією каталогів так:
i686/
\- Linux/
\- glibc-2.12/
armv6l/
\- Linux/
\- glibc-2.17/
У кожному каталозі arch / OS / libc (довільний вибір) розмістіть специфічні для архітектури test
бінарні та компоненти, такі як .so
файли. Коли ви викликаєте його, необхідний підкаталог витягується до файлової системи пам'яті tmpfs ( /mnt/tmpfs
тут) і викликається.