I wrote the following program in nasm on a Windows 10 64bit machine
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
I would have cleaned it up, but this may affect something, so I won't (sorry). The _draw
function should output "abc\n" 9 (3*3) (3 and 3, because w
and h
are 3) times on the screen, but it only gets outputed 5 times. As far as I have checked, the _print
works as intended. Here's my build script if it helps:
@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
I build using the build filename
command, and it functions correctly.
I have checked my logic, and it seems fine, so it's something with the nested loop and I don't know what exactly.
Complete build
command output:
C:\Users\User\files>build filename
abc
abc
abc
abc
abc
------------------------
exited successfully
C:\Users\User\files>
If the loops were working properly, then it would be impossible to get the output 5 times, because it should be (repetitions of the outer one)*(repetitions of the inner one), but 5 is a prime number. I can not figure this out, so I leave it to this community. Have a great day and thanks in advance!
The first time through the outer loop, [ebp-8]
counts down to zero. The next two times through the outer loop, [ebp-8]
is already zero (or less), so the inner loop only executes once. For a total of five calls to print.
Note that the subsequent executions of push [h]
don't change [ebp-8]
.
On the second iteration, it writes to [ebp-12]
and on the third iteration it writes to [ebp-16]
, because the stack pointer continues to grow downward with each push.
To fix this, I suggest:
sub esp, 8
right after mov ebp, esp
.push [w]
to mov eax, [w]; mov [ebp-4], eax
.push [h]
to mov eax, [h]; mov [ebp-8], eax
.