SPO600 Lab5 64-Bit Assembly Language Lab Pt.1 ---AArch64 part


In this Lab, I am going to experiment with assembler on the x86_64 and aarch64 platforms.

Task 1 Observe the difference between source code and the object file of the aarch64 assembly language 

source file:
object file:


Task 2 -- A loop which print 6 "Loop" word

 I have to modify a provided code block in the aarch64 system to print loop for 6 times. 

modified code:

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

     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, msg     /* message location (memory address) */
     mov     x2, len     /* message length (bytes) */
     mov     x8, 64       /* write is syscall #64 */
     svc     0            /* invoke syscall */

     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 */
.data
msg:   .ascii      "Loop\n"
len=   . - msg
The yellow highlighted code : print the String "Loop"
 
result:


Task 3. Modify the code so that it also show the iteration number, i,e, Loop: 1, Loop: 2..etc


I would like to add an extra num variable to .data. Update the variable in every loop and print it.

code:
.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     
     adr    x21, num
loop:

     /* ... body of the loop ... do something useful here ... */
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, msg    /* message location (memory address) */
     mov     x2, len1           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */

        /* print the number*/
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, num    /* message location (memory address) */
     mov     x2, len2           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */

     add     w19, w19, 1     /* increment the loop counter */

     /* update the num value in .data*/
     mov    w20, w19
     add    w20, w20, 48
     strb   w20, [x21]

     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 */
.data
msg:    .ascii      "Loop: "
len1=   . - msg
num:     .ascii     "0 \n"
len2=   . - num
Yellow highlighted: the variable added to print the iteration number
Red highlighted: to change the num variable in .data
Green highlighted: to print the num variable in .data

result:

Task 4. Extend the code to loop from 00 to 32

I have two way to code. The first way is to do find the units digit and tens digits by division in every loop. But, it is quite boring and I tend to prevent performing division. As a result, I decide to use another way, which is use the registers to store each digit's ascii value to be display.

.text
.globl _start
min = 0                          /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
max = 33                         /* loop exits when the index hits this number (loop condition is i<max) */
_start:
     mov     x19, min
     adr     x22, num      //address of first digit
     add     x23, x22, 1   //address of second digit
     mov     w21, 48       //the ten digit
     mov     w20, 48
loop:

     /* ... body of the loop ... do something useful here ... */
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, msg    /* message location (memory address) */
     mov     x2, len1           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */

        /* print the number*/
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, num    /* message location (memory address) */
     mov     x2, len2           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */


     add     x19, x19, 1     /* increment the loop counter */
     add     w20, w20, 1     /* increment the units digit*/

     cmp     w20, 58
     b.lt    update

     /*update the  tens digit when units digit >10*/
     add     w21, w21, 1
     strb    w21, [x22]
     mov     w20, 48
 /* update the num value in .data*/
update:
     strb    w20, [x23]

     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 */
.data
msg:    .ascii      "Loop: "
len1=   . - msg
num:     .ascii     "00\n"
len2=   . - num

Yellow highlighted:  Initialize the register to store the address of output and the counter
Red highlighted: check if the units digit>10, then check the tens digits accordingly
Green highlighted: update num variable which is going to be printed

result:

Task 5. modify the code to make it suppress the leading zero

My plan is to use a register to store the memory address to be edited during the iteration and increment it instead. Then, when the loop first reach 10, it change the memory address to the digit after. 

code:
.text
.globl _start
min = 0                          /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
max = 33                         /* loop exits when the index hits this number (loop condition is i<max) */
_start:
     mov     x19, min
     adr     x22, num      //address of first digit
     adr     x23, num      //address  which increment during the loop
     mov     w21, 48       //the ten digit
     mov     w20, 48
loop:

     /* ... body of the loop ... do something useful here ... */
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, msg    /* message location (memory address) */
     mov     x2, len1           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */

        /* print the number*/
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, num    /* message location (memory address) */
     mov     x2, len2           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */


     add     x19, x19, 1     /* increment the loop counter */
     add     w20, w20, 1     /* increment the units digit*/


     cmp     x19, 10
     b.ne    checkten
     /*the first time reach 10*/
     add     x23, x22, 1
     mov     w20, 58
     mov     w21, 48
checkten:
     cmp     w20, 58
     b.lt    update
     /*update the  tens digit when units digit >10*/
     add     w21, w21, 1
     strb    w21, [x22]
     mov     w20, 48
 /* update the num value in .data*/
update:
     strb    w20, [x23]

     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 */
.data
msg:    .ascii      "Loop: "
len1=   . - msg
num:     .ascii     "0 \n"
len2=   . - num
 Yellow highlighted:  how the units digit changing
Red highlighted: check if the loop reach 10 the first time. If so, the incrementing digit will be changed. Also, move the current value in the digital to the new digit before the regular calculation with carry.

result:

Task 6. Modify the code so that it output in hexadecimal (0-20) instead of decimal (0-32)

This is easy. I just have to change the value to be compare before the branches and add an extra part to increase the ascii value stored in the register to "A"(65) whenever it reach 58 .

code:
.text
.globl _start
min = 0                          /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
max = 33                         /* loop exits when the index hits this number (loop condition is i<max) */
_start:
     mov     x19, min
     adr     x22, num      //address of first digit
     adr     x23, num      //address  which increment during the loop
     mov     w21, 48       //the ten digit
     mov     w20, 48
loop:

     /* ... body of the loop ... do something useful here ... */
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, msg    /* message location (memory address) */
     mov     x2, len1           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */

        /* print the number*/
     mov     x0, 1           /* file descriptor: 1 is stdout */
     adr     x1, num    /* message location (memory address) */
     mov     x2, len2           /* message length (bytes) */
     mov     x8, 64             /* write is syscall #64 */
     svc     0                  /* invoke syscall */


     add     x19, x19, 1     /* increment the loop counter */
     add     w20, w20, 1     /* increment the units digit*/

     cmp     w20, 58
     b.ne    chknewdg
     add     w20, w20, 7

chknewdg:
     cmp     x19, 16
     b.ne    check16
     /*the first time reach 16*/
     add     x23, x22, 1
     mov     w20, 71
     mov     w21, 48
check16:
     cmp     w20, 71
     b.lt    update
     /*update the  digit when units digit >16*/
     add     w21, w21, 1
     strb    w21, [x22]
     mov     w20, 48
 /* update the num value in .data*/
update:
     strb    w20, [x23]

     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 */
.data
msg:    .ascii      "Loop: "
len1=   . - msg
num:     .ascii     "0 \n"
len2=   . - num

Yellow highlighted:  check if the digit reach 10. If so, increase it to "A"
Red highlighted: criteria changed from 10 to 16

result:

 


Comments

Popular posts from this blog

SPO600 Project Stage 1 (Pt.1) - Create a GCC Pass

SPO600 Project Stage 2 (Pt.1) - GCC pass locating clone function

SPO600 Project Stage 2 (Pt.2) - GCC pass locating clone function -modified version