gpt4 book ai didi

assembly - 奇怪的宏 (TASM)

转载 作者:行者123 更新时间:2023-12-04 14:56:17 24 4
gpt4 key购买 nike

考虑以下宏:

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

在我的代码中的某个地方,我使用了 rendToolBar 宏。它应该画一个大的白色 Canvas ,然后是一个小方块,然后在它旁边画一些特定图案的小方块,这与我的问题无关。
请注意,rendToolBar 调用了 drawRect 5 次。我在 turbo 调试器中遵循了这段代码(因为出现了严重错误)并注意到在第 4 次执行 drawRect 宏时,pixelFast 中的“int 10h”实际上不是“int 10h”,而是“int 2”。这会导致一个 NMI,它把我的程序搞砸了。我想知道是什么让 TASM 在第四次调用该宏时为该行以不同的方式扩展宏,尽管这一行“int 10h”不依赖于任何宏参数。
enter image description here
如果您查看此图像,您会在那里看到意外的“int 2”,它应该是“int 10”。之后,您可以看到:
cmp [bx+si], ax
add ch, bh
cmp [bx+03], dx

根据宏的源代码,这3条指令实际上应该是
inc cx
cmp cx, COLORBTN3_X2
jna @@row_loop

还有一些其他指令在中断之前有点偏离,但你明白了。

最佳答案

考虑将逻辑(段:偏移量)地址转换为线性地址的数学运算:
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
| |

您的堆栈必须在屏幕截图之前的某个时刻与代码段发生冲突。
尝试设置堆栈,使其离代码足够远。

实模式下的最大堆栈大小为 64KiB,因为这是段的大小。
在 DOS 中可以安全地假设您的程序之后的内存未被使用 1 并且,只要它存在,您就可以将其用于堆栈。
这不会浪费内存,因为 DOS 不是多任务处理。
请注意,堆栈段不会占用二进制文件的空间,除非您在其中明确定义内容。

有两种管理堆栈的方法:
  • 使用汇编器
    TASM manual供引用,第 92 页。

    如果您使用的是 STACK指令只是在堆栈的估计大小上设置一个上限。

    如果您正在编写 EXE,您可以使用模型修改器 FARSTACK .SS:SP应根据链接器在 MZ header 上写入的值进行设置。
    这让您无需将堆栈段放入 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

    这给出了 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

    这假设最后一段如果完全使用,但可以使您免于某些段/偏移/符号算法。


  • 1 这是因为 DOS 不是多任务处理,程序是 loaded above TSR programs .
    COMMAND.COM 的非驻留部分加载到常规内存的顶部,但它可以被覆盖。

    关于assembly - 奇怪的宏 (TASM),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38575023/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com