Нужен ли современным компиляторам ассемблер?

Если я не ошибаюсь, у всех компиляторов есть ассемблер (ml, as и т. д.), и они используют его для перевода высокоуровневого кода на машинный язык в фоновом режиме (код c/c++ -> код asm -> машинный код) . Но интересно, современные компиляторы тоже так работают или компилируют высокоуровневый исходный код в прямой машинный код? Короче говоря, MSVC использует ml.exe или GCC использует ./as в фоновом режиме?

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

Jester 11.02.2023 12:37

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

fuz 11.02.2023 12:40

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

Erik Eidt 11.02.2023 17:04

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

Erik Eidt 11.02.2023 17:06

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

old_timer 12.02.2023 03:48

многие, если не все компиляторы превращают язык высокого уровня в своего рода внутренний «код» или набор структур, который затем является промежуточным шагом к серверной части генерации целевого кода. llvm, например, что сама промежуточная информация может быть выведена в виде файла, имеет язык программирования и т. д., поэтому с clang/llvm вы можете иметь высокий уровень, байт-код, байт-код в форме ascii, язык ассемблера, объект и компоновщик или. ... вы можете перейти от высокого уровня к объектному коду, а затем связать. вы можете оптимизировать на каждом уровне.

old_timer 12.02.2023 03:51

(хотя вы получаете только один компоновщик, если он есть, хотя остальная часть цепочки инструментов способна создавать код для разных целей)

old_timer 12.02.2023 03:51
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
100
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Проблема в том, что вы не смотрите на современные компиляторы. Обоим упомянутым вами компиляторам уже около 30 лет (GCC впервые выпущен в 1987 году, а MSVC впервые выпущен в 1993 году, согласно их страницам в Википедии), и никому не нравятся новые версии старых вещей, которые нарушают совместимость.

Вероятно, самым известным современным компилятором является Clang; но он разработан как замена для старого компилятора (Clang пытается поддерживать те же аргументы командной строки, встроенный синтаксис сборки, расширения, ... как GCC).

По сути, у того, кто пишет современный компилятор, есть 3 варианта:

а) ломать совместимость с древними вещами и генерировать только машинный код.

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

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

«Компилятору не нужен ассемблер, но автору компилятора может». Вариант «а» кажется высокомерным и нереалистичным. Большинство компиляторов могут выводить формы IR. Godbolt кто-нибудь использует? У компилятора может быть возможность перейти непосредственно к двоичному коду; но есть много случаев использования, когда возможность генерировать ассемблер является ценной. Я бы назвал компилятор, который не может генерировать ассемблер, неполноценным.

artless noise 11.02.2023 21:10
Ответ принят как подходящий

Различается.

  • gcc использует внешнюю программу as. Не «в фоновом режиме», а как отдельный проход, работающий с временным .s файлом, написанным компилятором. Или, если вы используете опцию -pipe, в конвейере. Вы можете увидеть команду as, которая запускается, если вы компилируете с gcc -v.

  • clang имеет «интегрированный ассемблер», который используется по умолчанию вместо as. Однако, если вы отключите его с помощью -fno-integrated-as, он будет работать as отдельно, и вы можете увидеть это в выводе clang -v.

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

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

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

Так что это действительно сводится к дизайнерскому решению. Компиляция непосредственно в машинный код имеет некоторые преимущества:

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

  • это может упростить некоторые микрооптимизации

и некоторые преимущества для внешнего ассемблера:

  • позволяет не изобретать велосипед, если в системе уже есть работающий ассемблер

  • разделение ответственности: компилятору не нужно ничего знать о машинном коде или формате объектного файла, ассемблеру не нужно ничего знать о IR компилятора

  • легче обеспечить 100% совместимость с кодом, написанным для существующего ассемблера. Например, clang иногда имеет проблемы со сборкой исходного кода, написанного для gcc/gas, если он содержит встроенный ассемблер с использованием неясных функций газа, поскольку интегрированный ассемблер clang не всегда поддерживает их совместимо.

MSVC не использует отдельный ассемблер, и из того, что я читал, ассемблерные листинги, которые он может выдать, не готовы для сборки в полностью рабочие объектные файлы, которые вы могли бы связать. (например, они содержат посторонние определения, которые приведут к конфликтам имен.) Вот почему его параметр вывода asm называется «листинг». learn.microsoft.com/en-us/cpp/build/reference/…

Peter Cordes 11.02.2023 21:16

Встроенный синтаксис __asm {} MSVC должен компилировать этот блок, а не просто передавать его ассемблеру. Или, по крайней мере, он должен проанализировать его на наличие имен переменных C++ и заменить их режимами адресации, а также знать, какие регистры записываются каждой инструкцией (так что он знает, что сохранять/восстанавливать в функции, содержащей блок asm). По этой причине встроенные ассемблерные блоки MSVC не поддерживают полный материал MASM, например. нет db для генерации произвольного машинного кода и IDK, если вы можете определить метки для выполнения сумасшедших вещей, таких как переход между операторами asm (что-то, что возможно, но не поддерживается для GCC).

Peter Cordes 11.02.2023 21:21

IIRC, clang по умолчанию использует встроенный ассемблер и обрабатывает каждый оператор GNU C asm() отдельно, а не как часть одного большого файла. IIRC вы не можете определить .macro в одном и использовать его в другом, если вы не используете clang -fno-integrated-as

Peter Cordes 11.02.2023 21:22

Мое понимание решения MSVC не поддерживать его ни на чем, кроме x86, заключается в том, что внутренняя реализация действительно хрупкая и сложная в обслуживании, а также небезопасна в функциях с регистровыми аргументами (даже на x86). И это никогда не было очень хорошим дизайном, заставляющим сохранение/перезагрузку для получения данных в операторе asm. Предоставление встроенных функций для всего лучше, чем неэффективный встроенный ассемблер. Также, вероятно, многие люди ожидали, что смогут делать сумасшедшие вещи за спиной компилятора.

Peter Cordes 11.02.2023 21:53

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

Peter Cordes 11.02.2023 21:54

Связанный: rust-lang.github.io/rfcs/… обсуждается тот факт, что синтаксис MSVC __asm { .. } в основном представляет собой предметно-ориентированный язык, встроенный в C++, который компилятор должен понимать для компиляции такого кода. (В отличие от встроенного ассемблера GNU C, который представляет собой просто %operand подстановку строки в шаблон и выдачу этого текста буквально в вывод ассемблера компилятора для сборки.) И что желательно не писать новый DSL для каждой поддерживаемой Rust архитектуры.

Peter Cordes 11.02.2023 21:58

Еще одно преимущество компиляции непосредственно в машинный код: если вы используете ассемблер, «вы никогда не знаете, куда он поместит вещи, поэтому вам придется использовать отдельные константы». web.archive.org/web/20180212083430/https://cboh.org/mel.txt

prl 12.02.2023 06:37

Другие вопросы по теме