I'm learning MASM and I can't get this simple code to work. I'm not getting the values I pass into invoke, I don't know what's happening. I've tried push 2, push 2, call pow. Same results. EAX and EDX look like garbage or maybe memory addresses.
The thread 0x1544 has exited with code -1073741510 (0xc000013a). The thread 0xd8 has exited with code -1073741510 (0xc000013a). The thread 0x898 has exited with code -1073741510 (0xc000013a). The thread 0x21c4 has exited with code -1073741510 (0xc000013a). The program '[2296] AssemblyTutorial.exe' has exited with code -1073741510 (0xc000013a).
This just means I closed the console window, but why are there 4 threads?
.386
.model flat,stdcall
option casemap:none
include windows.inc
include masm32.inc
includelib masm32.lib
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.code
;requires power > 0 for correct answers
pow proc x:DWORD, power:DWORD
;THESE TWO MOVES RIGHT HERE ARE NOT WORKING AS EXPECTED
;I PUSH 2 ONTO STACK BUT WHEN I LOOK AT REGISTER VALUES
;IN DEBUG THEY ARE INCORRECT/GARBAGE
mov eax, x ;eax has x
mov edx, power ;edx has power
mov ecx, eax ;ecx will be my constant base
start_power:
cmp edx, 1 ;is power 1?
je end_power ;then jump to end
imul eax, ecx ;else mul result/x with x
dec edx ;power--
jmp start_power ;jump back to beginning of loop
end_power:
ret ;return answer eax
pow endp
start:
invoke pow, 2, 2 ;eax should hold 4 after this
invoke ExitProcess, eax ;program should exit with code eax, ez way to print result
end start
Yes, the difference between cdecl and stdcall is that the former is caller-clean and the latter is callee-clean. (See also Raymond Chen's series on calling conventions in Windows.
The problem is, your pow
procedure was not following the stdcall convention because it was not cleaning the stack. You need to specify the number of bytes to pop as part of the ret
instruction. In this case, that would be ret 8
.
Or, you can make the function cdecl, in which case the caller becomes responsible for cleaning the stack, and MASM can automatically generate this code as part of the INVOKE
directive.
why are there 4 threads?
Windows starts background threads for various reasons. These are nothing to worry about. If you investigate them further, you'll probably see that they're started by the thread-pool worker thread (TppWorkerThread
in ntdll.dll).
For what it's worth, the pow
function could be more efficiently written as:
pow PROC x:DWORD, power:DWORD
; Load parameters into registers
mov eax, x
mov edx, power
mov ecx, eax
; Decrement 'power' by 1 and bail out if we're done.
dec edx
jz Finished
; The main loop.
CalculatePow:
imul eax, ecx
dec edx
jnz CalculatePow
Finished:
ret 8 ; assuming this function is STDCALL
pow ENDP