Как создать исполняемый файл для запуска на определенной архитектуре процессора (вместо определенной ОС)?

поэтому я беру свою программу на C++ в Visual studio, компилирую, и она выплюнет хороший маленький EXE-файл. Но EXEs будет работать только в windows, и я много слышу о том, как C/C++ компилируется на ассемблерный язык, который работает непосредственно на процессоре. EXE работает с помощью windows, или я мог бы иметь программу, которая делает исполняемый файл, который работает на mac. Но разве я не компилирую код C++ на ассемблерный язык, который специфичен для процессора?

Мои Выводы:

  1. Я предполагаю, что я, вероятно, нет. Я знаю, что есть компилятор Intel C++, так что он сделает сборочный код процессора? EXEs работают на windows, поэтому они используют множество вещей, уже настроенных, от графических пакетов до массивной .NET framework. Исполняемый файл, специфичный для процессора, будет буквально начинаться с нуля, только с набором инструкций процессора.

  2. это исполняемый файл типа? Мы могли бы бежать. windows и откройте его, но тогда будет ли управление переключаться только на процессор? Я предполагаю, что этот исполняемый файл будет чем-то вроде операционной системы, поскольку он должен быть запущен до загрузки чего-либо еще и иметь только инструкцию процессора, установленную для "использования".

10 ответов


давайте подумаем о том, что "работать" означает...

Что-то должно загрузить двоичные коды в память. Это функция ОС. Этот.EXE или двоичный исполняемый файл или пакет или что-то еще, отформатирован очень специфичным для ОС способом, чтобы ОС могла загрузить его в память.

Что-то должно передать управление этим двоичным кодам. Опять ОС.

процедуры ввода-вывода (на C++, но это верно в большинстве мест) - это просто библиотека, которая инкапсулирует API ОС. Черт бы побрал эту ОС, она повсюду.

воспоминания.

в старые времена (да, я такой старый) я работал на машинах, у которых не было ОС. У нас также не было C.

мы писали машинные коды, используя такие инструменты, как" ассемблеры "и" компоновщики", чтобы создавать большие двоичные изображения, которые мы могли загружать в машину. Мы должны были загрузить эти двоичные изображения через болезненный процесс загрузки.

мы будем использовать клавиши на передней панели для загрузки кода в память читать на таком удобном устройстве, как перфоратор. Это загрузило бы небольшую часть довольно стандартного загрузочного загрузчика. (Мы использовали майларовую ленту, чтобы она не изнашивалась.)

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

мы написали наши собственные драйверы устройств. Или мы использовали библиотечные процедуры, которые были в исходной форме, пробитые на бумажных лентах.

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

позже у нас были простые ОС, которые имели простые API, простые драйверы устройств и несколько утилит, таких как "файловая система", "редактор" и "компилятор". Это было для языка под названием Jovial, но мы также иногда использовали Fortran.

нам пришлось припаять платы последовательного интерфейса, чтобы мы могли подключить устройство. Нам пришлось написать драйверы устройств.

Итог.

вы можете легко писать программы на C++, которые не требуют ОС.

  1. узнайте об аппаратных средствах BIOS (или BIOS-подобных), которые являются частью чипсета вашего процессора. Большинство современных аппаратных средств имеет простую ОС, подключенную к ПЗУ, которая выполняет самотестирование (POST), загружает несколько простых драйверов и находит загрузочные блоки.

  2. научиться напишите свой собственный загрузочный блок. Это первая правильная "программная" вещь, которая загружается после публикации. Это не так уж сложно. Вы можете использовать различные инструменты секционирования, чтобы заставить вашу программу блока загрузки на диск, и вы будете иметь полный контроль над оборудованием. Нет ОС.

  3. узнайте, как GRUB, LILO или BootCamp запускают ОС. Это не сложно. Как только они загружаются, они могут загрузить вашу программу, и вы выключены и запущены. Это немного проще, потому что вы создаете вид раздела, который загрузчик хочет загрузить. База ваша на ядре Linux и вы будете счастливее. Не пытайтесь выяснить, как Windows загружается - это слишком сложно.

  4. читайте на ELF. http://en.wikipedia.org/wiki/Executable_and_Linkable_Format

  5. узнайте, как пишутся драйверы устройств. Если вы не используете ОС, вам нужно будет написать драйверы устройств.


проблема в том, что ОС действительно много делает для запуска ваших программ. Сам EXE-файл имеет информацию заголовка на нем, что Windows распознает, идентифицируя себя как EXE-файл. Ваше приложение делает все, от доступа к файловой системе на выделение памяти через ОС.

Но да, вы можете запускать приложения, скомпилированные для Windows / intel на других платформах без эмуляции. Если вы хотите запустить EXE на Mac или UNIX, вам нужно будет установить немного больше программного обеспечения для выполнения работы это Windows сделает для запуска вашей программы - взгляните на проект "Wine".


то, о чем вы говорите,-это то, что известно во встроенном мире как приложение "голый металл". Они очень распространены для таких вещей, как ARM Cortex-M3, который входит (скажем) в коробку валидатора дебетовой карты или интерактивную игрушку и не имеет достаточной памяти или возможности для запуска полной операционной системы. Таким образом, вместо компилятора" ARM/Linux", который будет компилировать приложение для запуска на Linux на процессоре ARM, вы получаете компилятор" ARM bare-metal", который компилирует вещи для запуска на ARM процессор без операционной системы. (Я использую ARM, а не x86 в качестве примера, потому что x86 голые металлические приложения действительно довольно редки в эти дни.)

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

во-первых, он должен Инициализировать систему памяти, векторы прерываний и различные другие биты платы. Как правило, это то, что компилятор bare-metal сделает для вас, хотя, если у вас есть странная доска, вам может потребоваться рассказать ей, как это сделать. Это получает вещи от точки, где плата включается до точки, где начинается ваша функция main ().

затем вам нужно взаимодействовать с вещами за пределами процессора и ОЗУ. Операционная система включает в себя всевозможные функции для этого-дисковый ввод - вывод, Вывод на экран, ввод с клавиатуры и мыши, сеть и т. д. и так далее , и так далее. Без операционной системы, у вас есть чтобы получить это откуда-то еще. Вы можете получить некоторые из них из библиотек от вашего производителя оборудования; например, плата, с которой я недавно играл, имеет светодиодный экран 40x200-pixel, и он поставляется с библиотекой с кодом, чтобы включить его и установить на нем отдельные значения пикселей. И есть несколько компаний, продающих библиотеки для реализации стека TCP/IP и тому подобное, для создания сетей или чего-то еще.

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

О, и мы упоминали, что вам сначала нужно выяснить, как получить программу в процессор? Типовое значение компьютер имеет немного программируемого ПЗУ, который будет загружать инструкции при запуске. На x86 это BIOS, и он обычно уже содержит удобную программу, которая запускает процессор, настраивает дисплей, ищет диски и загружает программу с диска, который он находит. В встроенной системе, как правило, ваша программа идет именно туда, что означает, что вам нужно каким-то образом поместить свою программу туда. Часто это означает, что у вас есть устройство под названием "отладчик", которое физически подключено к ваша встроенная плата, которая загружает программу , а также может делать вещи, которые позволяют приостановить процессор и определить его состояние, так что вы можете пройти через свою программу так же, как если бы вы запускали ее в отладчике программного обеспечения на вашем компьютере. Но я отвлекся.

в любом случае, чтобы ответить на ваш второй вопрос, этот исполняемый файл, который вы создадите, - это то, что хранится в этом ПЗУ на вашей встроенной плате, или, возможно, вы просто сохраните его немного в ПЗУ (что, в конце концов,, довольно маленький) и хранить остальное на флэш-накопителе, а бит в ПЗУ будет включать инструкции, чтобы получить остальную часть его с флэш-накопителя. Вероятно, он будет храниться как файл на вашем основном компьютере (то есть на компьютере Linux или Windows, где вы его создаете), но это только для хранения, он не будет работать там.

вы заметите, что когда у вас есть много этих библиотек вместе, они делают изрядную часть того, что делает операционная система, и есть что-то вроде этого пространство между кучей библиотек и реальной операционной системой. В этом пространстве идет то, что называется RTOS-"операционная система реального времени". Меньшие из них на самом деле просто коллекции библиотек, которые работают вместе, чтобы делать все вещи операционной системы, а иногда также включают в себя материал, чтобы вы могли запускать несколько потоков одновременно (и тогда у вас могут быть разные потоки, действующие как разные программы), хотя все это скомпилировано в одну и ту же скомпилированную "программу", а RTOS-это на самом деле это всего лишь библиотека, которую вы включили. Более крупные начинают хранить части кода в разных местах, и я думаю, что некоторые из них могут даже загружать фрагменты кода с дисков-так же, как Windows и Linux при запуске программы. Это своего рода континуум, а не Или/Или.

система FreeRTOS-это RTOS с открытым исходным кодом, который находится в меньшем конце пространства RTOS; они могут быть хорошим местом, чтобы посмотреть на некоторые из этого, если вы больше заинтересованы. У них есть некоторые примеры приложений x86, которые дадут вам представление о том, какие системы x86 будут запускать программу на основе голого металла или RTOS и как вы скомпилируете что-то для запуска на одном; ссылка здесь:http://www.freertos.org/a00090.html#186.


компьютер не является процессором. Чтобы сделать что-нибудь полезное, процессор должен быть подключен к памяти и контроллерам ввода-вывода и другим устройствам. ОС заботится о том, чтобы абстрагировать все это от запуска программ. Таким образом, если вы хотите написать программу, которая работает без ОС, ваша программа должна будет реплицировать по крайней мере некоторые функции ОС: переход от BIOS во время процесса загрузки, инициализация устройств, связь с контроллером диска для загрузки кода и данных, связь с контроллер дисплея для отображения информации пользователю, связи с контроллером клавиатуры и контроллером мыши для чтения пользовательского ввода и т. д. и т. д.

Если вы не создаете встроенную систему со специализированным оборудованием, нет смысла делать это. Кроме того, запуск вашей программы означал бы, что пользователю придется отказаться от запуска других программ. Хотя это может быть приемлемо для банкомата сегодня или WordStar в 1984 году, в эти дни люди не могут проверить электронную почту, пока слушать музыку.


конечно, они существуют. Они называются кросс-компиляторы. Например, вот как я могу программировать для платформы iPhone с помощью Xcode.

связанный тип компилятора-это тот, который компилируется для виртуальной платформы. вот как работает Java.


любой данный компилятор / набор инструментов создает код для определенной комбинации процессора / ОС. Таким образом, пример компиляции Visual Studio создает код для x86/Windows. Что.EXE будет работать только на x86 / Windows, а не на (например) ARM/Windows (как используется некоторыми мобильными телефонами).

для создания кода для комбинации процессора / ОС, отличной от того, на чем вы запускаете компилятор, требуется то, что обычно называют кросс-компилятором. Если у вас есть полная профессиональная Visual Studio подписка, вы можете получить компилятор ARM cross, который позволит вам производить ARM / Windows .EXE-файлы, которые не будут работать на вашем настольном компьютере, но будут работать на ARM/Windows на основе мобильного телефона или palmtop.


Да, вы можете сделать исполняемый файл, который работает на "голом металле" процессора. Очевидно, так работают ядра операционной системы. Главное, что вам нужно сделать, это создать исполняемый файл, который использует никаких библиотек. Однако ограничение "нет библиотек" включает стандартную библиотеку C! Так что это означает отсутствие malloc, printf и т. д. Вы должны в основном быть своей собственной ОС и управлять памятью и вводом-выводом самостоятельно. Это неизбежно потребует справедливой работы непосредственно в сборке на некоторых ступень.

вы также теряете несколько других предметов роскоши, таких как main (), которые не могут быть отправной точкой вашей программы, поскольку main () - это то, что вызывается ОС и средой выполнения C.


абсолютно! Вот что такое встроенное Программирование. Как многие, вероятно, уже сказали, операционная система делает довольно много для вас. И даже во встроенном мире без операционной системы ряд инструментов разработки предоставит код запуска, чтобы процессор работал достаточно, чтобы перейти к вашей программе. Некоторые/многие предоставляют полные библиотеки C / C++, чтобы вы могли вызывать такие функции, как memcpy (), а иногда даже malloc() и printf().

добро пожаловать предоставьте каждую строку кода и каждую инструкцию и не используйте пакет инструментов разработки, но все равно используйте компилятор, например gcc. Некоторые из двоичных форматов являются общими для тех, которые работают на операционных системах, таких как elf, например. Вы можете выполнять файлы elf в Linux, но также иметь встроенный результат программы в двоичном файле elf. Процессор не может выполнить elf в этом формате, но какие бы программы загрузочный выпускной вечер или ОЗУ в некоторых случаях будет извлекать двоичную программу из файла elf, не в отличие от операционная система извлечение программы для запуска из файла elf. EXE не является одним из этих форматов файлов. Ваш любимый компилятор приложений windows, вероятно, не является встроенным компилятором, хотя иногда вы можете использовать его для работы с языком высокого уровня, а затем использовать альтернативный ассемблер и компоновщик. Больше работы, чем обычно. Например, вы пишете функцию в C (которая не делает никаких библиотечных или системных вызовов), компилируете ее в объект. Написать свой или найти утилита для извлечения скомпилированного двоичного файла из этого объекта, преобразования его в другой формат объекта или в ассемблер (демонтаж). Добавьте к нему свой код запуска и другую сборку. Соберите и свяжите все вместе как встроенную программу. Я сделал это один раз с помощью Microsofts embedded visual C, чтобы увидеть, как он соответствует другим компиляторам, это было не ужасно, но, конечно, не стоило усилий взлома, чтобы получить результат.

каждый процессор от компьютера к у одного в вашем мобильном телефоне или микроволновой печи тоже есть код загрузки. Этот код не работает в операционной системе. Этот код использует те же или аналогичные компиляторы, что и приложения операционной системы. Для некоторых устройств этот код переводит процессор и память, а также периферийные устройства микросхем в состояние, в котором может быть запущена операционная система. Оттуда операционная система берет верх. На вашем компьютере это будет BIOS, за которым следует загрузчик, а затем в конечном итоге операционная система, dos, windows, Линукс, etc.


основная проблема заключается в формате файла. PE сильно отличается от ELF(используется в unix-подобных системах). Допустимая программа PE не может быть допустимым ELF. Таким образом, вы либо загружаете двоичный файл динамически с разными стартерами, либо вы должны сдаться.

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


Не забывайте также о библиотеках Windows. Посмотрите в QT и GTK+