Search code examples
macosassemblyarm64

How to store data and display it with assembly arm64 macos


I'm currently trying to learn assembly, I'm on mac M2, so with ARM64, and I can't find a way to display an user input. Here is my code:

.global _main
.align 2

_main:
    b _printf
    b _read
    b _prinfbuffer
    b _terminate

_printf:
    mov X0, #1                      // stdout
    adr X1, prompt                  // address of string
    mov X2, #17                     // nbyte
    mov X16, #4                     // write
    svc 0                           // call syscall

_read:
    mov X0, #0                      // stdin
    adr X1, buffer                  // address of buffer
    mov X2, #1024                   // maximum number of bytes to read
    mov X16, #3                     // read
    svc 0                           // call syscall

_prinfbuffer:
    mov X0, 1                       // stdout
    adr X1, buffer                  // address of buffer
    mov X2, #1024                   // nbyte
    mov X16, #4                     // write
    svc 0                           // call syscall

_terminate:
    mov X0, #0                      // return 0
    mov X16, #1                     // terminate
    svc 0                           // call syscall

// hello world string
prompt: .ascii "Say something: \n"
.align 2
buffer: .space 1024

The output is this:

❯ ./hello
Say something: 
a
❯ 

Yes, an empty space, after that it close the program.

Does anyone know how to fix this.

And yes I already took a look at the syscalls.master docs.

I tried to send back the input of the user with ARM64 assembly.


Solution

  • The problem is (as Jester suggested) that the .text section is read-only. You need to move the buffer to a .data section, which is writable. I believe that means that you need to shift from ADR to ADRP/ADD pattern, too (as discussed in Apple Clang12 LLVM - unknown AArch64 fixup kind).

    Thus, perhaps:

    .text
        .global _main
        .align 2
    
    _main:
        bl _printprompt
        bl _read
        bl _printbuffer
        bl _terminate
    
    _printprompt:
        mov x0, #1                      // stdout
        adrp x1, prompt@PAGE            // address of string
        add x1, x1, prompt@PAGEOFF
        mov x2, #17                     // nbyte
        mov x16, #4                     // write
        svc 0                           // call syscall
        ret
    
    _read:
        mov x0, #0                      // stdin
        adrp x1, buffer@PAGE            // address of buffer
        add x1, x1, buffer@PAGEOFF
        mov x2, #1024                   // maximum number of bytes to read
        mov x16, #3                     // read
        svc 0                           // call syscall
        ret
    
    _printbuffer:
        mov x2, x0                      // move byte count to x2 (the nbyte for write syscall)
        mov x0, #1                      // stdout
        adrp x1, buffer@PAGE            // address of buffer
        add x1, x1, buffer@PAGEOFF
        // mov x2, #1024                // nbyte
        mov x16, #4                     // write
        svc 0                           // call syscall
        ret
    
    _terminate:
        mov x0, #0                      // return 0
        mov x16, #1                     // terminate
        svc 0                           // call syscall
        ret
    
    .data
        prompt: .ascii "Say something: \n"
        .align 2
        buffer: .space 1024