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