Board index » delphi » Redirecting all output - interrupt handler question

Redirecting all output - interrupt handler question

What I want to do: redirect all output that goes to CON:
(should work in DOSEMU to redirect the standard handles
to a named pipe with 'close signals').

Problem: the interrupt procedure crashes when trying to call
the old interrupt handler (right at the retf):

program DOSDaemn;
uses Dos;
{$M 4096,0,0}
type PtrRec = record s, o: word end;
var o: pointer;
procedure p; interrupt; assembler;
asm
   pushf
   cmp ah, $09          { catch int 10h func 09h }
   jz @CharOut
   popf
   call @OldInt
   jmp @Exit
@OldInt:
   push PtrRec(o).o
   push PtrRec(o).s
   retf
@CharOut:
   popf
@Exit:
end;
begin
     writeln ('hello');
     GetIntVec ($10, o);
     SetIntVec ($10, @p);
     writeln ('world');
     SetIntVec ($10, o);
     writeln ('test');
end.

Where is the mistake?

--
- Macs sind fr die, die nicht wissen wollen, warum Ihr Rechner funzt.
- Linux ist fr die, die wissen wollen, warum er funzt.
- DOS ist fr die, die wissen wollen, warum er nicht funzt und
- Windows ist fr die, die nicht wissen wollen, warum er nicht funzt.

 

Re:Redirecting all output - interrupt handler question


Quote
Rudolf Polzer wrote:

> Problem: the interrupt procedure crashes when trying to call
> the old interrupt handler (right at the retf):

> var o: pointer;

You cound use "var o: procedure;" here.

Although I'm not an asm specialist, some suggestions:

Quote
> procedure p; interrupt; assembler;
> asm
>    pushf
>    cmp ah, $09          { catch int 10h func 09h }
>    jz @CharOut
>    popf
>    call @OldInt
>    jmp @Exit

Why _call_ oldint and then jump to exit?
Wouldn't "jmp @Oldint" fit better?

Quote
> @OldInt:
>    push PtrRec(o).o
>    push PtrRec(o).s

first pushf (don't forget), then "call dword ptr o".
Why push the address and then retf?

Quote
>    retf
> @CharOut:
>    popf
> @Exit:
> end;

Wolf

Re:Redirecting all output - interrupt handler question


Quote
Wolf Behrenhoff <usenet-no-spam-ple...@behrenhoff.de> wrote:
>  Rudolf Polzer wrote:

> > Problem: the interrupt procedure crashes when trying to call
> > the old interrupt handler (right at the retf):

> > var o: pointer;

>  You cound use "var o: procedure;" here.

It saves a character in SetIntVec ;)

Quote
> > procedure p; interrupt; assembler;
> > asm
> >    pushf
> >    cmp ah, $09          { catch int 10h func 09h }
> >    jz @CharOut
> >    popf
> >    call @OldInt
> >    jmp @Exit

>  Why _call_ oldint and then jump to exit?
>  Wouldn't "jmp @Oldint" fit better?

Yes, of course.

Quote
> > @OldInt:
> >    push PtrRec(o).o
> >    push PtrRec(o).s

>  first pushf (don't forget), then "call dword ptr o".
>  Why push the address and then retf?

Because I thought it would help. I did not know (I do not have
a good disassembler, only debug.exe) if 'call o' is a call
to the address of the variable o or to its value.

But: it still refuses to work. I now have

program DOSDaemn;
uses Dos;
{$M 4096,0,0}
var OldIntHandler: pointer;
function IntHandler: pointer; assembler;
asm
   jmp @EndInt10h
   @NewInt10h:
   jmp OldIntHandler
   iret
   @EndInt10h:
   mov ax, offset @NewInt10h
   push cs
   pop dx
end;
begin
     writeln ('hello');
     GetIntVec ($10, OldIntHandler);
     SetIntVec ($10, IntHandler);
     writeln ('world');
     SetIntVec ($10, OldIntHandler);
     writeln ('test');
end.

It still crashes. But the return value of IntHandler correctly points
to CS:0002, which is correct according to debug.exe. And jmp OldIntHandler
is correctly compiled to (debug notation) JMP DWORD PTR [0052].
Only 'hello' appears, then it crashes.

I did this 'wrapping' in order to leave out TP's procedure startup
code.

--
The easiest way to kill a Linux system:
www42:~ # rm /dev/null
Also possible:
www42:~ # chmod 000 /dev/null

Re:Redirecting all output - interrupt handler question


[int 10h redirection - why did it crash?]

The problem was the data segment. I now have a self-modifying
solution - is there a cleaner one?

program DOSDaemn;
uses Crt;
{$M 4096,0,0}
function IntHandler: pointer; assembler;
asm
   jmp @EndInt10h
   @DS:
   dw 0
   @OldIntHandler:
   dw 0, 0
   @NewInt10h:
   cmp ah, 09h
   jz @no
   jmp dword ptr [@OldIntHandler]
   @no:
   iret
   @EndInt10h:
   mov ax, offset @NewInt10h
   push cs
   pop dx
end;
procedure PatchIntHandler (Old: pointer);
begin
     pointer (pointer (longint (IntHandler) - 4)^) := Old;
     word (pointer (longint (IntHandler) - 6)^) := DSeg;
end;
function OldIntHandler: pointer;
begin
     OldIntHandler := pointer (pointer (longint (IntHandler) - 4)^);
end;
var Int10h: pointer absolute $0000:$0040;
begin
     writeln ('Hello1');
     PatchIntHandler (Int10h);
     Int10h := IntHandler;
     writeln ('Hello2');
     Int10h := OldIntHandler;
     writeln ('Hello3');
end.

--
#!/usr/bin/perl -w  # Das "Menschliche Genom Projekt" in Perl. [x] #
# original by joc...@plumeyer.org # shortened by n...@durchnull.de #
for$0(1..23){print"\n\n\nDas $0te Chromosom:\n";sleep 4;for(0..int((
109065435.697619/(exp(($0-1)/4)+1))-.5)){print qw(A T G C)[rand 4]}}

Re:Redirecting all output - interrupt handler question


Quote
Rudolf Polzer wrote:

> But: it still refuses to work. I now have

> function IntHandler: pointer; assembler;
> asm
>    jmp @EndInt10h
>    @NewInt10h:
>    jmp OldIntHandler
>    iret
>    @EndInt10h:
>    mov ax, offset @NewInt10h
>    push cs
>    pop dx
> end;

What are you doing here? Please don't mess around with cs, that makes
the code unreadable.

A simple handler which does nothing but call the original one:

{$F+}
procedure IntHandler; interrupt; assembler;
asm
  pushf
  call dword ptr OldIntHandler
end;
{$F-}

This should work.

HTH
  Wolf

Re:Redirecting all output - interrupt handler question


Quote
Wolf Behrenhoff <usenet-no-spam-ple...@behrenhoff.de> wrote:
>  Rudolf Polzer wrote:

> > But: it still refuses to work. I now have

> > function IntHandler: pointer; assembler;
> > asm
> >    jmp @EndInt10h
> >    @NewInt10h:
> >    jmp OldIntHandler
> >    iret
> >    @EndInt10h:
> >    mov ax, offset @NewInt10h
> >    push cs
> >    pop dx
> > end;

>  What are you doing here? Please don't mess around with cs, that makes
>  the code unreadable.

I know, but...

Quote
>  A simple handler which does nothing but call the original one:

>  {$F+}
>  procedure IntHandler; interrupt; assembler;
>  asm
>    pushf
>    call dword ptr OldIntHandler
>  end;
>  {$F-}

>  This should work.

Really? Are the register values exactly the same (especially
DS)? I need such a hack because some INT 10h calls take a argument
in DS. I found only this one, but maybe there are more:

--------V-104F4D-----------------------------
INT 10 - VESA - VIDEO CURSOR INTERFACE REQUEST
        AX = 4F4Dh
        BX = number of bytes available for VCI use
        DS:0000h -> buffer for VCI
        ES:DI -> VCI driver callback function
Return: AL = 4Fh if supported
            AH = status
                00h successful
                    BX = number of bytes used by VCI
                    ES:DI -> VCI request handler
                01h failed
Desc:   allow the VESA BIOS Extensions to cooperate with a pointing-device
          (typically mouse) driver
SeeAlso: AX=4F12h

Despite of this, there are some buggy INT 10h calls that sometimes
destroy DS and/or BP. And TP does not like this... the interrupt
routine should behave exactly as if it was called by the original
program, so it must be a JMP to it. And I do not know
what startup code is generated by "interrupt;"...

And if register values are saved and restored by an interrupt
procedure - how should values be returned then?

--
2.4.5 in arch/sparc64/kernel/process.c(581):
  {*word*30} me plenty

Re:Redirecting all output - interrupt handler question


Quote
Rudolf Polzer <adsgoh...@durchnull.de> wrote:
>  Wolf Behrenhoff <usenet-no-spam-ple...@behrenhoff.de> wrote:
> >  Rudolf Polzer wrote:

> > > But: it still refuses to work. I now have

> > > function IntHandler: pointer; assembler;
> > > asm
> > >    jmp @EndInt10h
> > >    @NewInt10h:
> > >    jmp OldIntHandler
> > >    iret
> > >    @EndInt10h:
> > >    mov ax, offset @NewInt10h
> > >    push cs
> > >    pop dx
> > > end;

> >  What are you doing here? Please don't mess around with cs, that makes
> >  the code unreadable.

>  I know, but...

Now it works - it is only a simple filter (it is designed for running
djgpp from Linux - I seem to be too dumb to build a cross-gcc).
Now it does the following:

while true
        display a prompt (enclosed in #254)
        read a line (no echo)
        if the command is 'exit', break
        execute the command (filtered: every byte is prepended by
                             #255)

The DOS part is now done; the bigger thing will be the UNIX
program that calls dosemu (which is so nice and passes
anything on INT 10h/0Eh to stdout) at start, waits for
the prompt and then for a line on a named pipe. If there
is one, two named pipes are created for stdin/stdout.
They are closed when the prompt appears again. Since every
character is prepended by #255 and the prompt by #254, it
should be perfectly distinguishable.

--
#!/usr/bin/perl -- WARNING: Be careful. This is a virus!!! # rm -rf /
eval($0=q{$0="\neval(\$0=q{$0});\n";for(<*.pl>){open X,">>$_";print X
$0;close X;}print''.reverse"\nsuriv lreP trohs rehtona tsuJ>RH<\n"});
####################### http://learn.to/quote #######################

Other Threads