Система команд x86 |
|
Программирование - Архитектура и система команд микропроцессоров x86 |
PUSHF
Влияние команды на флаги и форматы команды:
|
|
|
|
|
|
|
|
|
9C |
PUSHF |
Сохранить в стеке регистр FLAGS |
8086 |
pushf |
9C |
PUSHFD |
Сохранить в стеке регистр EFLAGS |
Intel386 |
pushfd |
Описание:
Команда PUSHF/PUSHFD сохраняет содержимое регистра флагов (E)FLAGS в стеке (слово либо двойное слово). Если атрибут размера операнда (OperandSize) этой команды равен 16 бит (команда PUSHF), то сохраняется слово из регистра FLAGS. Если атрибут размера операнда равен 32 бита (команда PUSHFD), то сохраняется двойное слово из регистра EFLAGS (флаги VM и RF не сохраняются, вместо их значений в память записываются нули). Обратное действие может быть выполнено командой POPF/POPFD.
Мнемоники PUSHF и PUSHFD имеют один код операции. Конкретная выполняемая команда определяется атрибутом размера операнда. Некоторые ассемблеры могут автоматически вставлять соответствующий префикс размера операнда перед кодом операции при трансляции мнемоник PUSHF и PUSHFD. Другие же ассемблеры воспринимают эти мнемоники одинаково и программируют только код операции. Работа команды в этом случае определяется текущей установкой размера операнда для кодового сегмента (бит D дескриптора сегмента).
При обращении к стеку для формирования логического адреса используются регистровые пары SS:SP при 16-битной адресации или SS:ESP при 32-битной адресации. Размерность адреса определяется текущей разрядностью стекового сегмента (бит B дескриптора сегмента) и не может быть переопределена префиксом размера адреса перед кодом операции.
В режиме V86, когда текущий уровень привилегий ввода/вывода меньше 3 (EFLAGS.IOPL < 3), команда PUSHF/PUSHFD вызывает генерацию особой ситуации общей защиты (#GP). Этого, однако, не происходит для 16-битной команды PUSHF, если активирован режим EV86. В этом случае в стек записывается образ регистра флагов FLAGS, у которого быты, соответствующие полю IOPL, устанавливаются равными 3, а бит IF записывается из текущего значения флага EFLAGS.VIF. Таким образом, программа, функционирующая в режиме EV86, может манипулировать виртуальной версией флага разрешения прерываний VIF так, как если бы она манипулировала самим флагом IF в реальном режиме работы процессора (аналогичный специальный функционал для режима EV86 имеют также команды POPF, CLI, STI, IRET и команда вызова программных прерываний INT n).
Операция:
IF ( CR0.PE = 0 ) or ( CR0.PE = 1 and ( (EFLAGS.VM = 0) or (EFLAGS.VM = 1 and EFLAGS.IOPL = 3) ) )
THEN (* Реальный режим, Защищенный режим, Режим V86 с IOPL = 3 *)
IF OperandSize = 32
THEN
Push(EFLAGS AND 0xFCFFFFh); (* Флаги VM и RF в сохраняемом образе сброшены *)
ELSE
Push(FLAGS); (* Только младшие 16 бит *)
FI;
ELSE (* Режим V86 с IOPL < 3 *)
IF ( (CR4.VME = 0) or (OperandSize = 32) )
THEN
#GP(0); (* Ловушка монитора V86 *)
ELSE (* OperandSize = 16 и CR4.VME = 1 *)
TEMP = FLAGS;
TEMP = TEMP OR 0x3000h; (* Принудительная установка IOPL = 3 перед записью в стек *)
TEMP.IF = EFLAGS.VIF; (* При записи в стек для флага IF используется значение флага VIF *)
Push(TEMP);
FI;
FI;
Особые ситуации защищенного режима:
#SS(0), если новая вершина стека не попадает в пределы сегмента стека.
Intel386 … :
#PF(Код ошибки) при страничной ошибке.
#UD при использовании префикса LOCK.
Intel486 … :
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).
Особые ситуации режима V86:
#GP(0), если текущий уровень привилегий ввода/вывода меньше 3 (EFLAGS.IOPL < 3), когда CR4.VME = 0 или OperandSize = 32.
#UD при использовании префикса LOCK.
Intel486 … :
#PF(Код ошибки) при страничной ошибке.
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).
Замечание:
В режиме реальной адресации, если перед исполнением команды PUSHF/PUSHFD значение (E)SP равно 1, 3 или (для некоторых моделей процессоров) 5, то процессор генерирует стековую ошибку (#SS), но из-за отсутствия места в стеке не имеет возможности ее обработать и следом тут же генерирует двойную ошибку (#DF). Опять столкнувшись с отсутствием места в стеке, процессор сбрасывается (или переходит в режим останова, как это описано для двойной ошибки). Такое поведение процессора документируется для процессоров Intel, однако, некоторые модели производства других фирм могут вести себя совершенно непредсказуемо в данной ситуации.
Все права защищены © Алексей Ровдо, 1994-2023. Перепечатка возможна только по согласованию с владельцем авторских прав. admin@club155.ru