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

.png)
.png)
.png)
.png)
.png)
Comments
Post a Comment