Assembly 在编写大型程序时,我们如何跟踪不同寄存器的值

Assembly 在编写大型程序时,我们如何跟踪不同寄存器的值,assembly,x86-16,Assembly,X86 16,在这里,我展示了一个msdos代码的快照,在这种类型的代码块中,我们经常会遇到非常失望的情况,我们可以清楚地看到在第26行,我们正在将DS:SI的值存储到ES:DI,但我们可以清楚地看到寄存器SI或它的内容在第26行附近。 我在理解汇编语言编码时经常遇到这种情况 01 PUSH CS 02 POP DS 03 PUSH CS 04 POP ES 05 ASSUME DS:DOSGROUP,ES:DOSGROUP 06

在这里,我展示了一个msdos代码的快照,在这种类型的代码块中,我们经常会遇到非常失望的情况,我们可以清楚地看到在第26行,我们正在将DS:SI的值存储到ES:DI,但我们可以清楚地看到寄存器SI或它的内容在第26行附近。 我在理解汇编语言编码时经常遇到这种情况

    01 PUSH    CS
    02 POP     DS
    03 PUSH    CS
    04 POP     ES
    05 ASSUME  DS:DOSGROUP,ES:DOSGROUP
    06 MOV     AX,OFFSET DOSGROUP:INITBLOCK
    07 ADD     AX,0Fh                  ; round to a paragraph
    08 MOV     CL,4
    09 SHR     AX,CL
    10 MOV     DI,DS
    11 ADD     DI,AX
    12 INC     DI
    13 MOV     [CurrentPDB],DI
    14 PUSH    BP
    15 PUSH    DX              ; Save COMMAND address
    16 MOV     AX,[ENDMEM]
    17 MOV     DX,DI

    18 invoke    SETMEM          ; Basic Header
    19 ASSUME  DS:NOTHING,ES:NOTHING
    20 PUSH    CS
    21 POP     DS
    23 ASSUME  DS:DOSGROUP
    24 MOV     DI,PDB_JFN_Table
    25 XOR     AX,AX
    26 STOSW              ;<--------------------here
    27 STOSB
01推送CS
02流行音乐
03推送CS
04流行音乐
05假设DS:DOSGROUP,ES:DOSGROUP
06 MOV AX,偏移量组:初始块
07增加AX,0Fh;整段
08 MOV CL,4
09 SHR AX,CL
10 MOV DI,DS
11加上DI,AX
12有限公司
13 MOV[CurrentPDB],DI
14推BP
15推送DX;保存命令地址
16移动轴[ENDMEM]
17 MOV DX,DI
18调用SETMEM;基本报头
19假设DS:无,ES:无
20推送CS
21首流行歌曲
23假设DS:DOSGROUP
24 MOV DI,PDB_JFN_表
25异或AX,AX

26东南欧 要回答标题问题:是,请使用注释来描述代码块的哪个逻辑“变量”将位于哪个寄存器中。并记录每个功能的输入/输出/关闭。比如
;;;输入:ds:si指针,指向某个假设函数(不是此函数)中以0结尾的字符串
。在临时函数中,再次在计算某物的位置进行注释

如果您正在阅读其他人的文档记录不良的代码,您可以在查看是否有任何内容更改某个寄存器后,在块的顶部添加此类注释。(当函数调用不知道哪些寄存器被破坏时,这是非常重要的。使用标准调用约定会让这变得容易很多,因为您知道应该假定哪些寄存器被破坏。)


正如Jester指出的,这是
stos
,而不是
movs
,因此它不读取
DS:SI
。它只将AX和AL存储到
ES:DI
()。然而,这段代码看起来是不完整的:它在这之前设置了
DS
,但没有设置
ES
,就好像它希望STOS使用
DS:DI
(它没有这样做)

也许它在实践中起作用是因为
SETMEM
实际上并没有对
ES
进行压缩,或者将其设置为该代码想要的值。但是从调用
SETMEM
后的
假设ES:NOTHING
来看,此代码似乎期望
SETMEM
销毁
ES

我假设这段代码来自您一直在看的DOS1.0,所以推测
ES
实际上仍然等于
CS
,这是由于运气或其他原因

在这种情况下,在调试器中单步执行可能有助于理解它。我认为BOCHS的内置调试器允许您在任何地方设置断点,即使在操作系统的代码中,它们也可以在禁用中断的情况下工作


无论如何,当事情变得复杂时,使用注释是有限制的。


这就是为什么在现实生活中,我们将远程/大规模优化/持续传播留给编译器(它们在这方面非常出色),并且主要只担心热循环的asm微优化(编译器并不总是很好)。

STOSW
不是
MOVSW
。它不使用
DS:SI
。读取指令集参考。它只将
AX
写入
ES:DI
,两者都设置在附近。这就是说,一般来说,您必须随时跟踪寄存器中的内容。x87协处理器也存在类似的问题,寄存器名称和类似堆栈的行为使其更加困难。跟踪的方法是制作一张图表,或者在每次安排发生变化时对其进行注释。在有练习的x86中,你会习惯它,就像变戏法的人知道哪些球在空中一样。@Jester:不过有些奇怪:这段代码将
DS
DI
设置在
stos
之前,但是它确实假设了ES:在最后一次函数调用之后没有任何东西,我认为如果它被SETMEM
撞坏了,这是有意义的。因此,除非
ES
实际上仍然等于此块顶部的push/pop中的
CS
,否则我们不知道
ES
设置为什么。这可能是个bug。