6.11.1 Базовый 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. В операторах базовогоasmвне функций нельзя использовать какие-либо квалификаторы. inlineЕсли вы используете квалификатор
inline, то при встраивании размер оператораasmсчитается минимально возможным (см. раздел Размерasm).
Параметры
- AssemblerInstructions
-
Это строковый литерал, задающий ассемблерный код. В C++ с -std=gnu++11 или более поздним стандартом он также может быть константным выражением в скобках (см. раздел Константные выражения C++11 вместо строковых литералов).
Строка может содержать любые инструкции, распознаваемые ассемблером, включая директивы. GCC не анализирует сами ассемблерные инструкции и не знает, что они означают и даже являются ли они допустимым вводом для ассемблера.
Можно поместить несколько ассемблерных инструкций в одну строку
asm, разделив их символами, обычно используемыми в ассемблерном коде для данной системы. В большинстве случаев подойдет сочетание перевода строки для разрыва строки и символа табуляции (записываемое как ‘\n\t’). Некоторые ассемблеры допускают использование точки с запятой в качестве разделителя строк. Однако обратите внимание: в некоторых диалектах ассемблера точка с запятой начинает комментарий.
Замечания
Использование расширенного asm (см. раздел Расширенный Asm — ассемблерные инструкции с операндами-выражениями C) обычно позволяет получать более компактный, безопасный и эффективный код и в большинстве случаев является лучшим решением, чем базовый asm. Однако для функций, объявленных с атрибутом naked, требуется только базовый asm (см. раздел Объявление атрибутов функций).
Операторы базового asm можно использовать как внутри функции C, так и на уровне файла («верхнего уровня»). В последнем случае этот прием позволяет выводить директивы ассемблера, определять макросы языка ассемблера для последующего вызова в других местах файла или записывать целые функции на языке ассемблера.
Безопасный доступ к данным 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. В результате строки базового asm и шаблоны расширенного asm немного различаются. Например, для обращения к регистрам в базовом asm можно использовать ‘%eax’, а в расширенном asm — ‘%%eax’.
На целевых платформах, таких как 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-15.3.0/gcc/Basic-Asm.html