Last active
September 8, 2016 21:25
-
-
Save sanekgusev/19e4862fcf6b4b25b0a329ef3dbf6977 to your computer and use it in GitHub Desktop.
arm64 super-forwarding IMP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.section __TEXT,__cstring,cstring_literals | |
L_.super_ivar_name: | |
.ascii "_super" | |
.byte 0 | |
.section __TEXT,__text,regular,pure_instructions | |
.globl _SGVObjcMsgSendSuperTrampolineNew | |
.align 2 | |
; This function will be used as an IMP for a runtime-added method in the super-forwarding proxy. | |
; The goal is to keep all arguments intact and only modify the first argument (in x0) | |
; to point to an 'objc_super' struct instead of proxy instance, and then simply tail-call to objc_msgSendSuper | |
; to call the superclass implementation | |
_SGVObjcMsgSendSuperTrampolineNew: | |
; InlineAsm Start | |
; push link register (x30) and structure return address register (x8) | |
; the first one contains the return address and will be modified by our callees | |
; the second one is needed for methods returning large structs by value | |
stp x30, x8, [sp, #-16]! | |
; push all argument/return value registers | |
stp x7, x6, [sp, #-16]! | |
stp x5, x4, [sp, #-16]! | |
stp x3, x2, [sp, #-16]! | |
stp x1, x0, [sp, #-16]! | |
; decrement SP one more time for the callees not to overwrite x0, | |
; since we were using pre-indexed addressing before and x0 would otherwise be at SP+8 | |
; keep the stack 16-byte aligned | |
sub sp, sp, #16 | |
; x0 already contains self (proxy instance), pass it to object_getClass to get the pointer to self's class | |
; x0 = object_getClass(x0) | |
bl _object_getClass | |
; load x1 with constant string '_super', this is the name of the ivar we're looking for | |
; L_.super_ivar_name is defined on top of this file. | |
; x1 is the location of the 2nd function argument | |
adrp x1, L_.super_ivar_name@PAGE | |
add x1, x1, L_.super_ivar_name@PAGEOFF | |
; x0 = class_getInstanceVariable(x0, x1) | |
bl _class_getInstanceVariable | |
; x0 now contains a pointer to objc ivar, time to get its offset | |
; x0 = ivar_getOffset(x0) | |
bl _ivar_getOffset | |
; x0 now contains the offset of the _super ivar (pointing to objc_super structure) from self (in saved x0) | |
; we now need to restore x0 to its previously stored value and add this | |
; reverse the sub command from our pseudo-'prologue' and prepare the stack for 'popping' | |
add sp, sp, #16 | |
; pop stored x1 to x1 and stored x0 to x9 (which is a scratch GPR) | |
ldp x1, x9, [sp], #16 | |
; add x9 into x0, this gives us exactly what we wanted: x0 now points to the start of objc_super structure from '_super' ivar in self | |
add x0, x0, x9 | |
; keep restoring the remaining argument/return value registers | |
ldp x3, x2, [sp], #16 | |
ldp x5, x4, [sp], #16 | |
ldp x7, x6, [sp], #16 | |
; restore link register (x30) and structure return address register (x8) | |
ldp x30, x8, [sp], #16 | |
; tail-call into objc_msgSendSuper with the same arguments as we were called with, and only x0 modified to point to 'objc_super' struct | |
; jump from the trampoline! | |
b _objc_msgSendSuper | |
; InlineAsm End |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment