1#include "common.S"
2
3#
4# This file defines some trampolines for calling blocks.  A block function
5# looks like this:
6#
7# retType blockFn(block*, ...)
8#
9# An IMP looks like this:
10#
11# retType imp(id, SEL,...)
12#
13# The trampoline must find the block pointer and then call the block function
14# with the correct first argument, the self pointer moved to the second real
15# argument (the first block argument) and the _cmd parameter excised
16
17.file	"block_trampolines.S"
18
19
20#if __x86_64
21////////////////////////////////////////////////////////////////////////////////
22// x86-64 trampoline
23////////////////////////////////////////////////////////////////////////////////
24.macro trampoline arg0, arg1
25	mov   -0x1007(%rip), \arg1   # Load the block pointer into the second argument
26	xchg  \arg1, \arg0           # Swap the first and second arguments
27	jmp   *-0x1008(%rip)         # Call the block function
28.endm
29// The Win64 and SysV x86-64 ABIs use different registers
30#	ifdef _WIN64
31#		define ARG0 %rcx
32#		define ARG1 %rdx
33#		define SARG1 %r8
34#	else
35#		define ARG0 %rdi
36#		define ARG1 %rsi
37#		define SARG1 %rdx
38#	endif
39#	define SARG0 ARG1
40
41#elif __i386
42////////////////////////////////////////////////////////////////////////////////
43// x86-32 trampoline
44////////////////////////////////////////////////////////////////////////////////
45
46#ifdef _WIN32
47// Mark this compilation unit as SEH-safe
48.text
49.def     @feat.00;
50.scl    3;
51.type   0;
52.endef
53.globl  @feat.00
54.set @feat.00, 1
55.data
56#endif
57
58.macro trampoline arg0, arg1
59	call  1f                   # Store the instruction pointer on the stack
601:
61	pop   %eax                 # Load the old instruction pointer
62	mov   \arg0(%esp), %ebx    # Load the self parameter
63	mov   %ebx, \arg1(%esp)    # Store self as the second argument
64	mov   -0x1005(%eax), %ebx  # Load the block pointer to %ebx
65	mov   %ebx, \arg0(%esp)    # Store the block pointer in the first argument
66	jmp   *-0x1001(%eax)       # Call the block function
67.endm
68// All arguments on i386 are passed on the stack.  These values are stack
69// offsets - on other platforms they're register values.
70#	define ARG0 4
71#	define ARG1 8
72#	define SARG0 8
73#	define SARG1 12
74
75#elif __mips__
76////////////////////////////////////////////////////////////////////////////////
77// MIPS trampoline
78////////////////////////////////////////////////////////////////////////////////
79#	ifdef _ABI64
80.macro trampoline arg0, arg1
81	move     \arg1, \arg0
82	ld       \arg0, -4096($25)
83	ld       $25, -4088($25)
84	jr       $25
85.endm
86#	else
87// 32-bit variant.  This ought to work with both n32 and o32, because they both
88// use 32-bit pointers and both use the same registers for the first four
89// arguments (and we only care about the first three).
90.macro trampoline arg0, arg1
91	move   \arg1, \arg0
92	lw     \arg0, -4096($25)
93	lw     $25, -4092($25)
94	jr     $25
95.endm
96#	endif
97#define ARG0 $a0
98#define ARG1 $a1
99#define ARG2 $a2
100
101#elif defined(__ARM_ARCH_ISA_A64)
102////////////////////////////////////////////////////////////////////////////////
103// AArch64 (ARM64) trampoline
104////////////////////////////////////////////////////////////////////////////////
105.macro trampoline arg0, arg1
106	adr x17, #-4096
107	mov \arg1, \arg0
108	ldp \arg0, x17, [x17]
109	br x17
110.endm
111#define ARG0 x0
112#define ARG1 x1
113#define SARG0 x0
114#define SARG1 x1
115
116#elif __arm__
117////////////////////////////////////////////////////////////////////////////////
118// AArch32 (ARM) trampoline
119////////////////////////////////////////////////////////////////////////////////
120
121#	if (__ARM_ARCH_ISA_THUMB == 2)
122// If we're on a target that supports Thumb 2, then we need slightly more
123// instructions to support Thumb/ARM code for the IMP and so we need to make
124// the trampolines thumb to be able to fit them in 16 bytes (they fit exactly
125// when assembled as Thumb-2).
126.thumb
127.macro trampoline arg0, arg1
128	sub r12, pc, #4095
129	mov \arg1, \arg0            // Move self over _cmd
130	ldr \arg0, [r12, #-5]       // Load the block pointer over self
131	ldr r12, [r12, #-1]         // Jump to the block function
132	bx  r12
133.endm
134#	else
135.macro trampoline arg0, arg1
136	sub r12, pc, #4096
137	mov \arg1, \arg0            // Move self over _cmd
138	ldr \arg0, [r12, #-8]       // Load the block pointer over self
139	ldr pc, [r12, #-4]          // Jump to the block function
140.endm
141#	endif // (__ARM_ARCH_ISA_THUMB == 2)
142#define ARG0 r0
143#define ARG1 r1
144#define SARG0 r1
145#define SARG1 r2
146
147#else
148
149#warning imp_implementationWithBlock() not implemented for your architecture
150.macro trampoline arg0, arg1
151.endm
152#define ARG0 0
153#define ARG1 0
154#define SARG0 0
155#define SARG1 0
156
157#endif
158
159
160.globl CDECL(__objc_block_trampoline)
161CDECL(__objc_block_trampoline):
162	trampoline ARG0, ARG1
163.globl CDECL(__objc_block_trampoline_end)
164CDECL(__objc_block_trampoline_end):
165.globl CDECL(__objc_block_trampoline_sret)
166CDECL(__objc_block_trampoline_sret):
167	trampoline SARG0, SARG1
168.globl CDECL(__objc_block_trampoline_end_sret)
169CDECL(__objc_block_trampoline_end_sret):
170
171
172#ifdef __ELF__
173.section .note.GNU-stack,"",%progbits
174#endif
175