Ita*_*mar 6 macros assembly interrupt tasm dosbox
考虑以下宏:
pixelFast MACRO
; This macro draws a pixel, assuming the coordinates are already loaded in cx&dx and the color is in al.
xor bh, bh
mov ah, 0ch
int 10h
ENDM
drawRect MACRO x1, y1, x2, y2, color
LOCAL @@loop, @@row_loop
xor cx, cx
mov dx, y1
mov al, BYTE PTR [color]
@@loop:
mov cx, x1
@@row_loop:
pixelFast
inc cx
cmp cx, x2
jna @@row_loop
inc dx
cmp dx, y2
jna @@loop
ENDM
rendToolBar MACRO
drawRect COLORDISP_X1, COLORDISP_Y1, COLORDISP_X2, COLORDISP_Y2, foreground_color
mov temp_color, 36h
drawRect COLORBTN1_X1, COLORBTN1_Y1, COLORBTN1_X2, COLORBTN1_Y2, temp_color
mov temp_color, 2Eh
drawRect COLORBTN2_X1, COLORBTN2_Y1, COLORBTN2_X2, COLORBTN2_Y2, temp_color
mov temp_color, 4h
drawRect COLORBTN3_X1, COLORBTN3_Y1, COLORBTN3_X2, COLORBTN3_Y2, temp_color
mov temp_color, 2Bh
drawRect COLORBTN4_X1, COLORBTN4_Y1, COLORBTN4_X2, COLORBTN4_Y2, temp_color
ENDM
Run Code Online (Sandbox Code Playgroud)
在我的代码中的某处,我使用了rendToolBar宏.它应该绘制一个大的白色画布,然后是一个小方块,旁边是一些特定图案的小方块,这与我的问题无关.请注意,rendToolBar调用drawRect 5次.我在turbo调试器中跟踪了这段代码(因为有些东西出了问题),并注意到在drawRect宏的第4次执行中,pixelFast的"int 10h"实际上并不是"int 10h",而是"int 2".这会导致一个NMI,这会让我的程序变得混乱.我想知道是什么让TASM在第4次调用该宏时对该行进行了不同的扩展,尽管这行"int 10h"不依赖于任何宏参数.
如果你看这个图像,你可以看到意外的"int 2",它应该是一个"int 10".之后,您可以看到:
cmp [bx+si], ax
add ch, bh
cmp [bx+03], dx
Run Code Online (Sandbox Code Playgroud)
根据宏的源代码,这3条指令实际上应该是
inc cx
cmp cx, COLORBTN3_X2
jna @@row_loop
Run Code Online (Sandbox Code Playgroud)
在中断之前还有一些其他指令有点断,但你明白了.
考虑将逻辑(段:偏移)地址转换为线性地址的数学运算:
CS:IP = 49ae:03cc = 49eac其中3cc是第一个意外字节的偏移量.
SS:SP = 39ed:fffc = 49ecc.
可视化两个线性地址,我们有
| |
| 49ecc | <-- Stack pointer, going down
| |
Only 32 bytes below
| |
| 49eac | <-- Execution flow, going up
| |
Run Code Online (Sandbox Code Playgroud)
您的堆栈必须在截屏之前的某个时刻与代码段发生冲突.
尝试设置堆栈,使其远离代码.
实模式下的最大堆栈大小为64KiB,因为这是段的大小.
在DOS中可以安全地假设程序之后的内存未被使用1,并且只要它存在,所以你可以将它用于堆栈.这不是浪费内存,因为DOS不是多任务处理.
请注意,除非您在其中明确定义内容,否则堆栈段不会占用二进制文件的空间.
管理堆栈有两种方法:
使用汇编程序
参见TASM手册以供参考,第92页.
如果您正在使用该STACK指令,只需在堆栈的估计大小上加上一个上限.
如果您正在编写EXE,则可以使用模型修改器FARSTACK.
SS:SP应根据链接器在MZ头上写入的值来设置.
这样就可以通过不将堆栈段放入dgroup来获得完整的64KiB堆栈.
手动
如果你知道你不需要一个完整的64KiB堆栈,你可以把它放在数据段的末尾(对于COM来说也是代码段)
;COM ;EXE
mov ax, cs mov ax, ds ;Assume SMALL memory model
mov ss, ax mov ss, ax ;see below
xor sp, sp xor sp, sp
Run Code Online (Sandbox Code Playgroud)
这给出了64KiB - <代码+数据大小>.
如果您需要一个完整的64KiB堆栈,您可以使用下一个可用的段
;COM ;EXE
mov ax, cs mov ax, ds ;Assume SMALL memory model, if not
add ax, 1000h add ax, 1000h ;use the symbol for the last data
mov ss, ax mov ss, ax ;segment
xor sp, sp xor sp, sp
Run Code Online (Sandbox Code Playgroud)
这假定最后一个段如果完全使用但是从一些段/偏移/符号算术中省去了.
1这是因为DOS不是多任务处理,程序是在TSR程序之上加载的.COMMAND.COM的
非常驻部分加载到常规内存的顶部,但可以覆盖它.