Skip to content

Latest commit

 

History

History
732 lines (577 loc) · 14 KB

File metadata and controls

732 lines (577 loc) · 14 KB

22: Complete Working Examples

Fully functional programs you can assemble, compile, and run.

Example 1: Simple Calculator

A basic calculator that adds, subtracts, multiplies, and divides.

calculator.asm:

; Simple calculator: add, subtract, multiply, divide
; Demonstrates: arithmetic, functions, calling conventions

global add_nums
global subtract_nums
global multiply_nums
global divide_nums

section .text

; Add two numbers
; RDI = a, RSI = b
add_nums:
    MOV RAX, RDI
    ADD RAX, RSI
    RET

; Subtract: a - b
; RDI = a, RSI = b
subtract_nums:
    MOV RAX, RDI
    SUB RAX, RSI
    RET

; Multiply: a * b
; RDI = a, RSI = b
multiply_nums:
    MOV RAX, RDI
    IMUL RAX, RSI
    RET

; Divide: a / b
; RDI = a, RSI = b
; Returns: RAX = quotient, RDX = remainder
divide_nums:
    MOV RAX, RDI
    CQO                     ; Sign extend RAX to RDX:RAX
    MOV RCX, RSI
    TEST RCX, RCX           ; Check for divide by zero
    JZ error
    IDIV RCX
    RET
error:
    MOV RAX, 0              ; Return 0 on error
    MOV RDX, 0
    RET

test_calculator.c:

#include <stdio.h>

extern long add_nums(long a, long b);
extern long subtract_nums(long a, long b);
extern long multiply_nums(long a, long b);
extern long divide_nums(long a, long b);

int main() {
    printf("10 + 5 = %ld\n", add_nums(10, 5));        // 15
    printf("10 - 5 = %ld\n", subtract_nums(10, 5));    // 5
    printf("10 * 5 = %ld\n", multiply_nums(10, 5));    // 50
    printf("10 / 5 = %ld\n", divide_nums(10, 5));      // 2
    
    printf("\n25 + 75 = %ld\n", add_nums(25, 75));      // 100
    printf("100 - 45 = %ld\n", subtract_nums(100, 45)); // 55
    printf("7 * 8 = %ld\n", multiply_nums(7, 8));      // 56
    printf("17 / 5 = %ld\n", divide_nums(17, 5));      // 3
    
    return 0;
}

Compile and run:

nasm -felf64 calculator.asm -o calculator.o
gcc calculator.o test_calculator.c -o calc
./calc

Example 2: Array Operations

Functions for common array manipulations.

array_ops.asm:

; Array operations: sum, max, min, average
; Demonstrates: loops, memory access, function calls

global array_sum
global array_max
global array_min
global array_average

section .text

; Sum all elements in array
; RDI = pointer to array (8-byte integers)
; RSI = count
array_sum:
    PUSH RBP
    MOV RBP, RSP
    
    TEST RSI, RSI           ; if count <= 0
    JLE error_sum
    
    XOR RAX, RAX            ; sum = 0
    XOR RCX, RCX            ; index = 0
    
loop_sum:
    CMP RCX, RSI
    JGE done_sum
    
    ADD RAX, [RDI + RCX*8]  ; sum += array[index]
    INC RCX
    JMP loop_sum
    
done_sum:
    POP RBP
    RET
    
error_sum:
    XOR RAX, RAX
    POP RBP
    RET

; Find maximum element
; RDI = pointer to array
; RSI = count
array_max:
    PUSH RBP
    MOV RBP, RSP
    
    TEST RSI, RSI
    JLE error_max
    
    MOV RAX, [RDI]          ; max = array[0]
    MOV RCX, 1              ; index = 1
    
loop_max:
    CMP RCX, RSI
    JGE done_max
    
    MOV RDX, [RDI + RCX*8]
    CMP RAX, RDX
    JGE skip_max
    MOV RAX, RDX            ; Update max
    
skip_max:
    INC RCX
    JMP loop_max
    
done_max:
    POP RBP
    RET
    
error_max:
    MOV RAX, 0
    POP RBP
    RET

; Find minimum element
; RDI = pointer to array
; RSI = count
array_min:
    PUSH RBP
    MOV RBP, RSP
    
    TEST RSI, RSI
    JLE error_min
    
    MOV RAX, [RDI]          ; min = array[0]
    MOV RCX, 1
    
loop_min:
    CMP RCX, RSI
    JGE done_min
    
    MOV RDX, [RDI + RCX*8]
    CMP RAX, RDX
    JLE skip_min
    MOV RAX, RDX            ; Update min
    
skip_min:
    INC RCX
    JMP loop_min
    
done_min:
    POP RBP
    RET
    
error_min:
    MOV RAX, 0
    POP RBP
    RET

; Calculate average (returns integer division)
; RDI = pointer to array
; RSI = count
array_average:
    PUSH RBP
    MOV RBP, RSP
    PUSH RDI
    PUSH RSI
    
    CALL array_sum          ; RAX = sum
    
    MOV RDI, [RBP - 8]     ; Restore count
    MOV RDX, 0
    DIV RDI                ; RAX = sum / count
    
    POP RSI
    POP RDI
    POP RBP
    RET

test_array_ops.c:

#include <stdio.h>

extern long array_sum(long *arr, long count);
extern long array_max(long *arr, long count);
extern long array_min(long *arr, long count);
extern long array_average(long *arr, long count);

int main() {
    long arr[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    long count = 10;
    
    printf("Array: ");
    for (int i = 0; i < count; i++) printf("%ld ", arr[i]);
    printf("\n\n");
    
    printf("Sum:     %ld\n", array_sum(arr, count));        // 550
    printf("Maximum: %ld\n", array_max(arr, count));        // 100
    printf("Minimum: %ld\n", array_min(arr, count));        // 10
    printf("Average: %ld\n", array_average(arr, count));    // 55
    
    return 0;
}

Example 3: String Functions

Common string operations.

string_ops.asm:

; String operations: length, compare, copy
; Demonstrates: memory, loops, character operations

global string_length
global string_compare
global string_copy

section .text

; Get string length (exclude null terminator)
; RDI = string pointer
; Return: RAX = length
string_length:
    XOR RAX, RAX            ; count = 0
    
loop:
    CMP BYTE [RDI + RAX], 0 ; Check for null terminator
    JE done
    INC RAX
    JMP loop
    
done:
    RET

; Compare two strings
; RDI = string1
; RSI = string2
; Return: RAX = 0 if equal, 1 if s1 > s2, -1 if s1 < s2
string_compare:
    XOR RAX, RAX
    
loop_cmp:
    MOV AL, BYTE [RDI]
    MOV CL, BYTE [RSI]
    CMP AL, CL
    JNE not_equal
    
    TEST AL, AL             ; Check for null terminator
    JZ equal
    
    INC RDI
    INC RSI
    JMP loop_cmp
    
equal:
    XOR RAX, RAX            ; return 0
    RET
    
not_equal:
    MOV RAX, 1
    MOVSX RCX, CL
    MOVSX RAX, AL
    SUB RAX, RCX            ; return diff
    RET

; Copy string
; RDI = destination
; RSI = source
; Copies until null terminator
string_copy:
    PUSH RBP
    MOV RBP, RSP
    
loop_copy:
    MOV AL, BYTE [RSI]
    MOV BYTE [RDI], AL
    TEST AL, AL
    JZ done_copy
    
    INC RDI
    INC RSI
    JMP loop_copy
    
done_copy:
    LEAVE
    RET

test_string_ops.c:

#include <stdio.h>
#include <string.h>

extern long string_length(char *s);
extern long string_compare(char *s1, char *s2);
extern void string_copy(char *dest, char *src);

int main() {
    printf("String Length:\n");
    printf("  strlen(\"Hello\") = %ld\n", string_length("Hello"));        // 5
    printf("  strlen(\"Assembly\") = %ld\n", string_length("Assembly"));  // 8
    
    printf("\nString Compare:\n");
    printf("  compare(\"abc\", \"abc\") = %ld (expected 0)\n", 
           string_compare("abc", "abc"));
    printf("  compare(\"abc\", \"abd\") = %ld (expected <0)\n", 
           string_compare("abc", "abd"));
    printf("  compare(\"abd\", \"abc\") = %ld (expected >0)\n", 
           string_compare("abd", "abc"));
    
    printf("\nString Copy:\n");
    char buffer[100];
    string_copy(buffer, "Hello, Assembly!");
    printf("  copied: \"%s\"\n", buffer);
    
    return 0;
}

Example 4: Utility Functions

Bit operations, power, and conversion functions.

utils.asm:

; Utility functions: power, abs, sign, is_even
; Demonstrates: conditional jumps, arithmetic

global power
global abs_value
global get_sign
global is_even
global is_power_of_two

section .text

; Calculate x^n
; RDI = x (base)
; RSI = n (exponent)
; Return: RAX = x^n
power:
    MOV RAX, 1              ; result = 1
    MOV RCX, RSI            ; counter = n
    
loop_pow:
    TEST RCX, RCX
    JZ done_pow
    IMUL RAX, RDI           ; result *= x
    DEC RCX
    JMP loop_pow
    
done_pow:
    RET

; Absolute value
; RDI = number
; Return: RAX = |number|
abs_value:
    MOV RAX, RDI
    TEST RAX, RAX
    JNS done_abs            ; if positive, return as-is
    NEG RAX                 ; negate if negative
done_abs:
    RET

; Get sign of number
; RDI = number
; Return: RAX = -1 if negative, 0 if zero, 1 if positive
get_sign:
    XOR RAX, RAX
    CMP RDI, 0
    JE zero_val
    JG pos_val
    MOV RAX, -1
    RET
zero_val:
    RET
pos_val:
    MOV RAX, 1
    RET

; Check if even
; RDI = number
; Return: RAX = 1 if even, 0 if odd
is_even:
    MOV RAX, RDI
    AND RAX, 1              ; Check low bit
    TEST RAX, RAX
    JNZ odd
    MOV RAX, 1              ; Even
    RET
odd:
    XOR RAX, RAX            ; Odd
    RET

; Check if power of 2
; RDI = number
; Return: RAX = 1 if power of 2, 0 otherwise
is_power_of_two:
    TEST RDI, RDI
    JZ not_power            ; 0 is not power of 2
    
    MOV RAX, RDI
    DEC RAX
    AND RAX, RDI
    
    TEST RAX, RAX
    JNZ not_power
    
    MOV RAX, 1              ; Is power of 2
    RET
    
not_power:
    XOR RAX, RAX
    RET

test_utils.c:

#include <stdio.h>

extern long power(long x, long n);
extern long abs_value(long num);
extern long get_sign(long num);
extern long is_even(long num);
extern long is_power_of_two(long num);

int main() {
    printf("Power:\n");
    printf("  2^3 = %ld (expected 8)\n", power(2, 3));
    printf("  2^10 = %ld (expected 1024)\n", power(2, 10));
    
    printf("\nAbsolute Value:\n");
    printf("  abs(-42) = %ld (expected 42)\n", abs_value(-42));
    printf("  abs(42) = %ld (expected 42)\n", abs_value(42));
    
    printf("\nSign:\n");
    printf("  sign(-5) = %ld (expected -1)\n", get_sign(-5));
    printf("  sign(0) = %ld (expected 0)\n", get_sign(0));
    printf("  sign(5) = %ld (expected 1)\n", get_sign(5));
    
    printf("\nEven Check:\n");
    printf("  is_even(4) = %ld (expected 1)\n", is_even(4));
    printf("  is_even(7) = %ld (expected 0)\n", is_even(7));
    
    printf("\nPower of Two:\n");
    printf("  is_power_of_two(16) = %ld (expected 1)\n", is_power_of_two(16));
    printf("  is_power_of_two(17) = %ld (expected 0)\n", is_power_of_two(17));
    printf("  is_power_of_two(1024) = %ld (expected 1)\n", is_power_of_two(1024));
    
    return 0;
}

Example 5: Matrix Operations

Working with 2D data.

matrix_ops.asm:

; Matrix operations: sum all, find max element, transpose
; RDI = matrix pointer (row-major, 8-byte elements)
; RSI = rows
; RDX = cols

global matrix_sum_all
global matrix_find_max
global matrix_element

section .text

; Sum all elements in matrix
; RDI = matrix, RSI = rows, RDX = cols
matrix_sum_all:
    PUSH RBP
    MOV RBP, RSP
    
    TEST RSI, RSI
    JZ error_msum
    TEST RDX, RDX
    JZ error_msum
    
    XOR RAX, RAX            ; sum = 0
    MOV RCX, RSI
    IMUL RCX, RDX           ; total elements = rows * cols
    MOV R8, 0               ; index = 0
    
loop_msum:
    CMP R8, RCX
    JGE done_msum
    
    ADD RAX, [RDI + R8*8]
    INC R8
    JMP loop_msum
    
done_msum:
    POP RBP
    RET
    
error_msum:
    XOR RAX, RAX
    POP RBP
    RET

; Find maximum element in matrix
; RDI = matrix, RSI = rows, RDX = cols
matrix_find_max:
    PUSH RBP
    MOV RBP, RSP
    
    TEST RSI, RSI
    JZ error_mmax
    TEST RDX, RDX
    JZ error_mmax
    
    MOV RAX, [RDI]          ; max = matrix[0][0]
    MOV RCX, RSI
    IMUL RCX, RDX           ; total = rows * cols
    MOV R8, 1               ; index = 1
    
loop_mmax:
    CMP R8, RCX
    JGE done_mmax
    
    MOV R9, [RDI + R8*8]
    CMP RAX, R9
    JGE skip_mmax
    MOV RAX, R9
    
skip_mmax:
    INC R8
    JMP loop_mmax
    
done_mmax:
    POP RBP
    RET
    
error_mmax:
    MOV RAX, 0
    POP RBP
    RET

; Get matrix element [row][col]
; RDI = matrix, RSI = rows, RDX = cols, RCX = row, R8 = col
; Return: RAX = matrix[row][col]
matrix_element:
    MOV RAX, RCX            ; row
    IMUL RAX, RDX           ; row * cols
    ADD RAX, R8             ; row * cols + col
    MOV RAX, [RDI + RAX*8]
    RET

test_matrix.c:

#include <stdio.h>

extern long matrix_sum_all(long *mat, long rows, long cols);
extern long matrix_find_max(long *mat, long rows, long cols);
extern long matrix_element(long *mat, long rows, long cols, long row, long col);

int main() {
    // 3x3 matrix
    long mat[9] = {
        1, 2, 3,
        4, 5, 6,
        7, 8, 9
    };
    
    printf("Matrix (3x3):\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%2ld ", mat[i*3 + j]);
        }
        printf("\n");
    }
    
    printf("\nSum of all elements: %ld (expected 45)\n", 
           matrix_sum_all(mat, 3, 3));
    printf("Maximum element: %ld (expected 9)\n", 
           matrix_find_max(mat, 3, 3));
    printf("Element [1][2]: %ld (expected 6)\n", 
           matrix_element(mat, 3, 3, 1, 2));
    printf("Element [2][1]: %ld (expected 8)\n", 
           matrix_element(mat, 3, 3, 2, 1));
    
    return 0;
}

Compilation Template

For any example:

# Assemble the .asm file
nasm -felf64 example.asm -o example.o

# Compile the C test file
gcc -c test_example.c -o test_example.o

# Link together
gcc example.o test_example.o -o test_example

# Run
./test_example

Or in one command:

nasm -felf64 example.asm -o example.o && gcc example.o test_example.c -o test_example && ./test_example

Expected Output Examples

calculator output:

10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2

25 + 75 = 100
100 - 45 = 55
7 * 8 = 56
17 / 5 = 3

array_ops output:

Array: 10 20 30 40 50 60 70 80 90 100 

Sum:     550
Maximum: 100
Minimum: 10
Average: 55

utils output:

Power:
  2^3 = 8 (expected 8)
  2^10 = 1024 (expected 1024)

Absolute Value:
  abs(-42) = 42 (expected 42)
  abs(42) = 42 (expected 42)

Sign:
  sign(-5) = -1 (expected -1)
  sign(0) = 0 (expected 0)
  sign(5) = 1 (expected 1)

Even Check:
  is_even(4) = 1 (expected 1)
  is_even(7) = 0 (expected 0)

Power of Two:
  is_power_of_two(16) = 1 (expected 1)
  is_power_of_two(17) = 0 (expected 0)
  is_power_of_two(1024) = 1 (expected 1)

Tips for Running

  1. On Windows: Use NASM and GCC from MinGW or WSL
  2. On Linux: Install nasm and gcc via package manager
  3. On macOS: Use HomeBrew: brew install nasm
  4. Test incrementally: Start with simple functions before complex ones
  5. Use GDB: Debug with gdb ./test_example if things go wrong