]> git.saurik.com Git - apple/libpthread.git/blob - src/pthread_asm.s
2a02f0949f3e1deac1004db4768e900b2d7e7539
[apple/libpthread.git] / src / pthread_asm.s
1 /*
2 * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "offsets.h"
25
26 #if defined(__x86_64__)
27
28 #include <mach/i386/syscall_sw.h>
29
30 #ifndef VARIANT_DYLD
31
32 .align 2, 0x90
33 .globl _start_wqthread
34 _start_wqthread:
35 // This routine is never called directly by user code, jumped from kernel
36 // Push a sentinel frame, so backtracers know when to stop.
37 push $0
38 push %rbp
39 mov %rsp,%rbp
40 sub $16,%rsp // align the stack
41 call __pthread_wqthread
42 ud2 // never returns
43
44 .align 2, 0x90
45 .globl _thread_start
46 _thread_start:
47 // This routine is never called directly by user code, jumped from kernel
48 // Push a sentinel frame, so backtracers know when to stop.
49 push $0
50 push %rbp
51 mov %rsp,%rbp
52 sub $16,%rsp // align the stack
53 call __pthread_start
54 leave
55 ret
56
57 .align 2, 0x90
58 .globl _thread_chkstk_darwin
59 _thread_chkstk_darwin:
60 .globl ____chkstk_darwin
61 ____chkstk_darwin: // %rax == alloca size
62 pushq %rcx
63 leaq 0x10(%rsp), %rcx
64
65 // validate that the frame pointer is on our stack (no alt stack)
66 cmpq %rcx, %gs:_PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET
67 jb Lprobe
68 cmpq %rcx, %gs:_PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET
69 jae Lprobe
70
71 // validate alloca size
72 subq %rax, %rcx
73 jb Lcrash
74 cmpq %rcx, %gs:_PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET
75 ja Lcrash
76
77 popq %rcx
78 retq
79
80 Lcrash:
81 // POSIX mandates that stack overflow crashes with SIGSEGV
82 // so load an address in the guard page and dereference it
83 movq %gs:_PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET, %rcx
84 testq %rcx, -8(%rcx)
85 // if main_thread caused stack growth with setrlimit()
86 // fall into Lprobe and eventually cause SIGSEGV.
87
88 Lprobe:
89 // probe the stack when it's not ours (altstack or some shenanigan)
90 cmpq $0x1000, %rax
91 jb Lend
92 pushq %rax
93 Lloop:
94 subq $0x1000, %rcx
95 testq %rcx, (%rcx)
96 subq $0x1000, %rax
97 cmpq $0x1000, %rax
98 ja Lloop
99 popq %rax
100 Lend:
101 subq %rax, %rcx
102 testq %rcx, (%rcx)
103
104 popq %rcx
105 retq
106
107 #endif
108
109 #elif defined(__i386__)
110
111 #include <mach/i386/syscall_sw.h>
112
113 #ifndef VARIANT_DYLD
114
115 .align 2, 0x90
116 .globl _start_wqthread
117 _start_wqthread:
118 // This routine is never called directly by user code, jumped from kernel
119 // Push a sentinel frame, so backtracers know when to stop.
120 push $0
121 push %ebp
122 mov %esp,%ebp
123 sub $24,%esp // align the stack
124 mov %esi,20(%esp) //arg5
125 mov %edi,16(%esp) //arg5
126 mov %edx,12(%esp) //arg4
127 mov %ecx,8(%esp) //arg3
128 mov %ebx,4(%esp) //arg2
129 mov %eax,(%esp) //arg1
130 call __pthread_wqthread
131 ud2 // never returns
132
133 .align 2, 0x90
134 .globl _thread_start
135 _thread_start:
136 // This routine is never called directly by user code, jumped from kernel
137 // Push a sentinel frame, so backtracers know when to stop.
138 push $0
139 push %ebp
140 mov %esp,%ebp
141 sub $24,%esp // align the stack
142 mov %esi,20(%esp) //arg6
143 mov %edi,16(%esp) //arg5
144 mov %edx,12(%esp) //arg4
145 mov %ecx,8(%esp) //arg3
146 mov %ebx,4(%esp) //arg2
147 mov %eax,(%esp) //arg1
148 call __pthread_start
149 leave
150 ret
151
152 .align 2, 0x90
153 .globl _thread_chkstk_darwin
154 _thread_chkstk_darwin:
155 .globl ____chkstk_darwin
156 ____chkstk_darwin: // %eax == alloca size
157 pushl %ecx
158 pushl %edx
159 leal 0xc(%esp), %ecx
160
161 // validate that the frame pointer is on our stack (no alt stack)
162 movl %gs:0x0, %edx // pthread_self()
163 cmpl %ecx, _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET(%edx)
164 jb Lprobe
165 movl _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET(%edx), %edx
166 cmpl %ecx, %edx
167 jae Lprobe
168
169 // validate alloca size
170 subl %eax, %ecx
171 jb Lcrash
172 cmpl %ecx, %edx
173 ja Lcrash
174
175 popl %edx
176 popl %ecx
177 retl
178
179 Lcrash:
180 // POSIX mandates that stack overflow crashes with SIGSEGV
181 // so load an address in the guard page and dereference it
182 movl %gs:0x0, %ecx // pthread_self()
183 movl _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET(%ecx), %ecx
184 testl %ecx, -4(%ecx)
185 // if main_thread caused stack growth with setrlimit()
186 // fall into Lprobe and eventually cause SIGSEGV.
187
188 Lprobe:
189 // probe the stack when it's not ours (altstack or some shenanigan)
190 cmpl $0x1000, %eax
191 jb Lend
192 pushl %eax
193 Lloop:
194 subl $0x1000, %ecx
195 testl %ecx, (%ecx)
196 subl $0x1000, %eax
197 cmpl $0x1000, %eax
198 ja Lloop
199 popl %eax
200 Lend:
201 subl %eax, %ecx
202 testl %ecx, (%ecx)
203
204 popl %edx
205 popl %ecx
206 retl
207
208 #endif
209
210 #elif defined(__arm__)
211
212 #include <mach/arm/syscall_sw.h>
213
214 #ifndef VARIANT_DYLD
215
216 // This routine is never called directly by user code, jumped from kernel
217 // args 0 to 3 are already in the regs 0 to 3
218 // should set stack with the 2 extra args before calling pthread_wqthread()
219 // arg4 is in r[4]
220 // arg5 is in r[5]
221
222 .text
223 .align 2
224 .globl _start_wqthread
225 _start_wqthread:
226 // Push a sentinel frame, so backtracers know when to stop.
227 mov ip, #0
228 str ip, [sp, #-4]!
229 str ip, [sp, #-4]!
230 stmfd sp!, {r4, r5}
231 bl __pthread_wqthread
232 trap // never returns
233
234 .text
235 .align 2
236 .globl _thread_start
237 _thread_start:
238 // Push a sentinel frame, so backtracers know when to stop.
239 mov ip, #0
240 str ip, [sp, #-4]!
241 str ip, [sp, #-4]!
242 stmfd sp!, {r4, r5}
243 bl __pthread_start
244 // Stackshots will show the routine that happens to link immediately following
245 // _start_wqthread. So we add an extra instruction (nop) to make stackshots
246 // more readable.
247 nop
248
249 #endif
250
251 #elif defined(__arm64__)
252
253 #include <mach/arm/syscall_sw.h>
254
255 #ifndef VARIANT_DYLD
256
257 // This routine is never called directly by user code, jumped from kernel
258 // args 0 to 5 in registers.
259 .text
260 .align 2
261 .globl _start_wqthread
262 _start_wqthread:
263 // Push a sentinel frame, so backtracers know when to stop.
264 stp xzr, xzr, [sp, #-16]!
265 bl __pthread_wqthread
266 brk #1 // never returns
267
268 .text
269 .align 2
270 .globl _thread_start
271 _thread_start:
272 // Push a sentinel frame, so backtracers know when to stop.
273 stp xzr, xzr, [sp, #-16]!
274 bl __pthread_start
275 nop
276
277 .text
278 .align 2
279 .globl _thread_chkstk_darwin
280 _thread_chkstk_darwin:
281 .globl ____chkstk_darwin
282 ____chkstk_darwin: // %w9/x9 == alloca size
283 stp x10, x11, [sp, #-16]
284
285 // validate that the frame pointer is on our stack (no alt stack)
286 mrs x10, TPIDRRO_EL0
287 and x10, x10, #0xfffffffffffffff8
288
289 // (%sp - pthread_self()->stackaddr) > 0 ?
290 #if defined(__ARM64_ARCH_8_32__)
291 ubfx x9, x9, #0, #32
292 ldur w11, [x10, _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET]
293 #else
294 ldur x11, [x10, _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET]
295 #endif
296 subs x11, sp, x11
297 b.hs Lprobe
298
299 // %sp <= pthread_self()->stackbottom ?
300 #if defined(__ARM64_ARCH_8_32__)
301 ldur w11, [x10, _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET]
302 #else
303 ldur x11, [x10, _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET]
304 #endif
305 mov x10, sp
306 cmp x10, x11
307 b.ls Lprobe
308
309 // %sp - (uintptr_t)%x9 < pthread_self()->stackbottom ?
310 subs x10, x10, x9
311 b.lo Lcrash
312 cmp x10, x11
313 b.lo Lcrash
314
315 Lexit:
316 ldp x10, x11, [sp, #-16]
317 ret
318
319 Lcrash:
320 // POSIX mandates that stack overflow crashes with SIGSEGV
321 // so load an address in the guard page and dereference it
322 //
323 // x11 contains pthread_self()->stackbottom already
324 ldr x11, [x11, #-8]
325 // if main_thread caused stack growth with setrlimit()
326 // fall into Lprobe and eventually cause SIGSEGV.
327
328 Lprobe:
329 mov x10, sp
330 cmp x9, #0x1000
331 b.lo Lend
332 Lloop:
333 sub x10, x10, #0x1000
334 ldr x11, [x10]
335 sub x9, x9, #0x1000
336 cmp x9, #0x1000
337 b.hi Lloop
338 Lend:
339 sub x10, x10, x9
340 ldr x11, [x10]
341 b Lexit
342
343 #endif
344
345 #else
346 #error Unsupported architecture
347 #endif