Assembly Playground - Help

Reference page for the simulator. Covers everything implemented in this small version of x86 assembly.

Registers

Registers are small storage slots inside the CPU, almost like pre-made variables! There are 4 general purpose ones (a, b, c, d) and each one has 4 names that all point to different parts of the same 32-bit value.

eax is the full 32-bit register. ax is the lower 16 bits of it, and ah/al are the two halves of ax. They all point to the same value, so changing one affects the others.

ebx, ecx and edx work exactly the same way with their own sub-registers (bx/bh/bl, etc).

Special registers

These dont have sub-registers, they each just do one specific thing.

name
full name
what it does
eip
Instruction Pointer
tracks which instruction runs next. jumps modify this directly.
esp
Stack Pointer
points to the top of the stack. push decreases it, pop increases it. starts at 1MB.
ebp
Base Pointer
general purpose, traditionally marks the bottom of the current function's stack frame.
esi
Source Index
general purpose, traditionally used as a source pointer in memory operations.
edi
Destination Index
general purpose, traditionally a destination pointer.

*note: currently only eip and esp have functionality attached to them.

Floating Point Registers

The registers st0 - st7 are all specifically designed to handle floating point values. Attempting to store a float like 3.14 in eax would end up clamping the value and reducing it simply to 3.

Unlike the general purpose registers, the float registers work as a stack. This means you don't write to them directly. Instead you push and pop values using fld and fstp. st0 is always the top of the stack, and pushing a new value shifts everything down.

For example, if you load two values with fld, the first one ends up in st1 and the second in st0, since st0 is always the most recently pushed value.

*note: these registers are based on the x87 FPU registers from real x86, but simplified. Real x87 uses 80-bit extended precision internally, while this emulator uses 64-bit double precision.

Flags

Flags are set automatically after arithmetic and cmp instructions. the jump instructions then read them to decide whether to jump or not.

flag
meaning
when it gets set
zero
result was zero
last arithmetic result was 0, or both sides of cmp were equal
carry
unsigned underflow
subtraction went negative (left side smaller than right)
sign
result was negative
highest bit of result is set, meaning it is negative as a signed number
overflow
signed overflow
set when a number overflows, wrapping around to a negative number

Memory

The simulator has 1MB of memory. (Indexing starts at 0x100) You access it by wrapping an address in square brackets.

mov [0x1000], eax ; write eax to address 0x1000
mov ebx, [0x1000] ; read from 0x1000 into ebx
mov [eax], 42 ; use eax as the address

*note: reads and writes are (almost) always 32-bit (4 bytes at once). writing to address 0x100 also changes 0x101, 0x102 and 0x103.

Sections

Sections split your program into named regions. section .text holds your instructions and section .data holds values that exist before your program runs.

*note: the .text section is where execution starts. any instructions placed outside a section are assumed to be in .text.

Data Declarations

Variables are declared in the section .data block using a name, size keyword, and initial value.

keyword
size
example
db
1 byte
flag db 1
dw
2 bytes (word)
count dw 256
dd
4 bytes (double word)
value dd 0x12345678
dq
8 bytes (quad word), used for floats
pi dq 3.1415

When you reference a data variable by name in the text section, you get its memory address. Use square brackets to read the actual value.

section .data
x dd 42

section .text
mov eax, [x] ; eax = 42 (read value)
mov ebx, x ; ebx = address of x

Strings are stored in a db, they must be null-terminated to work correctly. (see example)

section .data
msg db "string", 0 ; null-terminated string, add ', 0'

section .text
mov eax, msg ; move the address of 'msg' into eax
println [eax] ; loops over the string until it hits the null-terminator
println eax ; prints the address of the first character in the string

Macros

Macros are text replacements. Use %define to create a macro that gets replaced everywhere it appears.

%define MAX_COUNT 100
%define BUFFER_SIZE 1024

mov ecx, MAX_COUNT ; becomes mov ecx, 100
add edi, BUFFER_SIZE ; becomes add edi, 1024

*note: macros are case-insensitive and get replaced before any other processing happens. they are purely replacing text with their value.

Data movement

op
what it does
example
mov
copies a value into a register or memory address. doesnt affect flags.
mov eax, 42
mov ebx, eax
mov [0x200], eax

Arithmetic

op
what it does
example
add
adds src to dest
add eax, 10
sub
subtracts src from dest
sub eax, 5
mul
multiplies dest by src
mul eax, 3
div
divides dest by src. dont divide by zero.
div eax, 2
inc
adds 1 to dest
inc ecx
dec
subtracts 1 from dest
dec ecx
fld
loads a float onto the top of the float stack (st0)
fld 3.1415
fld [pi]
fstp
stores st0 into a destination then pops it off the float stack
fstp [result]
fadd
adds two float values, stores result in dest
fadd st0, st1
fsub
subtracts src from dest, both floats
fsub st0, st1
fmul
multiplies dest by src, both floats
fmul st0, st1
fdiv
divides dest by src, both floats. dont divide by zero.
fdiv st0, st1
cmp
updates CPU flags. compares if greater than or equal to and sets appropriate flags.
cmp ecx, 0
je .done
test
same as cmp but uses bitwise AND, sets CPU flags.
test eax, ebx

Bitwise Operations

These work on individual bits instead of whole numbers.

op
what it does
example
and
output bit is 1 only if both input bits are 1
and eax, 0xFF ; keep only lowest 8 bits
or
output bit is 1 if at least one input bit is 1
or eax, 0x100 ; set bit 8
xor
output bit is 1 only if the two input bits differ
xor eax, eax ; eax = 0
not
flips every bit, 1 becomes 0 and 0 becomes 1
not eax
shl
shifts bits left by src positions, equivalent to multiplying by 2 for each shift
shl eax, 1 ; eax * 2
shr
shifts bits right by src positions, equivalent to dividing by 2 for each shift
shr eax, 1 ; eax / 2

Jumps

These move execution to a label. the conditional ones check flags set by the last compare.

op
what it does
example
jmp
always jumps, no condition
jmp .end
je
jumps if equal
cmp eax, ebx
je .equal
jne
jumps if not equal
cmp ecx, 0
jne .loop
jg
jumps if dest was greater than src
cmp eax, 10
jg .big
jge
jumps if dest was greater or equal
jge .label
jl
jumps if dest was less than src
cmp eax, 10
jl .small
jle
jumps if dest was less or equal
jle .label
jo
jumps if overflow flag is set
jo .label
jno
jumps if overflow flag is not set
jno .label
jz
jumps if zero flag is set, same as je
jz .label
jnz
jumps if zero flag is not set, same as jne
jnz .label
js
jumps if sign flag is set, meaning the last result was negative
js .label
jns
jumps if sign flag is not set
jns .label
loop
decrements ecx then jumps to label if ecx is not zero
mov ecx, 5
.start:
loop .start ; repeats 5 times

*note: always put cmp right before a jump or the flags might be wrong from a previous instruction.

Stack and calls

The stack is a region of memory that grows downward. esp points to the top of it.

; standard function call
push eax
call .func

.func:
mov eax, 99
ret
op
what it does
example
push
esp -= 4, then writes value to memory at esp
push eax
pop
reads from memory at esp into dest, then esp += 4
pop ebx
call
pushes return address onto stack then jumps to label
call .function
ret
pops the return address and jumps back to it
ret

Misc

op
what it does
example
print
prints a value or string to the output panel, no newline
print eax
print "hello"
println
same as print but adds a newline at the end
println eax
println "hello"
printc
prints a single character
printc 'A'
prints
prints a string in double quotes
prints "hello"
printi
prints an integer value from a register or literal
printi eax
printi 42
printfl
prints a float value from a float register or literal
printfl st0
printfl 3.14
nop
does nothing, advances to the next instruction
nop

*note: some of the 'Misc' instructions are not real x86 instructions.

Syntax

Comments

mov eax, 1 ; semicolons start a comment

Labels

A label is just a name followed by a colon. The dot at the start is optional but often used to make labels easier to distinguish from variables and other identifiers.

.loop:
dec ecx
jne .loop

Numbers

mov eax, 255 ; decimal
mov eax, 0xFF ; same value in hex

Memory references

mov [0x1000], eax ; write to address 0x1000
mov ebx, [eax] ; treat eax as a memory address and read from it

; to get the address of a variable, remove the brackets
mov eax, myVar

*note: everything is case-insensitive so MOV, mov and mOv all work fine.