Lab 5 64-Bit Assembly Language
Lab 5 - 64-Bit Assembly Language
Introduction
In this post, I’ll go through my experiments with x86_64 assembly language. I’ll walk through each code example, explain what it does in simple terms, and show what kind of output you should expect. It’s all about understanding how loops work at the assembly level and figuring out how to output messages using system calls.
Let’s dive in and break things down step by step!
Basic Loop in Assembly
Let’s start with a simple loop. This loop doesn’t do anything yet — it just counts from 0 to 4:
.text
.globl _start
min = 0
max = 5
_start:
mov $min, %r15 # Start loop index at 0
loop:
# (Nothing here yet)
inc %r15 # Increment index
cmp $max, %r15 # Compare index to max (5)
jne loop # If not equal, keep looping
# Exit
mov $0, %rdi
mov $60, %rax
syscall
Print "Loop" Each Time
We modify the loop to print the word "Loop" every time it runs:
.text
.globl _start
min = 0
max = 5
_start:
mov $min, %r15
loop:
mov $len, %rdx # Length of the message
mov $msg, %rsi # Message location
mov $1, %rdi # STDOUT
mov $1, %rax # sys_write
syscall
inc %r15
cmp $max, %r15
jne loop
mov $0, %rdi
mov $60, %rax
syscall
.section .data
msg: .ascii "Loop\n"
len = . - msg
Output:
Loop
Loop
Loop
Loop
Loop
Print "Loop" with Number
Here we print Loop: 0, Loop: 1, etc.
.text
.globl _start
min = 0
max = 6
_start:
mov $min, %r15
loop:
# Print "Loop: "
mov $len, %rdx
mov $msg, %rsi
mov $1, %rdi
mov $1, %rax
syscall
# Print number (single digit)
lea buffer(%rip), %r9
mov %r15, %r8
add $48, %r8 # Convert to ASCII
movb %r8b, (%r9)
add $1, %r9
movb $10, (%r9) # Newline
mov $2, %rdx
mov $buffer, %rsi
mov $1, %rdi
mov $1, %rax
syscall
inc %r15
cmp $max, %r15
jne loop
mov $0, %rdi
mov $60, %rax
syscall
.section .data
msg: .ascii "Loop: "
len = . - msg
buffer: .space 2
Output:
Loop: 0
Loop: 1
Loop: 2
Loop: 3
Loop: 4
Loop: 5
Show 2 Digits (00–32)
This one prints numbers in two digits like 00, 01, ..., 32:
.text
.globl _start
min = 0
max = 33
_start:
mov $min, %r15
loop:
mov $len, %rdx
mov $msg, %rsi
mov $1, %rdi
mov $1, %rax
syscall
lea buffer(%rip), %r9
mov %r15, %rax
xor %rdx, %rdx
mov $10, %r11
div %r11 # Divide by 10
mov %rax, %r8 # Tens
mov %rdx, %r10 # Ones
add $48, %r8
movb %r8b, (%r9)
add $1, %r9
add $48, %r10
movb %r10b, (%r9)
add $1, %r9
movb $10, (%r9)
mov $3, %rdx
mov $buffer, %rsi
mov $1, %rdi
mov $1, %rax
syscall
inc %r15
cmp $max, %r15
jne loop
mov $0, %rdi
mov $60, %rax
syscall
.section .data
msg: .ascii "Loop: "
len = . - msg
buffer: .space 3
Output:
Loop: 00
Loop: 01
Loop: 02
...
Loop: 31
Loop: 32
Skip Leading Zero for Single Digit
Now, we skip the leading 0 for numbers < 10, so it looks like 0, 1, ..., 9, then 10, etc.
# (Same as above, but skips tens digit if it's 0)
cmp $0, %r8
je units_digit
Output:
Loop: 0
Loop: 1
...
Loop: 9
Loop: 10
...
Loop: 32
Print in Hexadecimal
Finally, we print loop numbers in hexadecimal (0, 1, 2, ..., A, B, C, ..., 1F):
mov $16, %r11 # Use base 16
cmp $58, %r10 # If > 9, convert to A–F using ASCII offset
Output:
Loop: 0
Loop: 1
...
Loop: 9
Loop: A
Loop: B
...
Loop: 1F
Reflection
Assembly programming is still very hard for me. Even simple tasks like printing a number require a lot of manual steps, moving data into registers, converting integers to ASCII, and managing buffers. Unlike high-level languages, nothing is abstracted. I had to slowly work through each instruction and understand what it does. While it's challenging, it's also satisfying when it works. This lab definitely gave me more respect for low-level development!
Comments
Post a Comment