Встроенная сборка в C (DOS) - недопустимая инструкция - PullRequest
3 голосов
/ 03 декабря 2011

Я пытаюсь перепрограммировать таблицу векторов инструкций.Вот код, который я использую:

#include <stdio.h>

int a=1;
void func();

void keyboard()
{
    printf("\n\nkeyboard!!!\n");
    a=0;
    asm{iret}
}

int main ()
{
    printf("starting...");
    func();
    return 0;
}

      int vectorcs = 0;
 int vectorip = 0;

void func()
{

    printf("\n*****\n");
    asm{
        cli
        mov ax,0
        mov es,ax
        mov bx,36
        mov ax,word ptr es:[bx]
        mov vectorip,ax
        push ax
         mov ax,word ptr es:[bx+2]
        mov vectorcs,ax
        push ax
        mov ax,cs
        mov word ptr es:[bx],offset keyboard
        mov es:[bx+2],ax
        sti
    }
    printf("\n%d %d\n",vectorip,vectorcs);

    while (a) {
    }
    asm {
        cli
        mov es,bx
        mov bx,36
        pop ax
        mov word ptr es:[bx+2],ax
    }
    asm{
        pop ax
        mov word ptr es:[bx],ax
        sti
    }
}

Я использую Turbo C ++ 3.0 Когда я пытаюсь запустить эту программу, «16-битная подсистема MS-DOS: ЦП NTVDM обнаружил недопустимую инструкцию».появляется.Затем он показывает содержимое регистров CS, OP и IP.Я не могу продолжить программу.Есть предложения?

Ответы [ 2 ]

8 голосов
/ 03 декабря 2011

То, что вы делаете, неправильно по нескольким причинам:

  1. Обычные функции C нельзя безопасно использовать в качестве подпрограмм обработки прерываний, поскольку они неправильно сохраняют, загружают и восстанавливают ЦП.регистры.Они должны быть объявлены с ключевым словом interrupt.И они будут иметь iret для вас в конце.
  2. Переменные, которые могут асинхронно изменяться в программе от подпрограмм прерывания, должны быть объявлены как volatile, в противном случае вы рискуете получить к ним неправильный доступоптимизировано компилятором.
  3. Ваш встроенный код сборки, вероятно, повреждает содержимое регистров процессора.В этом коде неправильно то, что ваш asm блокирует беспорядок с указателем стека.Первый блок выходит с несколькими дополнительными словами в стеке.Это может быть совершенно неожиданным для компилятора и может сломать вашу программу.Могут быть и другие проблемы, но я не собираюсь сверяться с документацией компилятора, какие регистры должны быть сохранены встроенными блоками сборки.Я бы вообще не делал этого и выбрал бы функцию setvect().
  4. Вызов большинства стандартных функций библиотеки изнутри подпрограмм обработки прерываний вызывает проблемы, потому что эти функции, как правило, не реентерабельныебезопасный.Они могут изменять некоторые глобальные переменные или состояния совершенно неожиданным образом для остальной части программы.То же самое относится и к вызову функций службы DOS из подпрограмм обработки прерываний (на которые полагается ваш printf (), кстати).Вы можете звонить только тогда, когда DOS говорит, что все в порядке.Он делает это через переменную флага InDos, и все же не все безопасно вызывать, когда InDos = 0.

Узнайте, как изменить векторы прерываний, определить подпрограммы обработки прерываний и вызвать функции DOSот них, все с Turbo C, в ответе на этот вопрос .

Вы также можете найти этот вопрос и его ответы полезными.

РЕДАКТИРОВАТЬ :

Вот как вы делаете это без функциональности dos.h со встроенным asm:

#include <stdio.h>

volatile int a = 1;
void interrupt (*pOldInt9)(void);
void func(void);

void interrupt keyboard(void)
{
    printf("\n\nkeyboard!!!\n");

    asm {
        in  al, 0x60
        in  al, 0x61
        mov ah, al
        or  al, 0x80
        out 0x61, al
        mov al, ah
        out 0x61, al
    }

    a = 0;

    asm {
        mov al, 0x20
        out 0x20, al
    }
}

int main(void)
{
    printf("starting...");
    func();
    return 0;
}

void func(void)
{
    printf("\n*****\n");

    asm {
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, es:[bx]
        mov     word ptr pOldInt9, ax
        mov     word ptr es:[bx], offset keyboard

        mov     ax, es:[bx + 2]
        mov     word ptr pOldInt9[2], ax
        mov     es:[bx + 2], cs

        sti

        pop     es
        pop     bx
    }

    while (a) {}

    asm {
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, word ptr pOldInt9
        mov     es:[bx], ax

        mov     ax, word ptr pOldInt9[2]
        mov     es:[bx + 2], ax

        sti

        pop     es
        pop     bx
    }
}
1 голос
/ 03 декабря 2011
asm {
    cli
    mov es,bx
    mov bx,36
    pop ax
    mov word ptr es:[bx+2],ax
}

Что содержит bx перед этим кодом?

void keyboard()
{
    printf("\n\nkeyboard!!!\n");
    a=0;
    asm{iret}
}

Эта функция установила кадр стека, который вы неправильно уничтожили.

...