2 * very-low-level utilities for runtime support
6 * This software is part of the SBCL system. See the README file for
9 * This software is derived from the CMU CL system, which was
10 * written at Carnegie Mellon University and released into the
11 * public domain. The software is in the public domain and is
12 * provided with absolutely no warranty. See the COPYING and CREDITS
13 * files for more information.
17 // Mark the object as not requiring an executable stack.
18 .section .note.GNU-stack,"",%progbits
21 #define LANGUAGE_ASSEMBLY
22 #include "genesis/config.h"
25 #include "genesis/closure.h"
26 #include "genesis/static-symbols.h"
27 #include "genesis/thread.h"
29 /* Minimize conditionalization for different OS naming schemes. */
30 #if defined __linux__ || defined LISP_FEATURE_FREEBSD || defined __OpenBSD__ || defined __NetBSD__ || defined __sun || defined _WIN64 || defined __DragonFly__
31 #define GNAME(var) var
33 #define GNAME(var) _##var
36 #if POSITION_INDEPENDENT_ASM
37 #define PIC_CALL(x) x@PLT
38 #define PIC_VAR(x) x(%rip)
44 /* Get the right type of alignment. Linux, FreeBSD and OpenBSD
45 * want alignment in bytes. */
46 #if defined(__linux__) || defined(LISP_FEATURE_FREEBSD) || defined(__OpenBSD__) || defined __NetBSD__ || defined(__sun) || defined _WIN64 || defined(__DragonFly__)
49 #define align_16byte 16
50 #define align_32byte 32
51 #define align_page 32768
55 #define align_16byte 4
60 * The assembler used for win32 doesn't like .type or .size directives,
61 * so we want to conditionally kill them out. So let's wrap them in macros
62 * that are defined to be no-ops on win32. Hopefully this still works on
65 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
66 #define TYPE(name) .type name,@function
67 #define SIZE(name) .size name,.-name
68 #define DOLLAR(name) $(name)
75 * x86/darwin (as of MacOS X 10.4.5) doesn't reliably fire signal
76 * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have
77 * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or
78 * 0F 0B in low-endian notation, that causes SIGILL to fire. We check
79 * for this instruction in the SIGILL handler and if we see it, we
80 * advance the EIP by two bytes to skip over ud2 instruction and
81 * call sigtrap_handler. */
82 #if defined(LISP_FEATURE_UD2_BREAKPOINTS)
89 * More Apple assembler hacks
92 #if defined(LISP_FEATURE_DARWIN)
93 /* global symbol x86-64 sym(%rip) hack:*/
94 #define GSYM(name) name(%rip)
96 #define GSYM(name) $name
101 .globl GNAME(all_threads)
104 .globl GNAME(call_into_lisp_first_time)
105 TYPE(GNAME(call_into_lisp_first_time))
107 /* We don't worry too much about saving registers
108 * here, because we never expect to return from the initial call to lisp
111 .align align_16byte,0x90
112 GNAME(call_into_lisp_first_time):
113 push %rbp # Save old frame pointer.
114 mov %rsp,%rbp # Establish new frame.
115 #if defined(LISP_FEATURE_DARWIN)
116 movq GSYM(GNAME(all_threads)),%rax
118 movq PIC_VAR(GNAME(all_threads)),%rax
120 mov THREAD_CONTROL_STACK_END_OFFSET(%rax) ,%rsp
124 .globl GNAME(call_into_lisp)
125 TYPE(GNAME(call_into_lisp))
128 * amd64 calling convention: C expects that
129 * arguments go in rdi rsi rdx rcx r8 r9
130 * return values in rax rdx
131 * callee saves rbp rbx r12-15 if it uses them
133 #ifdef LISP_FEATURE_WIN32
134 # define SUPPORT_FOMIT_FRAME_POINTER
136 .align align_16byte,0x90
137 GNAME(call_into_lisp):
138 #ifdef SUPPORT_FOMIT_FRAME_POINTER
141 push %rbp # Save old frame pointer.
142 mov %rsp,%rbp # Establish new frame.
144 #ifdef SUPPORT_FOMIT_FRAME_POINTER
145 /* If called through call_into_lisp_first_time, %r15 becomes invalid
146 * here, but we will not return in that case. */
150 /* FIXME x86 saves FPU state here */
151 push %rbx # these regs are callee-saved according to C
152 push %r12 # so must be preserved and restored when
153 push %r13 # the lisp function returns
157 mov %rsp,%rbx # remember current stack
158 push %rbx # Save entry stack on (maybe) new stack.
160 push %rdi # args from C
163 #ifdef LISP_FEATURE_SB_THREAD
164 # ifdef SUPPORT_FOMIT_FRAME_POINTER
167 call GNAME(carry_frame_pointer)
171 #ifdef LISP_FEATURE_GCC_TLS
173 movq GNAME(current_thread)@TPOFF(%rax), %r12
175 #ifdef LISP_FEATURE_DARWIN
176 mov GSYM(GNAME(specials)),%rdi
178 mov PIC_VAR(specials),%rdi
180 call PIC_CALL(GNAME(pthread_getspecific))
185 pop %rbx # arg vector
186 pop %rax # function ptr/lexenv
188 xor %rdx,%rdx # clear any descriptor registers
189 xor %rdi,%rdi # that we can't be sure we'll
190 xor %rsi,%rsi # initialise properly. XX do r8-r15 too?
192 # It's tempting to think 'cmov' for these assignments, but don't:
193 # cmov does a memory cycle whether or not it moves, succumbing to
194 # a classic buffer overrun bug if argv[] is "badly" placed.
196 mov 0(%rbx),%rdx # arg0
199 mov 8(%rbx),%rdi # arg1
202 mov 16(%rbx),%rsi # arg2
204 shl $(N_FIXNUM_TAG_BITS),%rcx # (fixnumize num-args)
205 /* Registers rax, rcx, rdx, rdi, and rsi are now live. */
206 xor %rbx,%rbx # available
208 /* Alloc new frame. */
209 push %rbp # Dummy for return address
210 push %rbp # fp in save location S1
211 mov %rsp,%rbp # The current sp marks start of new frame.
212 sub $8,%rsp # Ensure 3 slots are allocated, two above.
215 call *CLOSURE_FUN_OFFSET(%rax)
217 /* If the function returned multiple values, the carry flag will be set.
223 /* Restore the stack, in case there was a stack change. */
233 /* FIXME Restore the NPX state. */
235 mov %rdx,%rax # c-val
236 #ifdef SUPPORT_FOMIT_FRAME_POINTER
237 mov %r15,%rbp # orig rbp
239 add $8,%rsp # no need for saved (overridden) rbp
244 SIZE(GNAME(call_into_lisp))
246 /* Our call-site does not take care of caller-saved xmm registers, so it
247 * falls to us spill them beforing hopping into C.
249 * We simply save all of them.
251 * (But for the sake of completeness, here is my understanding of the specs:)
253 * argument passing xmm0-7 xmm0-3
254 * caller-saved xmm8-15 xmm4-5
255 * callee-saved - xmm6-15
259 #define stkxmmsave(n) movaps %xmm##n, n*16(%rsp)
260 #define stkxmmload(n) movaps n*16(%rsp), %xmm##n
261 #define map_all_xmm(op) \
262 op(0);op(1);op(2);op(3);op(4);op(5);op(6);op(7); \
263 op(8);op(9);op(10);op(11);op(12);op(13);op(14);op(15);
266 .align align_16byte,0x90
267 .globl GNAME(alloc_tramp)
268 TYPE(GNAME(alloc_tramp))
271 push %rbp # Save old frame pointer.
272 mov %rsp,%rbp # Establish new frame.
275 map_all_xmm(stkxmmsave)
276 # Doing rax twice is to maintain 16-byte stack alignment.
287 # r12 through r15 are callee-saved
300 pop %rax # corresponds to "extra" push
301 map_all_xmm(stkxmmload)
305 SIZE(GNAME(alloc_tramp))
308 .align align_16byte,0x90
309 .globl GNAME(alloc_to_r11)
310 TYPE(GNAME(alloc_to_r11))
313 push %rbp # Save old frame pointer.
314 mov %rsp,%rbp # Establish new frame.
317 map_all_xmm(stkxmmsave)
318 # Doing rax twice is to maintain 16-byte stack alignment.
329 # r12 through r15 are callee-saved
332 mov %rax,%r11 # move to result register
333 pop %rax # dummy. %rax gets popped again later
342 pop %rax # corresponds to "extra" push
343 map_all_xmm(stkxmmload)
346 retq $8 # remove 8 bytes from the stack
347 SIZE(GNAME(alloc_to_r11))
350 * fun-end breakpoint magic
354 * For an explanation of the magic involved in function-end
355 * breakpoints, see the implementation in ppc-assem.S.
359 .globl GNAME(fun_end_breakpoint_guts)
361 GNAME(fun_end_breakpoint_guts):
362 /* Multiple Value return */
363 jc multiple_value_return
364 /* Single value return: The eventual return will now use the
365 multiple values return convention but with a return values
367 mov %rsp,%rbx # Setup ebx - the ofp.
368 sub $8,%rsp # Allocate one stack slot for the return value
369 mov $(1 << N_FIXNUM_TAG_BITS),%rcx # Setup ecx for one return value.
370 mov GSYM(NIL),%rdi # default second value
371 mov GSYM(NIL),%rsi # default third value
372 multiple_value_return:
374 .globl GNAME(fun_end_breakpoint_trap)
375 .align align_16byte,0x90
376 GNAME(fun_end_breakpoint_trap):
378 .byte trap_FunEndBreakpoint
379 hlt # We should never return here.
381 .globl GNAME(fun_end_breakpoint_end)
382 GNAME(fun_end_breakpoint_end):
385 .globl GNAME(do_pending_interrupt)
386 TYPE(GNAME(do_pending_interrupt))
387 .align align_16byte,0x90
388 GNAME(do_pending_interrupt):
390 .byte trap_PendingInterrupt
392 SIZE(GNAME(do_pending_interrupt))
394 .globl GNAME(post_signal_tramp)
395 TYPE(GNAME(post_signal_tramp))
396 .align align_16byte,0x90
397 GNAME(post_signal_tramp):
398 /* this is notionally the second half of a function whose first half
399 * doesn't exist. This is where call_into_lisp returns when called
400 * using return_to_lisp_function */
411 /* skip RBP and RSP */
419 SIZE(GNAME(post_signal_tramp))
421 /* When LISP_FEATURE_C_STACK_IS_CONTROL_STACK, we cannot safely scrub
422 * the control stack from C, largely due to not knowing where the
423 * active stack frame ends. On such platforms, we reimplement the
424 * core scrubbing logic in assembly, in this case here:
427 .align align_16byte,0x90
428 .globl GNAME(arch_scrub_control_stack)
429 TYPE(GNAME(arch_scrub_control_stack))
430 GNAME(arch_scrub_control_stack):
431 /* We are passed three parameters:
432 * A (struct thread *) in RDI,
433 * the address of the guard page in RSI, and
434 * the address of the hard guard page in RDX.
435 * We may trash RAX, RCX, and R8-R11 with impunity.
436 * [RSP] is our return address, [RSP-8] is the first
437 * stack slot to scrub. */
439 /* We start by setting up our scrub pointer in RAX, our
440 * guard page upper bound in R8, and our hard guard
441 * page upper bound in R9. */
443 #ifdef LISP_FEATURE_DARWIN
444 mov GSYM(GNAME(os_vm_page_size)),%r9
446 mov PIC_VAR(os_vm_page_size),%r9
451 /* Now we begin our main scrub loop. */
454 /* If we're about to scrub the hard guard page, exit. */
456 jae ascs_check_guard_page
460 ascs_check_guard_page:
461 /* If we're about to scrub the guard page, and the guard
462 * page is protected, exit. */
467 cmpq $(NIL), THREAD_CONTROL_STACK_GUARD_PAGE_PROTECTED_OFFSET(%rdi)
470 /* Clear memory backwards to the start of the (4KiB) page */
477 /* If we're about to hit the hard guard page, exit. */
481 /* If the next (previous?) 4KiB page contains a non-zero
482 * word, continue scrubbing. */
492 SIZE(GNAME(arch_scrub_control_stack))