6.48.1 Basic Asm — Инструкции ассемблера без операндов
Базовое asm утверждение имеет следующий синтаксис:
asm asm-qualifiers ( AssemblerInstructions )
Для языка C, ключевое слово asm является расширением GNU. При написании кода C, который может быть скомпилирован с опциями -ansi и -std, выбирающими диалекты C без расширений GNU, используйте __asm__ вместо asm (см. Альтернативные ключевые слова). Для языка C++, asm является стандартным ключевым словом, но __asm__ может быть использовано для кода, скомпилированного с -fno-asm.
Квалификаторы
volatile-
Необязательный квалификатор
volatileне оказывает никакого влияния. Все базовыеasmблоки неявно являются volatile. inlineЕсли вы используете квалификатор
inline, то для целей встраивания размерasmутверждения принимается как наименьший возможный размер (см. Размерasm).
Параметры
- AssemblerInstructions
-
Это строковая литерал, которая определяет код ассемблера. Строка может содержать любые инструкции, распознаваемые ассемблером, включая директивы. GCC не анализирует сами инструкции ассемблера и не знает, что они означают или даже являются ли они допустимым вводом для ассемблера.
Вы можете объединить несколько инструкций ассемблера в одной
asmстроке, разделенных символами, обычно используемыми в коде ассемблера для системы. Сочетание, которое работает в большинстве мест, — это перевод строки, плюс табуляция (записанные как ‘\n\t’). Некоторые ассемблеры разрешают использовать точку с запятой в качестве разделителя строки. Однако обратите внимание, что некоторые диалекты ассемблера используют точку с запятой для начала комментария.
Замечания
Использование расширенного asm (см. Расширенный Asm — Инструкции ассемблера с операндами выражений C) обычно приводит к более компактному, безопасному и эффективному коду, и в большинстве случаев это лучшее решение, чем базовый asm . Однако существуют две ситуации, в которых можно использовать только базовый asm:
- Расширенные
asmутверждения должны находиться внутри функции C, поэтому для написания встроенного языка ассемблера на уровне файла («верхний уровень»), вне функций C, необходимо использовать базовыйasm. Вы можете использовать эту технику для вывода директив ассемблера, определения макросов языка ассемблера, которые могут быть вызваны в других местах файла, или для написания целых функций на языке ассемблера. Базовыеasmутверждения вне функций не могут использовать никаких квалификаторов. - Функции, объявленные с атрибутом
naked, также требуют базовогоasm(см. Объявление атрибутов функций).
Безопасный доступ к данным C и вызов функций из базового asm более сложен, чем может показаться. Для доступа к данным C лучше использовать расширенный asm.
Не ожидайте, что последовательность asm утверждений останется идеально последовательной после компиляции. Если определенные инструкции должны оставаться последовательными в выходе, поместите их в одно многоинструкционное asm утверждение. Обратите внимание, что оптимизаторы GCC могут перемещать asm утверждения относительно другого кода, включая перемещения через переходы.
asm утверждения не могут выполнять переходы в другие asm утверждения. GCC не знает об этих переходах и поэтому не может учесть их при принятии решения об оптимизации. Переходы от asm к меткам C поддерживаются только в расширенном asm.
В определенных обстоятельствах GCC может дублировать (или удалять дубликаты) ваш код ассемблера при оптимизации. Это может привести к неожиданным ошибкам дублирования символов во время компиляции, если ваш код ассемблера определяет символы или метки.
Предупреждение: Стандарты C не определяют семантику для asm, что делает их потенциальным источником несовместимости между компиляторами. Эти несовместимости могут не давать предупреждений/ошибок компилятора.
GCC не анализирует AssemblerInstructions базового asm, что означает, что нет способа сообщить компилятору о том, что происходит внутри них. GCC не имеет видимости символов в asm и может отбрасывать их как неиспользуемые. Он также не знает о побочных эффектах кода ассемблера, таких как изменения в памяти или регистрах. В отличие от некоторых компиляторов, GCC предполагает, что изменения в регистрах общего назначения не происходят. Это предположение может измениться в будущей версии.
Чтобы избежать проблем с будущими изменениями семантики и несовместимостей между компиляторами, рассмотрите возможность замены базового asm на расширенный asm. См. Как перевести базовый ассемблер в расширенный для получения информации о выполнении этого преобразования.
Компилятор копирует инструкции ассемблера в базовом asm дословно в выходной файл ассемблера без обработки диалектов или каких-либо операторов ‘%’, доступных с расширенным asm. Это приводит к небольшим различиям между строками базового asm и шаблонами расширенного asm. Например, для ссылки на регистры вы можете использовать ‘%eax’ в базовом asm и ‘%%eax’ в расширенном asm.
На целевых платформах, таких как x86, поддерживающих несколько диалектов ассемблера, все базовые asm блоки используют диалект ассемблера, указанный параметром командной строки -masm (см. Опции x86). Базовый asm не предоставляет механизм для предоставления различных строк ассемблера для разных диалектов.
Для базового asm с непустой строкой ассемблера GCC предполагает, что блок ассемблера не изменяет регистры общего назначения, но может читать или записывать любые глобально доступные переменные.
Вот пример базового asm для i386:
/* Note that this code will not compile with -masm=intel */
#define DebugBreak() asm("int $3")
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Basic-Asm.html