Моя цель - уметь разрабатывать для встроенного Linux. У меня есть опыт работы со встроенными голыми металлическими системами с использованием ARM.
У меня есть несколько общих вопросов о разработке для разных целей процессора. Мои вопросы как ниже:
Если у меня есть приложение, скомпилированное для запуска на « цели x86, версия ОС Linux xyz », могу ли я просто запустить тот же скомпилированный двоичный файл на другой системе « цель ARM, версия ОС Linux xyz »?
Если вышеприведенное неверно, единственный способ - получить исходный код приложения для перестройки / перекомпиляции с использованием соответствующей цепочки инструментов, например, arm-linux-gnueabi?
Точно так же, если у меня есть загружаемый модуль ядра (драйвер устройства), который работает на « цели x86, версия ОС Linux, xyz », могу ли я просто загрузить / использовать тот же скомпилированный файл .ko на другой системе « цель ARM, версия ОС Linux xyz» ? ?
Если вышеприведенное неверно, единственный способ - получить исходный код драйвера для перекомпиляции / перекомпиляции с использованием соответствующей цепочки инструментов, например, arm-linux-gnueabi?
Ответы:
Нет. Двоичные файлы должны быть (пере) скомпилированы для целевой архитектуры, и Linux не предлагает ничего похожего на толстые двоичные файлы из коробки. Причина в том, что код скомпилирован в машинный код для конкретной архитектуры, и машинный код сильно отличается в большинстве семейств процессоров (например, ARM и x86 сильно различаются).
РЕДАКТИРОВАТЬ: стоит отметить, что некоторые архитектуры предлагают уровни обратной совместимости (и даже реже, совместимость с другими архитектурами); на 64-битных процессорах обычно имеется обратная совместимость с 32-битными выпусками (но помните: ваши зависимые библиотеки также должны быть 32-битными, включая стандартную библиотеку C, если вы не статически связываете ). Также стоит упомянуть Itanium , где можно было запускать код x86 (только 32-битный), хотя и очень медленно; низкая скорость выполнения кода x86 была, по крайней мере, одной из причин, почему он не был очень успешным на рынке.
Имейте в виду, что вы все еще не можете использовать двоичные файлы, скомпилированные с более новыми инструкциями на старых процессорах, даже в режимах совместимости (например, вы не можете использовать AVX в 32-разрядном двоичном файле на процессорах Nehalem x86 ; процессор просто не поддерживает его.
Обратите внимание, что модули ядра должны быть скомпилированы для соответствующей архитектуры; кроме того, 32-битные модули ядра не будут работать на 64-битных ядрах или наоборот.
Для получения информации о кросс-компиляции двоичных файлов (так что вам не нужно иметь цепочку инструментов на целевом устройстве ARM), смотрите полный ответ grochmal ниже.
источник
Элизабет Майерс права, каждая архитектура требует скомпилированный двоичный файл для рассматриваемой архитектуры. Чтобы создать двоичные файлы для архитектуры, отличной от той, на которой работает ваша система, вам нужно
cross-compiler
.В большинстве случаев вам нужно скомпилировать кросс-компилятор. У меня есть только опыт работы
gcc
(но я считаю, чтоllvm
и другие компиляторы имеют схожие параметры).gcc
Кросс-компилятор достигается путем добавления--target
к конфигурированию:Вам нужно собрать
gcc
,glibc
иbinutils
с этими параметрами (и обеспечивают заголовки ядра ядра на целевой машине).На практике это значительно сложнее, и в разных системах появляются разные ошибки сборки.
Существует несколько руководств по компиляции цепочки инструментов GNU, но я рекомендую Linux From Scratch , который постоянно поддерживается и очень хорошо объясняет, что делают представленные команды.
Другой вариант - это начальная компиляция кросс-компилятора. Благодаря борьбе за компиляцию кросс-компиляторов для разных архитектур на разных архитектурах
crosstool-ng
была создана. Он дает начальную загрузку над цепочкой инструментов, необходимой для создания кросс-компилятора.crosstool-ng
поддерживает несколько целевых триплетов на разных архитектурах, в основном это начальная загрузка, где люди посвящают свое время разбору проблем, возникающих при компиляции кросс-компиляторной цепочки инструментов.Несколько дистрибутивов предоставляют кросс-компиляторы в виде пакетов:
arch
обеспечивает MinGW кросс-компилятор и и рука EABI кросс - компилятор из коробки. Помимо других кросс-компиляторов в AUR.fedora
содержит несколько упакованных кросс-компиляторов .ubuntu
также предоставляет кросс-компилятор arm .debian
имеет целый репозиторий кросс-цепочекДругими словами, проверьте, что есть в вашем дистрибутиве с точки зрения кросс-компиляторов. Если в вашем дистрибутиве нет кросс-компилятора для ваших нужд, вы всегда можете скомпилировать его самостоятельно.
Ссылки:
Замечание по модулям ядра
Если вы собираете свой кросс-компилятор вручную, у вас есть все необходимое для компиляции модулей ядра. Это потому, что вам нужны заголовки ядра для компиляции
glibc
.Но если вы используете кросс-компилятор, предоставляемый вашим дистрибутивом, вам понадобятся заголовки ядра, которое работает на целевой машине.
источник
crosstool-ng
. Вы можете добавить это в список. Кроме того, настройка и компиляция кросс-цепочки GNU вручную для любой конкретной архитектуры невероятно сложна и гораздо более утомительна, чем просто--target
флаги. Я подозреваю, что это часть того, почему LLVM набирает популярность; Он спроектирован таким образом, что вам не нужно перестраивать для нацеливания на другую архитектуру - вместо этого вы можете ориентироваться на несколько бэкэндов, используя одни и те же библиотеки веб-интерфейса и оптимизатора.Обратите внимание, что в качестве крайней меры (т. Е. Когда у вас нет исходного кода), вы можете запускать двоичные файлы на другой архитектуре, используя эмуляторы, такие как
qemu
,dosbox
илиexagear
. Некоторые эмуляторы предназначены для эмуляции систем, отличных от Linux (напримерdosbox
, предназначены для запуска программ MS-DOS, и существует множество эмуляторов для популярных игровых консолей). Эмуляция значительно снижает производительность: эмулируемые программы работают в 2-10 раз медленнее, чем их собственные аналоги.Если вам нужно запустить модули ядра на не родном процессоре, вам придется эмулировать всю ОС, включая ядро, для той же архитектуры. AFAIK невозможно запустить сторонний код внутри ядра Linux.
источник
Мало того, что двоичные файлы не переносимы между x86 и ARM, есть и другие разновидности ARM .
Скорее всего, на практике вы столкнетесь с ARMv6 против ARMv7. Raspberry Pi 1 - это ARMv6, более поздние версии - ARMv7. Таким образом, можно скомпилировать код на более поздних, которые не работают на Pi 1.
К счастью, одним из преимуществ открытого исходного кода и свободного программного обеспечения является наличие источника, позволяющего перестроить его на любой архитектуре. Хотя для этого может потребоваться некоторая работа.
(Версионирование ARM сбивает с толку, но если перед номером стоит V, то это говорит об архитектуре набора команд (ISA). Если нет, то это номер модели, например, «Cortex M0» или «ARM926EJS». Номера моделей не имеют ничего общего с делать с номерами ISA.)
источник
Вам всегда нужно ориентироваться на платформу. В простейшем случае целевой ЦП непосредственно запускает код, скомпилированный в двоичном файле (это примерно соответствует исполняемым файлам MS DOS). Давайте рассмотрим две разные платформы, которые я только что изобрел - Перемирие и Интеллио. В обоих случаях у нас будет простая программа hello world, которая выводит 42 на экран. Я также предполагаю, что вы используете многоплатформенный язык независимо от платформы, поэтому исходный код одинаков для обоих:
На перемирии у вас есть простой драйвер устройства, который заботится о печати номеров, поэтому все, что вам нужно сделать, это вывести на порт. На нашем переносимом языке ассемблера это будет соответствовать примерно так:
Тем не менее, или система Intellio не имеет такой вещи, поэтому она должна пройти через другие слои:
Ой, у нас уже есть существенная разница между этими двумя, прежде чем мы даже доберемся до машинного кода! Это примерно соответствует разнице между Linux и MS DOS или IBM PC и X-Box (хотя оба могут использовать один и тот же процессор).
Но для этого нужны ОС. Предположим, у нас есть HAL, который гарантирует, что все различные аппаратные конфигурации обрабатываются одинаково на прикладном уровне - в основном, мы будем использовать подход Intellio даже в перемирии, и наш код «переносимой сборки» в итоге будет одинаковым. Это используется как современными Unix-подобными системами, так и Windows, часто даже во встроенных сценариях. Хорошо - теперь у нас может быть один и тот же действительно переносимый код ассемблера как для перемирия, так и для Intellio. Но как насчет двоичных файлов?
Как мы и предполагали, CPU должен напрямую выполнять двоичный файл. Давайте посмотрим на первую строку нашего кода
mov a, 10h
, на Intellio:Ой. Оказывается,
mov a, constant
он настолько популярен, что имеет собственную инструкцию со своим кодом операции. Как перемирие справляется с этим?Хм. Там есть код операции
mov.reg.imm
, поэтому нам нужен еще один аргумент, чтобы выбрать регистр, который мы назначаем. И константа всегда представляет собой 2-байтовое слово в формате с прямым порядком байтов - именно так было разработано перемирие, фактически все инструкции в перемирии имеют длину 4 байта, без исключений.Теперь представьте, что запускаете двоичный файл из Intellio по перемирию: процессор начинает декодировать инструкцию, находит код операции
20h
. По перемирию это соответствует, скажем,and.imm.reg
инструкции. Он пытается прочитать 2-байтовую константу слова (которая читает10XX
, уже проблема), а затем номер регистра (другойXX
). Мы выполняем неправильную инструкцию с неверными аргументами. И что еще хуже, следующая инструкция будет фиктивной, потому что мы на самом деле съели другую инструкцию, думая, что это данные.Приложение не имеет шансов на работу, и, скорее всего, оно почти сразу же зависнет или зависнет.
Теперь это не означает, что исполняемый файл всегда должен говорить, что он работает на Intellio или перемирии. Вам просто нужно определить платформу, которая не зависит от процессора (как
bash
в Unix), или как процессора, так и ОС (например, Java или .NET, а в настоящее время даже JavaScript). В этом случае приложение может использовать один исполняемый файл для всех разных ЦП и ОС, в то время как в целевой системе есть какое-то приложение или служба (которая нацелена на правильный ЦП и / или ОС), которая переводит независимый от платформы код в нечто Процессор действительно может выполняться. Это может или не может привести к снижению производительности, стоимости или возможностей.Процессоры обычно бывают семейными. Например, все процессоры семейства x86 имеют общий набор инструкций, которые кодируются одинаково, поэтому каждый процессор x86 может запускать каждую программу x86, если он не пытается использовать какие-либо расширения (например, операции с плавающей точкой или векторные операции). На x86 наиболее распространенными примерами сегодня являются, конечно, Intel и AMD. Atmel - известная компания, занимающаяся разработкой процессоров семейства ARM, довольно популярная для встраиваемых устройств. Например, у Apple также есть собственные процессоры ARM.
Но ARM совершенно несовместим с x86 - у них очень разные требования к дизайну и у них очень мало общего. Инструкции имеют совершенно разные коды операций, они декодируются по-разному, адреса памяти обрабатываются по-разному. Возможно, можно создать двоичный файл, работающий как на процессоре x86, так и на процессоре ARM, используя некоторые безопасные операции для различайте их и переходите к двум совершенно разным наборам инструкций, но это все равно означает, что у вас есть отдельные инструкции для обеих версий, просто с помощью загрузчика, который выбирает правильный набор во время выполнения.
источник
Возможно перевести этот вопрос в более знакомую среду. По аналогии:
«У меня есть программа на Ruby, которую я хочу запустить, но на моей платформе есть только интерпретатор Python. Могу ли я использовать интерпретатор Python для запуска своей программы на Ruby или мне нужно переписать свою программу на Python?»
Архитектура набора команд («цель») - это язык - «машинный язык» - и разные процессоры реализуют разные языки. Поэтому запросить процессор ARM для запуска двоичного файла Intel очень похоже на попытку запустить программу на Ruby с использованием интерпретатора Python.
источник
gcc использует термины «архитектура» для обозначения «набора команд» конкретного ЦП, а «цель» охватывает комбинацию ЦП и архитектуры, наряду с другими переменными, такими как ABI, libc, endian-ness и т. д. (возможно, включая «голый металл»). Типичный компилятор имеет ограниченный набор целевых комбинаций (вероятно, один ABI, одно семейство процессоров, но, возможно, 32- и 64-разрядные). Кросс-компилятор обычно означает либо компилятор с целью, отличной от системы, на которой он работает, либо с несколькими целями или ABI (см. Также это ).
В общем нет. Двоичный файл в обычных терминах - это нативный объектный код для конкретного процессора или семейства процессоров. Но есть несколько случаев, когда они могут быть от умеренно до высокой переносимости:
-march=core2
)Если вам как-то удастся решить эту проблему, другая проблема переносимых бинарных версий бесчисленных версий библиотек (glibc, которую я смотрю на вас) будет представлена сама собой. (Большинство встроенных систем избавляет вас от этой конкретной проблемы, по крайней мере.)
Если вы еще этого не сделали, сейчас самое время бежать
gcc -dumpspecs
иgcc --target-help
посмотреть, с чем вы столкнулись .Жирные двоичные файлы имеют различные недостатки , но все же имеют потенциальное использование ( EFI ).
Однако в других ответах отсутствуют еще два соображения: ELF и интерпретатор ELF, а также поддержка ядром Linux произвольных двоичных форматов . Я не буду вдаваться в подробности о двоичных файлах или байт-коде для нереальных процессоров здесь, хотя их можно рассматривать как «родные» и выполнять двоичные файлы Java или скомпилированные байт-коды Python , такие двоичные файлы не зависят от аппаратной архитектуры (но вместо этого зависят на соответствующей версии виртуальной машины, которая в конечном итоге запускает собственный двоичный файл).
Любая современная система Linux будет использовать двоичные файлы ELF (технические подробности в этом PDF- файле ), в случае динамических двоичных файлов ELF ядро отвечает за загрузку изображения в память, но это работа «интерпретатора», установленного в ELF. Заголовки, чтобы сделать тяжелую работу. Обычно это включает в себя обеспечение доступности всех зависимых динамических библиотек (с помощью раздела «Динамический», в котором перечислены библиотеки и некоторые другие структуры, в которых перечислены необходимые символы), - но это почти уровень общего назначения.
(
/lib/ld-linux.so.2
также является двоичным файлом ELF, не имеет интерпретатора и является собственным двоичным кодом.)Проблема с ELF заключается в том, что заголовок в двоичном (
readelf -h /bin/ls
) помечает его для конкретной архитектуры, класса (32- или 64-разрядного), порядкового номера и ABI («универсальные» двоичные файлы Apple используют альтернативный двоичный формат Mach-O). вместо этого, который решает эту проблему, он возник на NextSTEP). Это означает, что исполняемый файл ELF должен соответствовать системе, в которой он будет запущен. Один escape-штриховкой является интерпретатор, это может быть любой исполняемый файл (включая тот, который извлекает или отображает специфичные для архитектуры подразделы исходного двоичного файла и вызывает их), но вы все еще ограничены типом (ами) ELF, которые ваша система разрешит запускать , (У FreeBSD есть интересный способ обработки файлов ELF в Linux , онbrandelf
изменяет поле ELF ABI.)В Linux есть поддержка (использование
binfmt_misc
) Mach-O , там есть пример, который показывает, как создать и запустить толстый (32- и 64-битный) двоичный файл. Разветвление ресурсов / ADS , как это было изначально сделано на Mac, могло бы стать обходным путем, но ни одна нативная файловая система Linux не поддерживает это.Более или менее то же самое относится к модулям ядра,
.ko
файлы также являются ELF (хотя они не имеют установленного интерпретатора). В этом случае есть дополнительный слой, который использует ядро version (uname -r
) в пути поиска, что теоретически можно сделать вместо этого в ELF с версионированием, но при некоторой сложности и небольшом выигрыше, я подозреваю.Как отмечалось в другом месте, Linux изначально не поддерживает толстые двоичные файлы, но существует активный толстый двоичный проект: FatELF . Это было в течение многих лет , оно никогда не было интегрировано в стандартное ядро частично из-за (в настоящее время истекшего) проблем с патентами. В настоящее время требуется поддержка как ядра, так и набора инструментов. Это не использует
binfmt_misc
подход, это обходит проблемы заголовка ELF и учитывает также толстые модули ядра.Не с ELF, это не позволит вам сделать это.
Простой ответ - да. (Сложные ответы включают эмуляцию, промежуточные представления, трансляторы и JIT; за исключением случая «понижения версии» двоичного файла i686 для использования только кодов операций i386, они, вероятно, здесь не интересны, а исправления ABI потенциально сложны, как перевод собственного кода. )
Нет, ELF не позволит тебе сделать это.
Простой ответ - да. Я считаю, что FatELF позволяет вам создавать
.ko
мультиархитектуру, но в какой-то момент необходимо создать двоичную версию для каждой поддерживаемой архитектуры. Вещи, для которых требуются модули ядра, часто поставляются с исходным кодом и собираются по мере необходимости, например, VirtualBox делает это.Это уже длинный бессвязный ответ, есть только еще один обходной путь. В ядро уже встроена виртуальная машина, хотя и выделенная: виртуальная машина BPF, которая используется для сопоставления пакетов. Человекочитаемый фильтр "host foo, а не port 22") компилируется в байт-код, и фильтр пакетов ядра выполняет его . Новый eBPF предназначен не только для пакетов, теоретически код VM может переноситься через любой современный linux, и llvm поддерживает его, но по соображениям безопасности он, вероятно, не подойдет ни для чего, кроме административных правил.
Теперь, в зависимости от того, насколько вы щедры на определение двоичного исполняемого файла, вы можете (ab) использовать его
binfmt_misc
для реализации полной поддержки двоичного кода с помощью сценария оболочки и ZIP-файлов в качестве формата контейнера:Назовите это «wozbin», и настройте его следующим образом:
Это регистрирует
.woz
файлы в ядре,wozbin
вместо этого вызывается сценарий с его первым аргументом, установленным на путь вызываемого.woz
файла.Чтобы получить переносимый (толстый)
.woz
файл, просто создайтеtest.woz
ZIP-файл с иерархией каталогов так:В каждом каталоге arch / OS / libc (произвольный выбор) размещайте специфичные для архитектуры
test
двоичные.so
файлы и такие компоненты, как файлы. Когда вы вызываете его, требуемый подкаталог извлекается в файловую систему tmpfs в памяти (/mnt/tmpfs
здесь) и вызывается.источник
загрузку ягоды, решите некоторые из ваших проблем .. но это не решает проблему как запустить на arm hf, дистрибутив normall / regullAr linux для x86-32 / 64bit.
Я думаю, что он должен быть встроен в isolinux (linux для лодочного загрузчика на usb) в какой-то живой конвертер, который может распознавать regullar distro и конвертировать в ride / live в hf.
Почему? Потому что, если каждый linux может быть конвертирован загрузкой ягоды в работу на arm-hf, он сможет встроить механизм загрузки bery, чтобы изолировать то, что мы загружаем, используя exaple eacher или встроенный загрузочный диск ubuntu creat.
источник