Image Map Image Map
Page 1 of 3 123 LastLast
Results 1 to 10 of 28

Thread: x86 assembly question: modifying flags register on the stack

  1. #1

    Default 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.

    So, I implemented two different routines:

    Code:
    iret_fuss_with_carry_flag_old:
            ;; Since IRET will restore the carry flag, tamper with the stack to
            ;; set the carry flag to what we want.
            JC .carryset
            ADD SP, 4                      ; skip over CS and IP
            POPF
            CLC
            PUSHF
            SUB SP, 4                      ; restore stack pointer
            IRET
    .carryset:
            ADD SP, 4                      ; skip over CS and IP
            POPF
            STC
            PUSHF
            SUB SP, 4                      ; restore stack pointer
            IRET
    
    iret_fuss_with_carry_flag_new:
            JC .carryset
            PUSH    AX
            PUSH    BP
            MOV     BP, SP
            MOV     AX, [BP+8]
            AND     AX, 0FFFEh
            MOV     [BP+8], AX
            POP     BP
            POP     AX
            IRET
    .carryset:
            PUSH    AX
            PUSH    BP
            MOV     BP, SP
            MOV     AX, [BP+8]
            OR      AX, 1
            MOV     [BP+8], AX
            POP     BP
            POP     AX
            IRET
    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?

    Thanks,
    Scott

  2. #2
    Join Date
    Jan 2007
    Location
    Pacific Northwest, USA
    Posts
    25,230
    Blog Entries
    20

    Default

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

  3. #3

    Default

    Well that does seem much easier... It's been a while since I've done x86 assembly programming. I wasn't aware there was a far return with stack discard instruction!

  4. #4
    Join Date
    Jan 2007
    Location
    Pacific Northwest, USA
    Posts
    25,230
    Blog Entries
    20

    Default

    I think the original purpose was to clear the stack of parameters. e.g.

    push arg1
    push arg2
    push arg3
    call subr

    subr.:

    ret 6

    But it also work to discard the flags on a far return of an interrupt address.

  5. #5

    Default

    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.

  6. #6

    Default

    Quote Originally Posted by smbaker View Post
    I'm writing an int13h handler.
    I'm curious. What are you doing?

    When the int13h handler is called, the stack contains: FLAGS,CS,IP. These are at [SP-4], [SP-2], and [SP] respectively.
    The stack grows downwards so it looks like this actually;
    Code:
    	FLAGS	[SP+4]
    	CS	[SP+2]
    	IP	[SP+0]
    Looking for a cache card for the "ICL ErgoPRO C4/66d V"

  7. #7

    Default

    Quote Originally Posted by reenigne
    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.

    Quote 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).

    Quote Originally Posted by Krille View Post
    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.

    flashboard_boot.jpgflashboard_prototype.jpg

    Quote Originally Posted by Krille
    The stack grows downwards so it looks like this actually;
    Code:
    	FLAGS	[SP+4]
    	CS	[SP+2]
    	IP	[SP+0]
    Thanks, that's what I meant to write.

  8. #8
    Join Date
    Jan 2007
    Location
    Pacific Northwest, USA
    Posts
    25,230
    Blog Entries
    20

    Default

    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.

  9. #9

    Default

    Quote Originally Posted by smbaker View Post
    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.
    How long does your interrupt handler take to run? Is there any kind of interrupt from other hardware that it could be?

    Quote Originally Posted by smbaker View Post
    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.
    That's because the POPF turns interrupts on again.

  10. #10
    Join Date
    Jan 2007
    Location
    Pacific Northwest, USA
    Posts
    25,230
    Blog Entries
    20

    Default

    Is there any overwhelming reason to use POPF in that sequence? Can't you simply pop into any other register and modify the flag?

    As far as saving the caller's flags, there's no particular reason to expect that on an INT 13H handler. The PC BIOS uses a RET 2.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •