Есть ли какой-нибудь способ, которым я мог бы сделать это?
В 16-битном "Реальном режиме" без самоизменяющегося кода:
Большинство C компиляторов для DOS обеспечивали библиотечную функцию, которая позволяла выполнять эквивалент int al
.
. Это работало следующим образом:
В реальном режиме инструкция int
равна до pushf
, за которым следует дальний call
до обработчика прерываний.
Однако «дальний» call
- это не что иное, как нажатие «дальнего» адреса (cs
и ip
) следующей инструкции в стеке и выполнения прыжка. («Ближний» вызов только выталкивает ip
.) retf
вытолкнет ip
и cs
из стека и перейдет к этому адресу.
Адрес обработчика прерываний сохраняется в адрес 0: (4 * n).
Таким образом, чтобы ввести прерывание, сначала необходимо выполнить следующий код:
pushf
push cs # Leave this line out if "call helper" is a "far" call
call helper
При вводе функции helper
стек выглядит следующим образом this:
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
будет вести себя так же, как если бы первые два слова были выдвинуты инструкцией "far" call
: удалит первые два слова из стека и перейдет по адресу, описанному этими двумя словами - это означает: в обработчик прерываний.
В конце обработчика прерываний будут извлечены последние 3 слова из стек и выполнение продолжится по инструкции после * 105 2 *.
В 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
Self Модифицирующий код может иметь негативные побочные эффекты. Это означает, что могут быть проблемы ...
В (16- или 32-разрядном) "защищенном режиме":
В зависимости от настроек защиты памяти, которые у вас есть возможность записи в память, которая является "исполняемой". В этом случае вы можете использовать самоизменяющийся код.
Если у вас нет возможности использовать самоизменяющийся код, выполнить эквивалент int al
невозможно, если вы не хотите выполнить следующее:
performInt0:
int 0
ret
performInt1:
int 1
ret
performInt2:
int 2
ret
...
performInt255:
int 255
ret
... и затем выполнить call
для нужной метки.
Это, конечно, всегда возможно.