Lab 5 : Review the Assembly Code

My objective is to become proficient in assembly programming on the x86_64 and AArch64 platforms in this lab. Regarding Task 1,

1. I'll take a careful look at how the human-readable AArch64 assembly source code is converted into an object file with machine code. By emphasizing the distinctions between the high-level source instructions and the low-level binary output produced by the assembler, this inquiry will aid in my understanding of the assembly process.

Source file





Object file





2. Building a Loop That Seven Times Prints "Loop"
I have to modify the aarch64 server's assembly code for this task so that it prints the word "Loop" precisely six times. Using the given code as a starting point, I will add a counter to one of the general-purpose registers, set it to zero, and then increase it with each print. The loop will end when the counter hits six. To accomplish this, the assembly instructions must be modified to compare the loop counter to a maximum number, execute the relevant syscall to display "Loop" at each iteration, and then terminate the program when the loop has finished 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. 
Modify the code to show the current loop iteration next to the term "Loop." For instance, "Loop: 1", "Loop: 2", and so forth should be the result. This is accomplished by adding a new variable (num, for example) to the .data section, updating its value at each iteration, and printing it alongside 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. Loop from 00 to 32 by extending the code. I thought of two methods for this task. Dividing the loop counter in each iteration to get the tens and unit digits was one approach, but it felt laborious and ineffective. To update the two-digit output without dividing each time, I decided to use an alternative approach that involves directly storing the ASCII values for each digit in registers.


.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. Modify the code so that the leading zero is removed. In my method, the memory address that is modified during each iteration is stored in a register, which is incremented as necessary. The code will remove the superfluous leading zero from the output by adjusting the memory location to refer to the next digit when the loop counter first hits 10. 


.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: Modify the code to show the output in hexadecimal instead of decimal, which ranges from 0 to 20. This change is really easy; all I have to do is add an extra step that changes the ASCII value in the register to "A" (ASCII 65) anytime it hits 58 and update the comparison values before the branch instructions.


.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

Project Stage 3: Enhancing GCC Pass for Multiple Function Clone Handling: Progress Update

Project Stage 1: Troubleshooting a bit - Coming soon

Lab - 1: Exploring 6502 Assembly