Более реальным и интересным примером может служить пример, который позволет увидеть содержимое регистра флагов процессора:
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") -- сохранить значение флагов в переменной |