Параметры вывода
При желании сохранить содержиме регистра eax в какой-либо переменной, первым желанием будет написать что-нибудь подобное следующему:
procedure Getflags is
Eax : Unsigned_32; begin Asm ("pushfl" & LF & HT & -- сохранить регистр флагов в стеке "popl %%eax" & LF & HT & -- загрузить флаги из стека в регистр eax "movl %%eax, Eax") -- сохранить значение флагов в переменной Put_Line ("Flags register:" & Eax'Img); end Getflags; |
с попыткой сразу сохранить содержимое регистра процессора eax в переменной Eax.
Увы, также просто как это может выглядеть, это не будет работать, поскольку нельзя точно сказать чем будет являться переменная Eax.
Несколько подумав, можно сказать: Eax - это локальная переменная, которая, в обычной ситуации, будет размещена в стеке.
Однако, в результате оптимизации, компилятор, для хранения этой переменной во время выполнения подпрограммы, может использовать не пространство в стеке, а обычный регистр процессора.
Таким образом, возникает законный вопрос: как необходимо специфицировать переменную, чтобы обеспечить корректную работу для обоих случаев?
Ответ на этот вопрос заключается в том, чтобы не сохранять результат в переменной Eax
самостоятельно, а предоставить компилятору возможность самостоятельно выбирать правильный операнд для использования.
Для этой цели применяется понятие параметра вывода.
Программа, использующая инструкцию вывода, будет выглядеть так как она была написана ранее:
Asm ("pushfl" & LF & HT & -- сохранить регистр флагов в стеке "popl %%eax" & LF & HT & -- загрузить флаги из стека в регистр eax "movl %%eax, %0") -- сохранить значение флагов в переменной |
Следует обратить внимание на то, что мы заменили обращение к переменной Eax
на обращение к операнду %0.
Однако, компилятору необходимо указать, чем является %0:
Outputs => Unsigned_32'Asm_Output ("=g", Eax)); |
Здесь, часть "Outputs =>" укажет, что это именованный параметр инструкции ассемблера (полный синтаксис инструкций ассемблера будет рассмотрен позже в "Синтаксис GNAT").
Напомним также, что ранее мы описали переменную Eax, как переменную типа Interfaces.Unsigned_32.
Мы описали ее таким образом, поскольку 32-битный беззнаковый целый тип удачнее всего подходит для представления регистра процессора.
Не трудно заметить, что вывод назначен как атрибут типа, который мы реально хотим использовать для нашего вывода.
Unsigned_32'Asm_Output ("=g", Eax); |
Общая форма такого описания имеет следующий вид:
Type'Asm_Output (строка_ограничений, имя_переменной) |
Смысл имени переменной и атрибута 'Asm_Output достаточно понятны.
Остается понять, что означает и для чего используется строка_ограничений.