Apple Silicon calling printf

What is the proper way to pass arguments to printf with multiple variables using ARM64 Apple Silicon? Example: fOutputStr: .asciz "Element[%d] = %d\n" // formated output string

for an output of: Element[4] = 9 This code (see below) works on Raspberry Pi 5, on my Mac Studio, I am getting this output,

Element[9] = 1871655168

What do I need to do to use printf from an assembly language call with multiple variables?

I am using the following code. ` .align 2 // memory alignment model for 64-bit ARMc

#if defined(APPLE) .global _main // Provide program starting address to linker Mac OS _main: #else .global main // Raspian and Linux main: #endif

        // stack frame work setup START
        stp     x29, x30, [sp, -16]!
        str     x20, [sp, -16]!

        mov     x29, sp
        // stack frame work setup END

           // setup printf call

#if defined(APPLE) adrp x0, fOutputStr@PAGE add x0, x0, fOutputStr@PAGEOFF #else ldr x0, =fOutputStr #endif

            mov     w1, #4
            mov     w2, #9

print_brk:

#if defined(APPLE)

        stp X0, X1, [SP, #-16]!
        stp X2, X3, [SP, #-16]!
        
        bl _printf

        ldp X2, X3, [SP], #16
        ldp X0, X1, [SP], #16

#else bl printf #endif

done: // closing stack frame work ldr x20, [sp],16 ldp x29, x30, [sp],16

        // exit
        mov     w0, wzr
        ret

    .data
    .align 4

// intArrayPtr: .word 3,7,5,2,4,8 // word, each value is offset by 4 fOutputStr: .asciz "Element[%d] = %d\n" // formated output string


#if defined(__APPLE__)
     .global _main  // Provide program starting address to linker Mac OS
_main:
#else
    .global main    // Raspian and Linux
main:
#endif

            // stack frame work setup START
            stp     x29, x30, [sp, -16]!
            str     x20, [sp, -16]!

            mov     x29, sp
            // stack frame work setup END

               // setup printf call
#if defined(__APPLE__)
                adrp    x0, fOutputStr@PAGE
                add     x0, x0, fOutputStr@PAGEOFF
#else
                ldr     x0, =fOutputStr
#endif

                mov     w1, #4
                mov     w2, #9

print_brk:

#if defined(__APPLE__)

            stp X0, X1, [SP, #-16]!
            stp X2, X3, [SP, #-16]!
            
            bl _printf

            ldp X2, X3, [SP], #16
            ldp X0, X1, [SP], #16
 
#else
            bl      printf
#endif



done:
            // closing stack frame work
            ldr     x20, [sp],16
            ldp     x29, x30, [sp],16

            // exit
            mov     w0, wzr
            ret

        .data
        .align 4
// intArrayPtr:        .word   3,7,5,2,4,8      // word, each value is offset by 4
fOutputStr:         .asciz  "Element[%d] = %d\n"  // formated output string    

Oh wow, thanks for this awesome post, it’s been a while since I used asm and mainly for debugging. In Rasperry Pi you can use other languages that will provide you a faster and more transferable between devices. I recommend Python personally and no changes will be required on different devices.

I hope as many engineers jump into this thread as this is a great mind exercise in my book.

I think you’ll need to allocate space on the stack, store your 32-bit integers into that stack space, call _printf, and then restore the stack pointer. Since %d expects 32-bit integers, they take up 4 bytes each.

Variadic arguments are passed in registers exactly like normal function arguments. On Apple Silicon all variadic arguments must be passed on the stack.

My brain hurts now.

Albert Pascual
  Worldwide Developer Relations.

Accepted Answer

Thank you! Just figured this out. Much appreciated!!!!! This was my solution,

                 mov    w2, w20

                // Prepare printf arguments
                // x0 = format string.   x0
                // w1 = i               w20
                // w2 = element i       w1
#if defined(__APPLE__)

            // Apple Silicon store decimals
            stp X2, X1 , [SP, #-16]! 
            bl _printf
            ldp X2, X1, [SP], #16
#else
            bl      printf
#endif

Here is the desired output. ❯ ./a.out Through all my reading, Linux and Pi pass through registers and Apple Silicon pass on the stack (reverse order). Are there Apple Docs on this somewhere?

Here is the sample output from the terminal on Mac OS. Thank you, Albert!!!!

Element[4] = 9

@mnorton Great job! I think there might be some documentation online that can be referenced here. Reverse order well is the Big-endian issue that happens when we move from different chips. Awesome finding and great job again, can't wait to see what you do next!

Albert Pascual
  Worldwide Developer Relations.

Apple Silicon calling printf
 
 
Q