NOTE: This page mainly consists of elements from the NASM Tutorial by Ray Toe. See Resources section for the direct link to the source.
NASM is line-based. Most programs consist of directives followed by one or more sections. Lines can have an optional label. Most lines have an instruction followed by zero or more operands.
Generally, you put code in a section called
.text, your constant data in a section called
.data and reserved space (for data yet to be initialized) into the
bss segment / section.
NOTE: Any label may be up to 4095 characters of size. NASM does not support any labels longer than that.
Any variable, line of code, etc. will be placed at some place in the memory and labels may be used to reference on them. Labels will hold the address of the corresponding value. There are generally three common types of labels:
This label has no prefix and is declared only once in the segment. It can be accessed throughout the segment it's in.
This label has been declared global and can be accessed from other segments as well as other codes, as long as they're linked by the linker. For more on it, see Directives.
This label can be accessed locally. See Loops (Sum), there you'll notice two times the
.loop label in the code. We could have used names like
while_start instead of naming the same name with a prepending
., but this way we have created local labels, meaning the first
.loop is only accessible under
loopsum or needs to be referenced as
loopsum.loop elsewhere in the code. Using local labels can be quite useful.
There are hundreds of instructions. You can’t learn them all at once. Just start with these:
mov x, y ; x ← y and x, y ; x ← x and y or x, y ; x ← x or y xor x, y ; x ← x xor y add x, y ; x ← x + y sub x, y ; x ← x – y inc x ; x ← x + 1 dec x ; x ← x – 1 syscall ; Invoke an operating system routine db ; A pseudo-instruction that declares bytes that will be in memory when the program runs
Also see the explanation on pseudo-instructions.
These are the basic forms of addressing:
[ number ] [ reg ] [ reg + reg*scale ] ; scale is 1, 2, 4, or 8 only [ reg + number ] [ reg + reg*scale + number ]
The number is called the displacement; the plain register is called the base; the register with the scale is called the index.
 ; displacement only [rbp] ; base register only [rcx + rsi*4] ; base + index * scale [rbp + rdx] ; scale is 1 [rbx - 8] ; displacement is -8 [rax + rdi*8 + 500] ; all four components [rbx + counter] ; uses the address of the variable 'counter' as the displacement
These can be written in many ways. Here are some examples from the official docs:
200 ; decimal 0200 ; still decimal - the leading 0 does not make it octal 0200d ; explicitly decimal - d suffix 0d200 ; also decimal - 0d prefix 0c8h ; hex - h suffix, but leading 0 is required because c8h looks like a var 0xc8 ; hex - the classic 0x prefix 0hc8 ; hex - for some reason NASM likes 0h 310q ; octal - q suffix 0q310 ; octal - 0q prefix 11001000b ; binary - b suffix 0b1100_1000 ; binary - 0b prefix, and by the way, underscores are allowed
The sections following this will deal with more details on the NASM syntax and optimization advices.