Como ler e bandeiras gravação x86 registros diretamente?
Pergunta
Pelo que tenho lido, parece que há 9 bandeiras diferentes. É possível ler / alterá-los diretamente? Eu sei que eu posso saber, por exemplo, se a flag zero é definido depois de fazer uma instrução CMP / JMP, mas eu estou perguntando se é possível fazer algo parecido
mov eax, flags
ou algo assim.
Além disso, para a escrita, é possível configurá-los à mão?
Solução
Algumas bandeiras pode ser definido ou limpo diretamente com instruções específicas:
- CLC , STC , e CMC : clara, definida, e complementar a bandeira carry
- CLI e STI : clara e definir o sinalizador de interrupção (que deve ser feito atomicamente)
- CLD e STD : clara e definir o sinalizador de direção
Para ler e escrever o sinal, zero, carry auxiliar, paridade e bandeiras de transporte, você pode usar LAHF para carregar os 8 bits inferiores (aqueles 5 bandeiras mais 3 bits indeterminados) no registo AH, e você pode usar SAHF para armazenar esses valores de AH de volta para as bandeiras registo.
Você também pode usar o PUSHF instrução para empurrar as bandeiras para a pilha, leia e modificá-los na pilha, e depois usar o POPF 1 instrução para armazená-los de volta para as bandeiras registo.
Note que você não pode definir os sinalizadores VM e RF com POPF - eles mantêm seus valores anteriores. Da mesma forma, você só pode alterar o nível de privilégio de E / S durante a execução no nível de privilégio 0, ea bandeira interrupção só pode ser alterado durante a execução em um nível de privilégio, pelo menos, por mais privilegiado que o nível I / O privilégio.
Nota 1:
Note que popf
é bastante lento em CPUs modernas; Consulte o Guia de otimização e de instrução mesas Agner de nevoeiro. É microcodificadas porque no modo kernel que é capaz de mudar IF e AC, e nível de privilégio IO. Nós sofrer a penalidade independentemente do modo em CPUs atuais, porque os descodificadores não são sensíveis-mode.
Se possível, use LAHF / SAHF vez de pushf / popf para o desempenho, ou salvar uma única bandeira que você se preocupa com como setc al
então add al, 255
mais tarde para set CF = (AL!=0)
. Ou setnc al
/ sub al, 1
ou qualquer outra coisa. Sequências para configurar ou clara SF ou com base em um registro 0 ou 1 também são simples, com / sem inverter a bandeira.
Outras dicas
Você pode usar o pushf e instruções POPF que vai empurrar as bandeiras na pilha, você pode modificá-los, e, em seguida, pop-los recuar.
Se você precisa apenas o byte inferior do registrador de flags (que contém SF, ZF, AF, PF, CF), então não é o LAHF instrução estranho, mas conveniente (ha ha), que carrega o fundo 8 bits do bandeiras registar em AH, e sua contraparte SAHF para armazenar AH em bandeiras.
Para o flag carry especificamente, x86 ofertas CLC, STC e CMC, para limpar, set, e complementar a bandeira de transporte, respectivamente.
Maneira mais simples é usar pushf / popf .
Se você deseja mover eflags
em eax
, use o código abaixo.
pushf # push eflags into stack
pop %eax # pop it into %eax
SETcc
Esta família instrução é outra maneira de observar algumas bandeiras / combinação de sinalizadores.
Ele define o valor de um byte com base nos sinalizadores individuais.
por exemplo, para CF
:.
stc
setc al
; al == 1
clc
setc al
; al == 0
Runnable GitHub a montante com afirmações .
Jcc
Esta família instrução é, naturalmente, uma outra possibilidade para certas bandeiras, e poderia ser usado para implementar SETcc
:
jc set
mov al, 0
jmp end
set:
mov al, 1
end:
- LAHF: sinalizadores de status carrega na AH
- Copia o byte baixo dos EFLAGS registar incluindo Sinal, Zero, e bandeiras transportar.
-
Salvar uma cópia das bandeiras em uma variável para a guarda
.data saveflags BYTE ? .code lahf ; load flags into AH mov saveflags,ah ; save them into a variable
-
SAHF: lojas AH em sinalizadores de status
- Cópias AH para o byte baixo dos EFLAGS registar
-
Recuperar o valor de bandeiras armazenadas anteriormente
.code mov ah, saveflags ; load save flags into AH sahf ; copy into flags register