CSSE 132 Post-Homework Review

Homework 2 Review + Solutions: ARM64 Data and Loops

Use this page after Homework 2 to compare your approach with a worked one. It is an exam-review resource, not a replacement for doing the assignment yourself.

What Homework 2 Practiced

HW02 connects C function calls to ARM64: integer arguments and results use w registers, addresses use x registers, and ldr/str move 4-byte int values between a register and memory. Its four functions also practice loops made from cmp, branches, and ret.

The Register Rule That Prevents Many Bugs

Kind of valueUseExample
32-bit integerw0–wNarray element, length, sum, or result
64-bit address / pointerx0–xNbase address of an int array
Function argumentsw0/x0, then w1/x1swap(int *a, int *b) receives addresses in x0, x1
Return valuew0 for an intmult places its product in w0

Same numbered register, different width: w0 is the low 32 bits of x0. Writing w0 clears the top 32 bits of x0. Do not store an address in w0: an int * belongs in an x register, while an int loaded from it belongs in a w register.

Follow the Value, Not Just the Instruction

Memory → register

ldr w2, [x0]

x0 is an address. Read the 4-byte int stored there into w2.

Register → memory

str w2, [x0]

Write the 4-byte value in w2 to the location whose address is in x0.

Move through an int array

add x0, x0, 4

Each int is 4 bytes, so this advances from array[i] to array[i + 1].

Common mistake: brackets matter. [x0] means “the memory at this address.”

Worked Walkthroughs

swap(int *a, int *b)

Core idea: preserve both old values before either location is overwritten: temp = *a; *a = *b; *b = temp;.

swap:
    ldr w2, [x0]    // w2 = *a
    ldr w3, [x1]    // w3 = *b
    str w3, [x0]    // *a = old *b
    str w2, [x1]    // *b = old *a
    ret

x0 and x1 stay as addresses; w2 and w3 hold the values. Loading both values first prevents the original *a from being lost.

mult(int x, int y)

Core idea: multiplication is repeated addition. Since y is non-negative, add x until a counter reaches y.

mult:
    mov w2, 0       // count = 0
    mov w3, 0       // total = 0
.mult_loop:
    cmp w2, w1
    beq .mult_done
    add w3, w3, w0  // total += x
    add w2, w2, 1   // count++
    b .mult_loop
.mult_done:
    mov w0, w3      // return total
    ret

For mult(-2, 3), totals are 0, -2, -4, -6. Do not use mul; this homework explicitly forbids it.

if_zero(int *a, int len)

Core idea: inspect one item at a time, stopping when a zero is found or the length reaches zero.

if_zero:
.if_zero_loop:
    cmp w1, 0
    beq .no_zero
    ldr w2, [x0]
    cmp w2, 0
    beq .found_zero
    add x0, x0, 4
    sub w1, w1, 1
    b .if_zero_loop
.found_zero:
    mov w0, 1
    ret
.no_zero:
    mov w0, 0
    ret

Test len before ldr; otherwise the scan can read past the array. The pointer advances by 4 because each element is an int.

find_zero(int *a, int len)

Core idea: this scan returns an index rather than a yes/no result. An index changes by 1; an int byte offset changes by 4.

find_zero:
    mov w2, 0       // index = 0
    mov x3, 0       // byte offset = 0
.find_zero_loop:
    ldr w4, [x0, x3]
    cmp w4, 0
    beq .find_zero_done
    add w2, w2, 1
    add x3, x3, 4
    b .find_zero_loop
.find_zero_done:
    mov w0, w2
    ret

The homework guarantees a zero exists. Advancing x3 by 1 would read successive bytes instead of successive ints.

Test, Debug, and Submit

  1. On the VM, edit only problems.s in the Homework 2 directory.
  2. Run make clean for “file format not recognized,” then run make test_asm (or make) and ./test_asm.
  3. If you get Segmentation fault, inspect every ldr/str: is the base an x address register, are brackets present, and did the pointer stay within the array?
  4. Submit only after git add problems.s, git commit, git push, then pulling that commit into the local clone and uploading the correct problems.s to Gradescope.

Common HW02 Mistakes

Pointer in wN
Addresses need xN.
Wrong stride
An int array advances 4 bytes per element.
Return left elsewhere
Tests read an int result from w0.
Reused labels
Labels are file-wide; use distinct names in every function.

Check Yourself

  1. Why does ldr w2, [x0] use w2 but x0?
  2. After three array iterations, what byte offset reaches the fourth int?
  3. Where must an ARM function place an int result before ret?
Answers

The loaded item is a 32-bit int, while the base is a 64-bit address. The offset is 12 bytes. The return value goes in w0.