Examples to try

Load, run with F9, go through step by step with F8.

The ZIP has small programs for Windows (Intel and ARM) and DOS. On this page you see them with the code the assembler makes of them, and with the result. The files are in the folder examples of the ZIP; each opens in Asmonite and runs in the debugger with F9.

The examples with func are for 32-bit Windows (.arch i386).

The factorial, recursive

n! = n · (n−1)!, and 0! = 1! = 1. The function calls itself: func makes the frame, if / else the comparison and the jumps. File: examples\func\func_fact.asm.

You write
func Fact(n) uses ebx
begin
  if unsigned n > 1
    mov ebx, n
    dec ebx
    call Fact(ebx)
    imul eax, n
  else
    mov eax, 1
  endif
end
The assembler produces
Fact:
  push ebp
  mov ebp, esp
  push ebx
  cmp dword [ebp+8], 1
  jbe else1
  mov ebx, dword [ebp+8]
  dec ebx
  push ebx
  call Fact
  imul eax, dword [ebp+8]
  jmp end1
else1:
  mov eax, 1
end1:
  pop ebx
  pop ebp
  ret 4
added by the assembler (func, if, else, call) your line, the names are replaced unchanged

Three things are written that way on purpose. There are no expressions and no calls inside a call: call Fact(n-1) is not possible, so dec ebx counts down first and call Fact(ebx) gets the result. n stays in the frame of the function, so imul eax, n after the call works with its own n. ebx is in uses so the caller gets it back unchanged. An ordered comparison says signed or unsigned.

The same calculation as a loop

You write
func FactLoop(n)
begin
  mov ecx, n
  mov eax, 1
  if unsigned ecx > 1
    do
      imul eax, ecx
      dec ecx
    while unsigned ecx > 1
  endif
end
The assembler produces
FactLoop:
  push ebp
  mov ebp, esp
  mov ecx, dword [ebp+8]
  mov eax, 1
  cmp ecx, 1
  jbe end1
loop1:
  imul eax, ecx
  dec ecx
  cmp ecx, 1
  ja loop1
end1:
  pop ebp
  ret 4

The if around the loop skips it for 0 and 1; while jumps back to the do as long as ecx is greater than 1. The call in the main part and the output:

Main part
start:
  call Fact(10)
  call [printf](fmt, 10, eax)
  call FactLoop(5)
  call [printf](fmt, 5, eax)
  call [ExitProcess](0)
Output
10! = 3628800
5! = 120

.import msvcrt.dll cdecl printf says that printf does not remove the arguments itself; call [printf](...) cleans up afterwards. The arguments are in the order of the function: the format first.

if on x64, ARM 64 and Thumb

if, else and do … while exist for .arch x64, .arch arm64 and .arch thumb too (func and call Name(args) not yet). You write the operands as the architecture knows them; the assembler makes cmp (or tst) and the jump with the opposite condition around the block of it.

You write (ARM 64)
if w1 == 5
  add w0, w0, #1
endif

if signed w1 < 3
  add w0, w0, #100
else
  add w0, w0, #2
endif

if unsigned w2 > w1
  add w0, w0, #4
endif
The assembler produces
  cmp w1, #5
  b.ne endif1
  add w0, w0, #1
endif1:
  cmp w1, #3
  b.ge else2
  add w0, w0, #100
  b end2
else2:
  add w0, w0, #2
end2:
  cmp w2, w1
  b.ls endif3
  add w0, w0, #4
endif3:
added by the assembler (if, else, endif); the names of the labels are simplified here unchanged

A word like signed or unsigned says how to compare (see course, lesson 3); if w3 & w4 is tst; if zero uses the flags of the instruction before it. On ARM there are no memory operands in if: load into a register first. The complete programs: examples\windows_intel\if_x64.asm, examples\windows_arm\if_arm64.asm and examples\windows_arm\if_arm32.asm. Each ends with the exit code 31 (= 1 + 2 + 4 + 8 + 16): every block that runs adds its number, so the exit code shows which conditions were true.

All examples

Folder examples\func: functions, calls, if and loops for 32-bit Windows. The result is the output or the exit code (echo %errorlevel%).

FileShowsResult
func_add.asmparameters and the stack frame without counting offsetsexit code 12
func_call.asmcall Name(arguments): the assembler pushes the arguments and cleans upexit code 33
func_call_locals.asmlocals as arguments: an array, a byte, & for an addressexit code 36
func_locals.asmlocal variables, an array, uses and an early retexit code 39
func_cdecl.asmcdecl functions: the caller cleans up; wsprintfA into a local buffermessage box
func_if.asmif / else / endif: the larger of two numbersexit code 7
func_loop.asmdo … while: loops without a label of your ownoutput
func_fact.asmthe factorial recursive and as a loop (above)10! = 3628800
func_printf.asmprintf of the C runtime is cdecl: .import msvcrt.dll cdecl printfoutput
func_console.asmtext to the console: GetStdHandle, lstrlenA, WriteFileoutput
func_file.asmfiles: write, read, close and delete with CreateFileA (seven arguments)exit code 11
func_computername.asmthe name of this computer: GetComputerNameA(buffer, &size)exit code = length
func_time.asmthe local time in a message box: GetLocalTime, wsprintfAmessage box
func_yesno.asmMessageBoxA with Yes / No; the answer is the exit codeexit code 6 or 7

More folders

FolderContent
windows_intelhello world, a message box and a window, each for 32 bit (.arch i386) and 64 bit (.arch x64); demo.asm counts from 1 to 5 and is good for the first steps through the debugger; if_x64.asm shows if / else
windows_armhello world and a message box for Windows on ARM, 32 bit (Thumb-2) and 64 bit (ARM64); if_arm32.asm and if_arm64.asm show if / else
doshello world for DOS as .COM and as .EXE, and a prebuilt HELLO.EXE to examine in Dismonite

Try it

Open a file from examples in Asmonite (Ctrl+O) and press F9: assemble and start in the debugger. F8 goes one step on; with func, if and call one line of your text is one step, not the generated instructions. Without the window: asmoc func_fact.asm writes the .exe next to the file.

Next

func and call

Parameters, locals, uses and call Name(...) with the generated instructions.

The func page →

if and loops

if, else, do … while with the bytes they become.

The if page →

The syntax

Numbers, expressions, addresses, jumps and data with their bytes.

The syntax page →