Почему исполняемая программа для конкретного процессора не работает на Linux и Windows?

исполняемая проблема, такая как exe, не работает в Linux (без wine). При компиляции исходного кода компилятор создает объектный код, специфичный для конкретной архитектуры процессора. Но то же приложение не работает с другой ОС с тем же процессором. Я знаю, что код может включать инструкции для конкретной ОС, которые предотвратят запуск исполняемого файла. А как насчет простой программы 2+2 ? Запутанная часть-это то, что, черт возьми, мешает работать машинному коду. Машинный код, специфичный для cpu правильно? Если мы удалим формат исполняемого файла, сможем ли мы увидеть один и тот же машинный код (например, 2 + 2) для обеих операционных систем?

еще один вопрос: Как насчет ассемблера? Windows и Linux используют разные языки сборки для одного и того же процессора?.

6 ответов


есть много различий. Среди них:

  1. Исполняемый Формат: каждая ОС требует, чтобы двоичные файлы соответствовали определенному двоичному формату. Для Windows Это портативный исполняемый (PE) формат. Для Linux это ELF большую часть времени (он также поддерживает другие типы).

  2. Двоичный Интерфейс Приложения: каждая ОС определяет набор основных системных функций и способ их вызова программой. Это принципиально отличаются между Linux и Windows. Хотя инструкции, которые вычисляют 2 + 2, идентичны в Linux и Windows в архитектуре x86, способ запуска приложения, способ печати вывода и способ выхода различаются между операционными системами.

да, программы Linux и Windows на архитектуре x86 используют набор инструкций, который поддерживает процессор, определенный Intel.


Это связано с разницей в том, как программа загружается в память и данные ресурсы для запуска. Даже самые простые программы должны иметь пространство кода, пространство данных и возможность приобретать память времени выполнения и делать ввод-вывод.инфраструктура для выполнения этих задач низкого уровня полностью отличается между платформами, если у вас нет какого-то адаптационного уровня, такого как WINE или Cygwin.

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


Проблема 1-это формат изображения. Когда приложение запускается в исполнение, ОС должна загрузить образ приложения, узнать его точку входа и запустить его оттуда. Это означает, что ОС должна понимать формат изображения и существуют различные форматы между различными ОС.

Проблема 2-доступ к устройствам. После запуска приложение может читать и писать реестры в CPU, и это все. Сделать что-нибудь интересное, как для отображения символов на консоль, ей нужен доступ к устройствам, и это означает, что она должна запросить такой доступ из ОС. Каждая ОС имеет другой API, который предлагается для доступа к таким устройствам.

Проблема 3-это привилегии инструкции. Недавно запущенный процесс, возможно, потребуется место памяти для хранения чего-то, не может выполнить все с regiestries. Это означает, что ему нужно выделить ОЗУ и настроить перевод с VA на физический адрес. Это операции привилегий, которые может выполнять только ОС и опять же, API для доступа к этим службам различаются между OSs.

суть в том, что приложения пишутся не для ЦП, а для набора примитивных сервисов, предлагаемых ОС. альтернативой является написание приложений для набора примитивных сервисов, предлагаемых виртуальной машиной, что приводит к более или менее портативным приложениям, таким как Java-приложения.


да, но код неизменно вызывает библиотечные функции, чтобы делать что угодно-например, печатать "4" на терминале. И эти библиотеки специфичны для платформы и отличаются между Linux и Windows. Вот почему он не переносится - на самом деле это не проблема уровня инструкций.


вот некоторые из причин, которые я могу придумать с верхней части моей головы:

  1. различные форматы контейнеров (которые до сих пор кажутся ведущим дифференциатором в этом ответе, однако это не единственная причина).
  2. различная семантика динамического компоновщика.
  3. разные ABI.
  4. различные механизмы обработки исключений -- windows имеет SEH -- на котором построена обработка исключений C++
  5. различная семантика системных вызовов и разные системные вызовы-следовательно, разные низкоуровневые библиотеки.

ко второму вопросу: Windows работает только на x86, x64 и IA64 (не уверен в мобильных версиях). Для Linux, см. здесь.