lab04

 This is the blog for SPO600 lab 4. In this lab, we mainly focus on writing the loop to output some things like the number in 6502, x86_64, aarch64 assembler. This is quite new to me since nowadays we use modern programming language like Python, C and Javascript. But for this lab, we will go into the assembler language to see how the programs work.

This lab has two part, one is class part, which means that we will be seperated into group and there was a driver to share his screen and watchers would watch him to code. The program that out group has generated in the class was:

.text

.globl _start


min = 0                         /* starting value of the loop idx. this is a symbol */

max = 10                        /* ending value of the loop idx. this is a symbol */


_start:

        mov     x19, min        /* store min to x19, which will be our idx register */

loop:

        mov     x0, 1           /* file descriptor: 1 is stdout */

        adr     x1, msg         /* message location (memory address) */

        mov     x2, len         /* message length (bytes) */


        mov     x4, x19         /* copy idx(x19) to x4 */

        add     x4, x4, 48      /* add 48 to make it ASCII */

        strb    w4, [x1, 6]     /* store 1 byte into the memory loc of msg + 6 */


        mov     x8, 64          /* write is syscall #64 */

        svc     0               /* invoke syscall */


        add     x19, x19, 1     /* add 1 to idx(x19) */

        cmp     x19, max        /* compare x19 to max */

        b.ne    loop            /* branch if not equal to loop */


        mov     x0, 0           /* status -> 0 */

        mov     x8, 93          /* exit is syscall #93 */

        svc     0               /* invoke syscall */


.data

msg:    .ascii      "Loop: 0\n"

len=    . - msg


These codes will generate a loop to output the number from 0-9. And that is all the things that our group has researcher in the class due to time limit. But the lab hasm;t been finished.

The next task in the lab is Extend the AArch64 code to loop from 00-30, printing each value as a 2-digit decimal number. And I tried to generate this program after class. The code:

.text

        .globl _start


min = 0                          /* starting value of the loop index */

max = 31                         /* ending value (loop until 30) */


_start:

        mov     x19, min         /* store min to x19 (loop index register) */

loop:

        /* Calculate quotient (first digit) and remainder (second digit) */

        mov     x0, x19          /* copy index to x0 */

        mov     x1, 10           /* divisor: 10 */

        udiv    x2, x0, x1       /* x2 = quotient (first digit) */

        msub    x3, x2, x1, x0   /* x3 = remainder (second digit), msub: x3 = x0 - (x2 * x1) */


        /* Convert quotient and remainder to ASCII */

        add     x2, x2, 48       /* add 48 to quotient to convert to ASCII */

        add     x3, x3, 48       /* add 48 to remainder to convert to ASCII */


        /* Store the digits in the message */

        adr     x1, msg          /* address of the message */

        strb    w2, [x1, 6]      /* store first digit (quotient) at msg + 6 */

        strb    w3, [x1, 7]      /* store second digit (remainder) at msg + 7 */


        /* Write the message to stdout */

        mov     x0, 1            /* file descriptor: 1 is stdout */

        mov     x2, len          /* message length */

        mov     x8, 64           /* write is syscall #64 */

        svc     0                /* invoke syscall */


        /* Increment loop index */

        add     x19, x19, 1      /* add 1 to index */

        cmp     x19, max         /* compare index to max (31) */

        b.ne    loop             /* if not equal, continue looping */


        /* Exit the program */

        mov     x0, 0            /* status -> 0 */

        mov     x8, 93           /* exit syscall number 93 */

        svc     0                /* invoke syscall */


        .data

msg:    .ascii      "Loop: 00\n"  /* message template: 00 will be replaced by digits */

len =   . - msg                  /* message length */ 


This update code will generate the loop from 00 to 30. The new part in this the code is the  mov     x0, x19          /* copy index to x0 */

        mov     x1, 10           /* divisor: 10 */

        udiv    x2, x0, x1       /* x2 = quotient (first digit) */

        msub    x3, x2, x1, x0   /* x3 = remainder (second digit), msub: x3 = x0 - (x2 * x1) */. 

This part of code basically take a number stored in x19 and divided it by 10, and then we store the result in x2, this is the first digit. The reminder is stored in the x3. And we will display the first and second digit


The next task is Change the code as needed to suppress the leading zero (printing 0-30 instead of 00-30). To do this, you'll need to add a conditional into your code (the equivalent of an “if” statement, implemented as a compare followed by a conditional branch or conditional jump).

My code is

.text

        .globl _start


min = 0                          /* starting value of the loop index */

max = 31                         /* ending value (loop until 30) */


_start:

        mov     x19, min         /* store min to x19 (loop index register) */


loop:

        /* Calculate quotient (first digit) and remainder (second digit) */

        mov     x0, x19          /* copy index to x0 */

        mov     x1, 10           /* divisor: 10 */

        udiv    x2, x0, x1       /* x2 = quotient (first digit) */

        msub    x3, x2, x1, x0   /* x3 = remainder (second digit), msub: x3 = x0 - (x2 * x1) */


        /* Convert quotient and remainder to ASCII */

        add     x2, x2, 48       /* add 48 to quotient to convert to ASCII */

        add     x3, x3, 48       /* add 48 to remainder to convert to ASCII */


        /* Check if the number is less than 10 */

        cmp     x2, 48           /* compare first digit with '0' */

        b.ne    two_digits       /* if not equal, print two digits */


        /* For single digit numbers */

        adr     x1, msg          /* address of the message */

        strb    w3, [x1, 6]      /* store single digit at msg + 6 */

        mov     x4, ' '          /* space character */

        strb    w4, [x1, 7]      /* store space at msg + 7 */

        b       print            /* branch to print */


two_digits:

        /* For two digit numbers */

        adr     x1, msg          /* address of the message */

        strb    w2, [x1, 6]      /* store first digit at msg + 6 */

        strb    w3, [x1, 7]      /* store second digit at msg + 7 */


print:

        /* Write the message to stdout */

        mov     x0, 1            /* file descriptor: 1 is stdout */

        mov     x2, len          /* message length (always 9 now) */

        mov     x8, 64           /* write is syscall #64 */

        svc     0                /* invoke syscall */


        /* Increment loop index */

        add     x19, x19, 1      /* add 1 to index */

        cmp     x19, max         /* compare index to max (31) */

        b.ne    loop             /* if not equal, continue looping */


        /* Exit the program */

        mov     x0, 0            /* status -> 0 */

        mov     x8, 93           /* exit syscall number 93 */

        svc     0                /* invoke syscall */


        .data

msg:    .ascii      "Loop: 00\n"  /* message template: 00 will be replaced by digits */

len =   . - msg                  /* message length */


The update part for this code is /* Check if the number is less than 10 */

        cmp     x2, 48           /* compare first digit with '0' */

        b.ne    two_digits       /* if not equal, print two digits */


        /* For single digit numbers */

        adr     x1, msg          /* address of the message */

        strb    w3, [x1, 6]      /* store single digit at msg + 6 */

        mov     x4, ' '          /* space character */

        strb    w4, [x1, 7]      /* store space at msg + 7 */

        b       print            /* branch to print */


two_digits:

        /* For two digit numbers */

        adr     x1, msg          /* address of the message */

        strb    w2, [x1, 6]      /* store first digit at msg + 6 */

        strb    w3, [x1, 7]      /* store second digit at msg + 7 */.

This will check if the number that we are going to output is single number or not, if this is the single number it will not print the 0 as the first digit. If it detect that the number is second digit, it will directly jump to  two_digits store the two digit for output.


The last part for this lab is that we need to repeat the whole process in x86_64. For this part I have chosen nasm to finish the job. The code for outputing the loop from 0 to 30 is

section .text

global _start


_start:

    xor r12, r12        ; Initialize loop counter


loop:

    ; Print "Loop: "

    mov rax, 1          ; sys_write

    mov rdi, 1          ; stdout

    mov rsi, prefix

    mov rdx, 6          ; length of "Loop: "

    syscall


    ; Convert the number to ASCII

    mov rax, r12

    mov rsi, buffer

    call int_to_string


    ; Print the number

    mov rax, 1          ; sys_write

    mov rdi, 1          ; stdout

    mov rsi, buffer

    mov rdx, 3          ; Max 3 digits (including null terminator)

    syscall


    ; Print newline

    mov rax, 1          ; sys_write

    mov rdi, 1          ; stdout

    mov rsi, newline

    mov rdx, 1          ; length of newline

    syscall


    ; Increment and continue loop

    inc r12

    cmp r12, 31

    jl loop


    ; Exit

    mov rax, 60         ; sys_exit

    xor rdi, rdi        ; status 0

    syscall


int_to_string:

    add rsi, 2          ; Point to end of buffer

    mov byte [rsi], 0   ; Null terminator

    mov rbx, 10         ; Divisor


.divide_loop:

    xor rdx, rdx        ; Clear RDX for division

    div rbx             ; Divide RAX by 10

    add dl, '0'         ; Convert remainder to ASCII

    dec rsi             ; Move back in buffer

    mov [rsi], dl       ; Store digit

    test rax, rax       ; Check if quotient is zero

    jnz .divide_loop    ; If not, continue loop


    ret


section .data

prefix db 'Loop: '

newline db 10           ; Newline character


section .bss

buffer resb 4           ; Buffer for number conversion (3 digits + null terminator)


Baed on my experience, the main difference between x86_64 and aarch64 are the instruction sets. For x86_64 it typically use Intel syntax in NASM, but for aarch64, it use the ARM's syntax and x86 use condition code and conditional jump instructions. But for aarch64, it can conditionally execute more instructions using prediction. That is the things I have discover for the difference between aarch64 and x86. I don't have specific preference for these two architectures. I found both of them are really complex and inconvenient to use for daily program.

评论

此博客中的热门博文

Project-stage 2

Project- Stage 1

lab1