Excercise Script

We are going to make a Fibonacci calculator. Fibonacci is simpley 1 + 1 = 2, then take last numbers and add to 1 + 2 = 3. The program will take an input of max number.

We start with data movement by setting 0 to rax and 1 to rxb.

global  _start    ; Tell assembler to make entry point _start visible to linker.

section .text     ; .text is where code and instructions go.
_start:
    mov rax, 0    ; Put 0 value into rax
    mov rbx, 1    ; Put 1 value into rbx

As 1 would be 0x00000001 in 64 bit, its not efficient so we use 1 byte register bl.

global  _start

section .text
_start:
    mov al, 0
    mov bl, 1

Address Pointers

Pointer registers do not contain values but the point to another address that holds the value. For example if we would mov rax, rsp as rsp is the current stack pointer. We are not moving the value but move the pointer address to rax.

To move the value we use brackets like

mov rax, rsp    ; copies address in rsp to rax
mov rax, [rsp]  ; copies value stored at address that rsp point to into rax.

Loading Value Pointers

Using lea or Load Effective Address we load a pointer to a specific value like: lea rax, [rsp]. This is the opposite from above where we load pointer to a value and here we move value from pointer, it loads the address not the value.

global  _start

section .text
_start:
    lea rax, [rsp+10]
    mov rax, [rsp+10]

lea rax, [rsp+10] loaded the address that is 10 addresses away from rsp so 10 addresses away from top of stack moving the value stored there to rax.

Arithmetic Instructions

Assuming rax starts at 1 for each instruction.

Instruction
Description
Example

inc

Increment by 1

inc rax -> rax++ or rax += 1 -> rax = 2

dec

Decrement by 1

dec rax -> rax-- or rax -= 1 -> rax = 0

Now lets increment the value of bl with 1.

global  _start
section .text
_start:
    mov al, 0    ; al more efficent than rax, set value 0
    mov bl, 0    ; set value at 0 
    inc bl       ; increment with 1

Binary Instructions

Instruction
Description
Example

add

Add both operands

add rax, rbx -> rax = 1 + 1 -> 2

sub

Subtract Source from Destination (i.e rax = rax - rbx)

sub rax, rbx -> rax = 1 - 1 -> 0

imul

Multiply both operands

imul rax, rbx -> rax = 1 * 1 -> 1

global  _start

section .text
_start:
   mov al, 0      
   mov bl, 0
   inc bl            ; we increment with 1
   add rax, rbx      ; rax is equal to 0x1 + 0x0. rax = rax + rbx

Bitwise Intstructions

Instruction
Description
Example

not

Bitwise NOT (invert all bits, 0->1 and 1->0)

not rax -> NOT 00000001 -> 11111110

and

Bitwise AND (if both bits are 1 -> 1, if bits are different -> 0)

and rax, rbx -> 00000001 AND 00000010 -> 00000000

or

Bitwise OR (if either bit is 1 -> 1, if both are 0 -> 0)

or rax, rbx -> 00000001 OR 00000010 -> 00000011

xor

Bitwise XOR (if bits are the same -> 0, if bits are different -> 1)

xor rax, rbx -> 00000001 XOR 00000010 -> 00000011

We can uss xor to torn any value to 0 by xoring a value with itself. So if rax would 8888, you xor it with itself which is 8888 and thus is 0.

global  _start

section .text
_start:
    xor rax, rax  ; better than mov al, 0
    xor rbx, rbx  ; better than mov bl, 0
    inc rbx
    add rax, rbx

Loop Structure

Instruction
Description
Example

mov rcx, x

Sets loop (rcx) counter to x

mov rcx, 3

loop

Jumps back to the start of loop until counter reaches 0

loop exampleLoop

global  _start

section .text
_start:
    xor rax, rax    ; initialize rax to 0
    xor rbx, rbx    ; initialize rbx to 0
    inc rbx         ; increment rbx to 1
    mov rcx, 10     ; 10 iterations
loopFib:
    add rax, rbx    ; get the next number
    xchg rax, rbx   ; swap values
    loop loopFib

Unconditional Branching

jump will allow us to jump to any point in the program if a condition is met. After that it will continue processing instructions from that point. The basic jmp will always jump to the specified location, regardless of conditions.

Conditional Branching

Conditional Branching instructions are only processed when a specific condition is meet.

jz   D = 0     ; Destination equal to Zero
jnz  D != 0    ; Destination Not equal to Zero

For all conditions: https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf#page=585

CMP

The compare instruction compares 2 operands, by subtracting the 2nd operand from the first. So after the first Fibonacci number is calculated it will 1 - 10 = -9 and as its negative it will jump, once it hits positve number it will not jump.

global  _start

section .text
_start:
    xor rax, rax    ; initialize rax to 0
    xor rbx, rbx    ; initialize rbx to 0
    inc rbx         ; increment rbx to 1
loopFib:
    add rax, rbx    ; get the next number
    xchg rax, rbx   ; swap values
    cmp rbx, 10		; do rbx - 10
    js loopFib		; jump if result is <0

PUSH/POP

To preserve our registers and values we can push it to the stack and get them back after syscall using pop.

global  _start

section .text
_start:
    xor rax, rax    ; initialize rax to 0
    xor rbx, rbx    ; initialize rbx to 0
    inc rbx         ; increment rbx to 1
    push rax        ; push registers to stack
    push rbx
    ; call function
    pop rbx         ; restore registers from stack
    pop rax

Syscalls

Syscall is function written in C, like read or write. The write syscall has number 1 so mov rax, 1 . However write requires arguments.

  1. rdi -> 1 (for stdout)

  2. rsi -> 'Fibonacci Sequence:\n' (pointer to our string)

  3. rdx -> 20 (length of our string)

As the string is longer than 16 chars - 64 bits we need a variable. Message label is the pointer to where our strings is stored in memory. Below will not work yet.

global  _start

section .data
    message db "Fibonacci Sequence:", 0x0a
    
    mov rax, 1       ; rax: syscall number 1
    mov rdi, 1       ; rdi: fd 1 for stdout
    mov rsi,message  ; rsi: pointer to message
    mov rdx, 20      ; rdx: print length of 20 bytes
syscall              ; call write syscall intro message
    xor rbx, rbx     ; initialize rbx to 0
    inc rbx          ; increment rbx to 1
loopFib:
    add rax, rbx     ; get the next number
    xchg rax, rbx    ; swap values
    cmp rbx, 10	     ; do rbx - 10
    js loopFib	     ; jump if result is <0
    mov rax, 60
    mov rdi, 0
    syscall

Procedures

A procedure (sometimes referred to as a subroutine) is usually a set of instructions we want to execute at specific points in the program. Using ret we return to the point where we were before jumping tot the procedure.

Instruction
Description
Example

call

push the next instruction pointer rip to the stack, then jumps to the specified procedure

call printMessage

ret

pop the address at rsp into rip, then jump to it

ret

global  _start

section .data
    message db "Fibonacci Sequence:", 0x0a

section .text
_start:
    call printMessage   ; print intro message
    call initFib        ; set initial Fib values
    call loopFib        ; calculate Fib numbers
    call Exit           ; Exit the program

printMessage:
    mov rax, 1       ; rax: syscall number 1
    mov rdi, 1       ; rdi: fd 1 for stdout
    mov rsi,message  ; rsi: pointer to message
    mov rdx, 20      ; rdx: print length of 20 bytes
    syscall          ; call write syscall to the intro message
    ret
    
initFib:
    xor rax, rax     ; initialize rax to 0
    xor rbx, rbx     ; initialize rbx to 0
    inc rbx          ; increment rbx to 1
    ret
    
loopFib:
    add rax, rbx     ; get the next number
    xchg rax, rbx    ; swap values
    cmp rbx, 10	     ; do rbx - 10
    js loopFib	     ; jump if result is <0
    ret
    
Exit:
    mov rax, 60      ; 60 is syscall nr for exit
    mov rdi, 0
    syscall

Last updated

Was this helpful?