I work with some trampoline functions for use with higher-level calling in C / Objective-C, a little twist on the way Apple does this .
If you are familiar with how Objective-C IMP works, it is basically a pointer to a function where the first two arguments are the receiver of the message and the name of the message selector, for example void(*)(id obj, SEL sel, ...) , More later versions of executable implementations allow synthesizing implementation methods at runtime using C blocks, such as void(^)(id obj, ...) . These blocks do not have a selector; the runtime creates a trampoline that overwrites the selector with the receiver, the receiver with the block pointer, and then executes it.
I want to do something vaguely similar, which does not contain either of the first two arguments, so the arguments of this block are exactly the same as the arguments of the traditional send method, plus a block pointer for execution purposes, i.e., void(*)(Block *, ...) . It only requires copying in the block pointer, and I suppose getting rid of the argument.
__a1a2_tramphead_argonly: popl %eax andl $0xFFFFFFF8, %eax subl $0x1000, %eax movl 4(%esp), %ecx // self -> ecx movl %ecx, 8(%esp) // ecx -> _cmd movl (%eax), %ecx // blockPtr -> ecx movl %ecx, 4(%esp) // ecx -> self jmp *12(%ecx) // tail to block->invoke
Here's the build on my ARM:
__a1a2_tramphead_argonly: // calculate the trampoline index (512 entries, 8 bytes each) #ifdef _ARM_ARCH_7 // PC bias is only 4, no need to correct with 8-byte trampolines ubfx r1, r1, #3, #9 #else sub r1, r1, #8 // correct PC bias lsl r1, r1, #20 lsr r1, r1, #23 #endif // load block pointer from trampoline data adr r12, __a1a2_tramphead_argonly // text page sub r12, r12, #4096 // data page precedes text page ldr r12, [r12, r1, LSL #3] // load block pointer from data + index*8 // shuffle parameters mov r1, r0 // _cmd = self mov r0, r12 // self = block pointer // tail call block->invoke ldr pc, [r12, #12]
Similar code exists for x86_64; the above code is so far directly from Apple. For personal knowledge, I wonder where to start by tempting an argument, so the first argument (what used to be a receiver) is a block literal, the second is the first real argument, etc.
I am incredibly noobish at ASM, so any help is greatly appreciated. Everything I tried exploded in increasingly interesting ways. Thanks in advance.