Почему программная ОС специфична?

77

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

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

Операционные системы - внутреннее устройство и принципы проектирования 7-е изд. - У. Сталлингс (Пирсон, 2012)

Как вы можете видеть, API не указаны как часть операционной системы.

Если, например, я строю простую программу на C, используя следующий код:

#include<stdio.h>

main()
{
    printf("Hello World");

}

Компилятор делает что-то конкретное для ОС при компиляции?

user139929
источник
15
Вы печатаете в окно? или консоль? или в графическую память? Как вы размещаете данные там? Глядя на printf для Apple] [+ было бы немного по-другому, чем для Mac OS 7, и снова совершенно иначе, чем для Mac OS X (просто придерживаясь одной «линии» компьютеров).
3
Потому что если бы вы написали этот код для Mac OS 7, он отобразился бы в тексте в новом окне. Если бы вы делали это на Apple] [+, это было бы запись непосредственно в некоторый сегмент памяти. В Mac OS X он записывает это на консоль. Таким образом, это три разных способа написания обработки кода на основе исполнительного оборудования, которое обрабатывается библиотечным уровнем.
2
@StevenBurnap yep - en.wikipedia.org/wiki/Aztec_C
10
Ваша функция FFT будет успешно работать под Windows или Linux (на том же процессоре), даже без перекомпиляции. Но тогда как вы собираетесь отображать результат? Конечно, используя API операционной системы. ( printfиз msvcr90.dll это не то же самое, что printfиз libc.so.6)
user253751
9
Даже если API-интерфейсы «не являются частью операционной системы», они все равно будут другими, если вы переходите с одной ОС на другую. (Что, конечно, поднимает вопрос о том, что на самом деле означает фраза «не является частью операционной системы», согласно диаграмме.)
Theodoros Chatzigiannakis

Ответы:

78

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

Модель безопасности процессора

Первая программа, запускаемая на большинстве архитектур ЦП, выполняется внутри так называемого внутреннего кольца или кольца 0 . То, как конкретная арка ЦП реализует кольца, варьируется, но это означает, что почти каждый современный ЦП имеет по крайней мере 2 режима работы, один из которых является привилегированным и выполняет код «с нуля», который может выполнять любую законную операцию, которую может выполнять ЦП, а другой - ненадежный и выполняет защищенный код, который может выполнять только определенный безопасный набор возможностей. Однако некоторые процессоры имеют гораздо более высокую степень детализации, и для безопасного использования виртуальных машин необходимы как минимум 1 или 2 дополнительных кольца (часто помеченных отрицательными числами), однако это выходит за рамки этого ответа.

Где операционная система входит

Ранние однозадачные ОС

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

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

Современные многозадачные ОС

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

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

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

Каждая ОС выбрала свою реализацию для этих средств защиты, частично основанную на архитектуре, для которой была разработана ОС, и частично основанную на дизайне и принципах рассматриваемой ОС. Например, UNIX фокусировалась на машинах, пригодных для многопользовательского использования, и была ориентирована на доступные функции для этого, в то время как окна были разработаны для упрощения работы на медленном оборудовании с одним пользователем. В X86 программы пользовательского пространства также взаимодействуют с ОС совершенно по-другому, как, например, в ARM или MIPS, заставляя многоплатформенную ОС принимать решения, основанные на необходимости работать на оборудовании, для которого она предназначена.

Эти специфичные для ОС взаимодействия обычно называются «системными вызовами» и охватывают то, как программа пользовательского пространства полностью взаимодействует с аппаратным обеспечением через ОС, они принципиально различаются в зависимости от функции ОС, и, следовательно, программе, которая выполняет свою работу через системные вызовы, необходимо быть конкретной ОС.

Загрузчик программы

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

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

Библиотеки

Программы редко используют системные вызовы напрямую, однако они почти исключительно приобретают свою функциональность, хотя библиотеки, которые оборачивают системные вызовы в немного более дружественный формат для языка программирования, например, C имеют C Standard Library и glibc под Linux и аналогичные библиотеки win32 под Windows NT и выше, большинство других языков программирования также имеют схожие библиотеки, которые оборачивают функциональность системы соответствующим образом.

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

Исключения из вышесказанного

Несмотря на все, что я здесь сказал, были попытки преодолеть ограничения, связанные с невозможностью запуска программ более чем в одной операционной системе. Несколько хороших примеров - проект Wine, который успешно эмулировал загрузчик программ win32, двоичный формат и системные библиотеки, позволяющие программам Windows работать в различных UNIX. Существует также уровень совместимости, позволяющий нескольким операционным системам BSD UNIX запускать программное обеспечение Linux, и, конечно, собственная оболочка Apple, позволяющая запускать старое программное обеспечение MacOS под MacOS X.

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

Vality
источник
6
+1 "Почему программная ОС специфична?" Потому что история.
Пол Дрейпер
2
модель безопасности процессора x86? почему и когда была изобретена модель?
n611x007
8
@naxa Нет, он давно предшествует x86, он был впервые частично реализован для Multics в 1969 году, которая является первой ОС с полезными многопользовательскими функциями разделения времени, требующими эту модель на компьютере GE-645 , однако эта реализация была неполной и на нее полагались Поддержка программного обеспечения, первая полная и безопасная реализация в аппаратном обеспечении была в его преемнике, Honeywell 6180 . Это было полностью аппаратно и позволило Multics запускать код от нескольких пользователей без возможности перекрестного вмешательства.
Vality
@Vality Кроме того, IBM LPAR составляет ~ 1972.
Эллиотт Фриш
@ElliottFrisch Ух ты, это впечатляет. Я не понял, что это было так рано. Спасибо за эту информацию.
Vality
48

Как вы можете видеть, API не указаны как часть операционной системы.

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

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

printf - это функция из библиотеки времени выполнения C, и в типичной реализации это довольно сложная функция. Если вы Google, вы можете найти источник для нескольких версий в Интернете. Смотрите эту страницу для экскурсии по одному . Вниз по траве, хотя в итоге он совершает один или несколько системных вызовов, и каждый из этих системных вызовов специфичен для операционной системы хоста.

Чарльз Э. Грант
источник
4
Что, если бы все, что сделала программа, это добавило два числа без ввода или вывода. Будет ли эта программа по-прежнему зависеть от ОС?
Пол
2
Операционные системы предназначены для того, чтобы помещать большинство аппаратных вещей позади / на уровне абстракции. Однако сама ОС (абстракция) может отличаться от реализации к реализации. Есть POSIX, к которым некоторые ОС (более или менее) придерживаются и, возможно, некоторые другие, но в целом ОС просто слишком сильно различаются по своей «видимой» части абстракции. Как сказано выше: вы не можете открыть / home / user в Windows и не можете получить доступ к HKEY_LOCAL_MACHINE \ ... в системе * N * X. Для этого вы можете написать виртуальное («эмулируемое») программное обеспечение, которое поможет сблизить эти системы, но это всегда будет «сторонняя организация» (из OS POV).
RobIII
16
@ Пол Да. В частности, способ его упаковки в исполняемый файл будет зависеть от ОС.
Стоп Harm Моника
4
@TimSeguine Я не согласен с вашим примером XP vs 7. Microsoft проделала большую работу, чтобы гарантировать, что в 7 существует тот же API, что и в XP. Очевидно, что здесь произошло то, что программа была разработана для работы с определенным API или контрактом. Новая ОС просто придерживалась того же API / контракта. Однако в случае Windows этот API является очень проприетарным, поэтому ни один другой поставщик ОС не поддерживает его. Даже тогда есть множество примеров программ, которые НЕ работают на 7.
ArTs
3
@Paul: Программа, которая не выполняет ввод / вывод, является пустой программой , которая должна компилироваться в неоперативный режим .
Берги
14

Компилятор делает что-то конкретное для ОС при компиляции?

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

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

Калеб
источник
12

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

Затем каждая ОС предоставляет свой набор библиотек для взаимодействия с аппаратным уровнем. Это API-интерфейсы, о которых вы упомянули, и они, как правило, представляют собой библиотеки, которые предоставляют разработчику более простой интерфейс, переводя его в более сложные, более конкретные вызовы в глубины самой ОС, причем эти вызовы часто недокументированы или защищены. Этот уровень часто довольно серый, с новыми API «OS», частично или полностью построенными на более старых API. Например, в Windows многие из новых API-интерфейсов, которые Microsoft создавала на протяжении многих лет, по сути являются слоями поверх оригинальных API-интерфейсов Win32.

Проблема, которая не возникает в вашем примере, но является одной из наиболее серьезных, с которыми сталкиваются разработчики, - это интерфейс с оконным менеджером для представления графического интерфейса. То, является ли оконный менеджер частью «ОС», иногда зависит от вашей точки зрения, а также от самой ОС: графический интерфейс в Windows интегрируется с ОС на более глубоком уровне, а графический интерфейс для Linux и OS X более непосредственно разделены. Это очень важно, потому что сегодня то, что люди обычно называют «Операционная система», является гораздо большим чудовищем, чем то, что обычно описывают в учебниках, поскольку оно включает в себя множество компонентов прикладного уровня.

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

Горт Робот
источник
2
Возможно, стоит отметить, что более простые исполняемые форматы могут быть загружены с использованием лишь небольшого объема ОЗУ (если таковой имеется) сверх того, который требуется для хранения загруженного кода, в то время как для более сложных форматов может потребоваться значительно больший объем ОЗУ во время, а в некоторых случаях даже после загрузки. MS-DOS будет загружать COM-файлы размером до 63,75 КБ, просто считывая последовательные байты в ОЗУ, начиная со смещения 0x100 произвольного сегмента, загружая CX с конечным адресом и переходя к нему. Однопроходная компиляция может быть выполнена без бэкапов (полезно с дискетами) ...
суперкат
1
... имея компилятор, включающий в каждую подпрограмму список всех точек исправления, каждая из которых будет включать в себя адрес предыдущего такого списка, и помещая адрес последнего списка в конец кода. ОС просто загружает код в виде необработанных байтов, но небольшая подпрограмма в коде может применить все необходимые исправления адресов перед выполнением основной части кода.
суперкат
9

Из другого моего ответа :

Рассмотрим ранние DOS-машины и реальный вклад Microsoft в мир:

Autocad должен был написать драйверы для каждого принтера, на который они могли печатать. Так сделал лотос 1-2-3. На самом деле, если вы хотите, чтобы ваше программное обеспечение печатало, вы должны были написать свои собственные драйверы. Если было 10 принтеров и 10 программ, то 100 разных частей одного и того же кода должны были быть написаны отдельно и независимо.

Что Windows 3.1 пытался сделать (наряду с GEM и многими другими уровнями абстракции), так это сделать так, чтобы производитель принтера написал один драйвер для своего принтера, а программист написал один драйвер для класса принтера Windows.

Теперь, с 10 программами и 10 принтерами, нужно написать только 20 частей кода, и поскольку сторона кода для Microsoft была одинаковой для всех, то примеры из MS означали, что у вас было очень мало работы.

Теперь программа была ограничена не только 10 принтерами, которые они выбрали для поддержки, но и всеми принтерами, производители которых предоставляли драйверы для Windows.

Таким образом, ОС предоставляет сервисы приложениям, поэтому приложениям не приходится выполнять работу, которая является избыточной.

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

Поскольку ОС предоставляет эти ресурсы, программисты могут добиться гораздо большего с минимальными усилиями.

Однако даже запуск программы сложен. ОС ожидает, что исполняемый файл будет иметь определенную информацию в начале, которая сообщает ОС, как он должен быть запущен, и в некоторых случаях (более продвинутые среды, такие как Android или iOS), какие ресурсы потребуются, которые требуют одобрения, поскольку они касаются ресурсов вне «песочница» - мера безопасности, помогающая защитить пользователей и другие приложения от ненадлежащего поведения программ.

Таким образом, даже если исполняемый машинный код такой же, а ресурсы ОС не требуются, программа, скомпилированная для Windows, не будет работать в операционной системе OS X без дополнительного уровня эмуляции или перевода, даже на том же аппаратном обеспечении.

Ранние операционные системы в стиле DOS часто могли совместно использовать программы, потому что они реализовывали один и тот же API в аппаратном обеспечении (BIOS) и ОС подключалась к аппаратному обеспечению для предоставления сервисов. Поэтому, если вы написали и скомпилировали COM-программу, представляющую собой образ памяти из серии инструкций процессора, вы можете запустить ее на CP / M, MS-DOS и некоторых других операционных системах. На самом деле вы все еще можете запускать программы COM на современных машинах Windows. Другие операционные системы не используют те же хуки API BIOS, поэтому COM-программы не будут работать без них, опять же, без уровня эмуляции или трансляции. Программы EXE следуют структуре, которая включает в себя гораздо больше, чем просто инструкции процессора, и поэтому, наряду с проблемами API, она не будет работать на машине, которая не понимает, как загрузить ее в память и выполнить.

Адам Дэвис
источник
7

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

Конечно, реальность такова, что это не так. EXEФайл не имеет такой же формат , как ELFфайл, даже если оба содержат двоичный код для того же процессора. * Таким образом , каждая операционная система должна будет иметь возможность интерпретировать все форматы файлов, и они просто не делали этого в начало, и у них не было причин начинать делать это позже (почти наверняка по коммерческим причинам, а не по техническим причинам).

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

Так что в принципе это вполне возможно. Фактически, WINE запускает исполняемые файлы Windows непосредственно в Linux.
Но это тонна работы и (обычно) коммерчески неоправданна.

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

Mehrdad
источник
Интересный факт: существует стандартизированный двоичный формат posiz, который можно запускать в разных операционных системах. Это просто не часто используется.
Марчин
@ Марчин: Похоже, вы не считаете Windows операционной системой. (Или вы говорите, что Windows может запускать двоичные файлы POSIX ?!) Для моего ответа POSIX не является стандартом, о котором я говорю. X в POSIX обозначает Unix. Он никогда не предназначался для использования, например, Windows, даже если Windows действительно имеет подсистему POSIX.
Мердад
1. Что-то может работать в нескольких ОС, но не во всех ОС; 2. Windows, так как NT может запускать двоичные файлы posix.
Марчин
1
@Marcin: (1) Как я уже сказал, X в POSIX означает UNIX . Это не стандарт, которому должны были следовать другие ОС, это была просто попытка достичь общего знаменателя между различными Unix, что замечательно, но не так удивительно. Тот факт, что существует множество разновидностей ОС Unix, совершенно не имеет отношения к вопросу, который я пытался сделать в отношении совместимости между другими операционными системами, кроме Unix. (2) Можете ли вы предоставить ссылку на № 2?
Мердад
1
@ Mehrdad: Марцин прав; Windows SUA (подсистема для приложений Unix) совместима с POSIX
MSalters
5

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

Проблема в том, что «библиотека» состоит из трех частей: реализации, интерфейса с приложением и интерфейса с ОС. В принципе, первые два можно сделать «универсальными» в отношении ОС (это зависит от того, где вы ее нарезаете), но третья часть - интерфейс с ОС - обычно не может. Интерфейс к ОС будет обязательно зависеть от ОС, предоставляемых ей API, механизма упаковки (например, формат файла, используемого Windows DLL) и т. Д.

Поскольку «библиотека» обычно предоставляется в виде одного пакета, это означает, что, как только программа выбирает «библиотеку» для использования, она фиксирует свою работу в конкретной ОС. Это происходит одним из двух способов: а) программист полностью выбирает заранее, и тогда привязка между библиотекой и приложением может быть универсальной, но сама библиотека привязана к ОС; или b) программист настраивает все так, чтобы библиотека выбиралась при запуске программы, но затем сам механизм привязки между программой и библиотекой зависит от ОС (например, механизм DLL в Windows). У каждого есть свои преимущества и недостатки, но в любом случае вам придется сделать выбор заранее.

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

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

К настоящему времени вы должны были заметить, куда я иду. Языковые платформы, такие как Java, делают именно это. Среда выполнения Java (библиотека) определяет нейтральную для ОС привязку между вашей программой Java и библиотекой (как среда выполнения Java открывает и запускает вашу программу) и обеспечивает реализацию, специфичную для текущей ОС. В некоторой степени .NET делает то же самое, за исключением того, что Microsoft не предоставляет «библиотеку» (среду выполнения) ни для чего, кроме Windows (но другие делают - см. Mono). И, на самом деле, Flash тоже делает то же самое, хотя по своим возможностям он более ограничен браузером.

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

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

Евро Мицелли
источник
3

Программное обеспечение не всегда зависит от ОС. Как Java, так и более ранняя система p-кода (и даже ScummVM) допускают перенос программного обеспечения в операционных системах. У Infocom (создателей Zork и Z-machine ) также была реляционная база данных, основанная на другой виртуальной машине. Однако на каком-то уровне что-то должно переводить даже эти абстракции в реальные инструкции, выполняемые на компьютере.

Эллиот Фриш
источник
3
Java работает на виртуальной машине, которая не является кросс-ОС. Вы должны использовать разные двоичные
файлы
3
@Izkata Правда, но вы не перекомпилируете программное обеспечение (только JVM). Также см. Мое последнее предложение. Но я укажу, что у Sun был микропроцессор, который мог напрямую выполнять байт-код.
Эллиотт Фриш
3
Java - это операционная система, хотя ее обычно не считают одной. Программное обеспечение Java является специфическим для ОС Java, и для большинства «настоящих» ОС существуют эмуляторы ОС Java. Но вы можете сделать то же самое с любым хостом и целевой ОС - например, запустить программное обеспечение Windows в Linux, используя WINE.
user253751
@immibis Я бы был более конкретным. Базовые классы Java (JFC, стандартная библиотека Java) - это фреймворк. Сама Java - это язык. JVM похожа на ОС: в ее названии присутствует «Виртуальная машина», и она выполняет функции, аналогичные ОС, с точки зрения выполняющегося в ней кода.
1

Ты говоришь

Программное обеспечение, созданное с использованием языков программирования для определенных операционных систем, работает только с ними

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

Здесь важно различать исходный код и скомпилированный двоичный файл. Язык программирования C специально разработан, чтобы быть независимым от ОС в исходном виде. Это достигается путем предоставления интерпретации таких вещей, как «печать на консоль», до разработчика. Но C может соответствовать чему-то, что зависит от ОС (причины см. В других ответах). Например, исполняемые форматы PE или ELF.

Дэн
источник
6
Кажется совершенно ясным, что ОП спрашивает о двоичных файлах, а не об исходном коде.
Калеб
0

Другие люди хорошо рассмотрели технические детали, я хотел бы упомянуть менее техническую причину, UX / UI сторону вещей:

Напиши один раз, чувствуешь себя неловко везде

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

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

  • Кнопки подтверждения имеют свои кнопки в различном порядке в Windows и OSX; поймите это неправильно, и пользователи будут нажимать не ту кнопку мышечной памятью. Windows имеет «Ok», «Cancel» в этом порядке. В OSX поменялся порядок, а текст кнопки «do-it» представляет собой краткое описание выполняемого действия: «Отмена», «Переместить в корзину».
  • Поведение «назад» отличается для iOS и Android. Приложения для iOS рисуют свою собственную кнопку «Назад», как обычно, в верхнем левом углу. Android имеет специальную кнопку в левом нижнем или правом нижнем углу в зависимости от поворота экрана. Быстрые порты для Android будут работать неправильно, если кнопка возврата ОС игнорируется.
  • Прокрутка импульса отличается между iOS, OSX и Android. К сожалению, если вы не пишете собственный код пользовательского интерфейса, вам, вероятно, придется написать собственное поведение прокрутки.

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

Ник Пинни
источник
-2

Важным отличием на этом этапе является отделение компилятора от компоновщика. Компилятор, скорее всего, выдает более или менее одинаковые выходные данные (различия в основном связаны с различными значениями #if WINDOWS). Компоновщик, с другой стороны, должен обрабатывать все специфичные для платформы вещи - связывать библиотеки, создавать исполняемый файл и т. Д.

Другими словами, компилятор заботится главным образом об архитектуре ЦП, поскольку он создает реально выполняемый код и должен использовать инструкции и ресурсы ЦП (обратите внимание, что байт-код IL или JVM .NET будет рассматриваться как набор команд виртуального ЦП). в этом представлении). Вот почему вы должны компилировать код отдельно для x86и ARM, например.

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

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

Программное обеспечение эпохи DOS часто было более переносимым в двоичном формате, но вы должны понимать, что оно также было скомпилировано не для DOS или Unix, а скорее для определенного контракта, который был обычен для большинства ПК в стиле IBM - разгрузка того, что сегодня называют вызовами API программное обеспечение прерывает Для этого не требовалось статическое связывание, поскольку вам нужно было только установить необходимые регистры, например, вызвать int 13hдля графических функций, и процессор просто перешел на указатель памяти, объявленный в таблице прерываний. Конечно, опять же, практика была намного сложнее, потому что для достижения высокой производительности педалирования вы должны были написать все эти методы самостоятельно, но в целом это означало обход всей ОС. И, конечно, есть что-то, что неизменно нуждается во взаимодействии с OS API - завершение программы. Но все же, если вы использовали самые простые доступные форматы (например,COMна DOS, у которого нет заголовка, только инструкции) и не хотелось выходить, ну что ж - удачи вам! И, конечно, вы также можете обрабатывать правильное завершение во время выполнения, так что вы можете иметь код как для завершения Unix, так и для завершения DOS в одном исполняемом файле, и определять во время выполнения, какой из них использовать :)

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