Introduction

Hello World

Printing variables

User input

Testing printf

Mathematical operations

Functions

Arrays

Loops

Projects:

Estimating sin(x)

Calculating cube roots

Sieve of Eratosthenes

Arrays

The first example, below, declares a fixed array of five 64 bit numbers. The .quad specifier indicates 64 bit and the values are specified in the declaration.

        
        .data
        array:
            .quad 10, 20, 30, 40, 50    // Use .quad to specify 64 bit values
        
    

There are two implementations of the process to extract a value at an index. The first is more laborious but the logic is clearer.

        
        // main code
        ldr x0, =output
        ldr x1, =array      // Base address of array
        mov x2, #2          // Element pointer, 30
        lsl x2, x2, #3      // Multiply x2 by 8 to get the number of addresses to offset
        add x1, x1, x2      // Add the offset to the base address
        ldr x1, [x1]        // Get value at address
        bl printf
        
    

Ignoring the ldr x0, =output as that is setting up the string to be passed to printf. X1 is loaded with the base address of the array. This is the address of element 0 in the array, 10 in this case. Because the array was declared to be of type .quad, each location is eight bytes wide. That is, if the base address was 0x1000, the element 20 would be stored at 0x1008, the element 30 would be stored at 0x1010.
As there are five elements in the array and each element requires eight bytes, the entire array will be in 40 contiguous memory addresses.
This means that we can find the exact memory address of an element by knowing its index in the array and multiplying that index by eight then adding that value to the base address to find the address of the required element.

In the example above the base address is loaded into x1. X2 is then loaded with the immediate value, #2, being the index of the element we want to extract. The next instruction, lsl x2, x2, #3, takes the value in x2, performs a "Logical Shift Left" by the immediate value provided, 3 in this case, and stores the result back in x2. For example, x2 contains 0000 0010. The lsl instruction will shift the bits to the left by three places, appending a zero to the least significant bit each time. The result in x2 will be 0001 0000 or in hex, 0x10

The next line adds the offset in x2 to the base address in x1 to get the address of required element.
In this case: 0x1000 + 0x0010 = 0x1010 which was established earlier.

The final line, ldr x1, [x1] loads x1 with the value stored at the address currently in x1.

The more efficient way of addressing the nth element is using this code:

    
    // main code
    ldr x0, =output
    ldr x1, =array      // Base address of array
    mov x2, #2          // Element of interest, 30
    ldr x1, [x1, x2, LSL #3 ]       // Get value at address
    bl printf
    

The code is the same as the above with one exception, the line ldr x1, [x1, x2, LSL #3]. This mode of addressing is called Register Offset Addressing. The register, x1, will be loaded with the address in x1 added to the value in x2 once that has been logically left shifted by the immediate value.
Conceptually, it may look like this: x1 <- x1 + (x2, LSL 3 places).
The result is the same in both cases.

        
            // arrays1.s

    .global main
    .extern printf

    .data
    array:
        .quad 10, 20, 30, 40, 50    // Use .quad to specify 64 bit values
    output:
        .asciz "Value = %d\n"

    .text
    main:
        // prolog
        stp x29, x30, [sp, -16]!
        mov x29, sp

        // main code
        ldr x0, =output
        ldr x1, =array      // Base address of array
        mov x2, #2          // Element pointer, 30
        lsl x2, x2, #3      // Multiply x2 by 8 to get the number of addresses to offset
        add x1, x1, x2      // Add the offset to the base address
        ldr x1, [x1]        // Get value at address
        bl printf

        // Cleanup
        mov x0, #0
        ldp x29, x30, [sp], 16
        RET
        
    
        
            // arrays1.s

        .global main
        .extern printf

        .data

        array:
            .quad 10, 20, 30, 40, 50    // Use .quad to specify 64 bit values
        output:
            .asciz "Value = %d\n"

        .text
        main:
            // prolog
            stp x29, x30, [sp, -16]!
            mov x29, sp

            // main code
            ldr x0, =output
            ldr x1, =array      // Base address of array
            mov x2, #2          // Element of interest, 30
            ldr x1, [x1, x2, LSL #3 ]       // Get value at address
            bl printf

            // Cleanup
            mov x0, #0
            ldp x29, x30, [sp], 16
            RET