Ада-95. Компилятор GNAT

       

Более реальный пример


Более реальным и интересным примером может служить пример, который позволет увидеть содержимое регистра флагов процессора:

with Interfaces; use Interfaces; with Ada.Text_IO; use Ada.Text_IO; with System.Machine_Code; use System.Machine_Code; with Ada.Characters.Latin_1; use Ada.Characters.Latin_1;

procedure Getflags is

Eax : Unsigned_32; begin

Asm ("pushfl" & LF & HT & -- сохранить регистр флагов в стеке "popl %%eax" & LF & HT & -- загрузить флаги из стека в регистр eax "movl %%eax, %0", -- сохранить значение флагов в переменной Outputs => Unsigned_32'Asm_Output ("=g", Eax)); Put_Line ("Flags register:" & Eax'Img); end Getflags;

Текст этого примера может неожиданно показаться несколько сложным.

Однако это не должно вызывать большие опасения, поскольку далее будут рассмотрены все тонкости этого примера.

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

Первое, на что необходимо обратить внимание - это способ записи множества инструкций ассемблера.

Реально, следующий пример записи множества инструкций ассемблера будет полностью корректным:

Asm ("pushfl popl %%eax movl %%eax, %0")

В генерируемом ассемблерном файле этот фрагмент будет отображен следующим образом:

#APP pushfl popl %eax movl %eax, -40(%ebp) #NO_APP

Не трудно заметить, что такой результат не очень легко и удобно читать.

Таким образом, удобнее записывать различные инструкции ассемблера в отдельных строчках исходного текста, заключая их в двойные кавычки, а с помощью стандартного пакета Ada.Characters.Latin_1

выполнять "ручную" вставку символов перевода строки(LineFeed / LF) и горизонтальной табуляции (Horizontal Tab / HT).

Это позволяет сделать более читабельным как исходный текст Ады:

Asm ("pushfl" & LF & HT & -- сохранить регистр флагов в стеке "popl %%eax" & LF & HT & -- загрузить флаги из стека в регистр eax "movl %%eax, %0") -- сохранить значение флагов в переменной

<


так и генерируемый файл ассемблера:

#APP pushfl popl %eax movl %eax, -40(%ebp) #NO_APP

Однако, стоит обратить внимание на тот факт, что Ада полностью игнорирует комментарии в конце строки при записи реальных инструкций ассемблера в генерируемый ассемблерный файл.

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

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

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

Следовательно, поскольку ассемблер сам требует использование символа процента перед именем регистра, то мы получаем следующую инструкцию встроенного ассемблера для пересылки содержимого из регистра ax в регистр bx:

Asm ("movw %%ax, %%bx");

Это будет отображено в сгенерированном ассемблерном файле как:

#APP movw %ax, %bx #NO_APP

Фактическое использование символа процента в инструкциях ассемблера необходимо для введения операнда более общего вида:

Asm ("pushfl" & LF & HT & -- сохранить регистр флагов в стеке "popl %%eax" & LF & HT & -- загрузить флаги из стека в регистр eax "movl %%eax, %0", -- сохранить значение флагов в переменной Outputs => Unsigned_32'Asm_Output ("=g", Eax));

Здесь, %0, %1, %2... индицируют операнды которые позже описывают использование параметров ввода (Input) и вывода (Output).


Содержание раздела