2011-12-03 47 views
3

我試圖重新編程指令向量表。下面是我的代碼使用方法:C(DOS)中的嵌入式彙編 - 非法指令

#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 CPU遇到非法指令。」出現。然後顯示CS,OP和IP寄存器的內容。我無法繼續該計劃。有什麼建議麼?

回答

8

你正在做什麼是不適合多種原因:

  1. 常規的C函數不能安全地用於中斷服務程序,因爲他們不正確保存,加載和恢復CPU寄存器。必須用interrupt關鍵字聲明它們。最後他們會爲你提供iret
  2. 程序可以在程序中異步改變中斷程序的變量,必須聲明爲volatile,否則你可能會冒着對編譯器錯誤地進行優化的風險。
  3. 您的內聯彙編代碼可能會損壞CPU寄存器的內容。這段代碼有一個錯誤,就是你的asm塊與堆棧指針混亂。第一個程序段在堆棧中多出一些字。這對編譯器來說可能是完全意想不到的,並且會破壞你的程序。可能還有其他問題,但我不打算用編譯器文檔檢查哪些寄存器必須通過內聯彙編塊保留。我會盡量避免這樣做,而是選擇setvect()函數。
  4. 從中斷服務例程中調用大多數標準庫函數會引起麻煩,因爲這些函數通常不是可重入/線程安全的。他們可以以完全意想不到的方式修改某些全局變量或狀態,以用於其他程序。從中斷服務例程調用DOS服務函數(您的printf()所依賴的btw)也是如此。當DOS說沒關係的時候,你只能調用這些。它通過InDos標誌變量這樣做,並且仍然,當InDos = 0時,並非所有人都可以安全地呼叫。

查看如何在this question的答案中更改中斷向量,定義中斷服務程序並調用它們的DOS功能,全部使用Turbo C。

您還可能會發現this question及其答案有用。

編輯

這是你如何與內聯彙編做沒有DOS.H的功能:

#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 
    } 
} 
+0

不使用dos.h怎麼辦?通過getvect和setvect我瞭解您的代碼,您可以在代碼段之後調用原始鍵盤功能。如果我不能使用getvect-setvect,你有什麼建議嗎? – Mikael

+0

查看我答案中的最後一個鏈接。有足夠的asm代碼讓你開始使用中斷處理程序。 –

+0

我再次看到,但我要求內聯彙編。我無法設法解決C中的函數或中斷向量表,我在兩天內得到相同的錯誤。我用函數中斷關鍵字,將函數添加到函數結尾(再次),但仍然是同樣的事情。 – Mikael

1
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} 
} 

該函數設置了一個堆棧框架,但沒有正確銷燬。

+0

bx應該在那裏。我想使用內聯彙編來處理標籤,例如(假設有一個名爲LABEL1的標籤)mov eax,offset LABEL1 - 我不能使用它,彙編程序將LABEL1視爲符號,並表示它是未定義的。即使我嘗試jmp LABEL1 - 標籤未定義。我不得不使用功能,然後,它似乎不工作... – Mikael