Lab 5 - Part 1 - Aarch 64
In this lab, my goal is to dive into assembly programming on both the x86_64 and AArch64 platforms. For Task 1,
1. I will closely examine how the AArch64 assembly source code—written in a human-readable format—is transformed into an object file containing machine code. This investigation will help me understand the assembly process by highlighting the differences between the high-level source instructions and the low-level binary output generated by the assembler.
Source file
Object file
In this task, I need to adapt the assembly code on the aarch64 server so that it outputs the word “Loop” exactly six times. Starting with the provided code, I will introduce a counter in one of the general-purpose registers, initialize it to zero, and increment it after each print. Once the counter reaches six, the loop will terminate. This requires adjusting the assembly instructions to compare the loop counter against a maximum value, calling the appropriate syscall for printing “Loop” during each iteration, and finally exiting the program when the loop completes its sixth print.
.text .globl _start min = 0 /* constant representing the initial loop counter */ max = 6 /* loop terminates once this value is reached */ _start: mov x19, min /* load the starting counter into register x19 */ loop: /* print "Loop\n" to stdout */ mov x0, 1 /* set file descriptor to stdout (1) */ adr x1, msg /* place the address of the string msg into x1 */ mov x2, len /* specify the length of the message in x2 */ mov x8, 64 /* syscall number for write is 64 */ svc 0 /* invoke the write syscall */ add x19, x19, 1 /* increment the loop counter */ cmp x19, max /* compare current counter to max */ b.ne loop /* if not equal, continue looping */ /* exit the program */ mov x0, 0 /* set exit status to 0 */ mov x8, 93 /* syscall number for exit is 93 */ svc 0 /* invoke the exit syscall */ .data msg: .ascii "Loop\n" /* message to be printed each iteration */ len = . - msg /* calculate the length of msg */
output:

3: Update the code so that it displays the current loop iteration alongside the word "Loop." For example, the output should be "Loop: 1", "Loop: 2", and so on. To achieve this, add an extra variable (e.g., num) in the .data section, update its value during each iteration, and print it along with the base message.
3: Update the code so that it displays the current loop iteration alongside the word "Loop." For example, the output should be "Loop: 1", "Loop: 2", and so on. To achieve this, add an extra variable (e.g., num) in the .data section, update its value during each iteration, and print it along with the base message.
.text .globl _start min = 0 /* Define the initial counter value (a constant) */ max = 6 /* Set the maximum counter value; the loop continues while counter < max */ start: mov x19, min /* Load the initial counter into register x19 */ adr x21, num /* Get the address of the 'num' variable into register x21 */ loop: /* Print the base message "Loop: " */ mov x0, 1 /* File descriptor 1 (stdout) */ adr x1, msg /* Load the address of the message string into x1 */ mov x2, len1 /* Load the length of the message into x2 */ mov x8, 64 /* Syscall number for write is 64 */ svc 0 /* Execute the write syscall */ /* Print the current iteration number */ mov x0, 1 /* File descriptor 1 (stdout) */ adr x1, num /* Load the address of the number buffer into x1 */ mov x2, len2 /* Load the length of the number buffer into x2 */ mov x8, 64 /* Syscall number for write is 64 */ svc 0 /* Execute the write syscall */ add w19, w19, 1 /* Increment the loop counter in w19 */ /* Update the 'num' value with the new iteration count */ mov w20, w19 /* Copy the counter value from w19 to w20 */ add w20, w20, 48 /* Convert the numeric value to its ASCII code by adding 48 */ strb w20, [x21] /* Store the resulting ASCII character into memory at the address in x21 */ cmp x19, max /* Compare the current counter with the maximum value */ b.ne loop /* If the counter hasn't reached max, jump back to the loop label */ /* Exit the program */ mov x0, 0 /* Set the exit status to 0 */ mov x8, 93 /* Syscall number for exit is 93 */ svc 0 /* Execute the exit syscall */ .data msg: .ascii "Loop: " /* Base message printed before the iteration number */ len1 = . - msg /* Compute the length of the msg string */ num: .ascii "0 \n" /* Buffer to display the iteration number followed by a newline */ len2 = . - num /* Compute the length of the num buffer */
output:

4: Extend the code to loop from 00 to 32. I considered two approaches for this task. One option was to extract the tens and units digits by dividing the loop counter in each iteration, but that method felt tedious and inefficient. Instead, I chose a different strategy—storing the ASCII values for each digit directly in registers—so that the two-digit output is updated without performing division every time.
4: Extend the code to loop from 00 to 32. I considered two approaches for this task. One option was to extract the tens and units digits by dividing the loop counter in each iteration, but that method felt tedious and inefficient. Instead, I chose a different strategy—storing the ASCII values for each digit directly in registers—so that the two-digit output is updated without performing division every time.
.text .globl _start min = 0 /* initial value for the loop counter (defined as a constant symbol) */ max = 33 /* loop will terminate once the counter reaches this value (i.e., when counter < max fails) */ _start: mov x19, min /* load the initial counter value into register x19 */ adr x22, num /* retrieve the memory address of the 'num' buffer (first digit) into x22 */ add x23, x22, 1 /* calculate the address for the second digit by adding 1 to x22, store it in x23 */ mov w21, 48 /* initialize the tens digit with ASCII '0' (48) in register w21 */ mov w20, 48 /* initialize the units digit with ASCII '0' (48) in register w20 */ loop: /* Output the base string "Loop: " */ mov x0, 1 /* set file descriptor to stdout (1) in x0 */ adr x1, msg /* load the address of the message string into x1 */ mov x2, len1 /* load the length of the message into x2 */ mov x8, 64 /* set the syscall number for write (64) in x8 */ svc 0 /* invoke the write syscall to print the message */ /* Output the current two-digit iteration number */ mov x0, 1 /* set file descriptor to stdout (1) */ adr x1, num /* load the address of the number buffer into x1 */ mov x2, len2 /* load the length of the number buffer into x2 */ mov x8, 64 /* set the syscall number for write (64) */ svc 0 /* invoke the write syscall to print the number */ add x19, x19, 1 /* increment the loop counter in x19 */ add w20, w20, 1 /* increment the ASCII value for the units digit in w20 */ cmp w20, 58 /* compare the units digit against ASCII 58 (i.e., value just after '9') */ b.lt update /* if units digit is less than 58, skip tens digit adjustment */ /* Adjust the tens digit when the units digit surpasses '9' */ add w21, w21, 1 /* increment the tens digit in w21 */ strb w21, [x22] /* store the updated tens digit at the memory address in x22 */ mov w20, 48 /* reset the units digit back to ASCII '0' (48) */ /* Write the current units digit to the number buffer */ update: strb w20, [x23] /* store the current units digit at the memory address in x23 */ cmp x19, max /* compare the current counter with the maximum limit */ b.ne loop /* if the counter is not equal to max, continue the loop */ /* Exit the program */ mov x0, 0 /* set exit status to 0 in x0 */ mov x8, 93 /* load the exit syscall number (93) into x8 */ svc 0 /* invoke the exit syscall to terminate the program */ .data msg: .ascii "Loop: " /* string literal for the prompt to be printed */ len1 = . - msg /* compute the length of the message string */ num: .ascii "00\n" /* buffer for displaying a two-digit number followed by a newline */ len2 = . - num /* compute the length of the number buffer */
output:

5: Adapt the code to eliminate the leading zero. My approach involves using a register to hold the memory address that is updated during each iteration, incrementing this pointer as needed. When the loop counter first reaches 10, the code will adjust the memory address to point to the next digit, thereby removing the unnecessary leading zero from the output.
5: Adapt the code to eliminate the leading zero. My approach involves using a register to hold the memory address that is updated during each iteration, incrementing this pointer as needed. When the loop counter first reaches 10, the code will adjust the memory address to point to the next digit, thereby removing the unnecessary leading zero from the output.
.text
.globl _start
min = 0 /* Define the starting value for the loop counter (a constant) */
max = 33 /* The loop will terminate when the counter reaches 33 */
_start:
mov x19, min /* Initialize the loop counter (x19) with the starting value */
adr x22, num /* Load the memory address of the 'num' buffer (for the tens digit) into x22 */
adr x23, num /* Set x23 to point to the 'num' buffer; this pointer will be updated as the loop progresses */
mov w21, 48 /* Set the initial ASCII value for the tens digit to '0' (ASCII 48) in w21 */
mov w20, 48 /* Set the initial ASCII value for the units digit to '0' (ASCII 48) in w20 */
loop:
/* Output the static message "Loop: " */
mov x0, 1 /* Specify stdout (file descriptor 1) in x0 */
adr x1, msg /* Load the address of the message string into x1 */
mov x2, len1 /* Place the length of the message in x2 */
mov x8, 64 /* Specify the write syscall number (64) in x8 */
svc 0 /* Invoke the syscall to print the message */
/* Output the current iteration number from the 'num' buffer */
mov x0, 1 /* Set stdout (file descriptor 1) for output */
adr x1, num /* Load the address of the number buffer into x1 */
mov x2, len2 /* Set x2 to the length of the number string */
mov x8, 64 /* Specify the write syscall number (64) in x8 */
svc 0 /* Invoke the syscall to print the number */
add x19, x19, 1 /* Increment the loop counter (x19) by 1 */
add w20, w20, 1 /* Increment the units digit's ASCII value in w20 by 1 */
cmp x19, 10 /* Compare the loop counter with 10 */
b.ne checkten /* If x19 is not 10, branch to 'checkten' */
/* When the counter first reaches 10: adjust the pointer for the next digit */
add x23, x22, 1 /* Update x23 to point to the next byte after x22 */
mov w20, 58 /* Set the units digit to 58 as a trigger (indicating reset is needed) */
mov w21, 48 /* Reset the tens digit to ASCII '0' in w21 */
checkten:
cmp w20, 58 /* Compare the units digit with 58 (ASCII value just above '9') */
b.lt update /* If less than 58, skip tens digit adjustment */
/* If the units digit exceeds '9', update the tens digit */
add w21, w21, 1 /* Increment the tens digit in w21 */
strb w21, [x22] /* Store the updated tens digit into the memory location pointed to by x22 */
mov w20, 48 /* Reset the units digit back to '0' (ASCII 48) */
update:
strb w20, [x23] /* Save the current units digit into the memory location at x23 */
cmp x19, max /* Compare the current loop counter with the maximum limit */
b.ne loop /* If the counter is less than max, repeat the loop */
/* Terminate the program */
mov x0, 0 /* Set the exit code to 0 in x0 */
mov x8, 93 /* Load the exit syscall number (93) into x8 */
svc 0 /* Invoke the exit syscall to end the program */
.data
msg: .ascii "Loop: " /* The static message to display before the iteration number */
len1 = . - msg /* Compute the length of the 'msg' string */
num: .ascii "0 \n" /* Buffer for the iteration number (initially "0", a space, and a newline) */
len2 = . - num /* Compute the length of the 'num' buffer */
output:

6: Adapt the code to display the output in hexadecimal (ranging from 0 to 20) rather than decimal (0 to 32). This modification is relatively simple—I only need to update the comparison values before the branch instructions and incorporate an extra step that adjusts the ASCII value in the register to "A" (ASCII 65) whenever it reaches 58.
6: Adapt the code to display the output in hexadecimal (ranging from 0 to 20) rather than decimal (0 to 32). This modification is relatively simple—I only need to update the comparison values before the branch instructions and incorporate an extra step that adjusts the ASCII value in the register to "A" (ASCII 65) whenever it reaches 58.
.text
.globl _start
min = 0 /* Set the initial value of the loop counter (constant) */
max = 33 /* Define the maximum loop counter value; the loop runs while counter < max */
_start:
mov x19, min /* Load the starting counter value into register x19 */
adr x22, num /* Obtain the address of the 'num' buffer (for tens digit) in x22 */
adr x23, num /* Set x23 to point to the 'num' buffer; this pointer will be updated for the units digit */
mov w21, 48 /* Initialize the tens digit to ASCII '0' (48) in register w21 */
mov w20, 48 /* Initialize the units digit to ASCII '0' (48) in register w20 */
loop:
/* Print the prompt "Loop: " */
mov x0, 1 /* Specify stdout (file descriptor 1) in x0 */
adr x1, msg /* Load the address of the message string into x1 */
mov x2, len1 /* Set x2 with the length of the message */
mov x8, 64 /* Load the write syscall number (64) into x8 */
svc 0 /* Invoke the syscall to output the message */
/* Print the current iteration number stored in the 'num' buffer */
mov x0, 1 /* Set stdout (file descriptor 1) in x0 */
adr x1, num /* Load the address of the number buffer into x1 */
mov x2, len2 /* Set x2 with the length of the number buffer */
mov x8, 64 /* Load the write syscall number (64) into x8 */
svc 0 /* Invoke the syscall to output the number */
add x19, x19, 1 /* Increment the loop counter (x19) by 1 */
add w20, w20, 1 /* Increase the units digit's ASCII value in w20 by 1 */
cmp w20, 58 /* Compare the units digit with ASCII value 58 (just after '9') */
b.ne chknewdg /* If w20 is less than 58, jump to label chknewdg */
add w20, w20, 7 /* Otherwise, add 7 to adjust w20 for hexadecimal conversion */
chknewdg:
cmp x19, 16 /* Check if the loop counter has reached 16 */
b.ne check16 /* If not, branch to check16 */
/* When the counter first reaches 16, update the pointer for the units digit */
add x23, x22, 1 /* Adjust x23 to point to the next byte after x22 */
mov w20, 71 /* Set w20 to 71 (the trigger value for hex conversion) */
mov w21, 48 /* Reset the tens digit to ASCII '0' (48) */
check16:
cmp w20, 71 /* Compare the units digit with 71 */
b.lt update /* If w20 is less than 71, branch to update */
/* If the units digit is not less than 71, update the tens digit */
add w21, w21, 1 /* Increment the tens digit stored in w21 */
strb w21, [x22] /* Store the updated tens digit into memory at address x22 */
mov w20, 48 /* Reset the units digit to ASCII '0' (48) */
update:
strb w20, [x23] /* Save the current units digit into memory at address x23 */
cmp x19, max /* Compare the current loop counter with the maximum limit */
b.ne loop /* If counter is less than max, repeat the loop */
/* Exit the program */
mov x0, 0 /* Set the exit status to 0 in x0 */
mov x8, 93 /* Load the exit syscall number (93) into x8 */
svc 0 /* Invoke the exit syscall to terminate the program */
.data
msg: .ascii "Loop: " /* Message to print before the iteration number */
len1 = . - msg /* Calculate the length of the msg string */
num: .ascii "0 \n" /* Buffer for the iteration number (initially "0", space, newline) */
len2 = . - num /* Calculate the length of the num buffer */
Comments
Post a Comment