Fully functional programs you can assemble, compile, and run.
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
RETtest_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
./calcFunctions 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
RETtest_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;
}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
RETtest_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;
}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
RETtest_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;
}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]
RETtest_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;
}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_exampleOr in one command:
nasm -felf64 example.asm -o example.o && gcc example.o test_example.c -o test_example && ./test_examplecalculator 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)
- On Windows: Use NASM and GCC from MinGW or WSL
- On Linux: Install
nasmandgccvia package manager - On macOS: Use HomeBrew:
brew install nasm - Test incrementally: Start with simple functions before complex ones
- Use GDB: Debug with
gdb ./test_exampleif things go wrong