Fading Coder

An Old Coder’s Final Dance

You are here: Home > Tech > Content

Core NASM Instructions: Moves, Arithmetic, Branching, and String Operations

Tech 3

Data Movement

mov

Moves data between registers and/or memory.

; register to register
a mov eax, ebx

; memory to register (base + displacement)
mov edx, [ecx + 8]

; register to memory
mov [edi + 4], eax
  • Only one operand may be a memory location (memory-to-memory moves are not allowed with mov).

movsx / movzx

Extend a smaller operand to a larger size.

  • movsx: sign-extend the source into the destination
  • movzx: zero-extend the source into the destination
; sign-extend 16-bit to 32-bit
movsx eax, word [esi]      ; if [esi] = 0xFF80, eax = 0xFFFF8080

; zero-extend 8-bit to 32-bit
movzx ecx, byte [edx]      ; if [edx] = 0x80, ecx = 0x00000080

lea (Load Effective Address)

Computes an address expression and stores the result.

; if ebx = 0x00403A40, result becomes 0x00403A48
lea eax, [ebx + 8]

; scaled-index addressing example
lea edi, [esi + ecx*4 + 12]

Increment / Decrement

inc destination   ; destination = destination + 1
dec destination   ; destination = destination - 1

; examples
inc ecx
dec dword [ebp - 4]

Addition / Subtraction

add destination, source
sub destination, source

; valid forms include:
; - register ← register
; - register ← memory
; - memory   ← register
; - register ← immediate
; - memory   ← immediate

; memory ← memory is not allowed

; examples
add eax, 5
sub [esp + 16], ebx
add edx, [edi]

Add/Subtract with Carry

adc (Add with Carry)

Adds source + destination + CF.

; generate a carry and then propagate it
mov al, 0xFF
add al, 0x01          ; AL = 0x00, CF = 1

mov dl, 0
adc dl, 0             ; DL = 1 because CF = 1

sbb (Subtract with Borrow)

Subtracts source + CF from destination.

; force a borrow, then subtract with borrow
mov ebx, 0
sub ebx, 5            ; CF = 1 (borrow occurred)

mov ecx, 20
sbb ecx, 0            ; ECX = 19 because CF = 1

Multiplication

mul (unsigned) / imul (signed)

Implicit-operand forms place the full product in a pair of registers:

  • AL × r/m8 → AX
  • AX × r/m16 → DX:AX
  • EAX × r/m32 → EDX:EAX
  • RAX × r/m64 → RDX:RAX
; unsigned 8-bit multiply
mov al, 25           ; AL = 25
mov bl, 10           ; BL = 10
mul bl               ; AX = 250 (0x00FA)

; signed 32-bit multiply
mov eax, -7
imul dword [multiplier32]   ; EDX:EAX = eax * [mem]

Division

div (unsigned) / idiv (signed)

Dividend is taken from a fixed register pair; quotient and remainder are returned as follows:

  • (AX) ÷ r/m8 → AL (quotient), AH (remainder)
  • (DX:AX) ÷ r/m16 → AX (quotient), DX (remainder)
  • (EDX:EAX) ÷ r/m32 → EAX (quotient), EDX (remainder)
  • (RDX:RAX) ÷ r/m64 → RAX (quotient), RDX (remainder)
; unsigned 16-bit divide by byte
mov dx, 0            ; clear high half of dividend
mov ax, 1000
mov bl, 24
div bl               ; AL = 41, AH = 16 (1000 = 41*24 + 16)

Comparison

cmp

Subtracts source from destination and sets flags; operands are unchanged.

cmp eax, ebx
je  .equal
jne .notequal

Unconditional Jump

jmp target_label

Condisional Jumps

Use after cmp or any flag-setting instruction. Two common families exist: signed and unsigned comparisons.

Signed comparisons

  • JE/JZ → equal (ZF = 1)
  • JNE/JNZ → not equal (ZF = 0)
  • JG/JNLE → greater than (ZF = 0 and SF = OF)
  • JGE/JNL → greater or equal (SF = OF)
  • JL/JNGE → less than (SF ≠ OF)
  • JLE/JNG → less or equal (ZF = 1 or SF ≠ OF)

Unsigned comparisons

  • JE/JZ → equal (ZF = 1)
  • JNE/JNZ → not equal (ZF = 0)
  • JA/JNBE → above (CF = 0 and ZF = 0)
  • JAE/JNB → above or equal (CF = 0)
  • JB/JNAE → below (CF = 1)
  • JBE/JNA → below or equal (CF = 1 or ZF = 1)

Single-flag and special jumps

  • JO/JNO → overflow set/clear (OF = 1/0)
  • JS/JNS → sign set/clear (SF = 1/0)
  • JC/JNC → carry set/clear (CF = 1/0)
  • JP/JPE → parity even (PF = 1)
  • JNP/JPO → parity odd (PF = 0)
  • JECXZ/JRCXZ → jump if ECX/RCX == 0

loop

loop label decremants ECX/RCX, jumps if the result is not zero.

mov ecx, 5
.repeat:
; ... body ...
loop .repeat          ; runs 5 times

Bitwise and Test

AND  destination, source
OR   destination, source
XOR  destination, source
NOT  destination
TEST destination, source   ; like AND for flags, result is not stored

; examples
and eax, 0xFF
or  edx, [mem]
xor ecx, ecx              ; set ECX to 0
test eax, eax             ; sets ZF if eax == 0

Shifts and Rotates

  • SHL/SHR: logical left/right (zero-filled)
  • SAL/SAR: arithmetic left/right (SAR preserves sign bit)
  • ROL/ROR: rotate left/right
  • RCL/RCR: rotate through CF (includes carry)
  • SHLD/SHRD: double-precision shift between two registers
; logical shift right
shr eax, 1

; arithmetic shift right (preserve sign)
sar ebx, 3

; rotate left by 1
rol edx, 1

; shift left double-precision: EDX:EAX << CL, result in EAX
shld eax, edx, 4

String and Block Operations

movsX (movsb/movsw/movsd/movsq)

Copies from [RSI/ESI] to [RDI/EDI]. Element size is 1/2/4/8 bytes. Direction is controlled by DF (0 = increment, 1 = decrement).

; copy 10 bytes from srcBuf to dstBuf
cld                      ; DF = 0 (increment)
lea esi, [srcBuf]
lea edi, [dstBuf]
mov ecx, 10
rep movsb

cld / std

  • cld: clear direction flag (DF = 0)
  • std: set direction flag (DF = 1)

rep prefixes

  • rep → repeat while ECX/RCX > 0
  • repe/repz → repeat while ECX/RCX > 0 and ZF = 1
  • repne/repnz → repeat while ECX/RCX > 0 and ZF = 0
; scan for zero byte in a buffer (stop when found or count exhausted)
cld
mov edi, buf
mov ecx, buf_len
mov al, 0
repne scasb            ; stop when AL == [EDI] (ZF=1) or ECX==0

cmpsX (cmpsb/cmpsw/cmpsd/cmpsq)

Compares [RSI/ESI] with [RDI/EDI], updates flags, advances pointers per DF. Often used with repe/repne.

; compare two blocks for equality
cld
lea esi, [blockA]
lea edi, [blockB]
mov ecx, length
repe cmpsb             ; stop on mismatch (ZF=0) or ECX==0

scasX (scasb/scasw/scasd/scasq)

Compares AL/AX/EAX/RAX against [RDI/EDI], updates flags, advances per DF. Useful for searching.

stosX (stosb/stosw/stosd/stosq)

Stores AL/AX/EAX/RAX into [RDI/EDI], advances per DF.

; fill 32-bit values
d cld
mov edi, buffer
mov ecx, count
mov eax, 0xDEADBEEF
rep stosd

lodsX (lodsb/lodsw/lodsd/lodsq)

Loads from [RSI/ESI] into AL/AX/EAX/RAX, advances per DF.

Stack and Control Transfer

push / pop

Manipulate the stack via RSP/ESP. RBP/EBP is commonly used as a frame pointer.

push eax
push ebx
; ...
pop ebx
pop eax

call / ret

call pushes the return address and transfers control to the target. ret pops the saved address into IP/EIP/RIP.

call my_function
; execution resumes here after ret

my_function:
    ; ... work ...
    ret
Tags: NASM

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.