diff options
author | comex | 2015-01-16 06:32:58 -0500 |
---|---|---|
committer | comex | 2015-01-16 06:32:58 -0500 |
commit | 4ac639ebb0172560f6719f3eed45d1a3f054efe5 (patch) | |
tree | 6d9d2dd67d92928a0463d0585ff827d4c332a876 /lib | |
parent | handle oom and silly machos and stuff (diff) | |
download | substitute-4ac639ebb0172560f6719f3eed45d1a3f054efe5.tar.gz |
and now for something completely different: assembly maybestret-IMPL
forwarding functions for atomicity
Diffstat (limited to 'lib')
-rw-r--r-- | lib/objc-asm.S | 81 | ||||
-rw-r--r-- | lib/substitute.h | 32 |
2 files changed, 113 insertions, 0 deletions
diff --git a/lib/objc-asm.S b/lib/objc-asm.S new file mode 100644 index 0000000..d3dae8a --- /dev/null +++ b/lib/objc-asm.S @@ -0,0 +1,81 @@ +/* These all try to re-invoke old_ptr. To make things worse, we don't know + * whether it will be called as stret or not, so we have to guess. */ +.globl _temp_block_invoke +.section __TEXT,__text,regular,pure_instructions +#if defined(__x86_64__) +_temp_block_invoke: + push %rcx + mov 0x10(%rsi), %rax; /* block if stret, else self */ + lea _temp_block_invoke(%rip), %rcx + cmp %rax, %rcx + pop %rcx + je 2f + mov %rdi, %rax + mov %rsi, %rdi + mov 0x28(%rax), %rsi + mov 0x20(%rax), %rax + jmp *(%rax) +2: /* stret */ + mov %rsi, %rax + mov %rdx, %rsi + mov 0x28(%rsi), %rdx + mov 0x20(%rsi), %rax + jmp *(%rax) +#elif defined(__i386__) +_temp_block_invoke: + call 1f +1: + pop %edx + lea _temp_block_invoke-1b(%edx), %edx + mov 8(%esp), %ecx; /* block if stret, else self */ + mov 0xc(%ecx), %eax + cmp %eax, %edx + je 2f + mov 4(%esp), %eax; /* block */ + mov %ecx, 4(%esp) + mov 0x18(%eax), %ecx + mov %ecx, 8(%esp) + mov 0x14(%eax), %eax + jmp *(%eax) +2: /* stret */ + mov 12(%esp), %ecx; /* self */ + mov 8(%esp), %eax; /* block */ + mov %ecx, 4(%esp) + mov 0x18(%eax), %ecx + mov %ecx, 12(%esp) + mov 0x14(%eax), %eax + jmp *(%eax) +#elif defined(__arm__) +.thumb_func _temp_block_invoke +.thumb +_temp_block_invoke: +1: + ldr r9, [r1, #0xc] + adr r12, 1b + cmp r9, r12 + beq 2f + mov r9, r0 + mov r0, r1 + ldr r1, [r9, #0x18] + ldr r9, [r9, #0x14] + ldr r9, [r9] + bx r9 +2: /* stret */ + mov r9, r1 + mov r1, r2 + ldr r2, [r9, #0x18] + ldr r9, [r9, #0x14] + ldr r9, [r9] + bx r9 +#elif defined(__arm64__) +.align 2 +_temp_block_invoke: + mov x9, x0 + mov x0, x1 + ldr x1, [x9, #0x28] + ldr x9, [x9, #0x20] + ldr x9, [x9] + br x9 +#else +#error No forwarding assembly definition for this arch +#endif diff --git a/lib/substitute.h b/lib/substitute.h index 11141bf..181fb7c 100644 --- a/lib/substitute.h +++ b/lib/substitute.h @@ -43,6 +43,10 @@ enum { /* substitute_interpose_imports: couldn't redo relocation for an import * because the type was unknown */ SUBSTITUTE_ERR_UNKNOWN_RELOCATION_TYPE, + + /* substitute_hook_objc_message: no such selector existed in the class's + * inheritance tree */ + SUBSTITUTE_ERR_NO_SUCH_SELECTOR, }; struct substitute_function_hook { @@ -167,6 +171,34 @@ int substitute_interpose_imports(const struct substitute_image *handle, #endif /* 1 */ +#if defined(__APPLE__) && __BLOCKS__ +#include <objc/runtime.h> +/* Hook a method implementation for a given Objective-C class. By itself, this + * function is thread safe: it is simply a wrapper for the atomic Objective-C + * runtime call class_replaceMethod, plus the superclass-call generation + * functionality described below, and some code to ensure atomicity if the + * method is called while the function is in progress. However, it will race + * with code that modifies class methods without using atomic runtime calls, + * such as Substrate. + * + * @klass the class + * @selector the selector + * @replacement the new implementation + * @old_ptr optional - out pointer to the 'old implementation'. + * If there is no old implementation, a custom IMP is + * returned that delegates to the superclass. This IMP is + * created with imp_implementationWithBlock, so it can be + * freed if desired with imp_removeBlock. + * @created_imp_ptr optional - out pointer to whether a fake superclass-call + * IMP has been placed in <old_ptr> + * + * @return SUBSTITUTE_OK + * SUBSTITUTE_ERR_NO_SUCH_SELECTOR + */ +int substitute_hook_objc_message(Class klass, SEL selector, IMP replacement, + IMP *old_ptr, bool *created_imp_ptr); +#endif + #ifdef __cplusplus } /* extern */ #endif |