【问题标题】:DOSBox Debug AssemblyDOSBox 调试程序集
【发布时间】:2016-09-09 01:33:32
【问题描述】:

我正在使用调试实用程序运行 DOSBox 来构建汇编代码。我只是想弄清楚如何读取字符串。到目前为止我有这个。

-n test.com
-a
072A:0100 db 15
072A:0101 db 16
072A:0102 mov dx, 100
072A:0105 mov ah, 0A
072A:0107 int 21
072A:0109 int 20

-rcx 15
-w
-q

所以我可以从缓冲区中读取 15 个或更少字符的字符串。当我读入字符串时,它放在哪里?我想尝试将字符串打印出来。

【问题讨论】:

  • 您没有保留 15 个字节,您在位置 100 保留了一个包含 15 的字节,在位置 101 保留了另一个包含 16 的字节。我很确定您想要一个查看DUP 指令。
  • @DavidHoelzer :不要相信 DOS 调试支持 DUP 之类的东西。甚至不支持标签。
  • @DrBeco 我只想知道,当我使用 AH 设置为 0A 从缓冲区中拉出字符串时,会将其读取到何处。
  • 在您的情况下,字节存储在内存地址 DX +3=103h 处。 Int 21h/ah=0ah 有合理的记录。但正如大卫试图指出的那样,你必须为它留出空间。同样将数据放在代码之前可能会导致问题,因为数据将作为指令执行。
  • 您是否可以选择使用真正的汇编程序(例如 NASM,您出于某种原因对其进行了标记),而不是调试器脚本?我并不是说这是一个无效的问题,我只是要确保您意识到尝试使用这些工具进行 asm 开发使您自己变得困难。 (特别是如果你只是在学习。)

标签: assembly x86 dos dosbox


【解决方案1】:

您的示例代码有 2 个问题。

您不想将原始数据放在偏移量 100 处,因为 DOS 将从该地址开始执行。因此,您从偏移量 102 开始的代码将无法正确执行,因为它将汇编为“ADC AX,BA16”指令,该指令从您的“mov dx,100”指令中窃取 BA 字节,其余指令将被误解.

如果您没有遇到问题 #1,那么第二个问题是输入字符将覆盖您的代码,从偏移量 102 开始(因为 100 处缓冲区的前两个字节被保留)。如果您可以执行代码,那么这可能不是您想要的。 ;)

您不想在偏移量 100 处定义任何数据,因为这是 .COM 程序的入口点。处理此问题的一种简单方法是在代码之后定义数据。当使用调试之类的东西时,您必须直接指定内存位置而不使用标签,必须考虑组装操作数的大小。

一种方法是从地址 100 开始组装您的代码,并为您的字符串和缓冲区地址使用占位符;然后在定义数据后修复这些说明。

这是您修改后的示例:

注意:我忍不住在字符串输入函数之前添加了一个输出提示

-n test2.com
-a
0100: mov dx,100    ;100 is a placeholder for the address of output prompt
0103: mov ah,9
0105: int 21        ;output prompt
0107: mov dx,100    ;100 is a placeholder for the address of the input buffer
010A: mov ah,0a
010C: int 21        ;read user input
010E: int 20
0110: db 48         ;"H"
0111: db 65         ;"e"
0112: db 6c         ;"l"
0113: db 6c         ;"l"
0114: db 6f         ;"o"
0115: db 3a         ;":"
0116: db 20         ;<space>
0117: db 24         ;"$" / DOS strings terminated by dollar sign
0118: db 0f         ;buffer member: hold 15 chars
0119: db 00         ;buffer member: character input count stored here

;the remainder of the .COM memory segment can be used to store the data
; starting at address 11A

;now that we know where our data fits, lets plug the addresses in

-a 100
0100: mov dx,110    ;address of "H" in prompt string
-a 107
0100: mov dx,118    ;address of input buffer with first two bytes reserved (see above)
                    ;max length to read and characters read

-rcx
CX 0000
:1a
-w
Writing 001A bytes

;lets run the program

-g
Hello: <lets assume you type "cat" followed by RETURN>
Program terminated normally

;now look at the 2nd byte in the buffer for the number of characters typed
;   along with the character data entered

-d 118 11e
0110          0F 03 63 61 74 0D 0D      ..cat..

一旦您定义了最大输入字符成员,我认为您不必担心为缓冲区保留空间;由于缓冲区位于程序的末尾,因此您可以访问 64k 段的其余部分作为缓冲区空间。 (64k 减去 0x11b 字节的代码和环境空间)。

编辑 2016/09/11

这是一个修订版(带有解释),用于解决您关于输出用户键入的内容的问题:

0100  MOV     DX,0140
0103  MOV     AH,09
0105  INT     21            ;output prompt
0107  MOV     DX,014B
010A  MOV     AH,0A
010C  INT     21            ;read user input
010E  MOV     DX,0148
0111  MOV     AH,09
0113  INT     21            ;output CRLF
0115  MOV     DI,[014C]     ;load DI with value of characters read
0119  AND     DI,00FF       ;   MOV above read WORD, but we only want lower byte
011D  LEA     DI,[DI+014D]  ;point DI to end of input string
0121  MOV     AL,24         ;load DOS terminator char "$" in AL
0123  STOSB                 ;write it to end input string
0124  MOV     DX,014D
0127  MOV     AH,09
0129  INT     21            ;print the input string
012B  INT     20            ;exit program

;I inserted NOPS until address 0140 so I would have room to insert code without my
;   data offsets changing

0140 DB 48                  ;"Hello: $" prompt begin
0141 DB 65
0142 DB 6C
0143 DB 6C
0144 DB 6F
0145 DB 3A
0146 DB 20
0147 DB 24
0148 DB 0D                  ;CRLF$ sequence begin
0149 DB 0A
014A DB 24
014B DB 20                  ;Buffer begin (32 bytes max length)
014C DB 00

有多种方法可以达到相同的结果,例如使用用户输入计数加载 CX 寄存器,并使用 LOOP 指令使用适当的 DOS 函数打印每个字符。祝你好运!

【讨论】:

  • 哇,这更有意义!我可以看到内存中的字符,但我将如何将它们放入 DL 并一个接一个地打印出来。我尝试使用 mov DL, (memory location) 但这给了我一个错误。
  • 如果您没有将内存位置括在括号中,表明您要移动内存的内容而不是 WORD 地址本身,则会出现错误,因为 DL是字节大小的。此外,由于 debug.com 不支持“BYTE PTR”语法,您可能需要使用“movsb”而不是“mov”来暗示这一点。例如。 "movsb dl,[11a]"
  • 完美!我已经很多年没有做过这个组装的东西了。好的,假设我的字符串位于 115,所以第一个字符位于 [117]。 (mov DL, [117]) 如果我将增量​​增加到DL,它只会给我字母表中的下一个字符。如何递增到字符串中的下一个字符,即[118]
  • 如果你想遍历任意数量的字符,你需要将地址存储在寄存器中而不是硬编码它。如果您在 SI 中分配起始地址,则可以使用 LODSB 将其加载到 AL 中,如果方向标志清零(使用 CLD 优先),它将自动增加它。然后打印字符。我尝试的选项是“$”终止输入字符串,然后使用正常的打印字符串函数。但是,如果您在输入函数之后不输出 CRLF 序列(0Dh,0Ah),则不会正确显示任何内容,因为所有输出都将在同一行上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-16
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
相关资源
最近更新 更多