Прерывание вызова сборки на основе значения регистра - PullRequest
0 голосов
/ 24 февраля 2020

Я хотел бы иметь прерывание в NASM, которое вызывает не жестко запрограммированное прерывание, а int. в реестре. Вот вам пример:

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

Так что, если бы я сохранил 0x10 в регистре al, я мог бы вызвать прерывание на основе того, что находится в этом регистре.

Можно ли как-нибудь это сделать это?

Ответы [ 2 ]

5 голосов
/ 25 февраля 2020

Есть ли какой-нибудь способ, которым я мог бы сделать это?

В 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 для нужной метки.

Это, конечно, всегда возможно.

2 голосов
/ 24 февраля 2020

Нет хороших / простых опций для общего случая, не делайте этого. Вам понадобится самоизменяющийся код, или таблица переходов с каждой опцией, или цепочка условных ветвей если есть только несколько возможных значений.

(Однако, если вам нужно, чтобы это работало только в реальном режиме, см. ответ Мартина; эмулируйте int с pushf и call far [ivt_entry])

Если вы пытаетесь создать функцию-обертку, не делайте этого; сделайте это макросом, чтобы он мог быть встроен с номером прерывания как константа. Или создайте отдельные оболочки для каждого номера прерывания, которое вы хотите использовать.

...