.global _callvm_invoke_i .align 4 # x0 = (function ptr) impl # x1 = (struct callvm) context _callvm_invoke_i: # save the stack frame and link pointer stp x29, x30, [sp, #-16]! mov x29, sp # preserve callee-saved registers stp x19, x20, [sp, #-16]! # store function pointer and callvm context for later mov x19, x0 mov x20, x1 # First, set up the variable arguments ### calculate the amount of stack space needed for the varargs # store the original stack pointer, so it can be restored later mov x0, sp str x0, [sp, #-16]! # x8 = excess arg count ldr x8, [x20, #32] # x8 = excess arg buffer size (8 bytes per value) lsl x8, x8, #3 # allocate the stack space sub sp, sp, x8 # re-align the stack, and take a pointer to the newly-allocated buffer mov x0, sp and x0, x0, #0xFFFFFFFFFFFFFFF0 mov sp, x0 ldr x1, [x20, #176] mov x2, x8 # memcpy(stack vararg buffer, callvm excess buffer, arg size) bl _memcpy # Next, set up the fixed integer arguments ldr x0, [x20, #48] ldr x1, [x20, #56] ldr x2, [x20, #64] ldr x3, [x20, #72] ldr x4, [x20, #80] ldr x5, [x20, #88] ldr x6, [x20, #96] ldr x7, [x20, #104] # Finally, set up the fixed double arguments ldr d0, [x20, #112] ldr d1, [x20, #120] ldr d2, [x20, #128] ldr d3, [x20, #136] ldr d4, [x20, #144] ldr d5, [x20, #152] ldr d6, [x20, #160] ldr d7, [x20, #168] # call the function implementation blr x19 # restore the saved stack pointer, and de-allocate the stack varargs buffer ldr x9, [x29, #-32] mov sp, x9 # restore callee-saved registers ldp x19, x20, [sp], #16 # restore the saved stack frame and link pointer ldp x29, x30, [sp], #16 ret .global _callvm_invoke_d .align 4 # x0 = (function ptr) impl # x1 = (struct callvm) context _callvm_invoke_d: b _callvm_invoke_i .global _callvm_invoke_v .align 4 # x0 = (function ptr) impl # x1 = (struct callvm) context _callvm_invoke_v: b _callvm_invoke_i