基于寄存器值的程序集调用中断



我希望在NASM中有一个中断,它调用的不是硬编码的中断,而是寄存器中的int。举个例子:

mov al, 0x10
int al    ; you can't do this for some reason

所以,如果我把0x10存储在寄存器al中,那么我可以根据寄存器中的内容调用中断。

有什么办法我能做到这一点吗?

有什么办法可以做到这一点吗?

在没有自修改代码的16位"真实模式"中:

大多数DOS的C编译器都提供了一个库函数,允许执行相当于int al的功能。

这是通过以下方式实现的:

在实际模式中,int指令等于pushf,然后是中断处理程序的远call

然而,"远"call只不过是在堆栈上推送下一条指令的"远"地址(csip(并执行跳转。("near"调用仅推送ip。(retf将从堆栈中弹出ipcs并跳到该地址。

中断处理程序的地址存储在地址0:(4*n(。

因此,要输入中断,您首先执行以下代码:

pushf
push cs       # Leave this line out if "call helper" is a "far" call
call helper

当进入函数helper时,堆栈如下所示:

Address (IP) of the instruction after "call helper"
Segment (CS) of the program
Flags
...

这三个元素位于int指令之后的堆栈上。

程序helper如下所示。

helper:
# Calculate BX = 4*AX
# (This can be done with less instructions on a modern CPU)
mov bl,al
mov bh,0
add bx,bx
add bx,bx
# Set DS to 0
xor ax,ax
mov ds,ax
# Push the segment part of the interrupt handler address
# to the stack
push word [bx+4]
# Push the offset part
push word [bx]
# Load all registers with the desired values
# TODO: Ensure all registers have the correct values
# Enter the interrupt
retf

retf之前,堆栈将如下所示:

Address (IP) of the interrupt routine
Segment (CS) of the interrupt routine
Address (IP) of the instruction after "call helper"
Segment (CS) of the program
Flags
...

retf指令的行为方式与前两个字被"远"call指令推送的方式相同:它将从堆栈中删除前两个词,并跳到这两个词所描述的地址-这意味着:进入中断处理程序。

在中断处理程序结束时,最后3个字将从堆栈中弹出,并在call helper之后的指令处继续执行。

在带有自修改代码的16位"真实模式"中:

这很简单:

# AL contains the interrupt number
# Modify the "int" instruction, so "int 42" becomes
# "int 31" if the value of AL is 31.
mov cs:[theIntInstruction+1], al
# Load all registers with the desired values
# TODO: Ensure all registers have the correct values
# Now perform the "int" instruction
theIntInstruction:
int 42

自我修改的代码可能会产生负面的副作用。这意味着可能会出现问题。。。

在(16位或32位("保护模式"中:

根据内存保护设置,您有机会写入"可执行"的内存。在这种情况下,您可能会使用自修改代码。

如果您不可能使用自修改代码,则不可能执行等效的int al,除非您想执行以下操作:

performInt0:
int 0
ret
performInt1:
int 1
ret
performInt2:
int 2
ret
...
performInt255:
int 255
ret

然后对期望的标签执行CCD_ 20。

这当然总是有可能的。

一般情况下没有好的/简单的选项,不要这样做如果只有几个可能的值,则需要自修改代码,或者每个选项都有一个跳转表,或者条件分支链。

(但是,如果您只需要在真实模式下工作,请参阅Martin的答案;使用pushfcall far [ivt_entry]模拟int(

如果你试图制作一个包装器函数,不要;使其成为一个宏,这样它就可以作为常量与中断号内联。或者为您想要使用的每个中断编号制作单独的包装器。

最新更新