int modifying flags register

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

int modifying flags register

Post by Firestryke31 »

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?
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: int modifying flags register

Post by ~ »

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:

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.
User avatar
Combuster
Member
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

Post by Combuster »

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:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: int modifying flags register

Post by Firestryke31 »

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:
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.
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?
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: int modifying flags register

Post by qw »

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:
Maybe this advice is superfluous, but in real mode you must be sure that the top 16 bits of ESP are zero.
User avatar
Combuster
Member
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

Post by Combuster »

Better idea: don't use code written for 32-bits protected mode in real mode :wink:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: int modifying flags register

Post by Firestryke31 »

Yeah, I forgot to mention that I'm using SP and not ESP.

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
Here are the two flag setting functions I have so far:

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
This could probably actually be done better, but hey.
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?
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: int modifying flags register

Post by ~ »

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:

Code: Select all

.....
do something
.....
update_stack_flags(00000001b, stack_flags_ptr_offset);  //only update the CF
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:

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.
Post Reply