Почему компиляторы создают ассемблерный код?

19

Ассемблер конвертирует язык ассемблера в машинный язык. Зачем компилятору конвертировать язык высокого уровня в ассемблер? Разве он не может напрямую преобразовать язык высокого уровня в машинный код?

CODERSAM
источник

Ответы:

22

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

  • Символьные адреса, используемые ассемблерами вместо машинно-кодируемых адресов, значительно облегчают перемещение кода .
  • Связывание кода может включать проверки безопасности, такие как проверка типов, и это проще сделать с символическими именами.
  • Небольшие изменения в машинном коде легче учесть, изменив ассемблер, а не генератор кода.
Мартин Бергер
источник
почему язык ассемблера так эффективен, хотя он также написан на английском и как процессор понимает его?
CODERSAM
3
@CODERSAM Assembly - это формальный язык, а не естественный язык. Это очень близко к машинному языку. Таким образом, перевод не вводит неэффективности.
Мартин Бергер
когда вы говорите «очень близко к машинному языку», что это значит? Я действительно запутался с этим!
CODERSAM
2
@CODERSAM Точный смысл сложен, но что-то вроде гомоморфизма в алгебре. Когда вы переводите, скажем «add eax, # 2», который является сборкой x86, вы можете перевести его в d7f5 (или каким-либо другим кодом операции), сразу же, не глядя на контекст, не добавляя больше ничего. Сборка не имеет абстракции.
Мартин Бергер
1
«Сборка не имеет абстракции» - я бы сказал, что названия меток уже являются абстракцией (из смещений). Кроме того, контекст играет роль: например, add eax,2может быть переведен в 83 c0 02или в 66 83 c0 02зависимости от последней появившейся директивы, например use16.
Руслан
15

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

Юваль Фильмус
источник
Кроме того, если источник может включать в себя некоторый код сборки, то в любом случае должен быть доступен механизм для перевода этой встроенной сборки.
Пол А. Клейтон,
почему язык ассемблера так эффективен, хотя он также написан на английском и как процессор понимает его?
CODERSAM
1
Язык ассемблера - это «английское» описание машинного кода.
Юваль Фильмус
11

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

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

Supercat
источник
1

Даже платформы, которые используют один и тот же набор команд, могут иметь разные перемещаемые форматы объектных файлов. Я могу думать о «a.out» (ранний UNIX), OMF, MZ (MS-DOS EXE), NE (16-битная Windows), COFF (UNIX System V), Mach-O (OS X и iOS) и ELF (Linux и другие), а также их варианты, такие как XCOFF (AIX), ECOFF (SGI) и переносимый исполняемый файл (PE) на основе COFF в 32-битной Windows. Компилятору, который создает язык ассемблера, не нужно много знать о форматах объектных файлов, что позволяет ассемблеру и компоновщику инкапсулировать эти знания в отдельный процесс.

См. Также Разница между OMF и COFF при переполнении стека.

Дамиан Йеррик
источник
1

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

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

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

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

Компилятор, с которым я наиболее знаком (freepascal), может выводить ассемблер на всех платформах, но может выводить только двоичные объекты непосредственно на подмножестве платформ.

Питер Грин
источник
1

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

Однажды я просто не нашел ошибку в программе на C, работающей в Unix System V на компьютере с LSI-11. Казалось, ничего не работает. Наконец в отчаянии у меня был переносимый компилятор C, выделяющий версию его перевода на ассемблере. Я наконец нашел ошибку! Компилятор выделял больше регистров, чем было в машине! (Компилятор разместил регистры с R0 по R8 на машине только с регистрами с R0 по R7.) Мне удалось обойти ошибку в компиляторе, и моя программа сработала.

Еще одним преимуществом вывода ассемблера является попытка использовать «стандартные» библиотеки, которые используют другие протоколы передачи параметров. Более поздние компиляторы C позволяют мне устанавливать протокол с параметром («pascal» заставляет компилятор добавлять параметры в указанном порядке, а не в стандарте C, меняющем порядок).

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

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

Почему???

Роберт Пирсон
источник