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.
16 #define LANGUAGE_ASSEMBLY
19 #include "genesis/closure.h"
20 #include "genesis/fdefn.h"
21 #include "genesis/static-symbols.h"
22 #include "genesis/symbol.h"
23 #include "genesis/thread.h"
25 /* Minimize conditionalization for different OS naming schemes. */
26 #if defined __linux__ || defined __FreeBSD__ /* (but *not* OpenBSD) */
27 #define GNAME(var) var
29 #define GNAME(var) _##var
32 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
33 * want alignment in bytes. */
34 #if defined(__linux__) || defined(__FreeBSD__)
37 #define align_16byte 16
38 #define align_32byte 32
42 #define align_16byte 4
46 .global GNAME(foreign_function_call_active)
47 .global GNAME(all_threads)
50 /* From lower to higher-numbered addresses, the stack contains
51 * return address, arg 0, arg 1, arg 2 ...
52 * rax contains the address of the function to call
53 * Lisp expects return value in rax, whic is already consistent with C
54 * XXXX correct floating point handling is unimplemented so far
55 * Based on comments cleaned from x86-assem.S, we believe that
56 * Lisp is expecting us to preserve rsi, rdi, rsp (no idea about r8-15)
59 .align align_16byte,0x90
60 .global GNAME(call_into_c)
61 .type GNAME(call_into_c),@function
63 push %rbp # Save old frame pointer.
64 mov %rsp,%rbp # Establish new frame.
66 push %rsi # args are going in here
79 .size GNAME(call_into_c), . - GNAME(call_into_c)
83 .global GNAME(call_into_lisp_first_time)
84 .type GNAME(call_into_lisp_first_time),@function
86 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
87 * the stack changes. We don't worry too much about saving registers
88 * here, because we never expect to return from the initial call to lisp
91 .align align_16byte,0x90
92 GNAME(call_into_lisp_first_time):
93 push %rbp # Save old frame pointer.
94 mov %rsp,%rbp # Establish new frame.
95 mov %rsp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
96 mov GNAME(all_threads),%rax
97 mov THREAD_CONTROL_STACK_START_OFFSET(%rax) ,%rsp
98 /* don't think too hard about what happens if we get interrupted
100 add $THREAD_CONTROL_STACK_SIZE-16,%rsp
104 .global GNAME(call_into_lisp)
105 .type GNAME(call_into_lisp),@function
108 * amd64 calling convention: C expects that
109 * arguments go in rdi rsi rdx rcx r8 r9
110 * return values in rax rdx
111 * callee saves rbp rbx r12-15 if it uses them
114 .align align_16byte,0x90
115 GNAME(call_into_lisp):
116 push %rbp # Save old frame pointer.
117 mov %rsp,%rbp # Establish new frame.
119 /* FIXME x86 saves FPU state here */
120 push %rbx # these regs are callee-saved according to C
121 push %r12 # so must be preserved and restored when
122 push %r13 # the lisp function returns
126 mov %rsp,%rbx # remember current stack
127 push %rbx # Save entry stack on (maybe) new stack.
129 push %rdi # args from C
132 #ifdef LISP_FEATURE_SB_THREAD
134 call pthread_getspecific
138 pop %rbx # arg vector
139 pop %rax # function ptr/lexenv
141 xor %rdx,%rdx # clear any descriptor registers
142 xor %rdi,%rdi # that we can't be sure we'll
143 xor %rsi,%rsi # initialise properly. XX do r8-r15 too?
144 shl $3,%rcx # (fixnumize num-args)
147 mov 0(%rbx),%rdx # arg0
150 mov 8(%rbx),%rdi # arg1
153 mov 16(%rbx),%rsi # arg2
155 /* Registers rax, rcx, rdx, rdi, and rsi are now live. */
156 xor %rbx,%rbx # available
158 /* Alloc new frame. */
159 mov %rsp,%rbx # The current sp marks start of new frame.
160 push %rbp # fp in save location S0
161 sub $16,%rsp # Ensure 3 slots are allocated, one above.
162 mov %rbx,%rbp # Switch to new frame.
165 call *CLOSURE_FUN_OFFSET(%rax)
167 /* If the function returned multiple values, it will return to
168 this point. Lose them */
170 /* A singled value function returns here */
172 /* Restore the stack, in case there was a stack change. */
182 /* FIXME Restore the NPX state. */
184 /* return value is already in rax where lisp expects it */
187 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
189 /* support for saving and restoring the NPX state from C */
191 .global GNAME(fpu_save)
192 .type GNAME(fpu_save),@function
196 fnsave (%rax) # Save the NPX state. (resets NPX)
198 .size GNAME(fpu_save),.-GNAME(fpu_save)
200 .global GNAME(fpu_restore)
201 .type GNAME(fpu_restore),@function
205 frstor (%rax) # Restore the NPX state.
207 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
210 * the undefined-function trampoline
213 .align align_8byte,0x90
214 .global GNAME(undefined_tramp)
215 .type GNAME(undefined_tramp),@function
216 GNAME(undefined_tramp):
220 .byte UNDEFINED_FUN_ERROR
221 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
223 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
227 .align align_8byte,0x90
228 .global GNAME(alloc_tramp)
229 .type GNAME(alloc_tramp),@function
231 push %rbp # Save old frame pointer.
232 mov %rsp,%rbp # Establish new frame.
256 .size GNAME(alloc_tramp),.-GNAME(alloc_tramp)
260 * the closure trampoline
263 .align align_8byte,0x90
264 .global GNAME(closure_tramp)
265 .type GNAME(closure_tramp),@function
266 GNAME(closure_tramp):
267 mov FDEFN_FUN_OFFSET(%rax),%rax
268 /* FIXME: The '*' after "jmp" in the next line is from PVE's
269 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
270 * reasonable, and it certainly seems as though if CMU CL needs it,
271 * SBCL needs it too, but I haven't actually verified that it's
272 * right. It would be good to find a way to force the flow of
273 * control through here to test it. */
274 jmp *CLOSURE_FUN_OFFSET(%rax)
275 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
278 * fun-end breakpoint magic
281 .global GNAME(fun_end_breakpoint_guts)
283 GNAME(fun_end_breakpoint_guts):
284 /* Multiple Value return */
285 jmp multiple_value_return
286 /* the above jmp is only 2 bytes long, we need to add a nop for
287 * padding since the single value return convention jumps to original
288 * return address + 3 bytes */
290 /* Single value return: The eventual return will now use the
291 multiple values return convention but with a return values
293 mov %rsp,%rbx # Setup ebx - the ofp.
294 sub $8,%rsp # Allocate one stack slot for the return value
295 mov $8,%rcx # Setup ecx for one return value.
296 mov $NIL,%rdi # default second value
297 mov $NIL,%rsi # default third value
299 multiple_value_return:
301 .global GNAME(fun_end_breakpoint_trap)
302 GNAME(fun_end_breakpoint_trap):
304 .byte trap_FunEndBreakpoint
305 hlt # We should never return here.
307 .global GNAME(fun_end_breakpoint_end)
308 GNAME(fun_end_breakpoint_end):
311 .global GNAME(do_pending_interrupt)
312 .type GNAME(do_pending_interrupt),@function
313 .align align_8byte,0x90
314 GNAME(do_pending_interrupt):
316 .byte trap_PendingInterrupt
318 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
320 .globl GNAME(post_signal_tramp)
321 .type GNAME(post_signal_tramp),@function
322 .align align_8byte,0x90
323 GNAME(post_signal_tramp):
324 /* this is notionally the second half of a function whose first half
325 * doesn't exist. This is where call_into_lisp returns when called
326 * using return_to_lisp_function */
337 /* skip RBP and RSP */
345 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)