(Lab5) 64-Bit Assembly Language Lab
In this lab, you will experiment with assembler on the x86_64 and aarch64 platforms.
Get Code Examples:
Change the code as needed to suppress the leading zero:
The code examples for this lab are available in the file
/public/spo600-assembler-lab-examples.tgz
on each of the SPO600 Servers.Reminder: to unpack a tar archive (
.tar
, .tar.gz
, .tgz
, or similar file), use the tar
command with the x
(extract) and f
(archive filename) options; the v
(verbose) option is also recommended: cd ~ ; tar xvf /public/spo600-assembler-lab-examples.tgz
Get Code Examples:
AARCH64
we will see "spo600" folder after commands:
cd ~ ;
tar xvf /public/spo600-assembler-lab-examples.tgz

Investigation:
Here is a basic loop in AArch64 assembler - this loops from 0 to 5, using r19 as the index (loop control) counter:
run result:
run result:
Extend the AArch64 code to loop from 00-32, printing each value as a 2-digit decimal number.
run result:
Make a copy of the code and change it to output in hexadecimal (0-20) instead of decimal (0-32):
run result:
Optional Challenge
Write a program in aarch64 assembly language to print the times tables from 1-12 (“1 x 1 = 1” through “12 x 12 = 144”). Add a spacer between each table, and use a function/subroutine to format the numbers with leading-zero suppression.
run result:
we will see "spo600" folder after commands:
cd ~ ;
tar xvf /public/spo600-assembler-lab-examples.tgz
Investigation:
disassembly of the compiled hello binary, revealing its low-level machine instructions generated from hello.c:
Create a loop.s for the loop
Compile hello.c to Assembly using gcc -S:
cat hello.s:
cat hello.s:
Here is a basic loop in AArch64 assembler - this loops from 0 to 5, using r19 as the index (loop control) counter:
.text .globl _start min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */ max = 6 /* loop exits when the index hits this number (loop condition is i<max) */ _start: mov x19, min loop: /* ... body of the loop ... do something useful here ... */ add x19, x19, 1 /* increment the loop counter */ cmp x19, max /* see if we've hit the max */ b.ne loop /* if not, then continue the loop */ mov x0, 0 /* set exit status to 0 */ mov x8, 93 /* exit is syscall #93 */ svc 0 /* invoke syscall */
nano loop.s:
modify the code above to print "loop" 6 times:
.text
.globl _start
min = 0
max = 6
_start:
mov x19, min
loop:
// Print "Loop\n"
ldr x0, =1 // fd=1 (stdout)
ldr x1, =msg // message address
ldr x2, =len // message length
mov x8, 64 // syscall number (write)
svc 0
add x19, x19, 1 // i++
cmp x19, max
b.ne loop
// Exit
mov x0, 0
mov x8, 93
svc 0
msg: .asciz "Loop\n"
len = . - msg
run result:
Add Loop Index (0 to 5):
.text
.globl _start // Declare global entry point
// Constants (symbolic names)
min = 0 // Loop starting value (0)
max = 6 // Loop end condition (loop will run while x19 < max)
_start:
// ---------------------------
// Initialize loop counter
// ---------------------------
mov x19, min // Initialize x19 as loop counter with value 0
loop:
// ---------------------------
// Print "Loop: " prefix
// ---------------------------
mov x0, 1 // File descriptor 1 = stdout
adr x1, loop_msg // Load address of "Loop: "
mov x2, 6 // Length of "Loop: " (6 bytes)
mov x8, 64 // Syscall number for write()
svc 0 // Invoke syscall to write "Loop: " to stdout
// ---------------------------
// Convert loop index to ASCII character and print
// ---------------------------
mov w20, w19 // Move loop counter (x19) into w20 (32-bit register)
add w20, w20, 48 // Convert integer to ASCII ('0' = 48), now w20 holds ASCII code of digit
// Prepare string "0 \n" (template) for output
mov x0, 1 // File descriptor 1 = stdout
adr x1, int_str // Load address of "0 \n" string template
mov x2, 4 // Length of string "0 \n" (4 bytes, includes newline and space)
mov x8, 64 // Syscall number for write()
strb w20, [x1] // Store ASCII digit character in first byte of int_str
svc 0 // Invoke syscall to write digit and newline to stdout
// ---------------------------
// Increment loop counter and check loop condition
// ---------------------------
add x19, x19, 1 // Increment loop counter x19++
cmp x19, max // Compare x19 to max (6)
b.ne loop // If x19 != max, repeat loop
// ---------------------------
// Exit program
// ---------------------------
mov x0, 0 // Return status code 0 (success)
mov x8, 93 // Syscall number for exit()
svc 0 // Invoke syscall to exit
// ---------------------------
// Data Section (Strings)
// ---------------------------
.data
loop_msg:
.asciz "Loop: " // Null-terminated string "Loop: "
int_str:
.ascii "0 \n" // Template for digit with newline, will replace '0' each iteration
.text
.globl _start
// ----------------------------------------
// Constants for loop boundaries
// ----------------------------------------
min = 0 // Loop start index (0)
max = 33 // Loop runs until x19 == 33 (prints 0 to 32)
// ----------------------------------------
// Entry point of the program
// ----------------------------------------
_start:
mov x19, min // Initialize loop counter (x19 = 0)
loop:
// ----------------------------------------
// Print static message "Loop: "
// ----------------------------------------
mov x0, 1 // File descriptor: 1 (stdout)
adr x1, msg // Address of message "Loop: "
mov x2, len // Length of message
mov x8, 64 // Syscall number for write()
svc 0 // Make syscall to print "Loop: "
// ----------------------------------------
// Convert loop counter (x19) into two ASCII digits
// and store in buffer for printing
// ----------------------------------------
adr x5, buffer // Load buffer address into x5
mov x3, x19 // Copy loop counter to x3 for processing
mov x4, 10 // Constant value 10 for division (decimal system)
udiv x6, x3, x4 // x6 = x3 / 10 (tens digit)
msub x7, x6, x4, x3 // x7 = x3 - (x6 * 10) (units digit, remainder)
// Convert tens digit to ASCII
add x6, x6, 48 // '0' in ASCII is 48, so this converts digit to character
strb w6, [x5] // Store tens digit character into buffer
add x5, x5, 1 // Move buffer pointer to next byte
// Convert units digit to ASCII
add x7, x7, 48 // Convert units digit to ASCII character
strb w7, [x5] // Store units digit character into buffer
add x5, x5, 1 // Move buffer pointer to next byte
// Append newline character
mov x3, 10 // ASCII code for newline '\n' is 10
strb w3, [x5] // Store newline character in buffer
// ----------------------------------------
// Print the buffer containing number and newline
// ----------------------------------------
mov x0, 1 // File descriptor: 1 (stdout)
adr x1, buffer // Address of buffer
mov x2, 3 // Length of buffer (2 digits + '\n')
mov x8, 64 // Syscall number for write()
svc 0 // Make syscall to print the number and newline
// ----------------------------------------
// Loop control: increment and check limit
// ----------------------------------------
add x19, x19, 1 // Increment loop counter
cmp x19, max // Compare counter to max (33)
b.ne loop // If counter != max, continue loop
// ----------------------------------------
// Exit program
// ----------------------------------------
mov x0, 0 // Exit status 0
mov x8, 93 // Syscall number for exit()
svc 0 // Make syscall to exit
// ----------------------------------------
// Data Section
// ----------------------------------------
.data
msg:
.ascii "Loop: " // Static message to be printed before number
len = . - msg // Calculate length of message automatically
buffer:
.space 3 // Buffer to store two ASCII digits and newline
.text
.globl _start
// -----------------------------
// Constants for loop range
// -----------------------------
min = 0 // Loop start index (0)
max = 33 // Loop will exit when x19 == 33 (loop condition: i < 33)
// -----------------------------
// Program entry point
// -----------------------------
_start:
mov x19, min // Initialize loop counter (x19 = 0)
loop:
// -----------------------------
// Step 1: Print "Loop: "
// -----------------------------
mov x0, 1 // File descriptor: 1 (stdout)
adr x1, msg // Address of static message "Loop: "
mov x2, len // Length of message "Loop: "
mov x8, 64 // Syscall number for write
svc 0 // System call to print message
// -----------------------------
// Step 2: Prepare to convert loop counter to ASCII digits
// -----------------------------
adr x5, buffer // Load address of buffer into x5 (to store digits + newline)
mov x3, x19 // Copy loop counter to x3 for division
mov x4, 10 // Set divisor to 10 for decimal division
udiv x6, x3, x4 // Divide: x6 = x3 / 10 (tens digit)
msub x7, x6, x4, x3 // Modulo: x7 = x3 - x6 * 10 (units digit)
// -----------------------------
// Step 3: Conditional print of tens digit (skip leading zero)
// -----------------------------
cmp x6, 0 // Compare tens digit with 0
b.eq units_digit // If zero, skip printing tens digit (jump to units digit)
add x6, x6, 48 // Convert tens digit to ASCII ('0' = 48)
strb w6, [x5] // Store ASCII character of tens digit in buffer
add x5, x5, 1 // Move to next buffer position
// -----------------------------
// Step 4: Always print units digit
// -----------------------------
units_digit:
add x7, x7, 48 // Convert units digit to ASCII
strb w7, [x5] // Store ASCII character of units digit in buffer
add x5, x5, 1 // Move to next buffer position
// -----------------------------
// Step 5: Add newline character
// -----------------------------
mov x3, 10 // ASCII value for newline '\n' is 10
strb w3, [x5] // Store newline character in buffer
// -----------------------------
// Step 6: Print buffer (number + newline)
// -----------------------------
mov x0, 1 // File descriptor: 1 (stdout)
adr x1, buffer // Address of buffer containing digits + newline
mov x2, 3 // Max length of buffer (two digits + newline)
mov x8, 64 // Syscall number for write
svc 0 // System call to print number
// -----------------------------
// Step 7: Loop control
// -----------------------------
add x19, x19, 1 // Increment loop counter
cmp x19, max // Compare loop counter to max (33)
b.ne loop // If not equal, repeat the loop
// -----------------------------
// Step 8: Exit program
// -----------------------------
mov x0, 0 // Exit code 0 (success)
mov x8, 93 // Syscall number for exit
svc 0 // System call to terminate program
// -----------------------------
// Data Section
// -----------------------------
.data
msg:
.ascii "Loop: " // Static message printed before each number
len = . - msg // Compute length of "Loop: " dynamically
buffer:
.space 3 // Allocate 3 bytes for buffer (two digits + newline)
run result:
.text
.globl _start
// -----------------------------
// Constants for loop range
// -----------------------------
min = 0 // Loop start index (0)
max = 33 // Loop will stop when x19 == 33 (loop condition: i < 33)
// -----------------------------
// Program entry point
// -----------------------------
_start:
mov x19, min // Initialize loop counter (x19 = 0)
loop:
// -----------------------------
// Step 1: Print static message "Loop: "
// -----------------------------
mov x0, 1 // File descriptor: 1 (stdout)
adr x1, msg // Address of static message "Loop: "
mov x2, len // Length of message "Loop: "
mov x8, 64 // Syscall number for write
svc 0 // System call to print "Loop: "
// -----------------------------
// Step 2: Prepare to convert loop index into hexadecimal representation
// -----------------------------
adr x5, buffer // Address of buffer to store digits and newline
mov x3, x19 // Copy loop index into x3 for division
mov x4, 16 // Set divisor as 16 for hexadecimal conversion
udiv x6, x3, x4 // x6 = x3 / 16 (higher digit)
msub x7, x6, x4, x3 // x7 = x3 - (x6 * 16) = x3 % 16 (lower digit)
// -----------------------------
// Step 3: Conditionally print the higher digit if non-zero (avoid leading zero)
// -----------------------------
cmp x6, 0 // Check if higher digit is zero
b.eq units_digit // If zero, skip printing higher digit (jump to units digit)
add x6, x6, 48 // Convert digit to ASCII ('0' = 48)
cmp x6, 58 // If >= 58, it represents 'A'-'F'
b.lt store_high_digit // If less than 58, it's 0-9; store as is
add x6, x6, 7 // If >= 58, adjust for 'A'-'F' by adding 7
store_high_digit:
strb w6, [x5] // Store ASCII character of higher digit in buffer
add x5, x5, 1 // Move buffer pointer forward
// -----------------------------
// Step 4: Always print lower digit
// -----------------------------
units_digit:
add x7, x7, 48 // Convert lower digit to ASCII
cmp x7, 58 // If >= 58, it represents 'A'-'F'
b.lt store_low_digit // If less than 58, it's 0-9; store as is
add x7, x7, 7 // If >= 58, adjust for 'A'-'F' by adding 7
store_low_digit:
strb w7, [x5] // Store ASCII character of lower digit in buffer
add x5, x5, 1 // Move buffer pointer forward
// -----------------------------
// Step 5: Add newline character
// -----------------------------
mov x3, 10 // ASCII code for newline '\n'
strb w3, [x5] // Store newline character in buffer
// -----------------------------
// Step 6: Print buffer (digits + newline)
// -----------------------------
mov x0, 1 // File descriptor: 1 (stdout)
adr x1, buffer // Address of buffer
mov x2, 3 // Length of buffer (max 2 digits + newline)
mov x8, 64 // Syscall number for write
svc 0 // System call to print buffer
// -----------------------------
// Step 7: Loop control
// -----------------------------
add x19, x19, 1 // Increment loop counter
cmp x19, max // Compare counter with max
b.ne loop // If not equal, continue looping
// -----------------------------
// Step 8: Exit program
// -----------------------------
mov x0, 0 // Return code 0
mov x8, 93 // Syscall number for exit
svc 0 // Exit syscall
// -----------------------------
// Data Section
// -----------------------------
.data
msg:
.ascii "Loop: " // Static message "Loop: "
len = . - msg // Length of message
buffer:
.space 3 // Space for 2 digits and newline
Optional Challenge
Write a program in aarch64 assembly language to print the times tables from 1-12 (“1 x 1 = 1” through “12 x 12 = 144”). Add a spacer between each table, and use a function/subroutine to format the numbers with leading-zero suppression.
I tried using two loops but couldn't get it to display the correct format, pending completion..........
perform the same process as above:
X68-001
modify the code print "loop" 6 times and index:
.text
.global _start
min = 0
max = 6
_start:
mov $min, %r15 # loop index
loop:
# Print "Loop: "
mov $len, %rdx # message length
mov $msg, %rsi # message location
mov $1, %rdi # file descriptor stdout
mov $1, %rax # syscall sys_write
syscall
# Load buffer address
lea buffer(%rip), %r9
mov %r15, %r8 # copy loop index to r8
add $48, %r8 # convert to ASCII
movb %r8b, (%r9) # store character
add $1, %r9
movb $10, (%r9) # newline
# Print buffer
mov $2, %rdx
mov $buffer, %rsi
mov $1, %rdi
mov $1, %rax
syscall
inc %r15
cmp $max, %r15
jne loop
# Exit
mov $0, %rdi
mov $60, %rax
syscall
.data
msg: .ascii "Loop: "
len = . - msg
buffer: .space 2 # reserve space for one digit and newline
run result:
Extend the AArch64 code to loop from 00-32, printing each value as a 2-digit decimal number:
.text
.globl _start
min = 0 /* Starting value for loop index */
max = 33 /* Loop will run until index reaches 33 */
_start:
mov $min, %r15 /* Initialize loop index (counter) in %r15 */
loop:
/* ========== Print "Loop: " ========== */
mov $len, %rdx /* Message length of "Loop: " */
mov $msg, %rsi /* Address of the message */
mov $1, %rdi /* File descriptor: 1 for stdout */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Perform write syscall to output "Loop: " */
/* ========== Prepare number output ========== */
lea buffer(%rip), %r9 /* Load address of buffer into %r9 */
/* Divide loop index by 10 to get tens and units digits */
mov %r15, %rax /* Copy loop index into %rax (dividend) */
xor %rdx, %rdx /* Clear %rdx (high 64 bits of dividend) for division */
mov $10, %r11 /* Divisor: 10 */
div %r11 /* Unsigned divide RDX:RAX by 10; quotient in RAX, remainder in RDX */
mov %rax, %r8 /* Store quotient (tens digit) into %r8 */
mov %rdx, %r10 /* Store remainder (units digit) into %r10 */
/* Convert digits to ASCII characters */
add $48, %r8 /* Convert tens digit to ASCII */
movb %r8b, (%r9) /* Store ASCII character of tens digit into buffer */
add $1, %r9 /* Advance buffer pointer */
add $48, %r10 /* Convert units digit to ASCII */
movb %r10b, (%r9) /* Store ASCII character of units digit into buffer */
add $1, %r9 /* Advance buffer pointer */
/* Add newline character */
movb $10, (%r9) /* ASCII newline character */
/* ========== Print the number and newline ========== */
mov $3, %rdx /* Total length of number output: 2 digits + newline */
mov $buffer, %rsi /* Address of buffer */
mov $1, %rdi /* File descriptor: 1 for stdout */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Perform write syscall to output the digits and newline */
/* ========== End of loop body ========== */
inc %r15 /* Increment loop index */
cmp $max, %r15 /* Compare index with max */
jne loop /* If index != max, continue loop */
/* ========== Exit program ========== */
mov $0, %rdi /* Exit status 0 */
mov $60, %rax /* Syscall number for exit */
syscall /* Perform exit syscall */
.section .data
msg: .ascii "Loop: " /* Message "Loop: " to print before number */
len= .-msg /* Calculate length of msg dynamically */
buffer: .space 3 /* Buffer to hold 2-digit number and newline */
run result:
Change the code as needed to suppress the leading zero:
.text
.globl _start
min = 0 /* Starting value for loop index */
max = 33 /* Loop runs from min to max inclusive */
_start:
mov $min, %r15 /* Initialize loop counter in %r15 */
loop:
/* ============== Print "Loop: " ============== */
mov $len, %rdx /* Length of the message "Loop: " */
mov $msg, %rsi /* Address of "Loop: " */
mov $1, %rdi /* File descriptor: 1 (stdout) */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Call kernel to write "Loop: " */
/* ============== Prepare to print loop index (number) ============== */
lea buffer(%rip), %r9 /* Load address of output buffer into %r9 */
/* Split %r15 (loop index) into tens and units digits */
mov %r15, %rax /* Copy loop index into %rax as dividend */
xor %rdx, %rdx /* Clear %rdx (needed for division) */
mov $10, %r11 /* Divisor (10) */
div %r11 /* Unsigned divide rdx:rax by 10 */
/* Result: quotient (tens) in %rax, remainder (units) in %rdx */
mov %rax, %r8 /* Store quotient (tens) in %r8 */
mov %rdx, %r10 /* Store remainder (units) in %r10 */
/* ============== Leading zero suppression for tens digit ============== */
cmp $0, %r8 /* Check if tens digit is zero */
je units_digit /* If zero, skip tens digit and print only units */
add $48, %r8 /* Convert tens digit to ASCII */
movb %r8b, (%r9) /* Store tens digit in buffer */
add $1, %r9 /* Move buffer pointer to next byte */
units_digit:
add $48, %r10 /* Convert units digit to ASCII */
movb %r10b, (%r9) /* Store units digit in buffer */
add $1, %r9 /* Move buffer pointer to next byte */
/* ============== Add newline character ============== */
movb $10, (%r9) /* Store newline character (ASCII 10) */
/* ============== Print buffer contents ============== */
mov $3, %rdx /* Length of message: max 3 characters (2 digits + newline) */
mov $buffer, %rsi /* Address of buffer */
mov $1, %rdi /* File descriptor: 1 (stdout) */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Call kernel to write buffer */
/* ============== Loop control ============== */
inc %r15 /* Increment loop index */
cmp $max, %r15 /* Compare index with max value */
jne loop /* If not equal, continue loop */
/* ============== Exit program ============== */
mov $0, %rdi /* Exit code 0 */
mov $60, %rax /* Syscall number for exit */
syscall /* Call kernel to exit */
.section .data
msg: .ascii "Loop: " /* Static message */
len= .-msg /* Length of "Loop: " */
buffer: .space 3 /* Buffer for digits + newline */
run result:
Make a copy of the code and change it to output in hexadecimal (0-20) instead of decimal (0-32):
.text
.globl _start
min = 0 /* Starting value for loop index */
max = 33 /* Loop will iterate from 0 to 33 (decimal), which is 0x21 in hex */
_start:
mov $min, %r15 /* Initialize loop index (counter) to min (0) */
loop:
/* ============================ */
/* Print "Loop: " prefix message */
/* ============================ */
mov $len, %rdx /* Length of message */
mov $msg, %rsi /* Address of message "Loop: " */
mov $1, %rdi /* File descriptor 1 (stdout) */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Call kernel to print "Loop: " */
/* ============================ */
/* Prepare and print loop index */
/* ============================ */
lea buffer(%rip), %r9 /* Load address of buffer into %r9 for storing output characters */
/* Divide the loop index by 16 to get hex digits */
mov %r15, %rax /* Copy loop index to %rax as dividend */
xor %rdx, %rdx /* Clear %rdx (high part for division) */
mov $16, %r11 /* Divisor is 16 for hexadecimal */
div %r11 /* Unsigned divide rdx:rax by 16 */
/* Result: quotient (high digit) in %rax, remainder (low digit) in %rdx */
mov %rax, %r8 /* Store high digit (quotient) in %r8 */
mov %rdx, %r10 /* Store low digit (remainder) in %r10 */
/* ======== Leading Zero Suppression for High Digit ======== */
cmp $0, %r8 /* Check if high digit is zero */
je units_digit /* If zero, skip high digit and go to units digit */
/* Convert high digit to ASCII (0-9, A-F) */
add $48, %r8 /* Add ASCII '0' (48) */
cmp $58, %r8 /* Check if beyond '9' */
jl store_high_digit /* If less than '9', store directly */
add $7, %r8 /* If 'A'-'F', adjust ASCII code */
store_high_digit:
movb %r8b, (%r9) /* Store high digit to buffer */
add $1, %r9 /* Move to next byte */
units_digit:
/* ======== Units Digit (Always Printed) ======== */
add $48, %r10 /* Add ASCII '0' (48) */
cmp $58, %r10 /* Check if beyond '9' */
jl store_units_digit /* If less than '9', store directly */
add $7, %r10 /* If 'A'-'F', adjust ASCII code */
store_units_digit:
movb %r10b, (%r9) /* Store units digit */
add $1, %r9 /* Move to next byte */
/* ======== Add Newline Character ======== */
movb $10, (%r9) /* Store ASCII newline '\n' */
/* ======== Print Buffer ======== */
mov $3, %rdx /* Length: up to 3 bytes (2 digits + newline) */
mov $buffer, %rsi /* Address of buffer */
mov $1, %rdi /* File descriptor 1 (stdout) */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Call kernel to print buffer */
/* ======== Loop Increment & Check ======== */
inc %r15 /* Increment loop index */
cmp $max, %r15 /* Compare with max */
jne loop /* Repeat loop if not equal */
/* ======== Exit Program ======== */
mov $0, %rdi /* Exit code 0 */
mov $60, %rax /* Syscall number for exit */
syscall /* Exit program */
.section .data
msg: .ascii "Loop: " /* Static prefix message */
len= .-msg /* Length of message */
buffer: .space 3 /* Buffer for digits + newline */
run result:
Comments
Post a Comment