Search code examples
macosassemblyscanfarm64

How to use _scanf in Apple Silicon (aarch64 macos) assembly to read in user input?


I'm new to assembly programming, but I've been figuring a lot out by googling and trial and error. I'm trying to write a simple program that prompts the user to enter a number (with _printf), then reads in and saves that number (_scanf), then prints out a message using the stored number (_printf).

I was able to get the _printf code to work under aarch64 (Apple Silicon) assembly, but no matter what I do, I cannot seem to get _scanf to work. I have looked through the ARM Developer docs, looked at the HelloSilicon github page, and googled for hours, and I cannot come up with anything that works.

In my code (included below), if I comment out the "read_from_keyboard" branch in the following code, the printf functions work just fine. But when I include the "read_from_keyboard" code, I get a "Segmentation fault: 11" error.

Where is my mistake?

.global main
.align 4

main:
    // PRINT MESSAGE
    ADRP    X0, message@PAGE
    ADD X0, X0, message@PAGEOFF
    BL  _printf

//  BL read_from_keyboad

    // READ NUMBER FROM DATA AND MOVE TO STACK FOR PRINTING
    ADRP    X10, num@PAGE
    ADD X10, X10, num@PAGEOFF
    LDR X1, [X10]
    STR X1, [SP, #-16]!

    // LOAD THE PRINTF FORMATTED MESSAGE
    ADRP    X0, output_format@PAGE
    ADD X0, X0, output_format@PAGEOFF

end:
    BL  _printf
    mov X16, #1
    svc 0

read_from_keyboard:
    ADRP    X0, input_format@PAGE
    ADD X0, X0, input_format@PAGEOFF

    ADRP    X11, num@PAGE
    ADD X11, X11, num@PAGEOFF
    BL _scanf

    ret


.data
.balign 4
message:    .asciz "What is your favorite number?\n"
.balign 4
num:    .word 32
.balign 4
input_format:   .asciz "%d"
.balign 4
output_format:  .asciz "Your favorite number is %d \n"

Solution

  • On the call to _printf, your variadic arg is in [sp]. On the call to _scanf, you put it in x11. Why? Just do the same str xN, [sp, #-16]! that you do on _printf, that'll fix your segfault.

    In addition though, you also need a stack frame for read_from_keyboard. The bl _scanf clobbers x30, so the following ret would just get stuck in an infinite loop.

    Fix these two issues and your code works:

    .global _main
    .align 4
    
    _main:
        // PRINT MESSAGE
        ADRP    X0, message@PAGE
        ADD X0, X0, message@PAGEOFF
        BL  _printf
    
        BL read_from_keyboard
    
        // READ NUMBER FROM DATA AND MOVE TO STACK FOR PRINTING
        ADRP    X10, num@PAGE
        ADD X10, X10, num@PAGEOFF
        LDR X1, [X10]
        STR X1, [SP, #-16]!
    
        // LOAD THE PRINTF FORMATTED MESSAGE
        ADRP    X0, output_format@PAGE
        ADD X0, X0, output_format@PAGEOFF
    
    end:
        BL  _printf
        mov X16, #1
        svc 0
    
    read_from_keyboard:
        STP X29, X30, [SP, #-16]!
    
        ADRP    X0, input_format@PAGE
        ADD X0, X0, input_format@PAGEOFF
        ADRP    X11, num@PAGE
        ADD X11, X11, num@PAGEOFF
        STR X11, [SP, #-16]!
        BL _scanf
        ADD SP, SP, #16
    
        LDP X29, X30, [SP], #16
        ret
    
    
    .data
    .balign 4
    message:    .asciz "What is your favorite number?\n"
    .balign 4
    num:    .word 32
    .balign 4
    input_format:   .asciz "%d"
    .balign 4
    output_format:  .asciz "Your favorite number is %d \n"