Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to index page
Thread view  Board view
RayeR

Homepage

CZ,
10.05.2012, 10:46
 

indirect far jmp in NASM (Developers)

Hi,
I need in code to use indirect far jump that will take the pointer as immediate argument. I mean something like this jmp [0:100] that would not jump at 0:100 but load address from 0:100 and jump to it.
Here is description of JMP where is a possibility of
JMP m16:16
indirect jump. I'm not sure if m16:16 can be a constant or must be done via some segment register only. I need sysntax for NASM. When tried jmp [0:100] I got error: invalid segment override.

---
DOS gives me freedom to unlimited HW access.

RayeR

Homepage

CZ,
10.05.2012, 13:16

@ RayeR
 

indirect far jmp in NASM

Well OK, it seems not possible, only via segment registers JMP [CS/ES/DS/SS:xxxx] but I don't want to modify this regs before jump.

---
DOS gives me freedom to unlimited HW access.

ecm

Homepage E-mail

Düsseldorf, Germany,
10.05.2012, 13:26

@ RayeR
 

indirect far jmp

this isn't NASM-specific. you have to load a segment register to access data there. you can use the stack to preserve it though; in that case, use a far return instead of the far jump instruction. example:

__seg equ 1234h
__ofs equ 5678h

        push ds
        push ax
        mov ax, __seg
        mov ds, ax
        push bp
        mov bp, sp
        mov ax, [__ofs+2]
        xchg ax, [bp+4]
        push ax
        mov ax, [__ofs]
        xchg ax, [bp+2]
        pop ds
        pop bp
        retf


freeing up one of the segment registers (usually es or ds) for direct access is usually simpler of course

---
l

Rugxulo

Homepage

Usono,
10.05.2012, 13:26

@ RayeR
 

indirect far jmp in NASM

> Well OK, it seems not possible, only via segment registers JMP
> [CS/ES/DS/SS:xxxx] but I don't want to modify this regs before jump.


jmp far [blah]
blah: dw 100h,0

RayeR

Homepage

CZ,
10.05.2012, 14:07

@ Rugxulo
 

indirect far jmp in NASM

>
> jmp far [blah]
> blah: dw 100h,0
>


But this will load pointer from current CS:place_of_constant and I need to load the pointer from different segment (0). I know it's possible to do it via stack and use retf but the code is longer than my current hack with farjmp opcode placed just before the pointer and jumping to address-1. Just wanted to check if there's better/more clean way.

---
DOS gives me freedom to unlimited HW access.

ecm

Homepage E-mail

Düsseldorf, Germany,
10.05.2012, 15:17

@ RayeR
 

indirect far jmp

> I need to
> load the pointer from different segment (0). I know it's possible to do it
> via stack and use retf but the code is longer than my current hack with
> farjmp opcode placed just before the pointer and jumping to address-1. Just
> wanted to check if there's better/more clean way.

What exactly is it that you want to jump at anyway?

---
l

RayeR

Homepage

CZ,
11.05.2012, 00:47

@ ecm
 

indirect far jmp

> What exactly is it that you want to jump at anyway?

Old saved interrupt vector (when chaining).

---
DOS gives me freedom to unlimited HW access.

ecm

Homepage E-mail

Düsseldorf, Germany,
11.05.2012, 12:46

@ RayeR
 

indirect far jmp

> > What exactly is it that you want to jump at anyway?
>
> Old saved interrupt vector (when chaining).

Why do you not save it in your program's allocation?

---
l

bretjohn

Homepage E-mail

Rio Rancho, NM,
11.05.2012, 18:53

@ RayeR
 

indirect far jmp

> > What exactly is it that you want to jump at anyway?
>
> Old saved interrupt vector (when chaining).

So, your code is part of a new/modified interrupt handler but you haven't placed your own address in the IVT?

RayeR

Homepage

CZ,
11.05.2012, 19:31

@ bretjohn
 

indirect far jmp

> So, your code is part of a new/modified interrupt handler but you haven't
> placed your own address in the IVT?

I placed old vector at INT 85h, I'm not sure if it's safe to call int from another int, I don't want to mess up something. Also it increase stack usage, probably not problem. And I have to change ISR because it will return back instead of case FAR JMP... (it's INT 13h handler hook)

---
DOS gives me freedom to unlimited HW access.

bretjohn

Homepage E-mail

Rio Rancho, NM,
11.05.2012, 22:31

@ RayeR
 

indirect far jmp

> I placed old vector at INT 85h, I'm not sure if it's safe to call int from
> another int, I don't want to mess up something. Also it increase stack
> usage, probably not problem. And I have to change ISR because it will
> return back instead of case FAR JMP... (it's INT 13h handler hook)

It's OK to call one INT from within another -- that happens all the time. You just need to be sure there aren't going to be any reentrancy issues. So, if you're vector address is stored at INT 13h in the IVT and the old INT 13h vector is stored at INT 85h, you can just issue an INT 85h. But, it will be processed as a (INT) CALL, not a JMP.

That being said, what you're doing is probably not a good idea -- using the IVT as storage space for some of your program's internal data. I'll rant one more time about AMIS here, which is what I think you should be doing instead.

ecm

Homepage E-mail

Düsseldorf, Germany,
11.05.2012, 22:33

@ bretjohn
 

indirect far jmp

> That being said, what you're doing is probably not a good idea -- using the
> IVT as storage space for some of your program's internal data. I'll rant
> one more time about AMIS here, which is what I think you should be doing
> instead.

iirc rayer does some rom programming stuffs, maybe it's for that? in that case, they normally don't have any writeable program-internal data

---
l

RayeR

Homepage

CZ,
12.05.2012, 00:33

@ ecm
 

indirect far jmp

> iirc rayer does some rom programming stuffs, maybe it's for that? in that
> case, they normally don't have any writeable program-internal data

Yes :)
OK I'll rewrite it to call old ISR via INT.

---
DOS gives me freedom to unlimited HW access.

Arjay

12.05.2012, 01:07

@ RayeR
 

indirect far jmp

> > iirc rayer does some rom programming stuffs, maybe it's for that?
> Yes :)
No AMIS then ;-)

> OK I'll rewrite it to call old ISR via INT.
Depending on what it is you need to do you could also use a FAR CALL to simulate the INT call, e.g.

xor bp,bp
pushf
call FAR [BP+0084]


where 0084 is the int offset in the IVT, Int 21h in this case. Nasty trick but sometimes useful. Not an easy example to follow but this old short code of mine uses it:

N MSG2MARK.COM
E 0100  50 53 20 FF 41 43 41 44 41 4D 59 21 FF 24 FF 0D
E 0110  52 4A 1A C0 18 E4 53 5A 5B 33 ED 8E D5 C1 E2 08
E 0120  0D 00 52 80 EC 49 BC FD FF 9C FF 9E 84 00 E9 CF
E 0130  FE 47 52 45 45 54 49 4E 47 53 20 32 4D 41 52 4B

RCX
40

W

Q

ecm

Homepage E-mail

Düsseldorf, Germany,
12.05.2012, 01:27

@ Arjay
 

indirect far jmp

> Depending on what it is you need to do you could also use a FAR CALL to
> simulate the INT call, e.g.
>
> xor bp,bp
> pushf
> call FAR [BP+0084]

That doesn't seem to have any advantages over just executing the corresponding int opcode? Additionally, as opposed to the int instruction, this one needs a segment register (in your example, ss) pointing to the IVT area again. (Of course the pushf, call far (or pushf, push cs, call to where a jmp far is) sequence is useful when calling an interrupt handler that isn't actually stored in the IVT.)

> E 0100  50 53 20 FF 41 43 41 44 41 4D 59 21 FF 24 FF 0D
> E 0110  52 4A 1A C0 18 E4 53 5A 5B 33 ED 8E D5 C1 E2 08
> E 0120  0D 00 52 80 EC 49 BC FD FF 9C FF 9E 84 00 E9 CF
> E 0130  FE 47 52 45 45 54 49 4E 47 53 20 32 4D 41 52 4B

Hahah~ (You really shouldn't use the stack at 10000h though.)

---
l

Arjay

12.05.2012, 11:09

@ ecm
 

indirect far jmp

> That doesn't seem to have any advantages over just executing the
> corresponding int opcode?
Under normal circumstances I agree. There are times when it can be useful, e.g. see Art Of Assembly - Chapter Seventeen: Interrupts Traps and Exeptions for more info / better examples to use. Also can be useful for obscuration / basic anti-disassembler trickery.

> where a jmp far is) sequence is useful when calling an interrupt handler
> that isn't actually stored in the IVT.)
Yup. e.g. under runcom etc.

> Hahah~ (You really shouldn't use the stack at 10000h though.)
Indeed. That particular quick and dirty demo was to give a few friends a little puzzle a number of years ago; with a normal version of the same thing.

Interestingly last night whilst quickly digging that out I did note a DOS compatibility bug in the versions of both DOSEmu and DOSBox that are on this little box. One of several Easter eggs that I expect you spotted in that code is to print my initials over the PS if the .COM program is typed from the DOS prompt, "TYPE MSG2MARK.COM" however I noted it fails on both of the old versions of DOSEmu and DOSBox that are on this box. e.g. under DOSBox v0.73 EOF (1Ah) is ignored. Likewise the DOSEmu ignores the CR (0Dh) - as both are older versions (due to this box) I will at some point test to see if bugs present in newer versions. Obviously not critical bugs however there are a number of programs/data that use character tricks (inc. 08h) as "type" easter eggs.

ecm

Homepage E-mail

Düsseldorf, Germany,
12.05.2012, 21:18

@ Arjay
 

indirect far jmp

> > That doesn't seem to have any advantages over just executing the
> > corresponding int opcode?
> Under normal circumstances I agree. There are times when it can be useful,
> e.g. see
> Art
> Of Assembly - Chapter Seventeen: Interrupts Traps and Exeptions for
> more info / better examples to use.

I was referring specifically to the case where you call an address stored in the IVT anyway; in that case, you'd generally need a reason to prefer the longer call form, for example because you specifically want to bypass a V86 Mode monitor's additional interrupt handling; or because you don't want the flags for the handler set the way the int instruction would by default. (The debugger sources that I have, from Japheth's simpler debugger (as used by FreeDOS), usually do this if to trace into an interrupt handler's code.)

> Also can be useful for obscuration / basic anti-disassembler trickery.

Of course, but that's not something I usually consider a concern ;)

> > where a jmp far is) sequence is useful when calling an interrupt handler
> > that isn't actually stored in the IVT.)
> Yup. e.g. under runcom etc.

Well, basically, to call the original one whenever any interrupt handler has been intercepted.

> > Hahah~ (You really shouldn't use the stack at 10000h though.)
> Indeed. That particular quick and dirty demo was to give a few friends a
> little puzzle a number of years ago; with a normal version of the same
> thing.
>
> Interestingly last night whilst quickly digging that out I did note a DOS
> compatibility bug in the versions of both DOSEmu and DOSBox that are on
> this little box. One of several Easter eggs that I expect you spotted in
> that code is to print my initials over the PS if the .COM program is typed
> from the DOS prompt, "TYPE MSG2MARK.COM"

Actually, I only looked at the machine code. But you're right, writing a 13 (CR) code to the console without a 10 (LF) code should just return to the start of the line, readying it for overwriting.

> however I noted it fails on both of the old versions of DOSEmu
> and DOSBox that are on this box.

That's a very basic compatibility thing (if unimportant) and it surprises me that it shouldn't work in those? (Even though DOSBox's support of DOS functions (especially internal ones) is known terrible generally.) Maybe they fixed it in the newer versions? I'm fairly certain that for private testing I fixed the CPU emulation of DOSBox ~0.74 orso at some point, and I didn't notice issues with my programs that sometimes use codes 10 and 13 separately. Then again, I always would boot an actual (hence, better) DOS kernel inside it instead of using the bad built-in one, so results might vary then.

> e.g. under DOSBox v0.73 EOF (1Ah) is ignored.

That is inside the TYPE command's implementation I think. If you use FreeCOM's TYPE instead, maybe it'd work. (I don't know whether FreeCOM properly runs on DOSBox's built-in DOS though.)

> Likewise the DOSEmu ignores the CR
> (0Dh) - as both are older versions (due to this box) I will at some point
> test to see if bugs present in newer versions. Obviously not critical bugs
> however there are a number of programs/data that use character tricks (inc.
> 08h) as "type" easter eggs.

Well, in actual program output, I use 13 without 10 to overwrite a more-type prompt when it has been acknowledged, and I often use 10 without 13 in stored messages when several consecutive linebreaks are to be displayed. I'm not yet using code 8, but I might enhance my programs' output with LESS-style highlighting which heavily employs 8, which will either cause the normal "unenhanced" output to be visible, or make the LESS-compatible display highlight the output in whatever way it does. (The highlighting methods are called "underlined" and "bold", but the simple text-mode parser that I use will instead display the highlighted parts in yellow and green respectively.)

---
l

RayeR

Homepage

CZ,
12.05.2012, 21:17

@ Arjay
 

indirect far jmp

> xor bp,bp
> pushf
> call FAR [BP+0084]


I shouldn't modify BP, caller program may use it for its own and get confused when INT13 will accidentally zero it...

---
DOS gives me freedom to unlimited HW access.

Arjay

13.05.2012, 13:16

@ RayeR
 

indirect far jmp/call - Chaining Interrupt Service Routines

> > pushf
> > call FAR [BP+0084][/code]
>
> I shouldn't modify BP, caller program may use it for its own and get
> confused when INT13 will accidentally zero it...
Ok, that was just a short example I had to hand which I also thought might be a fun one for people to play with. I strongly recommend reading the link I shared earlier re Chaining Interrupt Service Routines and the "Reentrancy Problems" section that follows it.

RayeR

Homepage

CZ,
13.05.2012, 04:01
(edited by RayeR, 13.05.2012, 04:19)

@ RayeR
 

indirect far jmp - calling old INT problem

> OK I'll rewrite it to call old ISR via INT.

I tried it in BOCHS and I have problem with calling old ISR via INT.
I got error messages when freedos boots and in bochs.log I can see:

00482449844i[BIOS ] int13_harddisk: function 00, unmapped device for ELDL=80
00482456146i[BIOS ] int13_harddisk: function 08, unmapped device for ELDL=80
00482460917i[BIOS ] int13_harddisk: function 00, unmapped device for ELDL=80
00482465680i[BIOS ] int13_harddisk: function 00, unmapped device for ELDL=81
00482470443i[BIOS ] int13_harddisk: function 00, unmapped device for ELDL=82
00482475206i[BIOS ] int13_harddisk: function 00, unmapped device for ELDL=83
...

I still can use "real" drive A: (I emulate B:) so it seems that old ISR is called but something got messed... I modified my code this way:

NEW_INT13H:                     ;INT XX do PUSH F, CLI, PUSH CS,IP (6B) / INT XX provadi PUSH F, CLI, PUSH CS,IP (6B)
        PUSHF                   ;store flags (2B) / uloz flagy (2B)
        CMP     DL,ROMDISK_DRIVE;related to our disk ? / tyka se to naseho disku?
        JE      @NEW_INT13H_HUB ;if yes continue below else / pokud ano, pokracuj nize, jinak
        POPF                    ;restore flags (2B) and / obnov flagy (2B) a

;JMP 0xF000:0xE3FE ; OK (hardcoded BOCHS ISR vector)

;        push ds ; OK (cm's example)
;        push ax
;        mov ax, 0
;        mov ds, ax
;        push bp
;        mov bp, sp
;        mov ax, [OLD_INT13H*4+2]
;        xchg ax, [bp+4]
;        push ax
;        mov ax, [OLD_INT13H*4]
;        xchg ax, [bp+2]
;        pop ds
;        pop bp
;        retf

        INT     85h             ;call old INT 13h handler / zavolej puvodni preruseni INT 13h
        IRET                    ;and return to caller program / a predej rizeni zpet volajicimu programu

@NEW_INT13H_HUB:                ;subfunction hub / rozcestnik podfunkci
...


If I call old ISR by direct far call or via cm's method (longer code than my old) it boots ok without error. What can be wrong?

---
DOS gives me freedom to unlimited HW access.

ecm

Homepage E-mail

Düsseldorf, Germany,
13.05.2012, 04:27

@ RayeR
 

indirect far jmp - calling old INT problem

>  INT     85h             ;call old INT 13h handler
>  IRET                    ;and return to caller program
>
> If I call old ISR by direct far call or via cm's method (longer code than
> my old) it boots ok without error. What can be wrong?

This way, you're not passing the returned CF (Carry Flag) back to the caller, leaving theirs in their saved FL word unmodified instead. Here's some code that would return it correctly, it goes right before your iret instruction and needs to be entered with the CF that you want to return:

        push bp
        mov bp, sp
        rcr byte [bp+6], 1      ; flip
        rol byte [bp+6], 1      ; flop
        pop bp


Understanding what this does is left as an exercise to the reader ;)

Arguably though, jumping (by whatever method) to the old handler would be better. Not only will it execute the old handler with 6 bytes less on the stack as you have mentioned, it would also insure that, say, ZF is also passed back to the caller properly. I don't know of any Int13 functions modifying ZF off my head, but I suppose it's possible.

Maybe someone can optimise the code that uses retf as I suggested earlier more for you? By the way, it'd be trivial to optimise a bit or somewhat if you know that your code will only ever run on at least an 186 or 386 CPU.

---
l

RayeR

Homepage

CZ,
13.05.2012, 15:33
(edited by RayeR, 13.05.2012, 16:37)

@ ecm
 

indirect far jmp - calling old INT problem

> This way, you're not passing the returned CF (Carry Flag) back to the
> caller, leaving theirs in their saved FL word unmodified instead. Here's

Aha, it was too late yesterday :)

> some code that would return it correctly, it goes right before your iret
> instruction and needs to be entered with the CF that you want to return:
>
>         push bp
> mov bp, sp
> rcr byte [bp+6], 1      ; flip
> rol byte [bp+6], 1      ; flop
> pop bp

>
> Understanding what this does is left as an exercise to the reader ;)

Hm some magic with rotating saved flags on stack through carry... It works fine now. Anyway with this code it's still 3 bytes longer than my old method with placing FAR JMP byte opcode before saved vector and jumping on that...

EDIT:
I got some idea how to pass original int 13 flags:

        INT     OLD_INT13H      ;call old INT 13h handler / zavolej puvodni preruseni INT 13h
pushf
pop dx

add sp,6
push dx
sub sp,4
        IRET                    ;and return to caller program / a predej rizeni zpet volajicimu programu


but there's issue that ADD instruction also affect flags. so I temporarly use DX to save them and it works. But I must preserve DX too. To be continued...

---
DOS gives me freedom to unlimited HW access.

bretjohn

Homepage E-mail

Rio Rancho, NM,
13.05.2012, 17:05

@ RayeR
 

indirect far jmp - calling old INT problem

In general, I pass the entire original callers flags register, unchanged, to the old interrupt handler (whether I CALL it or JMP to it). I don't assume that the only thing that matters is one or two of the flags (like CF or ZF). In particular, modifying the Interrupt Flag or Direction flag can cause all kinds of problems, though modifying any flag other than the one(s) used to pass parameter(s) as defined by the API are potentially disastrous.

RayeR

Homepage

CZ,
13.05.2012, 17:15

@ bretjohn
 

indirect far jmp - calling old INT problem

> In general, I pass the entire original callers flags register, unchanged,
> to the old interrupt handler (whether I CALL it or JMP to it). I don't
> assume that the only thing that matters is one or two of the flags (like CF
> or ZF). In particular, modifying the Interrupt Flag or Direction flag can
> cause all kinds of problems, though modifying any flag other than the
> one(s) used to pass parameter(s) as defined by the API are potentially
> disastrous.

Well I did it this way:


INT     OLD_INT13H
push ax
pushf
pop ax
add sp,byte 8
push ax
sub sp,byte 6
pop ax
IRET


So all regs and flags are preserved but this is also +3 bytes increase size like above cm's code :P Damn it...

---
DOS gives me freedom to unlimited HW access.

RayeR

Homepage

CZ,
13.05.2012, 19:19

@ RayeR
 

indirect far jmp - calling old INT problem

OK, I optimized it a bit, now just 1 byte greater than old code, not bad, I leave it...

NEW_INT13H:                     ;INT XX do CLI, PUSH F,CS,IP (6B), SP=x-6
        PUSHF                   ;store flags (2B), SP=x-8
        CMP     DL,ROMDISK_DRIVE;related to our disk ?
        JE      @NEW_INT13H_HUB ;if yes continue below else
        POPF                    ;restore flags (2B), SP=x-6
        INT     OLD_INT13H      ;call old INT 13h handler, SP=x-6
        PUSH    BP              ;store BP (2B), SP=x-8
        MOV     BP,SP           ;set BP to current SP, BP=SP=x-8
        PUSHF                   ;store flags (2B) that was returned by old INT 13h handler, SP=x-10
        POP     WORD [SS:BP+6]  ;replace previously saved flags of INT caller on stack by current flags, SP=x-8
        POP     BP              ;restore BP (2B), SP=x-6
        IRET                    ;return from ISR, do POP IP,CS,F (6B), SP=x-0

---
DOS gives me freedom to unlimited HW access.

Rugxulo

Homepage

Usono,
13.05.2012, 20:02

@ RayeR
 

indirect far jmp - calling old INT problem

> OK, I optimized it a bit, now just 1 byte greater than old code, not bad, I
> leave it...

What, worried about one byte?


        PUSH    BP              ;store BP (2B), SP=x-8
        MOV     BP,SP           ;set BP to current SP, BP=SP=x-8


Reminds me of "ENTER ..,.." instruction (186+).


        POP     WORD [SS:BP+6]


Isn't SS: implicit when using [BP]? Make sure this isn't generating that extra byte you don't want as you probably don't need to say it explicitly.

RayeR

Homepage

CZ,
13.05.2012, 20:49
(edited by RayeR, 13.05.2012, 21:00)

@ Rugxulo
 

indirect far jmp - calling old INT problem

> What, worried about one byte?
> Reminds me of "ENTER ..,.." instruction (186+).

enter has 4 byte opcode...


> POP    WORD [SS:BP+6]
>

>
> Isn't SS: implicit when using [BP]? Make sure this isn't generating that
> extra byte you don't want as you probably don't need to say it explicitly.

Yes, you're right, thanks.
Register          Default Segment    Valid Overrides
        BP                      SS              DS, ES, CS
        SI or DI                DS              ES, SS, CS
        DI strings              ES              None
        SI strings              DS              ES, SS, CS

BTW I can see that I had more [SS:BP+x] occurences in code so I saved much more :)

---
DOS gives me freedom to unlimited HW access.

ecm

Homepage E-mail

Düsseldorf, Germany,
13.05.2012, 23:49

@ Rugxulo
 

indirect far jmp - calling old INT problem

>   PUSH    BP              ;store BP (2B), SP=x-8
>   MOV     BP,SP           ;set BP to current SP, BP=SP=x-8
>
>
> Reminds me of "ENTER ..,.." instruction (186+).

As RayeR noted, enter takes 4 bytes. It only saves any space if you additionally need to subtract a constant from sp, in which case the manual code will usually take 6 bytes (instead of only 3 bytes like the above.)

> Make sure this isn't generating that
> extra byte you don't want as you probably don't need to say it explicitly.

Generating an unnecessary extra byte in this case is one of NASM's "features" ;) Actually, it just simplifies the assembler implementation a lot, so, well, you'd better know what you're doing.

---
l

ecm

Homepage E-mail

Düsseldorf, Germany,
13.05.2012, 23:40

@ RayeR
 

indirect far jmp - calling old INT problem

This appears to clear the caller's interrupt flag (and trap flag, but that's not as important). It shouldn't do that.

---
l

ecm

Homepage E-mail

Düsseldorf, Germany,
14.05.2012, 00:07

@ ecm
 

indirect far jmp - calling old INT problem

Here's a better one I came up with just now. Note that it takes 2 more bytes than your last suggestion, but importantly it correctly preserves the caller's interrupt flag. It also preserves their trace, direction, and overflow flags. Which happen to be the flags stored in the high byte of the flag word. Look for yourself:

1319:0100 55                push    bp
1319:0101 89E5              mov     bp, sp
1319:0103 50                push    ax
1319:0104 9F                lahf
1319:0105 886606            mov     [bp+06], ah
1319:0108 58                pop     ax
1319:0109 5D                pop     bp

---
l

RayeR

Homepage

CZ,
14.05.2012, 01:19

@ ecm
 

indirect far jmp - calling old INT problem

> Here's a better one I came up with just now. Note that it takes 2 more
> bytes than your last suggestion, but importantly it correctly preserves the
> caller's interrupt flag. It also preserves their trace, direction, and
> overflow flags. Which happen to be the flags stored in the high byte of the
> flag word. Look for yourself:
>
> 1319:0100 55                push    bp
> 1319:0101 89E5              mov     bp, sp
> 1319:0103 50                push    ax
> 1319:0104 9F                lahf
> 1319:0105 886606            mov     [bp+06], ah
> 1319:0108 58                pop     ax
> 1319:0109 5D                pop     bp

Yes you's right. INT disables IF,TF after storing flags so futher INT got this disabled and I passed it disabled. My bad. Now we are passing only LSB of flags so MSB is untouched. I hope that INT13h ISR don't manipulate flags in MSB, AFAIK it uses only CF. Interrupts should be disabled all the time inside ISR until last IRET so another INT shouldn't occur. I didn't know LAHF instruction, just wonder there's no LALF or LAXF... x86 set if full of various exceptions...
Thx for help

---
DOS gives me freedom to unlimited HW access.

ecm

Homepage E-mail

Düsseldorf, Germany,
13.05.2012, 23:44
(edited by cm, 13.05.2012, 23:56)

@ RayeR
 

indirect far jmp - calling old INT problem

> Hm some magic with rotating saved flags on stack through carry...

Yeah, it rotates the current CF into bit 7 of the caller's flag byte (effectively discarding the original caller's CF saved there, by rotating it into our CF), then rotates just the 8 bits back to put all the flags into the correct locations again, including the returned CF.

> I got some idea how to pass original int 13 flags:

This depends on no interrupts occurring between the add and sub instruction, as it depends on the (unallocated) stack space below ss:sp-> staying unchanged. You might want to at least clear the interrupt flag (right after pushf) to try avoiding that error condition.

And then, like with your other suggestion, this appears to clear the caller's interrupt (and trap) flag, which it shouldn't do either.

> so I temporarly
> use DX to save them and it works. But I must preserve DX too.

Right.

---
l

bretjohn

Homepage E-mail

Rio Rancho, NM,
14.05.2012, 18:30

@ ecm
 

indirect far jmp - calling old INT problem

FWIW, these days (I didn't used to do this) most of my ISR's start as follows:

PUSH BP
MOV BP,SP
PUSHF
STI
CLD
...

At least in theory, the only difference between the flags at [BP+6] (what will be returned to the caller) and at [BP-2] (the flags I'm working with at the start of my code) will potentially be IF and TF. However, this is only guaranteed to be the case if I'm the first ISR in the chain and the CPU is the one providing the stack and flag and register input. If I'm not first, then that may not be the case unless all of the ISR's further up the chain all did things "correctly".

Unless a particular INT sub-function uses one of the flags as an input parameter (rare, but does happen, like INT 15.4F, and should never happen in an IRQ handler), making sure the input flags to the next ISR are the same ones that you got isn't necessarily a big deal, since it can test the flags on the stack (at [BP+6]) instead of just doing an immediate JC/JNC (or whatever). But, it is important that you do not simply CALL the old ISR like this, unless you're 100% sure your flags haven't changed since the start of your ISR handler:

PUSHF
CALL CS:[OldVector]

In most of my ISR's, if I need to call the old ISR, that's the first thing I do, so I haven't messed with any flags yet and it's not a problem. If this isn't the case for you, though, at an absolute minimum, you should do a "PUSH [BP+6]" instead of a "PUSHF" here (or something similar). It is also important that you do this for all interrupts, not just the ones where you think/know it may matter (like INT 15h), since there can be extensions and overloads and other things you don't know about. You should "emulate" exactly the same thing the CPU does. I think this may be a major cause over the years of TSR's needing to get installed in a particular order for unknown reasons.

If I JMP to the old ISR, I do this, guaranteeing that the old ISR gets the same input flags that I did:

...
POPF
POP BP
JMP CS:[OldVector]

If I need to return CF as a parameter, I do one or the other of the following as appropriate, guaranteeing that CF is the only modified flag:

OR B [BP+6],1 ;Set return CF
AND B [BP+6],(NOT 1) ;Clear return CF

Obviously, some of the details need to be modified to some degree if [OldVector] isn't stored in your own memory, or if you need to CALL the old ISR at the middle/end of your ISR instead of the beginning, or ...

To make code that is "correct", it's not always possible to make it as small as you would like it to be.


Also FWIW, not all assemblers will just automatically insert the SS: override OpCode if you do something like this:

OR B SS:[BP+6],1

Some are "smart enough" to know that the SS: override isn't needed, and some aren't. My assembler does not insert them, so in my code I put the SS: in there as a form of documentation, to remind myself that I'm working with the stack and not "regular" memory.

ecm

Homepage E-mail

Düsseldorf, Germany,
14.05.2012, 18:47

@ bretjohn
 

redundant override in "ss:bp" for clarity

> My assembler does not insert them, so in my code I put the
> SS: in there as a form of documentation, to remind myself that I'm working
> with the stack and not "regular" memory.

I merely insure to always put bp as the first addend if I address memory using it. So that I'd always use [bp+XX...], never [XX...+bp]. This way, I can (at least in my own source) quickly tell what segment registers an explicitly specified address uses; it'll either begin with an override "[Xs:" (indicating that segment register naturally), or with "[bp" (indicating ss), or neither of those (indicating ds).

To regularly use your method, I'd of course first have to extend NASM to have it optimise away redundant overrides - so I lacked that feature in the first place. On the other hand, I might have preferred the convention described above even if I had it, because I sometimes do tend to save some typing if I think it'd be overly redundant.

---
l

RayeR

Homepage

CZ,
14.05.2012, 18:50

@ bretjohn
 

indirect far jmp - calling old INT problem

> (or whatever). But, it is important that you do not simply CALL the old
> ISR like this, unless you're 100% sure your flags haven't changed since the
> start of your ISR handler:
>
> PUSHF
> CALL CS:[OldVector]

Anyway In my case I cannot store old vector in my code segment, it's rom segment and I don't have writable memory so this is why I placed into IVT...

---
DOS gives me freedom to unlimited HW access.

bretjohn

Homepage E-mail

Rio Rancho, NM,
14.05.2012, 20:16

@ RayeR
 

indirect far jmp - calling old INT problem

> Anyway In my case I cannot store old vector in my code segment, it's rom
> segment and I don't have writable memory so this is why I placed into
> IVT...

Which is why you may need to be careful when using the INT 85h approach, and make sure the flags in your code immediately before you issue the call are what they should be (the same as what's at your [BP+6]), e.g.:

PUSH [BP+6]
POPF
INT 85h

You should also make sure that the flags that are returned by INT 85h are stored unchanged at your [BP+6] when you exit, e.g:

INT 85h
PUSHF
POP [BP+6]
POP BP
IRET

This assumes that BP is not a parameter you need to "pass through", which is usually a safe assumption (safer than that you do not need to pass the flags through, anyway). There are ways (more complicated, of course) if you need to pass the original BP through as well.

ecm

Homepage E-mail

Düsseldorf, Germany,
14.05.2012, 20:21

@ bretjohn
 

indirect far jmp - calling old INT problem

> Which is why you may need to be careful when using the INT 85h approach,
> and make sure the flags in your code immediately before you issue the call
> are what they should be (the same as what's at your [BP+6]), e.g.:

This will set the Interrupt Flag and/or Trap Flag too early (inside your code) if they were clear for your entry and set for the calling code. Right here, that might not be a concern, but in general this is incorrect and should be avoided (especially if your handler does not return to the caller right after the call it made has returned).

---
l

bretjohn

Homepage E-mail

Rio Rancho, NM,
14.05.2012, 21:42

@ ecm
 

indirect far jmp - calling old INT problem

> This will set the Interrupt Flag and/or Trap Flag too early (inside your
> code) if they were clear for your entry and set for the calling code. Right
> here, that might not be a concern, but in general this is incorrect and
> should be avoided (especially if your handler does not return to the caller
> right after the call it made has returned).

You are correct. If you need to do a bunch of "clean-up" or additional processing after issuing the INT 85h (more than simply restoring BP like we do here), you would probably at least want to issue an STI (or CLI, as appropriate). In this example, the state of TF and IF don't affect or significantly delay anything critical, so it doesn't really matter.

bretjohn

Homepage E-mail

Rio Rancho, NM,
15.05.2012, 18:45

@ bretjohn
 

indirect far jmp - calling old INT problem

This morning I thought of an even smaller way to "clean up" after the INT 85h:

INT 85h
POP BP
RETF 2

RETF n usually doesn't even cross my mind as a way to end an ISR, since it has the potential to do undesirable things with the flags as discussed earlier. In this case, though, it would work just fine, and is more efficient than the IRET solution.

ecm

Homepage E-mail

Düsseldorf, Germany,
15.05.2012, 18:53
(edited by cm, 15.05.2012, 19:10)

@ bretjohn
 

indirect far jmp - calling old INT problem

> INT 85h
> POP BP
> RETF 2
>
> RETF n usually doesn't even cross my mind as a way to end an ISR, since it
> has the potential to do undesirable things with the flags as discussed
> earlier. In this case, though, it would work just fine, and is more
> efficient than the IRET solution.

This only works if you restore the flags from [bp+6] into the actual flags first, and in that case you'll re-enable TF and IF (if set in the saved flags word) too early - before even calling the ROM BIOS's handler, here.

Edited: Actually I did some tests just now because I wasn't sure, and if you do a popf (setting TF) right before an int instruction, then it will trap only after the int has been called. (Verified in Real and (JEMM's) Virtual 86 Mode on my machine.) I don't know/am not sure that the same is true of interrupts and IF respectively though.

Then, of course, it would still notionally trap/interrupt too early (ie before popping bp in your above suggestion, instead of after/before the caller's next instruction), but you already know that.

---
l

bretjohn

Homepage E-mail

Rio Rancho, NM,
15.05.2012, 20:13

@ ecm
 

indirect far jmp - calling old INT problem

> This only works if you restore the flags from [bp+6] into the actual flags
> first, and in that case you'll re-enable TF and IF (if set in the saved
> flags word) too early - before even calling the ROM BIOS's handler, here.
>
> Edited: Actually I did some tests just now because I wasn't sure, and if
> you do a popf (setting TF) right before an int instruction, then it will
> trap only after the int has been called. (Verified in Real and (JEMM's)
> Virtual 86 Mode on my machine.) I don't know/am not sure that the same is
> true of interrupts and IF respectively though.
>
> Then, of course, it would still notionally trap/interrupt too early (ie
> before popping bp in your above suggestion, instead of after/before the
> caller's next instruction), but you already know that.

I'm not sure the TF isn't being "honored" before the INT is being issued, though that's possible (I know there are delays in exactly when an IF change takes effect, but am not sure about TF). When the INT 85h is issued, the CPU automatically tampers with TF & IF and the ISR will never have TF set on entry, no matter what it was set to when the INT was issued. There is the potential that the POP BP and the RETF 2 will run with TF set, but that shouldn't actually hurt anything (though I suppose it could potentially confuse the debugger that set the TF). The state of IF during the few instructions after the INT returns shouldn't hurt anything, either.

RayeR

Homepage

CZ,
17.05.2012, 01:25

@ bretjohn
 

indirect far jmp - calling old INT problem

Sorry guys, I'm little bit loosing in your high-tech discussion. Just asking if I have to modify something in cm's code? I checked in BOCHS and on real PC too.

NEW_INT13H:                     ;INT XX do PUSHF, clear IF,TF, PUSH CS,IP (6B)
        PUSHF                   ;store flags (2B)
        CMP     DL,ROMDISK_DRIVE;related to our diskdisku?
        JE      @NEW_INT13H_HUB ;if yes continue below else
        POPF                    ;restore flags (2B)
        INT     OLD_INT13H      ;call old INT 13h handler
        PUSH    BP              ;store BP (2B)
        MOV     BP,SP           ;set BP to current SP
        PUSH    AX              ;store AX (2B)
        LAHF                    ;load flags[7:0] to AH that was returned by old INT 13h handler
        MOV     [BP+6],AH       ;replace previously saved flags[7:0] of INT caller on stack by current flags (SS is implicit)
        POP     AX              ;restore AX (2B)
        POP     BP              ;restore BP (2B)
        IRET                    ;return from ISR, do POP IP,CS,F (6B)

---
DOS gives me freedom to unlimited HW access.

Back to index page
Thread view  Board view
22049 Postings in 2034 Threads, 396 registered users, 250 users online (0 registered, 250 guests)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum