aboutsummaryrefslogtreecommitdiff
path: root/lib/objc-asm.S
blob: 94d9de9cc7dc7e0d639f91a3656e0150564206d0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* These all forward to the IMP obtained from block->get_imp(block); this
 * signature is just so that I don't have to have two different assembly
 * implementations for the temporary and fake-old blocks.  To make things
 * confusing, we don't know whether it will be called as stret or not, so we
 * have to guess.
 * (Could avoid the guessing by generating custom assembly instead, like
 * Substrate does, but meh.)
 */
.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 0x20(%rdi), %rax /* get_imp */
    push %rdi; push %rsi; push %rdx; push %rcx; push %r8; push %r9
    call *%rax
    pop %r9; pop %r8; pop %rcx; pop %rdx; pop %rdi; pop %rsi
    mov 0x28(%rsi), %rsi /* selector */
    jmp *%rax
2: /* stret */
    mov 0x20(%rsi), %rax /* get_imp */
    push %rdi; push %rsi; push %rdx; push %rcx; push %r8; push %r9
    mov %rsi, %rdi
    call *%rax
    pop %r9; pop %r8; pop %rcx; pop %rsi; pop %rdx; pop %rdi
    mov 0x28(%rdx), %rdx /* selector */
    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 */
    push %eax
    mov 0x14(%eax), %eax /* get_imp */
    call *%eax
    add $4, %esp
    mov 8(%esp), %edx /* self */
    mov 4(%esp), %ecx /* block */
    mov %edx, 4(%esp)
    mov 0x18(%ecx), %ecx
    mov %ecx, 8(%esp)
    jmp *%eax
2: /* stret */
    int3
    mov 8(%esp), %eax /* block */
    push %eax
    mov 0x14(%eax), %eax /* get_imp */
    call *%eax
    add $4, %esp
    int3
    mov 12(%esp), %ecx /* self */
    mov %ecx, 8(%esp)
    mov 8(%esp), %ecx /* block */
    mov 0x18(%ecx), %ecx
    mov %ecx, 12(%esp)
    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

    push {r0-r4, lr} /* r4 for align */
    ldr r9, [r0, #0x14]
    blx r9
    mov r12, r0
    pop {r0-r4, lr}
    mov r9, r0
    mov r0, r1
    ldr r1, [r9, #0x18]
    bx r12
2: /* stret */
    push {r0-r3, lr}
    ldr r9, [r1, #0x14]
    blx r9
    mov r12, r0
    pop {r0-r3, lr}
    mov r9, r1
    mov r1, r2
    ldr r2, [r9, #0x18]
    bx r12
#elif defined(__arm64__)
.align 2
_temp_block_invoke:
    stp x7, x6, [sp, #-0x10]!
    stp x5, x4, [sp, #-0x10]!
    stp x3, x2, [sp, #-0x10]!
    stp x1, x0, [sp, #-0x10]!
    str x30, [sp, #-0x10]!

    ldr x9, [x0, #0x20]
    blr x9
    mov x10, x0

    ldr x30, [sp], #0x10
    ldp x0, x9, [sp], #0x10
    ldp x3, x2, [sp], #0x10
    ldp x5, x4, [sp], #0x10
    ldp x7, x6, [sp], #0x10

    ldr x1, [x9, #0x28]
    br x10
#else
#error No forwarding assembly definition for this arch
#endif