在组装中打印星形三角形
Printing star triangle in assembly
我正在尝试打印这样的三角形:in assembly。
计算每行中星星数量的公式为:2 * x + 1。
到目前为止,这是我的代码。我好像在无限循环
.data
prompt BYTE "Please enter the number of rows in the pyramid: ", 0
numRows DWORD ?
count DWORD 0
.code
main PROC
mov edx, OFFSET prompt
call WriteString
call ReadInt
mov numRows,eax
mov ecx,numRows + 1 ; Let ecx = numRows + 1
L1:
inc count ; Increment count
mov eax,ecx
L2:
sub eax,count ; eax = eax - count
mov al, ' ' ; Print spaces
call WriteChar
loop L2
L3:
mov ebx,count ; ebx = count
add ebx,count ; ebx = ebx + count
sub ebx,1 ; 2x - 1
mov al, '*' ; Printing the star pattern
call WriteChar
loop L3
call CrLf
loop L1
exit
main ENDP
END main
我哪里错了?
虽然这不是完整的答案,但评论太长了,它应该对您有很大帮助,因为:
http://kipirvine.com/asm/debug/index.htm
这基本上是您应该首先研究的内容(太宽泛+太长,无法成为此答案的一部分)。
在您了解如何使用调试器之后,您可以查看您的代码在做什么,例如您将遇到的第一个问题:
mov ecx,numRows + 1
并没有按照你的想法去做,你不能在汇编中使用数学表达式,你必须将它们写成单个指令。
只有一些指令允许某种非常严格和有限的数学表达式,例如 mov
具有寻址内存模式,这实际上是您在编译时得到的:mov ecx,[numRows + 1]
=从 +1 地址获取值。 numRows
是 DWORD,所以如果用户确实输入了 10,则内存看起来像这样(从 numRows
地址开始:0A 00 00 00 00 00 00 00
- 前 4 个字节由 mov numRows,eax
设置( Irvine 在没有 []
内存引用的情况下写入,这是 IMO 非常糟糕 style/taste) 第 5 个字节位于 count
地址,由 count DWORD 0
行定义,因此 4 个归零字节. 现在 mov ecx,[numRows + 1]
将从内存中获取 4 个零,从 0A
字节之后开始,"leaking" 一个字节进入 count
.
在编译时意义上也允许使用数学表达式,即 add eax,12+13*14
可以,在汇编期间产生单个常量。但是您应该通读 this 之类的文档以了解哪种参数组合是合法的,mov ecx,label + 1
可以是立即常量负载(在 NASM 中)= "address + 1",或者MASM 中的内存加载(来自地址+1 的值),既不执行 "value + 1".
做你想做的你需要:
mov ecx,[numRows] ; load the VALUE numRows back into ecx
inc ecx ; ecx = numRows+1
但是由于 eax 已经包含 numRows
值,您可以避免获取内存,所以在这种特殊情况下这就足够了:
mov ecx,eax ; copy the numRows value from eax into ecx
inc ecx ; ecx = numRows+1
但是由于这个数学表达式足够简单以适合一种可能的寻址模式,您可以利用 LEA
instruction 认为它正在计算内存地址,而它只会计算您的表达式:
lea ecx,[eax+1] ; ecx = value_numRows + 1
这有效,即使 eax+1 是内存中的非法地址,但 LEA
不会尝试读取地址,它只会计算它并将其存储到目标寄存器中。
...等等等等...这里的重点是:
1) 学习调试您的代码(这对于取得更进一步的进展是绝对必要的)
2) 放弃 Irvine 风格并在每个内存取消引用周围严格使用 []
,即在 "variables" 周围,如果你写 mov ecx,[numRows]+1
(如果你知道哪些 mov
操作数是合法的,你应该觉得这看起来不太好)。
3) 尝试将您在 "variables" 方面的想法转向较低级别 "memory -> address -> content (bytes)","variables" 方式有时会限制您看到如何在 byte/bits水平以更简单的方式达到您需要的结果。
我正在尝试打印这样的三角形:in assembly。 计算每行中星星数量的公式为:2 * x + 1。 到目前为止,这是我的代码。我好像在无限循环
.data
prompt BYTE "Please enter the number of rows in the pyramid: ", 0
numRows DWORD ?
count DWORD 0
.code
main PROC
mov edx, OFFSET prompt
call WriteString
call ReadInt
mov numRows,eax
mov ecx,numRows + 1 ; Let ecx = numRows + 1
L1:
inc count ; Increment count
mov eax,ecx
L2:
sub eax,count ; eax = eax - count
mov al, ' ' ; Print spaces
call WriteChar
loop L2
L3:
mov ebx,count ; ebx = count
add ebx,count ; ebx = ebx + count
sub ebx,1 ; 2x - 1
mov al, '*' ; Printing the star pattern
call WriteChar
loop L3
call CrLf
loop L1
exit
main ENDP
END main
我哪里错了?
虽然这不是完整的答案,但评论太长了,它应该对您有很大帮助,因为:
http://kipirvine.com/asm/debug/index.htm
这基本上是您应该首先研究的内容(太宽泛+太长,无法成为此答案的一部分)。
在您了解如何使用调试器之后,您可以查看您的代码在做什么,例如您将遇到的第一个问题:
mov ecx,numRows + 1
并没有按照你的想法去做,你不能在汇编中使用数学表达式,你必须将它们写成单个指令。
只有一些指令允许某种非常严格和有限的数学表达式,例如 mov
具有寻址内存模式,这实际上是您在编译时得到的:mov ecx,[numRows + 1]
=从 +1 地址获取值。 numRows
是 DWORD,所以如果用户确实输入了 10,则内存看起来像这样(从 numRows
地址开始:0A 00 00 00 00 00 00 00
- 前 4 个字节由 mov numRows,eax
设置( Irvine 在没有 []
内存引用的情况下写入,这是 IMO 非常糟糕 style/taste) 第 5 个字节位于 count
地址,由 count DWORD 0
行定义,因此 4 个归零字节. 现在 mov ecx,[numRows + 1]
将从内存中获取 4 个零,从 0A
字节之后开始,"leaking" 一个字节进入 count
.
在编译时意义上也允许使用数学表达式,即 add eax,12+13*14
可以,在汇编期间产生单个常量。但是您应该通读 this 之类的文档以了解哪种参数组合是合法的,mov ecx,label + 1
可以是立即常量负载(在 NASM 中)= "address + 1",或者MASM 中的内存加载(来自地址+1 的值),既不执行 "value + 1".
做你想做的你需要:
mov ecx,[numRows] ; load the VALUE numRows back into ecx
inc ecx ; ecx = numRows+1
但是由于 eax 已经包含 numRows
值,您可以避免获取内存,所以在这种特殊情况下这就足够了:
mov ecx,eax ; copy the numRows value from eax into ecx
inc ecx ; ecx = numRows+1
但是由于这个数学表达式足够简单以适合一种可能的寻址模式,您可以利用 LEA
instruction 认为它正在计算内存地址,而它只会计算您的表达式:
lea ecx,[eax+1] ; ecx = value_numRows + 1
这有效,即使 eax+1 是内存中的非法地址,但 LEA
不会尝试读取地址,它只会计算它并将其存储到目标寄存器中。
...等等等等...这里的重点是:
1) 学习调试您的代码(这对于取得更进一步的进展是绝对必要的)
2) 放弃 Irvine 风格并在每个内存取消引用周围严格使用 []
,即在 "variables" 周围,如果你写 mov ecx,[numRows]+1
(如果你知道哪些 mov
操作数是合法的,你应该觉得这看起来不太好)。
3) 尝试将您在 "variables" 方面的想法转向较低级别 "memory -> address -> content (bytes)","variables" 方式有时会限制您看到如何在 byte/bits水平以更简单的方式达到您需要的结果。