GCC Inline Assembly

GCC Inline Assembly

GCC Inline Assembly — Встроенный ассемблер компилятора GCC, представляющий собой язык макроописания интерфейса компилируемого высокоуровнего кода с ассемблерной вставкой.

Содержание

Особенности

Синтаксис и семантика GCC Inline Assembly имеет следующие существенные отличия:

  • GCC не интерпретирует никак содержимое ассемблерной вставки.
  • Служит явное описание интерфейса с ассемблерной вставкой.
  • Даёт возможность компилятору свободу выбора регистров.
  • Позволяет явно указать на имеющиеся побочные действия ассемблерного кода.
  • Позволяет использовать все инструкции (и директивы тоже) которые распознает ассемблер, а не только те, что знает и применяет gcc

Предварительные сведения

Для того, чтобы хорошо понимать, как работает GCC Inline Assembly для начала неплохо сначала хорошо представлять процесс компиляции, как он происходит.

В начале gcc вызывает препроцессор cpp, который включает заголовочные файлы, разворачивает все условные директивы и выполняет макроподстановки. Посмотреть, что получилось после макроподстановки, можно командой gcc -E -o preprocessed.c some_file.c. Ключ -E редко используется, в основном когда вы занимаетесь отладкой макросов.

Затем gcc анализирует полученный код, на этой же фазе производит оптимизацию кода и в итоге производит ассемблерный код. Увидеть сгенерированный ассемблерный код можно командой gcc -S -o some_file.S some_file.c.

Затем gcc вызывает ассемблер gas для того, чтобы он создал из ассемблерного кода объектный код. Обычно ключ -c (compile only) используется в проектах, состоящих из многих файлов.

Затем gcc вызывает линкер ld для сборки исполняемого файла из полученных объектных файлов.

Для иллюстрации данного процесса создадим файл test.c следующего содержания:

int main()
 {
 asm ("Bla-Bla-Bla"); // вставим такую инструкцию
 return 0;
 }

Если мы скажем выполнить gcc -S -o test.S test.c, то мы обнаружим важный факт: компилятор обработал «неправильную» инструкцию и результирующий ассемблерный файл test.S содержит нашу строку «Bla-Bla-Bla». Однако, если мы попробуем создать объектный код или собрать бинарный файл, то gcc выведет следующее:

test.c: Assembler messages: test.c:3: Error: no such instruction: 'Bla-Bla-Bla'

Сообщение исходит именно от Ассемблера.

Отсюда следует важный вывод: GCC никак не интерпретирует содержимое ассемблерной вставки, воспринимая её как макроподстановку времени компиляции.

Синтаксис

Общая структура

Общая структура ассемблерной вставки выглядит следующим образом:

asm [volatile] («команды и директивы ассемблера» : выходные параметры : входные параметры : изменяемые параметры);

впрочем, существует и более короткая форма:

asm [volatile] («команды ассемблера»);

Синтаксис команд

Главный «камень преткновения» новичков представляет собой тот факт, что ассемблер gas и компилятор gcc используют синтаксис AT&T, который существенно отличается от ассемблера Intel. В Вики-учебнике есть статья об этом [1], поэтому законспектируем только основные факты, которые необходимо знать.

Итак, краткий конспект:

  1. Порядок операндов: Операция Источник,Приёмник. Мнемотехника для запоминания: как в командах cp или mv :)
  2. Названия регистров имеют явный префикс %, указывающий, что это регистр. То есть %eax,%dl,%esi,%xmm1 и т. д. Как показывает практика, весьма удобно, особенно учитывать подсветку синтаксиса, а также что вы можете «достать» из ассемблера переменную, которую кто-то назвал, например, ax, и даже сделать movw ax,%ax, что в Intel-синтаксисе было бы невозможно. То, что названия регистров не являются зарезервированными словами, — несомненный плюс.
  3. Явное задание размеров операндов в суффиксах команд: b-byte, w-word, l-long, q-quadword. В командах типа movl %edx,%eax это может показаться излишним, однако является весьма наглядным средством, когда речь идёт о incl (%esi) или xorw $0x7,mask
  4. Названия констант начинаются с $ и могут быть выражением. Например movl $1,%eax
  5. Значение без префикса означает адрес. Это ещё один камень преткновения новичков. Просто следует запомнить, что:
    movl $123,%eax — записать в %eax число 123,
    movl 123,%eax — записать в %eax содержимое ячейки памяти с адресом 123,
    movl var,%eax — записать в %eax значение переменной var,
    movl $var,%eax — загрузить адрес переменной var
  6. Для косвенной адресации необходимо использовать круглые скобки. Например movl (%ebx),%eax — загрузить в %eax значение переменной, по адресу находящемуся в регистре %ebx
  7. SIB-адресация: смещение(база, индекс, множитель)

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

 asm(
  "our_data_file:\n\t"
  ".incbin \"some_bin_file.txt\"\n\t" // используем директиву .incbin
  "our_data_file_len:\n\t"
  ".long .-our_data_file\n\t"  // вставляем значение .long с вычисленной длиной файла
  );

И затем адресоваться к этому бинарному файлу:

extern char our_data_file[];
extern long our_data_file_len;

Как работает макроподстановка

Рассмотрим, как происходит подстановка.

Конструкция:

asm ("movl %0,%%eax"::"i"(1));

Превратится в

movl $1,%eax

Входные и выходные параметры

Модификаторы

Тонкие моменты

Ключевое слово volatile

Для чего в случае asm служит ключевое слово volatile? Для того чтобы указать компилятору, что вставляемый ассемблерный код может давать побочные эффекты, поэтому попытки оптимизации могут привести к логическим ошибкам.

Случаи, когда ключевое слово volatile ставить обязательно:

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

СОВЕТ: Всегда указывайте asm volatile в тех случаях, когда ваша ассемблерная вставка должна «стоять там где стоит». Особенно это касается тех случаев, когда вы работаете с атомарными примитивами.

«memory» в clobber list

Следующий «тонкий момент» — явное указание «memory» в clobber list. Помимо простого указания компилятору, что ассемблерная вставка изменяет содержимое памяти, она ещё служит директивой Memory Barrier для компилятора. Что это означает? Это означает, что те операции обращений в память, которые стоят выше по коду, в результирующем машинном коде будут выполняться до тех, которые стоят ниже ассемблерной вставки. В случае многопоточной среды, когда от этого напрямую зависит риск возникновения race condition, это обстоятельство является существенным.

СОВЕТ № 1:

Быстрый способ сделать Memory Barier

#define mbarrier() asm volatile ("":::"memory")

СОВЕТ № 2: Указание «memory» в clobber list не только «хороший тон», но и в случае работы с атомарными операциями, призванными разрулить race condition, является обязательным.

Примеры использования

int main()
{
  int sum = 0, x = 1, y = 2;
  asm ( "add %1, %0" : "=r" (sum) : "r" (x), "0" (y) ); // sum = x + y;
  printf("sum = %d, x = %d, y = %d", sum, x, y); // sum = 3, x = 1, y = 2
  return 0;
}
  • код: добавить %1 к %0 и сохранить результат в %0
  • выходные параметры: универсальный регистр, сохранённый в локальную переменную, после выполнения ассемблерного кода.
  • входные параметры: универсальные регистры, инициализированные от локальных переменных x и y перед выполнением ассемблерного кода.
  • изменяемые параметры: ничего, кроме регистров ввода/вывода.

Ссылки


Wikimedia Foundation. 2010.

Игры ⚽ Нужно сделать НИР?

Полезное


Смотреть что такое "GCC Inline Assembly" в других словарях:

  • Inline assembler — In computer programming, the inline assembler is a feature of some compilers that allows very low level code written in assembly to be embedded in a high level language like C or Ada. This embedding is usually done for one of three reasons:*… …   Wikipedia

  • Assembly language — See the terminology section below for information regarding inconsistent use of the terms assembly and assembler. Motorola MC6800 Assembly Language An assembly language is a low level programming language for computers, microprocessors,… …   Wikipedia

  • High Level Assembly — Infobox Software name = High Level Assembly (HLA) Language developer = Randall Hyde latest release version = 1.102 Beta latest release date = release date|2008|05|02 operating system = Windows, Linux, FreeBSD, Mac OS X genre = Assembler license …   Wikipedia

  • Integrierter Assembler — Inline Assembler (oder auch integrierter Assemblercode) ist ein Assemblerspracheteil, der in einen in einer höheren Programmiersprache geschrieben Quelltext eines Programm integriert ist. Der Übergang wird Mittels einer speziellen Anweisung… …   Deutsch Wikipedia

  • Cross-Assembler — Ein Assembler (nach DIN 44300: Assemblierer) ist ein Hilfsprogramm der Programmierung (Programmierwerkzeug), das ein in einer einfachen, maschinennahen Assemblersprache geschriebenes Programm in Maschinensprache (auch Maschinencode oder Nativer… …   Deutsch Wikipedia

  • Сравнение с обменом — (англ. compare and set, compare and swap, CAS)  атомарная инструкция, сравнивающая значение в памяти с одним из аргументов, и в случае успеха записывающая второй аргумент в память. Поддерживается в семействах процессоров x86, Itanium,… …   Википедия

  • Assembler (Informatik) — Ein Assembler (nach DIN 44300: Assemblierer) ist ein Hilfsprogramm der Programmierung (Programmierwerkzeug), das ein in maschinennaher Assemblersprache geschriebenes Computerprogramm in Maschinensprache (auch Maschinencode oder Nativer Code… …   Deutsch Wikipedia

  • Tiny C Compiler — Infobox Software name = Tiny C Compiler logo = developer = Fabrice Bellard latest release version = 0.9.24 latest release date = release date|2008|04|01 programming language = C and Assembly operating system = Linux, Unix, Microsoft Windows genre …   Wikipedia

  • SSE2 — SSE2, Streaming SIMD Extensions 2, is one of the IA 32 SIMD (Single Instruction, Multiple Data) instruction sets. SSE2 was first introduced by Intel with the initial version of the Pentium 4 in 2001. It extends the earlier SSE instruction set,… …   Wikipedia

  • Intrinsic function — In compiler theory, an intrinsic function is a function available in a given language whose implementation is handled specially by the compiler. Typically, it substitutes a sequence of automatically generated instructions for the original… …   Wikipedia


Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»