assembly - 组装:嵌套循环的问题
问题描述
我正在使用程序集中的嵌套循环。所需的输出应该是“ABCD”(新行)“EFGH”(新行)“HIJK”(新行)“LMNO”,但目前我没有得到任何输出。整个循环将执行,但控制台中不会出现任何内容。
INCLUDE Irvine32.inc
.data
ALPHA byte "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"
count byte 4 ; inner loop counter
.code
main proc
mov esi, OFFSET ALPHA
mov ecx, 4 ;outer loop counter
mov ebx, 0 ; inner counter
call part1
main endp
;-----------------------------------------------------------------------------
;part1 proc
;print 4x4 letter matric
;Receives EBX: arr address ECX: outer loop counter
;Returns EAX: full array
;-----------------------------------------------------------------------------
part1 PROC USES ebx ecx edx esi
L1:
cmp ecx, 4 ; test outer loop count
je next ; yes?
call Crlf ; print new line
inc ecx
L2: ;inner loop
cmp ebx, ecx ;
mov eax, [esi] ; mov next letter
call WriteChar ; write it
inc esi ; point to the next element
inc ebx
loop L2 ; loop
next:
call Crlf
ret
part1 ENDP
end main
解决方案
你的代码没有你描述的那样..让我和你一起跳过一条指令,执行是如何发生的(这不是源代码,而是指令的顺序写下,因为它们将由 CPU 执行,有一些重要的最小注释部分):
mov esi, OFFSET ALPHA
mov ecx, 4
mov ebx, 0
call part1
cmp ecx, 4
je next ; jump is taken, because ecx == 4
call Crlf
... internal implementation of Crlf by Irvine32 ending with RET
ret ; part1 "ret" returning into main
; there is no more code in main, so the CPU continues
; with next memory interpreting it as machine code
; with a bit of luck (no padding between ENDP/PROC, or NOPs)
; the "part1" code follows after main, so it will get executed
cmp ecx, 4
je next ; jump is taken, because ecx == 4
call Crlf
... internal implementation of Crlf by Irvine32 ending with RET
ret ; part1 "ret" returning out of your code completely
; in some environments that may work as clean exit from app
; in others that ret will go to whatever address is at stack and crash
您应该能够在调试器中验证这一点。我想知道是什么让您认为“整个循环将执行”和“控制台中不会出现任何内容”,因为显然只有一小部分循环正在执行,并且控制台中应该出现两条新行。
如何修复您的代码...首先在 main 的末尾添加某种退出,如果您正在构建 win32 可执行文件,那么我认为退出 Irvin32 程序的标准方法是使用ExitProcess
(检查 Irvine32 包的工作示例)。我认为类似的东西invoke ExitProcess, 0
可能会起作用,invoke
是某种预定义的宏,它将扩展为mov + call
指令,但我没有 windows 和/或 Irvine32 来检查自己。
然后下定决心,你想如何实际跟踪循环。例如将外部计数器放入ecx
,将内部计数器放入ebx
,并且因为您知道大小如果固定为 4x4,请按样式进行倒计时do { ..; --counter; } while (counter);
,这自然适合编码的组装方式(但它不会在第一次迭代时检查计数器的有效性,所以这仅适用于计数器始终为有效值的情况)。
例如:
part1 PROC USES eax ebx ecx esi
mov ecx, 4
outerLoop:
mov ebx, 4 ; reset inner counter (for every outer loop)
innerLoop:
mov al, [esi] ; load next letter
call WriteChar
inc esi ; point to next element
dec ebx ; --innerCounter
jnz innerLoop
call Crlf ; print new line after 4 chars
dec ecx ; --outerCounter
jnz outerLoop
ret
part1 ENDP
现在这应该在控制台中产生如下内容:
A,B,
C,D,
E,F,
G,H,
那是因为您确实将其定义ALPHA
为一个长字符串,包括逗号等……您可能确实想要类似的东西
ALPHA byte 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'
或同等的
ALPHA byte "ABCDEFGHIJKLMNOP"
它们都产生 16 个字节,值为 65、66、67、...('A' == 65
)。
同样在您的原始代码中:
mov eax, [esi] ; mov next letter
将加载四个字节。WriteChar
确实忽略了高 24 位并且将eax
仅使用低 8 位(“ al
”),并且您仅递增esi
1,因此最终这是无害的错误,但您应该了解它是如何工作的。mov al,[esi]
在处理字符时,只会从内存中获取 8 位,在这种情况下就足够了。
推荐阅读
- laravel - Laravel 按需广播
- python - 用于内部转换的 pytransitions json 配置
- c++ - 为什么使用全局变量会使多线程执行速度减慢 2 倍,而在其他环境中却使其速度加快 2 倍?
- flutter - 我的列表在索引后不会更新事件
- c# - 优化 GameObject 唯一 ID 分配器 Unity
- powershell - 使用 PowerShell 监控共享文件夹的权限更改
- ruby-on-rails - 扩展设计以使用电话号码和 OTP 以及普通电子邮件和密码登录
- android - 如何在bottomSheet中检查recyclerview项目并通过bottomSheet中的按钮传递多个检查数据
- c++ - 为什么这个二进制文件容易受到缓冲区溢出的影响?
- android - 当视图滚出屏幕时使工具栏滚出