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

Итак, я беру свою программу на C++ в Visual Studio, компилирую, и она выдает небольшой симпатичный EXE-файл. Но EXE-файлы будут работать только в Windows, и я много слышал о том, как C/C++ компилируется в язык ассемблера, который работает непосредственно на процессоре. EXE запускается с помощью Windows, или у меня может быть программа, которая создает исполняемый файл, работающий на Mac. Но разве я не компилирую код C++ в язык ассемблера, зависящий от процессора?

Мои выводы:

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

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


person Gordon Gustafson    schedule 28.08.2009    source источник
comment
Компилятор Intel — это не то, что вы думаете — это просто еще один компилятор для Windows (или Linux; они делают и то, и другое), написанный Intel. Он создает EXE-файлы или стандартные бинарные файлы Linux.   -  person Brooks Moses    schedule 28.08.2009


Ответы (10)


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

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

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

Подпрограммы ввода-вывода (на C++, но это верно в большинстве случаев) — это просто библиотека, которая инкапсулирует API ОС. К черту эту ОС, она везде.

Вспоминая.

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

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

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

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

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

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

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

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

Итог.

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

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

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

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

  4. Почитайте про ЭЛЬФ. http://en.wikipedia.org/wiki/Executable_and_Linkable_Format

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

person S.Lott    schedule 28.08.2009
comment
дополнение к Вы можете легко писать программы на C++, которые не требуют ОС. Легче всего это сделать с помощью микроконтроллеров, большинство (возможно, все) из них сегодня имеют компиляторы C++ или, по крайней мере, C. - person vsz; 05.08.2012

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

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

person Dave Markle    schedule 28.08.2009

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

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

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

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

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

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

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

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

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

person Brooks Moses    schedule 28.08.2009

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

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

person Sinan Ünür    schedule 28.08.2009

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

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

person Shaggy Frog    schedule 28.08.2009
comment
Я не думаю, что это то, что спросили. Вопрос был о том, что делает исполняемый файл специфичным для ОС. - person sleske; 28.08.2009

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

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

person Chris Dodd    schedule 28.08.2009

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

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

person Tyler McHenry    schedule 28.08.2009
comment
Кажется, вы путаете библиотеку с динамически загружаемой библиотекой. Каждый компилятор на «голом железе» (или, по крайней мере, почти каждый) включает в себя статически компонуемую копию стандартной библиотеки C, которая подключается во время компиляции, поэтому соответствующие функции становятся частью исполняемого файла, и он отлично работает. Многие поставщики оборудования включают дополнительные библиотеки для взаимодействия с конкретным оборудованием, и вы даже можете купить библиотеки TCP/IP и тому подобное. Многие поставщики оборудования и компиляторов также предоставляют необходимый базовый загрузочный код, чтобы плата переходила от включения к вызову main(). - person Brooks Moses; 28.08.2009
comment
Важным моментом является то, что это заменяет операционную систему. Большинство ОС не разрешают прямой доступ к некоторым аппаратным средствам, необходимым для работы. Таким образом, вы можете написать программу, которая заменит Windows или Linux, но не может быть запущена в существующей ОС. (Если только вы не пишете для одной ОС, а эмулируете на других). - person KeithB; 28.08.2009

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

Вы можете предоставить каждую строку кода и каждую инструкцию и не использовать пакет инструментов разработки, но по-прежнему использовать компилятор, такой как, например, gcc. Некоторые из двоичных форматов являются общими для тех, которые работают в таких операционных системах, как, например, elf. Вы можете выполнять файлы elf в Linux, но ваша встроенная программа также может привести к бинарному файлу elf. Процессор не может выполнять elf в этом формате, но какие бы программы загрузочный prom или ram в некоторых случаях не извлекал двоичную программу из elf-файла, в отличие от операционной системы, извлекающей программу для запуска из elf-файла. EXE не является одним из этих форматов файлов. Ваш любимый компилятор приложений Windows, вероятно, также не является встроенным компилятором, хотя иногда вы можете использовать его для выполнения высокоуровневого языка, а затем использовать альтернативный ассемблер и компоновщик. Больше работы, чем обычно. Например, вы пишете функцию на C (которая НЕ выполняет никаких библиотечных или системных вызовов), компилируете ее в объект. Напишите свою или найдите утилиту для извлечения скомпилированного двоичного файла из этого объекта, преобразования его в другой формат объекта или в ассемблер (дизассемблирование). Добавьте в него свой стартовый код и другую сборку. Соберите и свяжите все вместе как встроенную программу. Однажды я сделал это со встроенным Visual C от Microsoft, просто чтобы посмотреть, как он соотносится с другими компиляторами, это не было ужасно, но, конечно, не стоило усилий взлома, чтобы получить результат.

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

person old_timer    schedule 28.08.2009

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

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

person Community    schedule 28.08.2009

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

person Jordan Force    schedule 27.12.2010
comment
Добро пожаловать в СО. Это, вероятно, лучше всего оставить в качестве комментария, поскольку он не полностью отвечает на заданный вопрос. - person Levi Botelho; 03.12.2012