Search code examples
macosassemblyarm64

Capture input in assembly arm 64 bit mac os


Trying to capture two characters and new line from user input.

The program prints the 3 helloworlds to screen and then users can type in some characters. Everything seems to work, but it doesn't print the input

I suspect it is due to the way I operate on the X1 register in the _read function, or the way the buffer is allocated

No errors are reported when running the code.

The code is compiled using the following command. It should run on a Mac M1

as HelloWorld.s -o HelloWorld.o && ld -macosx_version_min 12.0.0 -o HelloWorld HelloWorld.o -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 && ./HelloWorld

//HelloWorld.s

.equ SYS_WRITE, 4
.equ SYS_READ, 3
.equ NEWLN, 10


.global _start             // Provide program starting address to linker
.align 2

// Setup the parameters to print hello world
// and then call Linux to do it.

_start: 
        adr X4, helloworld1
        mov X1, X4
        bl _sizeof
        bl _print

        adr X4, helloworld2
        mov X1, X4
        bl _sizeof                
        bl _print


        adr X4, helloworld3
        mov X1, X4
        bl _sizeof
        bl _print


        bl _read
        //mov X2, 4
       // bl _sizeof
        bl _print


_exit:
        mov     X0,  X2     // Use 0 return code
        mov     X16, #1     // Service command code 1 terminates this program
        svc     0           // Call MacOS to terminate the program





_sizeof: //X1 = address, X2 = out length, string must terminate with \n
        str LR, [SP, #-16]!     //Store registers
        //str W0, [SP, #-16]!


        mov X2, #0
        __loop:
             
                ldrb W0, [X1, X2]       //load a byte into W0 (32 bit)
                add X2, X2, #1          //Add 1 offset  
                cmp W0, NEWLN             //Compare byte with \n return
                bne __loop

        //ldr W0, [SP], #16
        ldr LR, [SP], #16       //Load registers
        ret




_print: //X2 = length, X1 = address
        str LR, [SP, #-16]!     //Store registers

        mov X0, #1     // 1 = StdOut
       // mov X1, X1      // string to print
       // mov X2, X2     // length of string
        mov X16, SYS_WRITE     // MacOS write system call
        svc 0     // Call kernel to output the string
        
        ldr LR, [SP], #16       //Load registers
        ret  

_read:
//3 AUE_NULL    ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); } 

        str LR, [SP, #-16]!     //Store registers
        
        adr X1, msg

        mov X0, #0    // 0 = StdIn
        ldr X1, [x1]    // address to store string

        mov X2, #4     // length 
        mov X16, SYS_READ     // MacOS read system call
        svc 0     // Call system

        ldr LR, [SP], #16       //Load registers
        ret

msg: .ds 4     //memory buffer for keyboard input


helloworld1:      .ascii  "Hello World\n"
helloworld2:      .ascii  "Happy new year for 2022\n"
helloworld3:      .ascii  "Welcome to AARCH64 assembly on Mac Silicon\n"


Solution

  • First you need to move msg to a writeable segment:

    .data
    msg: .ds 4     //memory buffer for keyboard input
    
    .text // keep everything else in __TEXT
    

    Then, because segments may be moved around arbitrarily at link-time, Apple's toolchain will no longer allow you to use adr to get the address of that buffer - you will have to use adrp and add:

    adrp x1, msg@page
    add x1, x1, msg@pageoff
    

    If you want, you can tell the linker to please optimise this back to an adr if possible:

    Lloh0:
        adrp x1, msg@page
    Lloh1:
        add x1, x1, msg@pageoff
    .loh AdrpAdd Lloh0, Lloh1
    

    Then you need to remove this line:

    ldr X1, [x1]
    

    That would load the contents of the buffer, which would just be null bytes.

    And finally, you should change the x0 value to exit to a constant:

    mov x0, 0
    

    The value in x2 will have been clobbered at this point, and you don't need it anyway.