奇怪的宏(TASM)

2023-12-28

考虑以下宏:

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

Somewhere in my code, I use the rendToolBar macro. It is supposed to draw a big white canvas, and then a small square and next to it some smaller squares in a certain pattern, which is irrelevant for my question. Notice that rendToolBar calls drawRect 5 times. I followed this code in turbo debugger (because something went awfully wrong) and noticed that in the 4th execution of the drawRect macro, the "int 10h" from pixelFast is not actually "int 10h", but rather "int 2". This causes an NMI, which messes stuff up for my program. I want to know what makes TASM expand the macro differently for that line in the 4th call for that macro, despite the fact that this line "int 10h" does not rely on any macro arguments. enter image description here If you look at this image, you can see the unexpected "int 2" there, which was supposed to be an "int 10". After it, you can see:

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 where 3cc是第一个意外字节的偏移量。

SS:SP = 39ed:fffc = 49ecc.

可视化这两个线性地址,我们有

   |       |
   | 49ecc | <-- Stack pointer, going down
   |       |

 Only 32 bytes below

   |       |
   | 49eac | <-- Execution flow, going up
   |       |

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


The maximum stack size in real mode is 64KiB, as this is the size of a segment.
In DOS is safe to assume that the memory after your program is not used1 and, as long as it exists, so you can use it for the stack. This is not wasting memory as DOS is not multitasking.
Note that the stack segment won't take space on the binary file unless you explicitly define things in it.

有两种方法来管理堆栈:

  1. 使用汇编器
    请参阅TASM手册 http://bitsavers.informatik.uni-stuttgart.de/pdf/borland/turbo_assembler/Turbo_Assembler_Version_5_Users_Guide.pdf供参考,第 92 页。

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

    如果您正在编写 EXE,则可以使用 model 修饰符FARSTACK.
    SS:SP应根据链接器在 MZ 标头上写入的值进行设置。
    这样您就可以通过不将堆栈段放入dgroup.

     

  2. Manually
    如果您知道不需要完整的 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 This is because DOS is not multitasking and programs are .
A non resident part of COMMAND.COM is loaded a the top of the conventional memory but it can be overwritten.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

奇怪的宏(TASM) 的相关文章

  • g++ 内联汇编括号中不匹配

    g 向我抱怨以下代码中缺少括号 1 2 3 v v v asm volatile inb 1 0 a result Nd portnumber 1 2 3 正如您所看到的 括号是匹配
  • 宏扩展忽略了 MSVC 中的一些标记

    我在 msvc 编译器中遇到宏扩展问题 我希望将以下代码扩展为F x 它在 gcc 和 clang 上执行 但 msvc 将其扩展为F忽略x令牌 这里发生了什么 define S s s define F define M S S F x
  • 汇编语言中的全局_start是什么?

    这是我的汇编级代码 section text global start start mov eax 4 mov ebx 1 mov ecx mesg mov edx size int 0x80 exit mov eax 1 int 0x80
  • MASM 字符串反转

    好吧 我正在讨论这个问题 可能是一个非常复杂的解决方案 但这是我脑海中浮现的第一件事 我需要编写一个汇编语言程序来反转 源 字符串 而不使用 目标 字符串 临时变量 这是我的尝试 INCLUDE Irvine32 inc data sour
  • C/C++ 中的简单“Hello World”内联汇编语言程序

    我使用 devcpp 和 borland c 编译器 asm mov ax 4 I O Func mov bx 1 Output func mov cx name address of the string mov dx 6 length
  • 使用 gdb 调试反汇编库

    在Linux和Mac OS X中可以使用strapi和next来调试应用程序而无需调试信息 在 Mac OS X 上 gdb 显示在库内部调用的函数 尽管有时会在每个 stepi 指令中推进多个汇编程序指令 在 Linux 上 当我进入动态
  • 为什么这个 C++ 包装类没有被内联掉?

    EDIT 我的构建系统出了问题 我还在弄清楚到底是什么 但是gcc产生了奇怪的结果 尽管它是 cpp文件 但是一旦我使用了g 然后它按预期工作 对于我一直遇到麻烦的事情来说 这是一个非常精简的测试用例 其中使用数字包装类 我认为会内联 使我
  • 宏、Clojure 与 Common Lisp

    我和我的一些朋友正在开发一个新平台 我们想用 lisp 构建它 主要吸引力是宏 我们都使用 Common Lisp 但我想探索 Clojure 的选择 当我提出这一点时 其中一位说宏观体系 较弱 我想知道这是否属实 以及在哪些领域 就您可以
  • C++ 中的 CPUID 实现

    我想知道这里是否有人有一些可以从任何托管 net 语言引用的 C CPUID 实现的好示例 另外 如果情况并非如此 我是否应该注意 X86 和 X64 之间的某些实现差异 我想使用 CPUID 来获取运行我的软件的机器上的信息 崩溃报告等
  • AVX512 掩码寄存器(k1...k7)的 GNU C 内联 asm 输入约束?

    AVX512 为其算术命令引入了 opmask 功能 一个简单的例子 上帝螺栓 org https godbolt org z P7xWD8 include
  • 如何让c代码执行hex机器代码?

    我想要一个简单的 C 方法能够在 Linux 64 位机器上运行十六进制字节码 这是我的 C 程序 char code x48 x31 xc0 include
  • 如何在汇编语言中换行打印多个字符串

    我试图在汇编中的不同行上打印多个字符串 但使用我的代码 它只打印最后一个字符串 我对汇编语言非常陌生 所以请耐心等待 section text global start start mov edx len mov edx len1 mov
  • NASM 轮班操作员

    您将如何在寄存器上进行 NASM 中的位移位 我读了手册 它似乎只提到了这些操作员 gt gt lt lt 当我尝试使用它们时 NASM 抱怨移位运算符处理标量值 您能解释什么是标量值并举例说明如何使用 gt gt and lt lt 另外
  • 用宏包装函数(无需重命名)C

    我有兴趣通过包装现有函数调用来添加一些额外的逻辑without重命名它们 仅供测试 我发现的现有解决方案依赖于将函数包装在不同名称的宏中 这可能意味着更改大量代码 有什么建议么 请注意 我知道LD PRELOAD 但我有兴趣使用宏来检查传递
  • ^ 和 _ 宏之后出现的数字(是:LaTeX 限制?)

    我在 LaTeX 中遇到了一个恼人的问题 我有一个大约 1000 行的 tex 文件 我已经有了一些数字 但是当我尝试添加另一个数字时 它会吐出 Undefined control sequence
  • 从 NASM 调用 C 函数 _printf 会导致分段错误

    我一直在尝试使用 NASM 在 Mac OS 和 Windows 上学习 64 位汇编 我的代码是 extern printf section data msg db Hello World 10 0 section text global
  • 大会,你好世界问题

    我正在 Linux 上学习 asm noobuntu 10 04 我得到了以下代码 http asm sourceforge net intro hello html http asm sourceforge net intro hello
  • AVX-512CD(冲突检测)与原子变量访问有何不同?

    所以我在看他们展示了如何 void Histogram const float age int const hist const int n const float group width const int m const float o
  • 使用 ## 和 __LINE__ 创建 C 宏(与定位宏的标记串联)

    我想创建一个 C 宏来创建一个基于名称的函数 在行号上 我想我可以做类似的事情 真正的函数在大括号内有语句 define UNIQUE static void Unique LINE void 我希望能扩展到类似的内容 static voi
  • F# 类型提供程序与 Lisp 宏

    我一直在阅读有关 F 3 0 类型提供程序的内容 例如here http msdn microsoft com en us library hh156509 aspx 并且它们似乎基于一种编译时代码生成 在这方面我想知道它们与 Lisp 宏

随机推荐