DEV Community

gus
gus

Posted on

AArch64 Assembly Language Part II

This is the second post in a series on writing assembly language code for a program on the AArch64 architecture. You can find the first here.

Once again the task for this last stretch of our AArch64 exploration is to write a loop that iterates 30 times, which necessitates dealing with 2 digit numbers. This can be done by dividing the index by 10. The result goes into the first digit, with a branch to the secondDigit procedure if the first digit is 0. The full code is as follows:

.text
.globl _start

min = 0                          /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 31                         /* loop exits when the index hits this number (loop condition is i<max) */

_start:

    mov     x19, min
    mov     x20, 0x0A

loop:

    udiv    x21, x19, x20
    cmp     x21, 0
    b.eq    secondDigit

    add     x18, x21, '0'
    adr     x17, msg+6 
    strb    w18, [x17] 

secondDigit:
    msub    x22, x20, x21, x19

    add     x18, x22, '0' 
    adr     x17, msg+7 
    strb    w18, [x17] 

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

// Proceed with loop
    add     x19, x19, 1   
    cmp     x19, max
    b.ne    loop

    mov     x0, 0           /* status -> 0 */
    mov     x8, 93          /* exit is syscall #93 */
    svc     0               /* invoke syscall */

.data
msg:    .ascii      "Loop:  #\n"
len=    . - msg
Enter fullscreen mode Exit fullscreen mode

With the following output:

Loop: #0
Loop: #1
Loop: #2
Loop: #3
Loop: #4
Loop: #5
Loop: #6
Loop: #7
Loop: #8
Loop: #9
Loop: #10
Loop: #11
Loop: #12
Loop: #13
Loop: #14
Loop: #15
Loop: #16
Loop: #17
Loop: #18
Loop: #19
Loop: #20
Loop: #21
Loop: #22
Loop: #23
Loop: #24
Loop: #25
Loop: #26
Loop: #27
Loop: #28
Loop: #29
Loop: #30
Enter fullscreen mode Exit fullscreen mode

This looks like the output we're looking for which is great, let me break down the program in a little more detail and summarize my experiences writing AArch64 assembly.

_start:

    mov     x19, min
    mov     x20, 0x0A
Enter fullscreen mode Exit fullscreen mode

We start the program by assigning 0 and 10 to registers 19 and 20, respectively. Both are being used as 64 bit widths as made evident by the x prefix.

loop:

    udiv    x21, x19, x20
    cmp     x21, 0
    b.eq    secondDigit
Enter fullscreen mode Exit fullscreen mode

This portion divides the values in x19 by x20 and places it in x21. The syntax for AArch64 assembly is such that you can look at operations as operand = value or operand = expression in this case, as the destination register comes first in this syntax.

The second line compares the first digit of the result with 0, branching to the secondDigit label if the expression evaluates true. That would be in the case that it's a single digit result, which it will be for the first 10 iterations.

    add     x18, x21, '0'
    adr     x17, msg+6 
    strb    w18, [x17] 
Enter fullscreen mode Exit fullscreen mode

The first line adds '0' to the value in x21 and places it in x18, after which the address of the pound sign in msg is read into x17. The final line stores a byte from w18 to the address pointed to by x17, the pound sign pointer we just created.

secondDigit:
    msub    x22, x20, x21, x19
Enter fullscreen mode Exit fullscreen mode

Finally, the secondDigit label gets the remainder with the msub instruction by setting x22 to the result of x20-(x21 * x19), or 10 - (result of the division) * (loop index).

The rest of the code is largely unchanged from the last few iterations of this program so I'll leave it at that.

This was a challenging program to write, although I thought the transition from 6502 assembly to 64 bit assembly would be harder. I'm sure my next step, writing the x86_64 equivalent, will be equally if not not more difficult. There's definitely a more robust feeling for lack of a better word, to writing and building assembly on a machine rather than an emulator, and during my debugging process it seemed like the error messages were more meaningful as well. Although I'm not very familiar with working with Linux and that made some things awkward I like knowing that if I need to dig deeper to find out why something's not working that's an option I have. That's it for this post, stay tuned for the x86_64 equivalent of this program coming soon.

Top comments (0)