我希望在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
只不过是在堆栈上推送下一条指令的"远"地址(cs
和ip
(并执行跳转。("near"调用仅推送ip
。(retf
将从堆栈中弹出ip
和cs
并跳到该地址。
中断处理程序的地址存储在地址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的答案;使用pushf
和call far [ivt_entry]
模拟int
(
如果你试图制作一个包装器函数,不要;使其成为一个宏,这样它就可以作为常量与中断号内联。或者为您想要使用的每个中断编号制作单独的包装器。