2011-12-03 9 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 
    } 
} 

私はこのプログラムを実行しようとすると、ターボC++ 3.0 を使用しています「16ビットMS-DOSサブシステム:NTVDM CPUは不正命令を検出しました」表示されます。 CS、OP、IPレジスタの内容を表示します。私はプログラムを続行できません。助言がありますか?何をやっている

答えて

8

は複数の理由のために右ではありません。彼らは正しく保存し、負荷とCPUレジスタを復元しませんので

  1. 通常のC関数は、安全に、割り込みサービスルーチンとして使用することはできません。それらはinterruptキーワードで宣言する必要があります。そして彼らは最後にiretを持っています。
  2. 割り込みルーチンからプログラムを非同期的に変更できる変数は、volatileと宣言する必要があります。そうしないと、コンパイラによって誤って最適化されたアクセスが発生する可能性があります。
  3. インラインアセンブリコードはおそらくCPUレジスタの内容を破壊します。このコードで間違っていることの1つは、asmがスタックポインタを混乱させることです。最初のブロックはスタック上にいくつかの余分な単語で終了します。これは、コンパイラにとってはまったく予期しないことがあり、プログラムを壊す可能性があります。他にも問題があるかもしれませんが、インラインアセンブリブロックで保持する必要があるコンパイラのドキュメントを確認するつもりはありません。私はこれをすべてやり直して、代わりにsetvect()関数を選択することは避けたいと思います。
  4. これらの関数は一般にリエントラントでもスレッドセーフでもないため、割込みサービスルーチンの内側から標準ライブラリ関数のほとんどを呼び出すことは問題を求めています。彼らは、プログラムの残りの部分について、まったく予期しない方法でいくつかのグローバル変数または状態を修正することができます。割り込みサービスルーチン(printf()が依存しているbtw)からDOSサービス関数を呼び出す場合も同様です。あなたはDOSがOKだと言ったときにしかそれらを呼び出すことができません。これはInDosフラグ変数を介して行われますが、InDos = 0の場合はすべてを安全に呼び出すことはできません。

割込みベクタを変更し、割込みサービスルーチンを定義し、それらからDOS関数を呼び出す方法については、すべてTurbo Cでthis questionへの回答を参照してください。

また、this questionとその回答が役に立ちます。

EDIT

これは、インラインアセンブラとdos.hの機能なしでそれを行う方法です:

bxは、そのコードの前に含まれていない何
#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または割り込みベクトルテーブルの関数を扱うことができなかった、私は2日間同じエラーが発生します。関数に割り込みキーワードを使用し、関数の最後にiretを追加しましたが(やはり同じことですが) – Mikael

1
asm { 
    cli 
    mov es,bx 
    mov bx,36 
    pop ax 
    mov word ptr es:[bx+2],ax 
} 

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

この関数は、正しく破棄していないスタックフレームを設定しました。

+0

bxは0にする必要があります。 LABEL1という名前のラベルがあると仮定して、インラインアセンブリでラベルを指定したいと思います。mov eax、offset LABEL1 - これは使用できません.LABEL1はシンボルとして認識され、未定義です。 LABEL1をjmpしようとしても、ラベルは未定義です。私は機能を使用しなければならなかった、それは動作していないようだ... – Mikael

関連する問題