Tuesday, March 26, 2024

Writing Assembly Code: AArch64 vs x86_64

Writing assembly code can be an enlightening experience, offering a deep dive into the inner workings of a computer's architecture. In this blog post on Lab 3, we'll explore the process of writing and debugging assembly code for two different architectures: AArch64 and x86_64. We'll contrast the two and share our experiences with each.

AArch64 Assembly Code

Here's a snippet of assembly code written for the AArch64 architecture:

.text


.globl _start


min_val = 0

max_val = 30

zero_char = 0x30


_start:


    mov     x19, min_val

    mov     w6, zero_char

    mov     w7, zero_char


loop:


    mov     x0, 1

    adr     x1, msg

    mov     x2, len

    mov     x8, 64

    mov     x23, 0xA

    udiv    x24, x19, x23

    msub    x25, x24, x23, x19

    cmp     x24, 0x0

    b.eq    setup_second_digit

    mov     w6, w24

    mov     w7, w25

    mov     w26, zero_char

    add     w6, w6, w26

    add     w7, w7, w26

    add     x3, x1, 6

    strb    w6, [x3]


setup_second_digit:


    add     x3, x1, 7

    strb    w7, [x3]

    svc     0

    add     x19, x19, 1

    add     w7, w7, 1

    cmp     x19, max_val

    b.ne    loop

    mov     x0, 0

    mov     x8, 93

    svc     0


.data


msg:            .ascii      "Loop:   \n"


len=    . - msg


Explanation:

- The code begins with `.text` directive, indicating the start of executable instructions.

- `_start` is declared as the entry point of the program.

- Constants such as `loop_index`, `loop_max`, and `zero_char` are defined.

- The loop iterates from `loop_index` to `loop_max`.

- Inside the loop, the current index is divided to obtain the first and second digits.

- ASCII characters for the digits are obtained and stored in the `msg` string.

- The message is printed to the standard output using the `syscall` instruction.

- The loop continues until `loop_index` reaches `loop_max`.

- Finally, the program exits with a system call.

- This is what the loop prints on screen:

[mwrajani@aarch64-001 lab3]$ ./loop

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

x86_64 Assembly Code

Here's a snippet of assembly code written for the x86_64 architecture:

.text


.globl _start


loop_index = 0

loop_max = 30

zero_char = 48


_start:


    movq    $loop_index, %rbx


loop:


    movq    %rbx,  %rax

    movq    $10,   %rcx

    xor     %rdx, %rdx

    div     %rcx

    add     $zero_char, %rdx

    cmp     $0, %rax

    je      setup_second_digit

    add     $zero_char, %rax

    movq    $msg, %rdi

    add     $6,   %rdi

    stosb


setup_second_digit:


    movq    $msg, %rdi

    add     $7,   %rdi

    movq    %rdx, %rax

    stosb

    movq    $1,   %rdi

    movq    $msg, %rsi

    movq    $len, %rdx

    movq    $1,   %rax

    syscall

    inc     %rbx

    cmp     $loop_max, %rbx

    jne     loop

    mov     $0,  %rdi

    mov     $60, %rax

    syscall


.data


msg:            .ascii      "Loop:   \n"


len=    . - msg

Explanation:

- The code starts with `.text` directive and `_start` as the entry point.

- Constants such as `min_val`, `max_val`, and `zero_char` are defined.

- The loop iterates from `min_val` to `max_val`.

- Inside the loop, the current index is divided to obtain the first and second digits.

- ASCII characters for the digits are obtained and stored in the `msg` string.

- The message is printed to the standard output using the `svc` instruction.

- The loop continues until `min_val` reaches `max_val`.

- Finally, the program exits with a system call.

- This is what the loop prints on screen, although it is the same as aarch64, but it is expected as we are also doing the same thing:

[mwrajani@x86-001 lab3]$ ./loop

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

Writing and Debugging Experience

Writing assembly code for both architectures offers a unique insight into how the underlying hardware operates. AArch64 assembly, with its distinct syntax and register names, requires a thorough understanding of the architecture's instruction set. Debugging AArch64 code often involves meticulous examination of register values and memory accesses.

On the other hand, x86_64 assembly, being more ubiquitous, may feel more familiar to those accustomed to Intel-based systems. Debugging x86_64 code is aided by the availability of numerous tools and resources, making it relatively straightforward to identify and fix issues.

Conclusion

In conclusion, writing assembly code for AArch64 and x86_64 architectures provides valuable insights into low-level system operations. While each architecture has its own syntax and nuances, the fundamentals of assembly programming remain consistent. By understanding these differences, developers can gain a deeper appreciation for the inner workings of modern computing systems.

No comments:

Post a Comment

Project Stage 2 & 3: Command Line Parsing

Hey there, fellow tech enthusiasts! It's time for another update on my SPO600 Winter Project journey. Stage 2 has been quite a rollercoa...