在DOS下更换定时器中断处理程序和GNU(GCC和GAS) [英] Replacing the Timer Interrupt Handler in DOS With GNU (GCC and GAS)

查看:324
本文介绍了在DOS下更换定时器中断处理程序和GNU(GCC和GAS)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如标题所暗示的,我想用我自己的一个替换为在DOS下定时器中断现有的处理程序。
搜索甚广的各种解决方案后,我发现了一些大会code这正是这么做的,我甚至设法编译和测试它,看到它的工作原理。

As the title suggests, I'm trying to replace the existing handler for the Timer interrupt in DOS with one of my own. After searching far and wide for a variety of solutions, I found some Assembly code which does exactly that, and I have even managed to compile and test it, and saw that it works.

现在的问题是,code,我发现(详见下)为TASM写的,我希望与一些C code,我正在写,这是我用GCC编译使用它。

The problem now is that the code I found (see further down) is written for TASM, and I wish to use it with some C code that I'm writing, which I compile with GCC.

我试过到code转换成GAS(GNU汇编语言)语法,但我似乎无法得到它(在我无数次的尝试我这样或那样的大多是经验丰富的崩溃)工作。

I've tried to convert the code into GAS (GNU Assembler) syntax, but I can't seem to get it to work (I mostly experienced crashes of one kind or another during my numerous attempts).

我非常AP preciate它,如果任何人都可以用一个解决方案赐教(无论是装配$ C $的工作版本C,它气体可编译,一个办法做到整个事情用C - 中断关键字不能正常工作,而且也不属性((中断))之类的 - 甚至是一种方法,TASM和GCC)之间的桥梁

I would very much appreciate it if anyone could enlighten me with a solution (be it a working version of the assembly code that GAS can compile, a way to do the entire thing in C -- the "interrupt" keyword doesn't work, and neither does "attribute ((interrupt))" and the like -- or even a way to bridge between TASM and GCC).

我也或许应该提,我使用的是DOS系统实际上是运行一个虚拟机上安装了FreeDOS的一个OracleVM VirtualBox虚拟管理器,我使用对C编译器是提供与海湾合作委员会DJGPP的开发环境。

I should also probably mention that the DOS system I'm using is actually an OracleVM VirtualBox Manager running a virtual machine with FreeDOS installed on it, and that the compiler I'm using for C is the GCC that is provided with the DJGPP development environment.

这是工作TASM code我已经(从<一所href=\"http://www.programmersheaven.com/mb/x86_asm/276128/276185/re-redefining-the-timer-interrupt-handler/\" rel=\"nofollow\">http://www.programmersheaven.com/mb/x86_asm/276128/276185/re-redefining-the-timer-interrupt-handler/):

This is the working TASM code I have (taken from 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

它完全工作在我的机器上。我启动程序,看看通过改变这一切的时候各色人物取代了控制台的整个第一行。

It fully works on my machine. I start the program and see the entire first line of the console replaced by colorful characters that change all the time.

这是我尝试上述code转换成气体语法:

And this is my attempt to convert the above code into GAS syntax:

.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),使用下面的命令:

I compile my file (called "ttv2.s") with the following commands:

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

当我运行生成的EXE文件(也有装配和连接过程中没有警告或错误),程序的错误,在环0异常0D(和大量的寄存器值的)崩溃。
该TASM版本,但是,工作顺利!
所以我猜测,有什么不对或者与我转换的code或与办法,我构建最终的EXE的方式。或者两者兼而有之。

When I run the resulting EXE file (there are no warnings or errors during the assembly and linkage), the program crashes with the error "Exception 0D in ring 0" (and lots of register values). The TASM version, however, works without a hitch! So I'm guessing that there is something wrong either with the way I converted the code, or with the way I'm building the final EXE. Or both.

附加信息的位,应该以任何方式帮助:

A bit of additional information, should it help in any way:


  • 如果我的删除安装命令( INT $ 0×21 ),没有死机,程序等待我打一个键,然后退出。

  • 如果我保持安装的命令,但删除等待换键命令( INT $ 0x16 ),程序立即退出,并没有崩溃。

  • 如果我保持安装的命令,和替换等待换键命令与主动延迟环(4十亿次迭代一个简单的循环),程序它崩溃时所做等待的-key命令到位的方式相同,但几秒钟,而不是立即之后。

  • 在这两种情况下的碰撞(用钥匙preSS或延迟),程序崩溃,即使我刚刚删除的2个安装命令之一。

  • If I remove the installation commands (the int $0x21), there is no crash, and the program waits for me to hit a key and then exits.
  • If I keep the installation commands, but remove the wait-for-key command (the int $0x16), the program exits immediately, and there is no crash.
  • If I keep the installation commands, and replace the wait-for-key command with an active delay loop (a simple loop of 4 billion iterations), the program crashes the same way it did when the wait-for-key command was in place, but after a couple of seconds, rather than immediately.
  • In both cases with the crash (with the key press or the delay), the program crashes even if I remove just one of the two installation commands.

先感谢您的任何和所有帮助和抱歉冗长的帖子...

Thanks in advance for any and all assistance, and sorry for the lengthy post...

推荐答案

这是你得到关于环的错误,这意味着你是出于某种原因不能在16位实模式(如DOS将运行)而是在某种形式的保护模式。因此,请确保1)你正在编译为16位实模式汇编指令(即二进制机器code是16位运算codeS,而不是32位运算codeS) 2)您在当您尝试运行EXE 16位实模式设置都在运行。

The fact that you're getting an error about rings means that you are for some reason not in 16-bit real mode (like DOS would be run), but rather are in some form of protected mode. So make sure that 1) you are compiling to 16-bit real mode for your assembly commands (i.e., the binary machine code is 16-bit opcodes, not 32-bit opcodes), and 2) that you are running in a 16-bit real mode setting when you attempt to run your EXE.

其次,注意在TASM版本,他们已经放在计数变量在code段,并访问计数器通过从目前的code-段偏移。您在另一手已经把你的计数器变量 _MyVar 在BSS部分。根据链接器链接您的二进制可执行文件,该变量可能无法从你的中断访问...例如,它可能不是当中断正在运行的当前数据段的64KB的窗口中访问。因此,我将反映他们在TASM版本做了,把你的计数器变量在code段,并从code段访问

Secondly, note that in the TASM version, they have placed the Counter variable in the code segment, and are accessing the Counter via an offset from the current code-segment. You on the other-hand have placed your counter variable _MyVar in the BSS section. Depending on how the linker links your binary executable, that variable may not be accessible from your interrupt ... for instance, it may not be accessible within the 64Kb window of the current data segment when the interrupt is running. Therefore I would mirror what they did in the TASM version, and place your counter variable in the code-segment, and access it from the code-segment

这篇关于在DOS下更换定时器中断处理程序和GNU(GCC和GAS)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆