¿Cómo leer y escribir registros de banderas x86 directamente?
Pregunta
Por lo que he leído, parece que hay 9 banderas diferentes. ¿Es posible leerlos / cambiarlos directamente? Sé que puedo saber, por ejemplo, si el indicador de cero se establece después de hacer una instrucción cmp / jmp, pero pregunto si es posible hacer algo como
mov eax, flags
o algo así
Además, para escribir, ¿es posible configurarlos a mano?
Solución
Algunas banderas se pueden establecer o borrar directamente con instrucciones específicas:
- CLC , STC , y CMC : borre, establezca y complemente la bandera de transporte
- CLI y STI : borre y establezca el indicador de interrupción (que debe hacerse atómicamente)
- CLD y STD : borre y establezca la bandera de dirección
Para leer y escribir el signo, cero, transporte auxiliar, paridad y banderas de transporte, puede usar LAHF para cargar los 8 bits inferiores (esos 5 indicadores más 3 bits indeterminados) en el registro AH, y puede usar SAHF para almacenar esos valores de AH nuevamente en el registro de banderas.
También puede utilizar la instrucción PUSHF para colocar las banderas en la pila, léalas y modifíquelas en la pila, y luego use el POPF 1 instrucción para almacenarlos nuevamente en el registro de banderas.
Tenga en cuenta que no puede configurar los indicadores de VM y RF con POPF: conservan sus valores anteriores. Del mismo modo, solo puede cambiar el nivel de privilegio de E / S cuando se ejecuta en el nivel de privilegio 0, y el indicador de interrupción solo se puede cambiar cuando se ejecuta en un nivel de privilegio al menos tan privilegiado como el nivel de privilegio de E / S.
Nota al pie 1:
Tenga en cuenta que popf
es bastante lento en las CPU modernas; consulte la guía de optimización y las tablas de instrucciones de Agner Fog . Está microcodificado porque en modo kernel puede cambiar IF y AC, y el nivel de privilegio IO. Sufrimos la penalización independientemente del modo en las CPU actuales porque los decodificadores no son sensibles al modo.
Si es posible, use lahf / sahf en lugar de pushf / popf para el rendimiento, o guarde una sola bandera que le interese como setc al
y luego add al, 255
para establezca CF = (AL! = 0)
. O setnc al
/ sub al, 1
o lo que sea. Las secuencias para establecer o borrar SF u OF en función de un registro 0 o 1 también son sencillas, con / sin invertir el indicador.
Otros consejos
Puede usar las instrucciones pushf y popf que empujarán las banderas a la pila, puede modificarlas y luego volver a activarlas.
Si solo necesita el byte inferior del registro de banderas (que contiene SF, ZF, AF, PF, CF), existe la extraña pero conveniente instrucción LAHF (ja, ja), que carga los 8 bits inferiores las banderas se registran en AH, y su contraparte SAHF para almacenar AH en banderas.
Para la bandera de transporte específicamente, x86 ofrece CLC, STC y CMC, para borrar, establecer y complementar la bandera de transporte, respectivamente.
La manera más simple es usar pushf / popf .
Si desea mover eflags
a eax
, use el código a continuación.
pushf # push eflags into stack
pop %eax # pop it into %eax
SETcc
Esta familia de instrucciones es otra forma de observar algunas banderas / combinación de banderas.
Establece el valor de un byte en función de las BANDERAS individuales.
Por ejemplo, para CF
:
stc
setc al
; al == 1
clc
setc al
; al == 0
Runnububble upUp GH con aserciones .
Jcc
Esta familia de instrucciones es, por supuesto, otra posibilidad para ciertos indicadores, y podría usarse para implementar SETcc
:
jc set
mov al, 0
jmp end
set:
mov al, 1
end:
- LAHF: carga indicadores de estado en AH
- Copia el byte bajo del registro EFLAGS, incluidas las banderas Sign, Zero y Carry.
-
Guardar una copia de las banderas en una variable para su custodia
.data saveflags BYTE ? .code lahf ; load flags into AH mov saveflags,ah ; save them into a variable
-
SAHF: almacena AH en indicadores de estado
- Copia AH en el byte bajo del registro EFLAGS
-
Recuperar el valor de las banderas almacenadas anteriormente
.code mov ah, saveflags ; load save flags into AH sahf ; copy into flags register