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




2: Constructing a Loop That Prints “Loop” Six Times
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.


.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.

.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.

.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.

.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 */
output:

Comments

Popular posts from this blog

Lab 2 - Lab Results

Project Stage 1