Я работаю с некоторыми функциями батута для использования с вызовами более высокого уровня в C / Objective-C, небольшой поворот на пути Apple делает это .
Если вы вообще знакомы с тем, как работает Objective-C IMP
, это в основном указатель на функцию, где первые два аргумента являются получателем сообщения и именем селектора сообщения, например void(*)(id obj, SEL sel, ...)
, Более поздние версии среды выполнения позволяют синтезировать реализации методов во время выполнения с использованием блоков C, например void(^)(id obj, ...)
. Эти блоки не имеют селектора; среда выполнения создает батут, который перезаписывает селектор получателем, получатель - указателем блока, а затем переходит к его выполнению.
Я хочу сделать что-то неопределенно похожее, что подразумевает отсутствие либо первых двух аргументов, так что аргументы этого блока в точности совпадают с аргументами традиционного метода send плюс блок указатель для выполнения, то есть void(*)(Block *, ...)
. Это требует только копирования в указателе блока, и я предполагаю избавиться от аргумента.
__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
Вот сборка, которая у меня есть на ARM:
__a1a2_tramphead_argonly:
// calculate the trampoline's 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's 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]
Аналогичный код существует для x86_64; приведенный выше код пока далек от Apple. Для личного знания мне интересно, с чего начать с удаления аргумента, чтобы первый аргумент (который раньше был получателем) - это литерал блока, второй - первый реальный аргумент и т. Д.
Я невероятно нобист в ASM, поэтому любая помощь очень ценится. Все, что я пробовал, взорвалось все более интересными способами. Заранее спасибо.