1

タイトルが示すように、DOSのタイマー割り込みの既存のハンドラーを自分のものに置き換えようとしています。さまざまなソリューションを幅広く検索した後、まさにそれを実行するアセンブリコードを見つけました。それをコンパイルしてテストすることもでき、それが機能することを確認しました。

ここでの問題は、私が見つけたコード(以下を参照)がTASM用に記述されていることです。これを、GCCでコンパイルする作成中のCコードで使用したいと思います。

コードをGAS(GNUアセンブラ)構文に変換しようとしましたが、機能しないようです(何度も試行したときに、ほとんどの場合、何らかのクラッシュが発生しました)。

誰かが私に解決策を教えてくれたらとてもありがたいです(GASがコンパイルできるアセンブリコードの動作バージョンであっても、Cですべてを実行する方法-"interrupt"キーワードは機能しません、また、「属性((割り込み))」なども、TASMとGCCの間を橋渡しする方法もありません。

また、私が使用しているDOSシステムは、実際にはFreeDOSがインストールされた仮想マシンを実行しているOracleVM VirtualBox Managerであり、Cに使用しているコンパイラはDJGPP開発環境で提供されるGCCです。 。

これは私が持っている動作中のTASMコードです(http://www.programmersheaven.com/mb/x86_asm/276128/276185/re-redefining-the-timer-interrupt-handler/から取得):

_stack        SEGMENT    STACK
              db         32 DUP ('STACK   ')
_stack        ENDS



_code        SEGMENT PARA 'CODE'
             ASSUME  CS:_code,  SS:_stack

Lstart  LABEL  NEAR

        JMP    Linstall

;+---------------------------------------------
;| My New 1Ch INT
;| Print 'random' chars to the first video line

new_Int PROC   FAR

        DEC    BYTE PTR CS:Counter

        CLD
        PUSH   AX

        MOV    AX, 0B800h
        MOV    ES,AX                   ; ES = b800h
        MOV    DI,000h                 ; DI = 0000h

        MOV    AH,CS:Counter           ; set foreground and background color
        MOV    AL,CS:Counter           ; set char

        MOV    CX,80
        REP    STOSW                   ; From AX to ES:DI

        POP    AX
        STI

        IRET

new_Int ENDP

Counter DB     0Fh

;+-----------------------------------------
;| Store old INT and Install the new one
;|

Linstall    LABEL    NEAR

old_INT     DD       00000000h

        MOV    AL,01Ch                 ;+-
        MOV    AH,35h                  ;| Save old_INT
        INT    21h                     ;|
        MOV    WORD PTR [old_INT],BX
        MOV    WORD PTR [old_INT][2],ES



        CLI                            ;+-
        PUSH   CS                      ;| Install
        POP    DS                      ;|
        LEA    DX,new_INT
        MOV    AL,1Ch
        MOV    AH,25h
        INT    21h


        MOV    AH,0                    ;+- 
        INT    16H                     ;| Wait for a keypress



;+-----------------------------------------
;| Disinstall and exit

        CLI
        PUSH   DS
        LDS    DX,CS:[old_INT]         ;+- 
        MOV    AL,1Ch                  ;| Disinstall int
        MOV    AH,25h                  ;| 
        INT    21h                     ;| 
        POP    DS
        STI        

        MOV    AL,0                    ;+-
        MOV    AH,4Ch                  ;| Exit 
        INT    21h                     ;| 


_code   ENDS
        END    Lstart

それは私のマシンで完全に動作します。プログラムを起動すると、コンソールの最初の行全体が、常に変化するカラフルな文字に置き換えられているのがわかります。

そして、これは上記のコードをGAS構文に変換する私の試みです。

.file   "ttv2.s"


# Define a variable for "randomizing" characters and colors
.globl _MyVar
        .section        .bss
_MyVar:
        .space 1
        .section .text


# Define a variable for storing the address of the current ISR
.globl _OldInt
        .section        .bss
        .p2align 2
_OldInt:
        .space 4
        .section .text


# Program entry point
.text
.globl start
start:
        jmp     _Install


# This is the new Interrupt Service Routine that is going to be installed
.globl _NewInt
_NewInt:
        movb    _MyVar,  %al
        decb    %al            # Decrement our variable
        movb    %al,     _MyVar

        cld
        pushw   %ax

        movw    $0xB800, %ax
        movw    %ax,     %es    # ES = 0xB800
        movw    $0,      %di    # DI = 0

        movb    _MyVar,  %ah    # Set the foreground and background colors
        movb    _MyVar,  %al    # Set the charater to be displayed

        movw    $80,     %cx    # The screen is 80 characters wide
        rep     stosw           # Start copying from AX to AS:DI

        popw    %ax
        sti

        iret



.globl _Install
_Install:
        # Save old ISR address
        movb    $0x1C,   %al  # Set the code for the Timer interrupt
        movb    $0x35,   %ah  # 0x35 is the code for getting the current ISR
        int     $0x21         # 0x21 is the interrupt fot s/getting ISRs
        movw    %es,     %dx     #
        shll    $16,     %edx    # Save the address of the
        movw    %bx,     %dx     #  old interrupt handler
        movl    %edx,    _OldInt #


        # Install the new ISR
        cli
        pushw   %cs
        popw    %ds
        lea     _NewInt, %dx  # Set the address of the ISR we're installing
        movb    $0x1C,   %al  # Set the code for the Timer interrupt
        movb    $0x25,   %ah  # 0x25 is the code for setting a new ISR
        int     $0x21         # 0x21 is the interrupt fot s/getting ISRs

        # Wait for a key press
        movl    $0,     %eax
        int     $0x16


.globl _Uninstall
_Uninstall:
        cli
        pushw   %ds
        lds     %cs:_OldInt,    %dx  # Install the address of the old ISR

        movb    $0x1C,   %al  # Set the code for the Timer interrupt
        movb    $0x25,   %ah  # 0x25 is the code for setting a new ISR
        int     $0x21         # 0x21 is the interrupt fot s/getting ISRs

        popw    %ds
        sti


.globl _End
_End:
        # Exit
        movb    $0,     %al
        movb    $0x4C,  %ah   # 0x4C is the code for program exit in DOS
        int     $0x21


        .ident  "GCC: (GNU) 4.5.2"

次のコマンドを使用してファイル(「ttv2.s」と呼ばれる)をコンパイルします。

as -o ttv2.o ttv2.s
ld -o ttv2.exe ttv2.o

結果のEXEファイルを実行すると(アセンブリおよびリンケージ中に警告やエラーは発生しません)、プログラムは「リング0の例外0D(および多数のレジスタ値)」というエラーでクラッシュします。ただし、TASMバージョンは問題なく動作します。したがって、コードを変換する方法、または最終的なEXEを作成する方法のいずれかに問題があると推測しています。または両方。

少しの追加情報、それが何らかの形で役立つ場合:

  • インストールコマンド( )を削除int $0x21してもクラッシュは発生せず、プログラムはキーを押すのを待ってから終了します。
  • インストールコマンドを保持しているが、キー待機コマンド( )を削除するint $0x16と、プログラムはすぐに終了し、クラッシュは発生しません。
  • インストールコマンドを保持し、wait-for-keyコマンドをアクティブな遅延ループ(40億回の反復の単純なループ)に置き換えると、wait-for-keyコマンドが配置されたときと同じようにプログラムがクラッシュします。 、しかし、すぐにではなく、数秒後。
  • どちらの場合も(キーを押すか遅延して)クラッシュすると、2つのインストールコマンドの1つだけを削除しても、プログラムがクラッシュします。

あらゆる支援を事前に感謝し、長い投稿をお詫びします...

4

2 に答える 2

1

.code1616 ビット リアル モード用のアプリケーションをビルドするように、おそらく指定する必要があります。

于 2011-09-13T17:40:52.970 に答える
1

リングに関するエラーが表示されるということは、なんらかの理由で 16 ビット リアル モード (DOS が実行されるようなモード) ではなく、なんらかの保護モードになっていることを意味します。したがって、1) アセンブリ コマンド用に 16 ビット リアル モードにコンパイルしていること (つまり、バイナリ マシン コードが 32 ビット オペコードではなく 16 ビット オペコードである)、および 2) 16 ビットで実行していることを確認してください。 EXE を実行しようとすると、ビット リアル モード設定が無効になります。

次に、TASM バージョンではCounter変数をコード セグメントにCounter配置し、現在のコード セグメントからのオフセットを介して にアクセスしていることに注意してください。一方、カウンター変数_MyVarを BSS セクションに配置しました。リンカーがバイナリ実行可能ファイルをリンクする方法によっては、割り込みからその変数にアクセスできない場合があります。たとえば、割り込みが実行されている場合、現在のデータ セグメントの 64Kb ウィンドウ内ではアクセスできない場合があります。したがって、TASM バージョンで行ったことをミラーリングし、カウンター変数をコード セグメントに配置し、コード セグメントからアクセスします。

于 2011-09-13T17:55:45.583 に答える