experchange > asm.x86

R.Wieser (10-27-18, 02:51 PM)
Hello all,

I'm dealing with a packet driver, which API (ABI?) can be put behind any
available INT (by specifying the number when loading it).

I would like my program to find the right INT at runtime (which is not hard,
as the packet driver has a certain string at a certain place, just so you
can check if its actually there) and than use that.

The problem is that no "INT [byte address]" exists.

So, I'm looking for a different solution.

The simplest is self-modifying code to change one byte and than have the
rest call the "int {number}", "RET" sequence. But that would wrap avery
call in a superfluous return.

I guess I could push the flags, clear some bitflags in it and than jump
indirect (thru the INT vector table at page zero) to the correct address,
but I'm wondering if there isn't maybe an easier(?), more direct way of
doing it.

Regards,
Rudy Wieser
Rick C. Hodgin (10-27-18, 03:35 PM)
On Saturday, October 27, 2018 at 8:55:25 AM UTC-4, R.Wieser wrote:
> I guess I could push the flags, clear some bitflags in it and than jump
> indirect (thru the INT vector table at page zero) to the correct address,
> but I'm wondering if there isn't maybe an easier(?), more direct way of
> doing it.


The standard method for calling an interrupt vector is to PUSHF/D,
then do a far call. This puts the three parameters the interrupt
vector expects to see on the stack when it issues IRET.

You could issue an interrupt redirect, where you are intercepting
INT Nn, and you choose some unused vector and point it to the
original vector you intercept, that way all calls to INT Nn go
through you, and then you issue the re-direct to INT Zz that you
setup, which goes to the real vector. Then the called API code
issues IRET like normal, then you issue IRET like normal.

It's a little less efficient on the stack, but it's pretty clean
and straight-forward.
Mateusz Viste (10-27-18, 08:47 PM)
On Sat, 27 Oct 2018 14:51:35 +0200, R.Wieser wrote:
> I'm dealing with a packet driver, which API (ABI?) can be put behind any
> available INT (by specifying the number when loading it).
> I would like my program to find the right INT at runtime (which is not
> hard,
> as the packet driver has a certain string at a certain place, just so
> you can check if its actually there) and than use that.
> The problem is that no "INT [byte address]" exists.


You do not have to use an INT instruction. As Rick suggested already, you
can simulate an INT using a "pushf + cli + far call" combo. This way all
you have to do is resolve the jump address from the vector table when
your program starts and then jump to this address whenever you need to
call the pktdrvr interface.

Here below is how I did it in DWOL:


I also used the same method in EtherDFS:

etherdfs.c#l319

Mateusz
Robert Wessel (10-27-18, 08:56 PM)
On Sat, 27 Oct 2018 14:51:35 +0200, "R.Wieser"
<address> wrote:

[..]
>indirect (thru the INT vector table at page zero) to the correct address,
>but I'm wondering if there isn't maybe an easier(?), more direct way of
>doing it.


We always did the self-modifying code thing. It's not hard to make a
list of those, and patch multiple locations at startup. Some macro
and segment trickery can help build the list automatically as well.
R.Wieser (10-27-18, 09:26 PM)
Rick,

> The standard method for calling an interrupt vector is to
> PUSHF/D, then do a far call.


Not even clearing those flags a standard INT does ? Hmm...

> This puts the three parameters the interrupt
> vector expects to see on the stack when it issues IRET.


Hmm... I would need to copy the actual vector and call it it indirectly
(referencing CS, as DS could be pointing elsewhere) , but if I do not
actually need to clear those flags it would be workable. Thank, I'll keep
it in mind.

> You could issue an interrupt redirect, where you are
> intercepting INT Nn, and you choose some unused vector


That one also entered my mind. But I don't think I will pursue anything in
that direction, because of the problem determining where an "unused
interrupt" might be.

Regards,
Rudy Wieser
Rod Pemberton (10-28-18, 07:58 AM)
On Sat, 27 Oct 2018 14:51:35 +0200
"R.Wieser" <address> wrote:

> I'm dealing with a packet driver, which API (ABI?) can be put behind
> any available INT (by specifying the number when loading it).
> I would like my program to find the right INT at runtime (which is
> not hard, as the packet driver has a certain string at a certain
> place, just so you can check if its actually there) and than use that.


I would suggest hooking two interrupts. One is for the random or
changing or relocatable interrupt that you call to access the API. The
other would be on a fixed interrupt with a unique registers value, say
in AX, for the call to detect the presence or installation of the
packet driver API. This is the same way you detect DPMI or XMS etc,
e.g., DPMI installs INT 0x2F, AX=1687h and XMS installs INT 0x2F,
4300h. However, DPMI's main interrupt is on INT 0x31 whereas XMS
returns an address to a function on INT 0x2F, AX-4310h. So, it seems
INT 0x2F might be a good place to install an installation check or
interrupt number check in your case.

DJGPP's online RBIL has a table of used or in-use AX values for INT
0x2F here:



Rod Pemberton
R.Wieser (10-28-18, 09:01 AM)
Mateusz,

> Here below is how I did it in DWOL: ....
> I also used the same method in EtherDFS:


Thanks. Its good to have a reference, if only to compare ones own
ideas/work with. :-)

Regards,
Rudy Wieser
R.Wieser (10-28-18, 09:14 AM)
Robert,

> We always did the self-modifying code thing. It's not hard to
> make a list of those, and patch multiple locations at startup.


I guess I could try to macro the call and have it generate the list
automatically (instead of adding every reference by hand I mean)

> Some macro ... trickery can help build the list automatically as well.


Ninja-ed! :-)

> Some ... segment trickery


In regard to the offsets you mean? No need for that yet, as my programs
tend to stay in the tiny model.

@all:
Reading the responses I take it that creating a procedure thats called
instead of performing the INT directly (meaning only one spot to modify) is
out of the question. (too many stack shennigans) ?

Regards,
Rudy Wieser
R.Wieser (10-28-18, 09:41 AM)
Rod,

> I would suggest hooking two interrupts. One is for the random
> or changing or relocatable interrupt that you call to access the
> API. The other would be on a fixed interrupt with a unique
> registers value, say in AX, for the call to detect the presence or
> installation of the packet driver API.


I'm afraid you misunderstood: Finding the API (and by it its INT) isn't the
problem, the packetdriver spec already took care of that (unique string at a
fixed offset).

The problem is that my program needs to adjust to the found INT value. By
default the packetdrivers at INT 0x60, but it can be pretty much anywhere.

In short, how do I change that "0x60" (in my program) into something
flexible -or- how do I create a single-point-of-change procedure (instead of
having to implement a fixup for multiple INT 0x60 calls).

Currently the absolute simpelest (in my mind) solution is to create a
procedure with only "INT 0x60", "ret" sequence in it, and have the
initialisation code change that (single!) 0x60 into whatever it found. The
downside to that is that the call itself adds another WORD to the used stack
(a total 8 bytes instead of 6).

> DJGPP's online RBIL has a table of used or in-use AX values
> for INT 0x2F here:


:-) Ralf Browns intlist has been my to-go source for literallly years, and
its files (still) have a dominant place on my machine.

Regards,
Rudy Wieser

> So, it seems INT 0x2F might be a good place to install an
> installation check or interrupt number check in your case.


I didn't think of such a method

> I would suggest hooking two interrupts.

...
Rick Hodgin also mentioned that (and I thought of it as well). I decided
against it though, as its too easy to have programs clash that way. Just
imagine two programs using that same mechanimsm (but targetting different
packet drivers) ...

"Rod Pemberton" <invalid> wrote in message
news:hgt1
[..]
Terje Mathisen (10-28-18, 10:06 AM)
Selfmodifying code, i.e. fixing the 60h constant to whichever INT value
is being used, is by far the simplest to implement in asm.

You can also do it by emulating an INT, it is after all a push of flags
followed by an indirect far call:

Copy the relevant far address into a local variable:

mov bx,[intnr]
xor ax,ax
shl bx,2

push ax
pop es

;; At this point ES:[BX] points at the relevant vector entry:

mov ax,es:[bx]
mov [local_int],ax
mov ax,es:[bx+2]
mov [local_int+2],ax

Then when you need to call the driver you can do this:

pushf
CLI
call far [local_int]

Terje

R.Wieser wrote:
[..]
R.Wieser (10-28-18, 02:08 PM)
Terje,

> Selfmodifying code, i.e. fixing the 60h constant to whichever INT value is
> being used, is by far the simplest to implement in asm.


Agreed.

But as that INT 0x60 is present at several different locations thruout the
program all those locations need to be stored, and walked thru on init.
Forget one, and the program will fail ... somewhere. Hence my "call a
procedure" preference (only one spot to change).

> Then when you need to call the driver you can do this:
> pushf
> CLI
> call far [local_int]


Don't forget the CS: prefix - DS can be, depending on the API function, be
pointing somewhere rather different than where the "local_int" is stored.
:-)

One question though: The specs mention three flags being cleared by the INT
instruction, and you only clear the interrupt flag. Experience or something
else ?

Regards,
Rudy Wieser
Terje Mathisen (10-28-18, 04:55 PM)
R.Wieser wrote:
> Terje,
> Agreed.
> But as that INT 0x60 is present at several different locations
> thruout the program all those locations need to be stored, and walked
> thru on init. Forget one, and the program will fail ... somewhere.
> Hence my "call a procedure" preference (only one spot to change).


I thought that one was obvious, you have to make a single function which
does the INT xx emulation, and which you call from all the paces where
you need to.
>> Then when you need to call the driver you can do this:
>> pushf CLI call far [local_int]

> Don't forget the CS: prefix - DS can be, depending on the API
> function, be pointing somewhere rather different than where the
> "local_int" is stored. :-)


Sorry, I agree. I intended for this one to use a segment overrride, and
CS and easier than FS or GS. :-)
> One question though: The specs mention three flags being cleared by
> the INT instruction, and you only clear the interrupt flag.
> Experience or something else ?


I have never seen any real need for more than the Int enable flag, and
for a sw API, even CLI is probably not needed, but safer if the code
called this way assumes CLI while doing something dangerous like
changing SS:SP.

Terje
Rick C. Hodgin (10-28-18, 05:14 PM)
On Saturday, October 27, 2018 at 3:32:12 PM UTC-4, R.Wieser wrote:
> Rick,
> > The standard method for calling an interrupt vector is to
> > PUSHF/D, then do a far call.

> Not even clearing those flags a standard INT does ? Hmm...


Oops. Yes. As others indicate, you need to issue CLI. My bad.
sdn45478 (10-28-18, 08:49 PM)
On Saturday, October 27, 2018 at 5:55:25 AM UTC-7, R.Wieser wrote:
Hi,
I don't know if this will work for your application but as an idea
maybe a config program that loads the executable you want to change ints with
into ram then figures out the right int calls for the situation,
changes the int calls in the executable then saves it to disk.
Then it's configured for whatever and hard wired.
Steve
R.Wieser (10-28-18, 09:32 PM)
Steve,

> I don't know if this will work for your application but as an idea [snip]


That would certainly work when the INT value would be a constant. But its a
setting provided to the packetdriver when loading it, and can be changed at
will. My program therefore has to follow the packetdrivers lead, and
dynamically change the INT it uses.

Thanks for the suggestion though.

Regards,
Rudy Wieser

Similar Threads