0.9.0.39:
[sbcl.git] / src / runtime / x86-64-assem.S
1 /*
2  * very-low-level utilities for runtime support
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
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.
14  */
15 \f
16 #define LANGUAGE_ASSEMBLY
17 #include "validate.h"
18 #include "sbcl.h"
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"
24         
25 /* Minimize conditionalization for different OS naming schemes. */
26 #if defined __linux__  || defined __FreeBSD__ /* (but *not* OpenBSD) */
27 #define GNAME(var) var
28 #else
29 #define GNAME(var) _##var
30 #endif
31
32 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
33  * want alignment in bytes. */
34 #if defined(__linux__) || defined(__FreeBSD__)
35 #define align_4byte     4
36 #define align_8byte     8
37 #define align_16byte    16
38 #define align_32byte    32
39 #else
40 #define align_4byte     2
41 #define align_8byte     3
42 #define align_16byte    4       
43 #endif                  
44
45         .text
46         .global GNAME(foreign_function_call_active)
47         .global GNAME(all_threads)
48         
49 \f
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)
57  */
58         .text
59         .align  align_16byte,0x90
60         .global GNAME(call_into_c)
61         .type   GNAME(call_into_c),@function
62 GNAME(call_into_c):
63         push    %rbp            # Save old frame pointer.
64         mov     %rsp,%rbp       # Establish new frame.
65
66         push    %rsi            # args are going in here
67         push    %rdi
68         mov     16(%rbp),%rdi
69         mov     24(%rbp),%rsi
70         mov     32(%rbp),%rdx
71         mov     40(%rbp),%rcx
72         mov     48(%rbp),%rcx
73         mov     56(%rbp),%r8
74         mov     64(%rbp),%r9
75         call    *%rax
76         mov     %rbp,%rsp
77         pop     %rbp
78         ret
79         .size   GNAME(call_into_c), . - GNAME(call_into_c)
80
81 \f
82         .text   
83         .global GNAME(call_into_lisp_first_time)
84         .type  GNAME(call_into_lisp_first_time),@function
85                 
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 
89  * anyway */
90         
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
99         * here */
100         add     $THREAD_CONTROL_STACK_SIZE-16,%rsp
101         jmp     Lstack
102 \f
103         .text   
104         .global GNAME(call_into_lisp)
105         .type  GNAME(call_into_lisp),@function
106                 
107 /*
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
112  */
113         
114         .align  align_16byte,0x90
115 GNAME(call_into_lisp):
116         push    %rbp            # Save old frame pointer.
117         mov     %rsp,%rbp       # Establish new frame.
118 Lstack:
119         /* FIXME x86 saves FPU state here */
120         push    %rbx
121         push    %r12
122         push    %r13
123         push    %r14
124         push    %r15
125
126
127         mov     %rsp,%rbx       # remember current stack
128         push    %rbx            # Save entry stack on (maybe) new stack.
129
130         /* Establish Lisp args. */
131         mov     %rdi,%rax       # lexenv?
132         mov     %rsi,%rbx       # address of arg vec
133         mov     %rdx,%rcx       # num args
134
135         xor     %rdx,%rdx       # clear any descriptor registers 
136         xor     %rdi,%rdi       # that we can't be sure we'll 
137         xor     %rsi,%rsi       # initialise properly.  XX do r8-r15 too?
138         shl     $3,%rcx         # (fixnumize num-args)
139         cmp     $0,%rcx
140         je      Ldone
141         mov     0(%rbx),%rdx    # arg0
142         cmp     $8,%rcx
143         je      Ldone
144         mov     8(%rbx),%rdi    # arg1
145         cmp     $16,%rcx
146         je      Ldone
147         mov     16(%rbx),%rsi   # arg2
148 Ldone:  
149         /* Registers rax, rcx, rdx, rdi, and rsi are now live. */
150         xor     %rbx,%rbx       # available
151
152         /* Alloc new frame. */
153         mov     %rsp,%rbx       # The current sp marks start of new frame.
154         push    %rbp            # fp in save location S0
155         sub     $16,%rsp        # Ensure 3 slots are allocated, one above.
156         mov     %rbx,%rbp       # Switch to new frame.
157
158 Lcall:
159         call    *CLOSURE_FUN_OFFSET(%rax)
160         
161         /* If the function returned multiple values, it will return to
162            this point.  Lose them */
163         mov     %rbx, %rsp
164         /* A singled value function returns here */
165
166 /* Restore the stack, in case there was a stack change. */
167         pop     %rsp            # c-sp
168
169 /* Restore C regs */
170         pop     %r15
171         pop     %r14
172         pop     %r13
173         pop     %r12
174         pop     %rbx
175
176 /* FIXME Restore the NPX state. */
177
178         /* return value is already in rax where lisp expects it */
179         leave
180         ret
181         .size   GNAME(call_into_lisp), . - GNAME(call_into_lisp)
182 \f
183 /* support for saving and restoring the NPX state from C */
184         .text
185         .global GNAME(fpu_save)
186         .type   GNAME(fpu_save),@function
187         .align  2,0x90
188 GNAME(fpu_save):
189         mov     4(%rsp),%rax
190         fnsave  (%rax)          # Save the NPX state. (resets NPX)
191         ret
192         .size   GNAME(fpu_save),.-GNAME(fpu_save)
193
194         .global GNAME(fpu_restore)
195         .type   GNAME(fpu_restore),@function
196         .align  2,0x90
197 GNAME(fpu_restore):
198         mov     4(%rsp),%rax
199         frstor  (%rax)          # Restore the NPX state.
200         ret
201         .size   GNAME(fpu_restore),.-GNAME(fpu_restore)
202 \f
203 /*
204  * the undefined-function trampoline
205  */
206         .text
207         .align  align_8byte,0x90
208         .global GNAME(undefined_tramp)
209         .type   GNAME(undefined_tramp),@function
210 GNAME(undefined_tramp):
211         int3
212         .byte   trap_Error
213         .byte   2
214         .byte   UNDEFINED_FUN_ERROR
215         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
216         ret
217         .size   GNAME(undefined_tramp), .-GNAME(undefined_tramp)
218
219
220         .text
221         .align  align_8byte,0x90
222         .global GNAME(alloc_tramp)
223         .type   GNAME(alloc_tramp),@function
224 GNAME(alloc_tramp):
225         push    %rbp            # Save old frame pointer.
226         mov     %rsp,%rbp       # Establish new frame.
227         push    %rax
228         push    %rcx
229         push    %rdx
230         push    %rsi
231         push    %rdi
232         push    %r8
233         push    %r9
234         push    %r10
235         push    %r11
236         mov     16(%rbp),%rdi   
237         call    alloc
238         mov     %rax,16(%rbp)
239         pop     %r11
240         pop     %r10
241         pop     %r9
242         pop     %r8
243         pop     %rdi
244         pop     %rsi
245         pop     %rdx
246         pop     %rcx
247         pop     %rax
248         pop     %rbp
249         ret
250         .size   GNAME(alloc_tramp),.-GNAME(alloc_tramp)
251
252                 
253 /*
254  * the closure trampoline
255  */
256         .text
257         .align  align_8byte,0x90
258         .global GNAME(closure_tramp)
259         .type   GNAME(closure_tramp),@function
260 GNAME(closure_tramp):
261         mov     FDEFN_FUN_OFFSET(%rax),%rax
262         /* FIXME: The '*' after "jmp" in the next line is from PVE's
263          * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
264          * reasonable, and it certainly seems as though if CMU CL needs it,
265          * SBCL needs it too, but I haven't actually verified that it's
266          * right. It would be good to find a way to force the flow of
267          * control through here to test it. */
268         jmp     *CLOSURE_FUN_OFFSET(%rax)
269         .size   GNAME(closure_tramp), .-GNAME(closure_tramp)
270
271 /*
272  * fun-end breakpoint magic
273  */
274         .text
275         .global GNAME(fun_end_breakpoint_guts)
276         .align  align_8byte
277 GNAME(fun_end_breakpoint_guts):
278         /* Multiple Value return */
279         jmp     multiple_value_return
280         /* the above jmp is only 2 bytes long, we need to add a nop for 
281          * padding since the single value return convention jumps to original
282          * return address + 3 bytes */
283         nop
284         /* Single value return: The eventual return will now use the
285            multiple values return convention but with a return values
286            count of one. */
287         mov     %rsp,%rbx       # Setup ebx - the ofp.
288         sub     $8,%rsp         # Allocate one stack slot for the return value
289         mov     $8,%rcx         # Setup ecx for one return value.
290         mov     $NIL,%rdi       # default second value
291         mov     $NIL,%rsi       # default third value
292                 
293 multiple_value_return:
294         
295         .global GNAME(fun_end_breakpoint_trap)
296 GNAME(fun_end_breakpoint_trap):
297         int3
298         .byte   trap_FunEndBreakpoint
299         hlt                     # We should never return here.
300
301         .global GNAME(fun_end_breakpoint_end)
302 GNAME(fun_end_breakpoint_end):
303
304 \f
305         .global GNAME(do_pending_interrupt)
306         .type   GNAME(do_pending_interrupt),@function
307         .align  align_8byte,0x90
308 GNAME(do_pending_interrupt):
309         int3
310         .byte   trap_PendingInterrupt
311         ret
312         .size   GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
313 \f
314         .globl  GNAME(post_signal_tramp)
315         .type   GNAME(post_signal_tramp),@function
316         .align  align_8byte,0x90
317 GNAME(post_signal_tramp):
318         /* this is notionally the second half of a function whose first half
319          * doesn't exist.  This is where call_into_lisp returns when called 
320          * using return_to_lisp_function */
321         popq %r15
322         popq %r14
323         popq %r13
324         popq %r12
325         popq %r11
326         popq %r10
327         popq %r9
328         popq %r8
329         popq %rdi
330         popq %rsi
331         addq $8, %rsp
332         popq %rsp
333         popq %rdx
334         popq %rbx
335         popq %rcx
336         popq %rax
337         leave
338         ret
339         .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)
340 \f
341         .end