Производит ли компилятор машинный код? - PullRequest
0 голосов
/ 20 октября 2018

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

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

Ответы [ 4 ]

0 голосов
/ 03 января 2019

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

0 голосов
/ 20 октября 2018

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

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

0 голосов
/ 22 октября 2018

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

Вменяемый автор компилятора будет использовать язык ассемблера как вывод компилятора, после чего компилятор или пользователь в своем make-файле вызывает ассемблер, который создает объект.Вот как работает GCC.И как clang работает, конечно, но теперь ООО может создавать объекты напрямую, а не просто сборку, которая собирается.

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

Если архитектура такая же, то нет причин, почемуу вас не может быть общего набора инструментов для генерации кода для несовместимых операционных систем.инструменты GNU, например, могут сделать это.Различия в операционных системах не определяются по определению на уровне машинного кода, большинство из них находятся на высокоуровневых библиотеках языка C, которые можно создавать для графических окон и т. Д., Не имеют ничего общего с машинным кодом или архитектурой процессора, для некоторых операционных систем то же самоеC-код, специфичный для операционной системы, может использоваться на mips, arm, powerpc или x86.где архитектура становится специфической - это механизм, который вызывает реальные системные вызовы.Специальная инструкция часто используется.и машинный код в конечном итоге используется да, но нет причин, почему это не может быть закодировано в реальной или встроенной сборке.

И это приводит к тому, что библиотеки, даже fopen и printf, которые являются общими вызовами C, в конечном итоге вынуждены делать системный вызов, так что большая часть кода поддержки библиотек может быть совместима между языками высокого уровня систем, поэтому потребуетсябыть частью системы и архитектуры для последней мили.Вы должны увидеть это в источниках glibc или в newlib, например, в других библиотечных решениях.Как примеры.

То же самое верно для других языков, таких как C ++, как и для C. Интерпретируемые языки имеют дополнительные уровни, но их виртуальные машины - это просто программы, которые находятся на похожих уровнях.

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

0 голосов
/ 20 октября 2018

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

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

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

...