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"
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.