nasm 中的嵌套循环
Nested loops in nasm
我在 Windows 10 64 位机器上 nasm 中编写了以下程序
extern _GetStdHandle@4
extern _WriteFile@20
extern _ReadFile@20
extern _ExitProcess@4
;ReadBufferSize
%define rbs 100
section .rodata
w: dd 3
h: dd 3
text: db "abc", 10
section .data
x: dd 4
y: dd 4
section .bss
stdout: resb 4
stdin: resb 4
readbuff: resb (rbs+2); allow for CR, LF
bytecnt: resb 4
section .text
_print:
push ebp
mov ebp, esp
push 0
lea eax, [ebp-4]
push eax
mov eax, [ebp+8]
push dword [eax]
push dword [ebp+12]
push dword [stdout]
call _WriteFile@20
mov esp, ebp
pop ebp
ret 8
_read:
push ebp
mov ebp, esp
push 0
push dword [ebp+8]
push rbs
push dword [ebp+12]
push dword [stdin]
call _ReadFile@20
sub dword [bytecnt], 2; remove CR and LF
mov esp, ebp
pop ebp
ret 8
_draw:
push ebp
mov ebp, esp
push dword [w]
L1:
push dword [h]
L2:
push text
push x
call _print
dec dword [ebp-8]
cmp dword [ebp-8], 0
jg L2
dec dword [ebp-4]
cmp dword [ebp-4], 0
jg L1
mov esp, ebp
pop ebp
ret
global _main
_main:
push -11
call _GetStdHandle@4 ;Get Stdout handle
mov [stdout], eax
push -10
call _GetStdHandle@4 ;Get Stdin handle
mov [stdin], eax
call _draw
push 0
call _ExitProcess@4
hlt
我会清理它,但这可能会影响某些东西,所以我不会(抱歉)。 _draw
函数应该在屏幕上输出“abc\n”9(3*3)(3和3,因为w
和h
是3)次,但它只输出 5 次。据我检查,_print
按预期工作。如果有帮助,这是我的构建脚本:
@echo off
IF "%~2" EQU "" set f0rm4t=win32
IF "%~2" NEQ "" set f0rm4t=%~2
if exist %1.exe rm %1.exe
if exist %1.obj rm %1.obj
nasm -f %f0rm4t% %1.asm
if exist %1.exe goto run
if not exist %1.obj goto end
gcc %1.obj -o %1.exe
if %errorlevel% EQU 0 goto run
:run
%1.exe
echo ------------------------
if %errorlevel% EQU -1073741819 (
echo exited with C0000005
goto end
)
if %errorlevel% EQU 0 (
echo exited successfully
goto end
)
echo exited with return value %errorlevel%
:end
我使用 build filename
命令构建,它运行正常。
我已经检查了我的逻辑,它似乎很好,所以这是嵌套循环的问题,我不知道到底是什么。
完成 build
命令输出:
C:\Users\User\files>build filename
abc
abc
abc
abc
abc
------------------------
exited successfully
C:\Users\User\files>
如果循环正常,那么输出5次是不可能的,因为它应该是(外圈的重复)*(内圈的重复),但是5是质数.我想不通,所以我把它留给这个社区。祝你有美好的一天,提前致谢!
第一次通过外循环,[ebp-8]
倒数到零。接下来两次通过外循环,[ebp-8]
已经为零(或更少),所以内循环只执行一次。总共五次调用打印。
请注意 push [h]
的后续执行不会更改 [ebp-8]
。
在第二次迭代中,它写入 [ebp-12]
,在第三次迭代中它写入 [ebp-16]
,因为堆栈指针随着每次推送继续向下增长。
要解决此问题,我建议:
- 在
mov ebp, esp
之后添加 sub esp, 8
。
- 将
push [w]
更改为 mov eax, [w]; mov [ebp-4], eax
。
- 将
push [h]
更改为 mov eax, [h]; mov [ebp-8], eax
。
在查看@prl 的回答开头后,我意识到,正如他们所说,[ebp-8]
在内循环的第一次迭代和下一次 push [h]
中递减为 0推送到 [ebp-12]
,因此 [ebp-8]
保持为 0。所以我要做的第一件事就是在跳转后添加一个 pop edx
(使用 edx 作为垃圾寄存器),如下所示:
_draw:
push ebp
mov ebp, esp
push dword [w]
L1:
push dword [h]
L2:
push text
push x
call _print
dec dword [ebp-8]
cmp dword [ebp-8], 0
jg L2
pop edx
dec dword [ebp-4]
cmp dword [ebp-4], 0
jg L1
pop edx
mov esp, ebp
pop ebp
ret
这将清除堆栈中已经置零的变量并为新变量腾出空间,并且它有效。
但我认为@prl 的回答通常更适用于在堆栈上分配变量的技术,所以如果可以的话,请使用它,因为它也不会那么令人困惑。
我在 Windows 10 64 位机器上 nasm 中编写了以下程序
extern _GetStdHandle@4
extern _WriteFile@20
extern _ReadFile@20
extern _ExitProcess@4
;ReadBufferSize
%define rbs 100
section .rodata
w: dd 3
h: dd 3
text: db "abc", 10
section .data
x: dd 4
y: dd 4
section .bss
stdout: resb 4
stdin: resb 4
readbuff: resb (rbs+2); allow for CR, LF
bytecnt: resb 4
section .text
_print:
push ebp
mov ebp, esp
push 0
lea eax, [ebp-4]
push eax
mov eax, [ebp+8]
push dword [eax]
push dword [ebp+12]
push dword [stdout]
call _WriteFile@20
mov esp, ebp
pop ebp
ret 8
_read:
push ebp
mov ebp, esp
push 0
push dword [ebp+8]
push rbs
push dword [ebp+12]
push dword [stdin]
call _ReadFile@20
sub dword [bytecnt], 2; remove CR and LF
mov esp, ebp
pop ebp
ret 8
_draw:
push ebp
mov ebp, esp
push dword [w]
L1:
push dword [h]
L2:
push text
push x
call _print
dec dword [ebp-8]
cmp dword [ebp-8], 0
jg L2
dec dword [ebp-4]
cmp dword [ebp-4], 0
jg L1
mov esp, ebp
pop ebp
ret
global _main
_main:
push -11
call _GetStdHandle@4 ;Get Stdout handle
mov [stdout], eax
push -10
call _GetStdHandle@4 ;Get Stdin handle
mov [stdin], eax
call _draw
push 0
call _ExitProcess@4
hlt
我会清理它,但这可能会影响某些东西,所以我不会(抱歉)。 _draw
函数应该在屏幕上输出“abc\n”9(3*3)(3和3,因为w
和h
是3)次,但它只输出 5 次。据我检查,_print
按预期工作。如果有帮助,这是我的构建脚本:
@echo off
IF "%~2" EQU "" set f0rm4t=win32
IF "%~2" NEQ "" set f0rm4t=%~2
if exist %1.exe rm %1.exe
if exist %1.obj rm %1.obj
nasm -f %f0rm4t% %1.asm
if exist %1.exe goto run
if not exist %1.obj goto end
gcc %1.obj -o %1.exe
if %errorlevel% EQU 0 goto run
:run
%1.exe
echo ------------------------
if %errorlevel% EQU -1073741819 (
echo exited with C0000005
goto end
)
if %errorlevel% EQU 0 (
echo exited successfully
goto end
)
echo exited with return value %errorlevel%
:end
我使用 build filename
命令构建,它运行正常。
我已经检查了我的逻辑,它似乎很好,所以这是嵌套循环的问题,我不知道到底是什么。
完成 build
命令输出:
C:\Users\User\files>build filename
abc
abc
abc
abc
abc
------------------------
exited successfully
C:\Users\User\files>
如果循环正常,那么输出5次是不可能的,因为它应该是(外圈的重复)*(内圈的重复),但是5是质数.我想不通,所以我把它留给这个社区。祝你有美好的一天,提前致谢!
第一次通过外循环,[ebp-8]
倒数到零。接下来两次通过外循环,[ebp-8]
已经为零(或更少),所以内循环只执行一次。总共五次调用打印。
请注意 push [h]
的后续执行不会更改 [ebp-8]
。
在第二次迭代中,它写入 [ebp-12]
,在第三次迭代中它写入 [ebp-16]
,因为堆栈指针随着每次推送继续向下增长。
要解决此问题,我建议:
- 在
mov ebp, esp
之后添加sub esp, 8
。 - 将
push [w]
更改为mov eax, [w]; mov [ebp-4], eax
。 - 将
push [h]
更改为mov eax, [h]; mov [ebp-8], eax
。
在查看@prl 的回答开头后,我意识到,正如他们所说,[ebp-8]
在内循环的第一次迭代和下一次 push [h]
中递减为 0推送到 [ebp-12]
,因此 [ebp-8]
保持为 0。所以我要做的第一件事就是在跳转后添加一个 pop edx
(使用 edx 作为垃圾寄存器),如下所示:
_draw:
push ebp
mov ebp, esp
push dword [w]
L1:
push dword [h]
L2:
push text
push x
call _print
dec dword [ebp-8]
cmp dword [ebp-8], 0
jg L2
pop edx
dec dword [ebp-4]
cmp dword [ebp-4], 0
jg L1
pop edx
mov esp, ebp
pop ebp
ret
这将清除堆栈中已经置零的变量并为新变量腾出空间,并且它有效。
但我认为@prl 的回答通常更适用于在堆栈上分配变量的技术,所以如果可以的话,请使用它,因为它也不会那么令人困惑。