int modifying flags register
- Firestryke31
- Member
- Posts: 550
- Joined: Sat Nov 29, 2008 1:07 pm
- Location: Throw a dart at central Texas
- Contact:
int modifying flags register
I have been bored recently and have decided to try my hand at a simple DOS clone, and have been working on implementing the int 21h functions. Many of them, like the BIOS, modify the FLAGS register to indicate various statuses like "there are no keys available" or "this call failed." My question is, since FLAGS is popped from the stack, how do they return these? Right now I modify the FLAGS value on the stack, but I was hoping there might be a more simple way to do this.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
Re: int modifying flags register
I think that in 16-bit x86 mode, the ordinary software INT instruction pushes the 16-bit EFLAGS, CS and IP onto the stack (in that order).
If you need that a particular ISR modifies the EFLAGS, you could do something like:
Remember that in Real Mode, the INT instruction clears automatically the IF (Interrupt Flag), TF (Trap Flag) and AC (Alignment Check). Once IRET is executed, the EFLAGS are automatically restored in the same way as with the instruction POPF (to pop 16 or 32-bit of flags into the EFLAGS register directly) and you are able to modify those flags before IRET by the method above or by having the value out of the stack and updating it before pushing it for IRET.
If you need that a particular ISR modifies the EFLAGS, you could do something like:
Code: Select all
myisr:
.........
.........
;Extract the return address and the EFLAGS
;just as the IRET instruction would
;;;
pop cx ;Pop 16-bit EIP
pop bx ;Pop CS
pop ax ;pop 16-bit EFLAGS
.........
.........
.........
;Modify the copy of EFLAGS that is in AX
;;;
........
........
;Push the original stack contents before IRET (with updated EFLAGS)
;;;
push ax ;Push 16-bit EFLAGS
push bx ;Push CS
push cx ;Push 16-bit EIP
iret
Remember that in Real Mode, the INT instruction clears automatically the IF (Interrupt Flag), TF (Trap Flag) and AC (Alignment Check). Once IRET is executed, the EFLAGS are automatically restored in the same way as with the instruction POPF (to pop 16 or 32-bit of flags into the EFLAGS register directly) and you are able to modify those flags before IRET by the method above or by having the value out of the stack and updating it before pushing it for IRET.
YouTube:
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: int modifying flags register
You don't need to pop the entire stack to fix a flag, you can just access the stack's memory, somewhat like this (lifted from my kernel):
Code: Select all
JC .setcarry
AND dword [ESP+16], ~ EFLAGS_CF
JMP .continue
.setcarry: OR dword [ESP+16], EFLAGS_CF
.continue:
- Firestryke31
- Member
- Posts: 550
- Joined: Sat Nov 29, 2008 1:07 pm
- Location: Throw a dart at central Texas
- Contact:
Re: int modifying flags register
This is basically what I am doing right now, so it seems I had the right idea. It's not too hard to do, and I guess I could write a few return stubs that automatically set/unset the flags.Combuster wrote:You don't need to pop the entire stack to fix a flag, you can just access the stack's memory, somewhat like this (lifted from my kernel):Code: Select all
JC .setcarry AND dword [ESP+16], ~ EFLAGS_CF JMP .continue .setcarry: OR dword [ESP+16], EFLAGS_CF .continue:
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
Re: int modifying flags register
Maybe this advice is superfluous, but in real mode you must be sure that the top 16 bits of ESP are zero.Combuster wrote:You don't need to pop the entire stack to fix a flag, you can just access the stack's memory, somewhat like this (lifted from my kernel):Code: Select all
JC .setcarry AND dword [ESP+16], ~ EFLAGS_CF JMP .continue .setcarry: OR dword [ESP+16], EFLAGS_CF .continue:
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: int modifying flags register
Better idea: don't use code written for 32-bits protected mode in real mode
- Firestryke31
- Member
- Posts: 550
- Joined: Sat Nov 29, 2008 1:07 pm
- Location: Throw a dart at central Texas
- Contact:
Re: int modifying flags register
Yeah, I forgot to mention that I'm using SP and not ESP.
Here's the ISR stub I have so far:
Here are the two flag setting functions I have so far:
This could probably actually be done better, but hey.
Here's the ISR stub I have so far:
Code: Select all
int21h:
push bp
mov bp, sp
push intReturn
cmp ah, 0x01
je getKeyWithEcho
cmp ah, 0x06
je directIO
cmp ah, 0x09
je simpleWriteStr
cmp ah, 0x25
je setIntVector
cmp ah, 0x48
je malloc
cmp ah, 0x49
je free
intReturn:
mov sp, bp
pop bp
iret
Code: Select all
paramFlags equ bp+10
retNZ:
push ax
mov al, [paramFlags]
and al, 0xFE
pop ax
ret
retZ:
push ax
mov al, [paramFlags]
or al, 1
pop ax
ret
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
Re: int modifying flags register
Maybe you could use instructions like CLC, STC, etc., to work directly with the real FLAGS in the ISR. Then when you get the state of flags you need, you can:
- Read the first byte of FLAGS from the stack into, say AL register.
- Apply AND mask to AL with the corresponding bits set to 0 to clear the old flags you need. For instance, if you need Carry flag the AND mask should be 11111110b.
- Now that you have "emptied" the old flags, you can use the LAHF instruction to load the real current first 8 bits of FLAGS into AH.
- Apply AND mask to AH with the correspondign bits set to 1 to save only the new flags you need. For instance, if you need Carry flag the AND mask should be 00000001b
- Now apply OR AL,AH
- Store the updated flags in the proper stack position
In a more natural way, I think you could do normal operations and based on them, again do something similar and just store the state of the current FLAGS. For example, maybe you could use something like XOR AX,AX to set the Zero Flag to 1 to indicate Zero, or use RCR/RCL to alter the Carry Flag in interesting ways.
Or you could make a function that does all of that automatically and all you have to do is pass it a bitmask with the bits set to 1 for the flags you want updated in the stack, and all you would need to concentrate in would be to keep the intended flags up to date and then call this function to update the flags in the stack. Something like:
But you would also need perfectly at all times where in the stack is your EFLAGS copy before calling such function as specified in the stack_flags_ptr_offset address parameter or attempting to update it "by hand".
The LAHF instruction stores these flags in AH:
The only warning is that the LAHF instruction (0x9F opcode) may or may not be supported in 64-bit mode.
- Read the first byte of FLAGS from the stack into, say AL register.
- Apply AND mask to AL with the corresponding bits set to 0 to clear the old flags you need. For instance, if you need Carry flag the AND mask should be 11111110b.
- Now that you have "emptied" the old flags, you can use the LAHF instruction to load the real current first 8 bits of FLAGS into AH.
- Apply AND mask to AH with the correspondign bits set to 1 to save only the new flags you need. For instance, if you need Carry flag the AND mask should be 00000001b
- Now apply OR AL,AH
- Store the updated flags in the proper stack position
In a more natural way, I think you could do normal operations and based on them, again do something similar and just store the state of the current FLAGS. For example, maybe you could use something like XOR AX,AX to set the Zero Flag to 1 to indicate Zero, or use RCR/RCL to alter the Carry Flag in interesting ways.
Or you could make a function that does all of that automatically and all you have to do is pass it a bitmask with the bits set to 1 for the flags you want updated in the stack, and all you would need to concentrate in would be to keep the intended flags up to date and then call this function to update the flags in the stack. Something like:
Code: Select all
.....
do something
.....
update_stack_flags(00000001b, stack_flags_ptr_offset); //only update the CF
The LAHF instruction stores these flags in AH:
Code: Select all
Bits in AH:
0 -- (CF) Carry Flag
1 -- (1) Always set to 1
2 -- (PF) Parity Flag
3 -- (0) Always set to 0
4 -- (AF) Auxiliary Carry Flag
5 -- (0) Always set to 0
6 -- (ZF) Zero Flag
7 -- (SF) Sign Flag
The only warning is that the LAHF instruction (0x9F opcode) may or may not be supported in 64-bit mode.
YouTube:
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64