1

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.

  • You have `mov X0, 1` instead of `mov X0, #1`. Although on my toolchain that assembles the same, try changing that first to see if it fixes the issue. PS: all the `b` instructions in your `main` are pointless. – Jester May 16 '23 at 14:01
  • A couple issues I can see off the bat: (1) Your "subroutines" are missing `ret`. (But this means that each one just falls through into the next, so by chance the code still happens to do what you want.) (2) The `b` instruction doesn't save the return address so it can't be used for a subroutine call; you want `bl` instead. (3) You need `.text` before your code and `.data` or `.bss` before your `buffer`. They need to be in sections with the appropriate set of read/write/execute memory permissions. – Nate Eldredge May 16 '23 at 14:06
  • Hi, thank you for your answer. Without `b` in front I get this ` hello.S:5:5: error: unrecognized instruction mnemonic _printf ^ hello.S:6:5: error: unrecognized instruction mnemonic _read ^ hello.S:7:5: error: unrecognized instruction mnemonic _terminate` I also fixed the `mov X0, #1` as you told me. But I still got the same thing. Thank you for trying to help me btw. – BlockOfSalt May 16 '23 at 14:06
  • No, don't just remove the `b` mnemonic, replace it with `bl` ("Branch with Link"). And I don't exactly recall if `.text` and `.data` work normally on MacOS or if you need some more elaborate directive; I'll try to check later. – Nate Eldredge May 16 '23 at 14:08
  • 2
    Yeah the problem is likely the `buffer` being read-only so nothing gets written there and the output is probably 1024 zero bytes which the terminal doesn't show. – Jester May 16 '23 at 14:13
  • Which actually is another bug: you don't really want to write out 1024 bytes, but only the number that were actually read (which would be the return value from the read system call). – Nate Eldredge May 16 '23 at 14:15
  • I tried [this](https://pastebin.com/SBV0aJaT) I also tried the `.text` and `.data` as you told me but it just put an bus error even with `=buffer`. I also tried to replace `adr` with `ldr`. But nothing work. – BlockOfSalt May 16 '23 at 14:24
  • It may take more work than `adr` to get the address of a symbol in another section, see the notes at https://github.com/below/HelloSilicon/blob/main/README.md under Chapter 4. I'll try to test it later. – Nate Eldredge May 16 '23 at 14:48
  • This is a very broad question, with a list of issues at play. My suggestion would be to write the same in C code, then compile it to assembly with `-S` (without optimisation), and look at the output. – Siguza May 16 '23 at 18:44
  • @Siguza: Well, `-S` compilation will just show a bunch of calls to library functions and not the raw `svc` system calls. It would help some with things like getting the address of `buffer` in a register, though. – Nate Eldredge May 16 '23 at 18:45
  • @NateEldredge fair point, load `/usr/lib/system/libsystem_kernel.dylib` into a disassembler then. – Siguza May 16 '23 at 18:46

1 Answers1

2

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
Rob
  • 415,655
  • 72
  • 787
  • 1,044