If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

x86 assembly question: modifying flags register on the stack

I'm writing an int13h handler. The semantics are that it returns carry flag set on error, carry flag clear on success. When the int13h handler is called, the stack contains: FLAGS,CS,IP. These are at [SP-4], [SP-2], and [SP] respectively. When the IRET at the end of the handler occurs, IRET pops these stored flags off the stack, overriding whatever the current carry flag may be. I figure, if I'm going to return with the carry flag set, I'm going to have to mess with the one that's stored on the stack.

iret_fuss_with_carry_flag_old was my first attempt, but doesn't work right. I think there's something wrong with the interrupt flag (putting an STI in front of iret_fuss_with_carry_flag_old will make it work correctly). iret_fuss_with_carry_flag_new works fine, so I'm going to go with that.

However, I just can't leave a mystery unsolved. What was wrong with my first attempt?

Seems to be the awkward way of doing it. How about ending the interrupt with far return 2? (CA 02 00), this discards 2 bytes off the stack after the return address. Then you can just set the carry flag before doing a RET 2...

The reason the first attempt didn't work is probably the "ADD SP,4" line. Any values on the stack at addresses lower than SP are liable to be overwritten at any time by a hardware interrupt. That's no problem as long as interrupts are off, but the very next line after the "ADD SP,4" is a POPF which will restore the state of the interrupt flag to the one from the calling code, i.e. probably enable interrupts. So if there is a timer interrupt pending (which will happen sooner or later, sooner the longer your interrupt handler takes) then the contents of the stack will get scribbled on immediately after this POPF.

I think your second attempt is the way to go, but you can simplify it by using "AND BYTE[BP+8],0FEh" and "OR BYTE[BP+8],1" (and then you don't need AX, so you can use [BP+6]). The advantage of doing it this way over the "RETF 2" method is that it keeps the calling code's flags separate from the interrupt handler's flags. This may be important when using a debugger that does single-stepping by using the trap flag. With the RETF method you'd either have the trap flag set in your interrupt handler (and users would be single stepping through your code as well as theirs) or you'd clear the trap flag (and on stepping on your interrupt the program would resume and run until the next breakpoint), both of which are undesirable.

So if there is a timer interrupt pending (which will happen sooner or later, sooner the longer your interrupt handler takes) then the contents of the stack will get scribbled on immediately after this POPF.

What surprised me is that the problem is 100% reproducible. It doesn't appear to me to be the intermittent clash of a timing interrupt. At one point, I tried wrapping my stack tampering in a CLI/STI just to be sure we weren't getting interrupted, but that didn't help.

Originally Posted by reenigne

you can simplify it by using "AND BYTE[BP+8],0FEh" and "OR BYTE[BP+8],1"

Thanks, I will add this simplification! (or pursue Chuck(G)'s suggestion; haven't quite decided which way to go yet).

Originally Posted by Krille

I'm curious. What are you doing?

I made an 8-bit Flash Drive using 39SF040 Flash chips. It's a bit of a silly project given that xt-ide and various compactflash boards are much more convenient from a usability perspective, but I did it as a personal challenge, and because I had a "Boca Start Card" back in the late 80s or early 90s that functioned this way. I developed an int13 BIOS extension that allows the PC to boot off the flash, appearing as a floppy drive.

I suspect that your original code will have worked if you simply disable interrupts around your stack-modification sequence. The PC's timer interrupt hits 18.2 times per second, so there's a pretty good possibility that it will get in the way.