Skip to content

Instantly share code, notes, and snippets.

@sanekgusev
Last active September 8, 2016 21:25
Show Gist options
  • Save sanekgusev/19e4862fcf6b4b25b0a329ef3dbf6977 to your computer and use it in GitHub Desktop.
Save sanekgusev/19e4862fcf6b4b25b0a329ef3dbf6977 to your computer and use it in GitHub Desktop.
arm64 super-forwarding IMP
.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