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 #include "genesis/sbcl.h"
23 #include "genesis/closure.h"
24 #include "genesis/symbol.h"
25 #include "genesis/static-symbols.h"
26 #include "genesis/thread.h"
28 /* Minimize conditionalization for different OS naming schemes. */
29 #if defined __linux__ || defined LISP_FEATURE_HAIKU || defined LISP_FEATURE_FREEBSD || \
30 defined __OpenBSD__ || defined __NetBSD__ || defined __sun || defined _WIN64 || defined __DragonFly__
31 #define GNAME(var) var
33 #define GNAME(var) _##var
36 // Produce position-independent code.
37 // macOS does not like the general way we do this, so do something different.
38 #if defined(LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_WIN32)
39 #define LOAD_PIC_VAR(x,dest) mov GNAME(x)(%rip), dest
41 #define LOAD_PIC_VAR(x,dest) mov GNAME(x)@GOTPCREL(%rip), dest ; mov (dest), dest
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__)
47 #define align_16byte 16
49 #define align_16byte 4
53 * The assembler used for win32 doesn't like .type or .size directives,
54 * so we want to conditionally kill them out. So let's wrap them in macros
55 * that are defined to be no-ops on win32. Hopefully this still works on
58 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
59 #define TYPE(name) .type name,@function
60 #define SIZE(name) .size name,.-name
66 #ifdef LISP_FEATURE_INT4_BREAKPOINTS
67 // assembler won't emit the invalid instruction INTO, so use .byte to encode
68 #define TRAP .byte 0xCE
73 #define CARD_TABLE_REG %r12
74 #define THREAD_BASE_REG %r13
76 #ifdef LISP_FEATURE_WIN32
86 #ifdef LISP_FEATURE_OS_THREAD_STACK
88 .globl GNAME(funcall1_switching_stack)
89 TYPE(GNAME(funcall1_switching_stack))
90 .align align_16byte,0x90
91 GNAME(funcall1_switching_stack):
92 /* The arguments are switched, funcall1_switching_stack(arg, function)
93 to avoid shuffling registers.
98 mov THREAD_CONTROL_STACK_END_OFFSET(CARG1),%rsp
100 #ifdef LISP_FEATURE_WIN32
101 /* _chkstk() is called at some unknown points and is
104 mov THREAD_CONTROL_STACK_START_OFFSET(CARG1), %rax
112 SIZE(GNAME(funcall1_switching_stack))
116 .globl GNAME(call_into_lisp_first_time_)
117 TYPE(GNAME(call_into_lisp_first_time_))
119 /* We don't worry too much about saving registers
120 * here, because we never expect to return from the initial call to lisp
123 .align align_16byte,0x90
124 GNAME(call_into_lisp_first_time_):
125 GNAME(lspmain): # so much easier to type 'b lspmain' in gdb
126 push %rbp # Save old frame pointer.
127 mov %rsp,%rbp # Establish new frame.
128 LOAD_PIC_VAR(all_threads, %rax)
129 mov THREAD_CONTROL_STACK_END_OFFSET(%rax) ,%rsp
133 .globl GNAME(call_into_lisp_)
134 TYPE(GNAME(call_into_lisp_))
137 * amd64 calling convention: C expects that
138 * arguments go in rdi rsi rdx rcx r8 r9
139 * return values in rax rdx
140 * callee saves rbp rbx r12-15 if it uses them
142 #ifdef LISP_FEATURE_WIN32
143 # define SUPPORT_FOMIT_FRAME_POINTER
145 .align align_16byte,0x90
146 GNAME(call_into_lisp_):
147 #ifdef SUPPORT_FOMIT_FRAME_POINTER
150 push %rbp # Save old frame pointer.
151 mov %rsp,%rbp # Establish new frame.
153 #ifdef SUPPORT_FOMIT_FRAME_POINTER
154 /* If called through call_into_lisp_first_time, %r15 becomes invalid
155 * here, but we will not return in that case. */
159 /* FIXME x86 saves FPU state here */
160 push %rbx # these regs are callee-saved according to C
161 push %r12 # so must be preserved and restored when
162 push %r13 # the lisp function returns
165 push %rdi # args from C
168 movq %rcx, THREAD_BASE_REG
170 pop %rbx # arg vector
171 pop %rax # function ptr/lexenv
173 # Why do we care what goes in unused argument-passing regs?
174 # These just seem like wasted instructions.
175 xor %rdx,%rdx # clear any descriptor registers
176 xor %rdi,%rdi # that we can't be sure we'll
177 xor %rsi,%rsi # initialise properly. XX do r8-r15 too?
183 mov 16(%rbx),%rsi # arg2
184 Ltwo: mov 8(%rbx),%rdi # arg1
185 Lone: mov 0(%rbx),%rdx # arg0
187 shl $(N_FIXNUM_TAG_BITS),%rcx # (fixnumize num-args)
188 /* Registers rax, rcx, rdx, rdi, and rsi are now live. */
189 xor %rbx,%rbx # available
191 /* Alloc new frame. */
192 push %rbp # Dummy for return address
193 push %rbp # fp in save location S1
194 mov %rsp,%rbp # The current sp marks start of new frame.
196 LOAD_PIC_VAR(gc_card_mark, CARD_TABLE_REG)
197 call *CLOSURE_FUN_OFFSET(%rax)
199 /* If the function returned multiple values, the carry flag will be set.
212 /* FIXME Restore the NPX state. */
214 mov %rdx,%rax # c-val
215 #ifdef SUPPORT_FOMIT_FRAME_POINTER
216 mov %r15,%rbp # orig rbp
218 add $8,%rsp # no need for saved (overridden) rbp
223 SIZE(GNAME(call_into_lisp_))
226 .globl GNAME(funcall_alien_callback)
227 TYPE(GNAME(funcall_alien_callback))
228 .align align_16byte,0x90
229 GNAME(funcall_alien_callback):
230 /* Specialized call_into_lisp for callbacks
234 rcx thread #+sb-thread
237 push %rbp # Save old frame pointer.
238 mov %rsp,%rbp # Establish new frame.
240 push %rbx # these regs are callee-saved according to C
241 push %r12 # so must be preserved and restored when
242 push %r13 # the lisp function returns
245 #ifdef LISP_FEATURE_SB_THREAD
246 mov %rcx, THREAD_BASE_REG
248 LOAD_PIC_VAR(all_threads, THREAD_BASE_REG)
250 mov $(3 << N_FIXNUM_TAG_BITS),%rcx
252 /* Alloc new frame. */
253 push %rbp # Dummy for return address
254 push %rbp # fp in save location S1
256 LOAD_PIC_VAR(gc_card_mark, CARD_TABLE_REG)
257 LOAD_PIC_VAR(linkage_space, %rax)
258 call *(8*ENTER_ALIEN_CALLBACK_fname_index)(%rax)
270 SIZE(GNAME(funcall_alien_callback))
273 * fun-end breakpoint magic
277 * For an explanation of the magic involved in function-end
278 * breakpoints, see the implementation in ppc-assem.S.
282 .globl GNAME(fun_end_breakpoint_guts)
284 GNAME(fun_end_breakpoint_guts):
285 /* Multiple Value return */
286 jc multiple_value_return
287 /* Single value return: The eventual return will now use the
288 multiple values return convention but with a return values
290 mov %rsp,%rbx # Setup ebx - the ofp.
291 sub $8,%rsp # Allocate one stack slot for the return value
292 mov $(1 << N_FIXNUM_TAG_BITS),%rcx # Setup ecx for one return value.
293 mov $(NIL),%rdi # default second value
294 mov $(NIL),%rsi # default third value
295 multiple_value_return:
297 .globl GNAME(fun_end_breakpoint_trap)
298 .align align_16byte,0x90
299 GNAME(fun_end_breakpoint_trap):
301 .byte trap_FunEndBreakpoint
302 hlt # We should never return here.
304 .globl GNAME(fun_end_breakpoint_end)
305 GNAME(fun_end_breakpoint_end):
308 .globl GNAME(do_pending_interrupt)
309 TYPE(GNAME(do_pending_interrupt))
310 .align align_16byte,0x90
311 GNAME(do_pending_interrupt):
313 .byte trap_PendingInterrupt
315 SIZE(GNAME(do_pending_interrupt))
317 #ifdef LISP_FEATURE_SB_SAFEPOINT
318 .globl GNAME(handle_global_safepoint_violation)
319 TYPE(GNAME(handle_global_safepoint_violation))
320 .align align_16byte,0x90
321 GNAME(handle_global_safepoint_violation):
323 .byte trap_GlobalSafepoint
325 SIZE(GNAME(handle_global_safepoint_violation))
327 .globl GNAME(handle_csp_safepoint_violation)
328 TYPE(GNAME(handle_csp_safepoint_violation))
329 .align align_16byte,0x90
330 GNAME(handle_csp_safepoint_violation):
332 .byte trap_CspSafepoint
334 SIZE(GNAME(handle_csp_safepoint_violation))
335 #endif /* SB-SAFEPOINT */
337 .globl GNAME(memory_fault_emulation_trap)
338 TYPE(GNAME(memory_fault_emulation_trap))
339 .align align_16byte,0x90
340 GNAME(memory_fault_emulation_trap):
342 .byte trap_MemoryFaultEmulation
343 SIZE(GNAME(memory_fault_emulation_trap))
345 .globl GNAME(post_signal_tramp)
346 TYPE(GNAME(post_signal_tramp))
347 .align align_16byte,0x90
348 GNAME(post_signal_tramp):
349 /* this is notionally the second half of a function whose first half
350 * doesn't exist. This is where call_into_lisp returns when called
351 * using return_to_lisp_function */
362 /* skip RBP and RSP */
370 SIZE(GNAME(post_signal_tramp))
372 /* When LISP_FEATURE_C_STACK_IS_CONTROL_STACK, we cannot safely scrub
373 * the control stack from C, largely due to not knowing where the
374 * active stack frame ends. On such platforms, we reimplement the
375 * core scrubbing logic in assembly, in this case here:
378 .align align_16byte,0x90
379 .globl GNAME(arch_scrub_control_stack)
380 TYPE(GNAME(arch_scrub_control_stack))
381 GNAME(arch_scrub_control_stack):
382 /* We are passed three parameters:
383 * A (struct thread *) in RDI,
384 * the address of the guard page in RSI, and
385 * the address of the hard guard page in RDX.
386 * We may trash RAX, RCX, and R8-R11 with impunity.
387 * [RSP] is our return address, [RSP-8] is the first
388 * stack slot to scrub. */
390 /* We start by setting up our scrub pointer in RAX, our
391 * guard page upper bound in R8, and our hard guard
392 * page upper bound in R9. */
394 #ifdef LISP_FEATURE_WIN32
395 LOAD_PIC_VAR(win32_page_size, %r9)
397 LOAD_PIC_VAR(os_vm_page_size, %r9)
402 /* Now we begin our main scrub loop. */
405 /* If we're about to scrub the hard guard page, exit. */
407 jae ascs_check_guard_page
411 ascs_check_guard_page:
412 /* If we're about to scrub the guard page, and the guard
413 * page is protected, exit. */
418 /* test state_word.control_stack_guard_page_protected */
419 cmpb $0, THREAD_STATE_WORD_OFFSET(%rdi)
422 /* Clear memory backwards to the start of the (4KiB) page */
429 /* If we're about to hit the hard guard page, exit. */
433 /* If the next (previous?) 4KiB page contains a non-zero
434 * word, continue scrubbing. */
444 SIZE(GNAME(arch_scrub_control_stack))