Подтвердить что ты не робот

Компиляторы языка программирования сначала переходят на сборку или непосредственно на машинный код?

Меня интересуют популярные и широко используемые компиляторы, такие как gcc. Но если все будет по-другому с разными компиляторами, я тоже хотел бы это знать.

Взяв gcc в качестве примера, он компилирует короткую программу, написанную на C, непосредственно в машинный код, или он сначала переводит ее на удобочитаемую сборку, а затем использует ассемблер (встроенный?) для перевода программа сборки в двоичный, машинный код - ряд инструкций для CPU?

Использует ли код сборки для создания бинарного исполняемого файла значительно дорогой операции? Или это относительно простая и быстрая работа?

(Предположим, что мы имеем дело только с семейством процессоров x86, а все программы написаны для Linux.)

Я был бы очень благодарен за любую помощь и подумал по этому поводу. Спасибо!

4b9b3361

Ответ 1

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

Некоторые компиляторы производят другой высокоуровневый языковой код в качестве своего вывода - например, cfront, первый компилятор С++ выпустил C как свой вывод, который затем был скомпилирован компилятором C.

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

Ответ 2

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

  • Стандартный ML Нью-Джерси, который работает в интерактивном режиме и компилирует каждое выражение на лету.

  • tinycc компилятор, который предназначен для того, чтобы быть достаточно быстрым для компиляции, загрузки и запуска C script в скважине менее 100 миллисекунд, и поэтому не хочет накладных расходов на вызов ассемблера и компоновщика.

У этих общих случаев есть желание "мгновенного" ответа. Ассемблеры и компоновщики достаточно быстры, но недостаточно хороши для интерактивного ответа. Тем не менее.

Существует также большое семейство языков, таких как Smalltalk, Java и Lua, которые компилируются в байт-код, а не код сборки, но реализация которых позже может перевести этот байт-код непосредственно на машинный код без преимущества ассемблера.

(Сноска: в начале 1990-х годов Мэри Фернандес и я написали набор инструментов машинного кода Нью-Джерси, для которых code находится в сети, который генерирует библиотеки C которые могут использовать авторы компилятора для обхода стандартного ассемблера и компоновщика. Мэри использовала его, чтобы примерно удвоить скорость своего оптимизирующего компоновщика при генерации a.out Если вы не пишете на диск, ускорение еще больше...)

Ответ 3

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

О gcc, он может скомпилировать для самых разных целей. Я не знаю, сначала ли он компилируется на сборку x86, но я дал вам некоторое представление о компиляторах - и вы тоже просили об этом.

Ответ 4

Согласно глава 2 Введение в обратное инженерное программное обеспечение (Майком Перри и Наско Осковым), как gcc, так и cl.exe(компилятор для MSVС++) имеют переключатель -S, который вы можете использовать для вывода сборки, которую производит каждый компилятор.

Вы также можете запустить gcc в подробном режиме (gcc -v), чтобы получить список команд, которые он выполняет, чтобы увидеть, что он делает за кулисами.

Ответ 5

GCC компилируется для ассемблера. Некоторые другие компиляторы этого не делают. Например, LLVM-GCC компилируется в LLVM-сборку или LLVM-байт-код, который затем скомпилируется в машинный код. Почти все компиляторы имеют какое-то внутреннее представление, LLVM-GCC использует LLVM, и, IIRC, GCC использует что-то, называемое GIMPLE.

Ответ 6

Visual С++ имеет switch для вывода кода сборки, поэтому я думаю, что он генерирует код сборки перед выдачей машинного кода.

Ответ 8

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

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

Ответ 9

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

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

код:

x = y + z + w

в

reg1 = y + z
x = reg1 + w

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

Ответ 10

Ни один из ответов не разъясняет тот факт, что ASSEMBLER является первым слоем абстракции между BINARY CODE и MACHINE DEPENDENT SYMBOLIC CODE. Компилятор - это второй уровень абстракции между МАШИНОСТРОЕННЫМ СИМВОЛИЧЕСКИМ КОДОМ И НЕЗАВИСИМЫМ СИМВОЛИЧЕСКИМ КОДОМ МАШИН.

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

Более уместно сказать, что компилятор использует INTERMEDIATE CODE, который может или не может быть языком ассемблера, например. Java использует байтовый код как промежуточный код, а байтовый код - ассемблер для виртуальной машины Java (JVM).

EDIT: Вы можете задаться вопросом, почему ассемблер всегда производит код, зависящий от машины, и почему компилятор способен создавать независимый от машины код. Ответ очень простой. Ассемблер - это прямое отображение машинного кода, и поэтому язык сборки, который он производит, всегда зависит от машины. Напротив, мы можем написать несколько версий компилятора для разных машин. Поэтому для запуска нашего кода независимо от машины мы должны скомпилировать тот же код, но в версии компилятора, написанной для этой машины.

Ответ 11

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

Хотя это может показаться медленным - это может быть быстрее, потому что JVM может использовать преимущества более поздних инструкций CPU и новых оптимизаций. Компилятор С++ этого не сделает - вам нужно настроить таргетинг на набор команд во время компиляции.

Ответ 12

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