在DOS下更换定时器中断处理程序和GNU(GCC和GAS) [英] Replacing the Timer Interrupt Handler in DOS With GNU (GCC and 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屋!