Как читать и писать регистры x86 флаги напрямую?
Из того, что я читал, кажется, что существует 9 разных флагов. Можно ли их напрямую читать/изменять? Я знаю, что знаю, например, если флаг нуля установлен после выполнения инструкции cmp/jmp, но я спрашиваю, можно ли сделать что-то вроде
mov eax, flags
или что-то в этом роде.
Также, для записи, можно ли их вручную установить?
Ответы
Ответ 1
Некоторые флаги могут быть установлены или удалены напрямую с помощью специальных инструкций:
- CLC, STC и CMC: очистить, установить и дополнить флаг переноса
- CLI и STI: очистить и установить флаг прерывания (что должно быть сделано атомарно)
- CLD и STD: очистить и установить флаг направления
Для чтения и записи знаков, нуля, вспомогательных флагов переноса, контроля четности и переноса вы можете использовать LAHF для загрузки младших 8 битов (эти 5 флагов плюс 3 неопределенных бита) в регистр AH и использовать SAHF для их сохранения. значения из AH возвращаются в регистр флагов.
Вы также можете использовать инструкцию PUSHF, чтобы поместить флаги в стек, прочитать и изменить их в стеке, а затем использовать инструкцию POPF 1, чтобы сохранить их обратно в регистр флагов.
Обратите внимание, что вы не можете установить флаги VM и RF с POPF - они сохраняют свои предыдущие значения. Точно так же вы можете изменять уровень привилегий ввода-вывода только при выполнении на уровне привилегий 0, а флаг прерывания можно изменять только при выполнении на уровне привилегий, по крайней мере с такими же привилегиями, как уровень привилегий ввода-вывода.
Сноска 1:
Обратите внимание, что popf
довольно медленный на современных процессорах; см . руководство по оптимизации Agner Fog и таблицы инструкций. Он микрокодируется, потому что в режиме ядра он может изменять IF и AC, а также уровень привилегий IO. Мы страдаем от штрафа независимо от режима на текущих процессорах, потому что декодеры не чувствительны к режиму.
Если возможно, используйте lahf/sahf вместо pushf/popf для производительности или сохраните один интересующий вас флаг, как setc al
затем add al, 255
чтобы установить CF = (AL!=0)
. Или setnc al
/sub al, 1
или что-то еще. Последовательности для установки или сброса SF или OF на основе регистра 0 или 1 также просты, с/без инвертирования флага.
Ответ 2
Вы можете использовать команды pushf и popf, которые будут вытолкнуть флаги в стек, вы можете их изменить и затем отбросить.
Ответ 3
Если вам нужен только младший байт регистра флагов (который содержит SF, ZF, AF, PF, CF), то есть нечетная, но удобная инструкция LAHF (ha ha), которая загружает нижние 8 бит флаги регистрируются в AH и его коллега SAHF для хранения AH во флагах.
Для флага переноса специально x86 предлагает CLC, STC и CMC, чтобы очистить, установить и дополнить флаг переноса, соответственно.
Ответ 4
Самый простой способ - использовать pushf/popf.
Если вы хотите переместить eflags
в eax
, используйте код ниже.
pushf # push eflags into stack
pop %eax # pop it into %eax
Ответ 5
SETcc
Это семейство инструкций - еще один способ наблюдать некоторые флаги/комбинации флагов.
Он устанавливает значение байта на основе отдельных флагов.
Например, для CF
:
stc
setc al
; al == 1
clc
setc al
; al == 0
Запускаемый GitHub upstream с утверждениями.
Jcc
Это семейство команд, конечно, является еще одной возможностью для определенных флагов и может использоваться для реализации SETcc
:
jc set
mov al, 0
jmp end
set:
mov al, 1
end:
Запускаемый GitHub upstream с утверждениями.
Ответ 6
- LAHF: загружает флаги состояния в AH
- Копирует младший байт регистра EFLAGS, включая флаги Sign, Zero и Carry.
-
Сохраните копию флагов в переменной для сохранения
.data
saveflags BYTE ?
.code
lahf ; load flags into AH
mov saveflags,ah ; save them into a variable
-
SAHF: сохраняет AH в флаги состояния
- Копирует AH в младший байт регистра EFLAGS
-
Получить значение ранее сохраненных флагов
.code
mov ah, saveflags ; load save flags into AH
sahf ; copy into flags register