Use os_allocate(), not os_validate(), for "anywhere" allocation
[sbcl.git] / src / runtime / x86-64-assem.S
blob7adf4dde5402888923910c75b5fe74364d3ce6d2
1 /*
2  * very-low-level utilities for runtime support
3  */
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  */
16 #ifdef __ELF__
17 // Mark the object as not requiring an executable stack.
18 .section .note.GNU-stack,"",%progbits
19 #endif
21 #define LANGUAGE_ASSEMBLY
22 #include "genesis/config.h"
23 #include "validate.h"
24 #include "sbcl.h"
25 #include "genesis/closure.h"
26 #include "genesis/static-symbols.h"
27 #include "genesis/thread.h"
28         
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
32 #else
33 #define GNAME(var) _##var
34 #endif
36 /* Get the right type of alignment. Linux, FreeBSD and OpenBSD
37  * want alignment in bytes. */
38 #if defined(__linux__) || defined(LISP_FEATURE_FREEBSD) || defined(__OpenBSD__) || defined __NetBSD__ || defined(__sun) || defined _WIN64 || defined(__DragonFly__)
39 #define align_4byte     4
40 #define align_8byte     8
41 #define align_16byte    16
42 #define align_32byte    32
43 #define align_page      32768
44 #else
45 #define align_4byte     2
46 #define align_8byte     3
47 #define align_16byte    4       
48 #define align_page      15
49 #endif                  
52  * The assembler used for win32 doesn't like .type or .size directives,
53  * so we want to conditionally kill them out. So let's wrap them in macros
54  * that are defined to be no-ops on win32. Hopefully this still works on
55  * other platforms.
56  */
57 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
58 #define TYPE(name) .type name,@function
59 #define SIZE(name) .size name,.-name
60 #define DOLLAR(name) $(name)
61 #else
62 #define TYPE(name)
63 #define SIZE(name)
64 #endif
67  * x86/darwin (as of MacOS X 10.4.5) doesn't reliably fire signal
68  * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have
69  * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or
70  * 0F 0B in low-endian notation, that causes SIGILL to fire. We check
71  * for this instruction in the SIGILL handler and if we see it, we
72  * advance the EIP by two bytes to skip over ud2 instruction and
73  * call sigtrap_handler. */
74 #if defined(LISP_FEATURE_UD2_BREAKPOINTS)
75 #define TRAP ud2
76 #else
77 #define TRAP int3
78 #endif
81  * More Apple assembler hacks
82  */
84 #if defined(LISP_FEATURE_DARWIN)
85 /* global symbol x86-64 sym(%rip) hack:*/
86 #define GSYM(name) name(%rip)
87 #else
88 #define GSYM(name) $name
89 #endif
91         
92         .text
93         .globl  GNAME(all_threads)
94         
95         .text   
96         .globl  GNAME(call_into_lisp_first_time)
97         TYPE(GNAME(call_into_lisp_first_time))
98                 
99 /* We don't worry too much about saving registers 
100  * here, because we never expect to return from the initial call to lisp 
101  * anyway */
102         
103         .align  align_16byte,0x90
104 GNAME(call_into_lisp_first_time):
105         push    %rbp            # Save old frame pointer.
106         mov     %rsp,%rbp       # Establish new frame.
107 #if defined(LISP_FEATURE_DARWIN)
108         movq    GSYM(GNAME(all_threads)),%rax
109 #else
110         movq    GNAME(all_threads),%rax
111 #endif
112         mov     THREAD_CONTROL_STACK_END_OFFSET(%rax) ,%rsp
113         jmp     Lstack
115         .text   
116         .globl  GNAME(call_into_lisp)
117         TYPE(GNAME(call_into_lisp))
118                 
120  * amd64 calling convention: C expects that
121  * arguments go in rdi rsi rdx rcx r8 r9
122  * return values in rax rdx
123  * callee saves rbp rbx r12-15 if it uses them
124  */
125 #ifdef LISP_FEATURE_WIN32
126 # define SUPPORT_FOMIT_FRAME_POINTER
127 #endif
128         .align  align_16byte,0x90
129 GNAME(call_into_lisp):
130 #ifdef SUPPORT_FOMIT_FRAME_POINTER
131         mov     %rbp,%rax
132 #endif
133         push    %rbp            # Save old frame pointer.
134         mov     %rsp,%rbp       # Establish new frame.
135 Lstack:
136 #ifdef SUPPORT_FOMIT_FRAME_POINTER
137         /* If called through call_into_lisp_first_time, %r15 becomes invalid
138          * here, but we will not return in that case. */
139         push    %r15
140         mov     %rax,%r15
141 #endif
142         /* FIXME x86 saves FPU state here */
143         push    %rbx    # these regs are callee-saved according to C
144         push    %r12    # so must be preserved and restored when 
145         push    %r13    # the lisp function returns
146         push    %r14    #
147         push    %r15    #
149         mov     %rsp,%rbx       # remember current stack
150         push    %rbx            # Save entry stack on (maybe) new stack.
152         push    %rdi    # args from C
153         push    %rsi    #
154         push    %rdx    #
155 #ifdef LISP_FEATURE_SB_THREAD
156 # ifdef SUPPORT_FOMIT_FRAME_POINTER
157         mov     (%rbp),%rcx
158         sub     $32,%rsp
159         call    GNAME(carry_frame_pointer)
160         add     $32,%rsp
161         mov     %rax,(%rbp)
162 # endif
163 #ifdef LISP_FEATURE_GCC_TLS
164         movq    %fs:0, %rax
165         movq    GNAME(current_thread)@TPOFF(%rax), %r12
166 #else
167 #ifdef LISP_FEATURE_DARWIN
168         mov     GSYM(GNAME(specials)),%rdi
169 #else
170         mov     specials,%rdi
171 #endif
172         call    GNAME(pthread_getspecific)
173         mov     %rax,%r12
174 #endif
175 #endif
176         pop     %rcx    # num args
177         pop     %rbx    # arg vector
178         pop     %rax    # function ptr/lexenv
180         xor     %rdx,%rdx       # clear any descriptor registers 
181         xor     %rdi,%rdi       # that we can't be sure we'll 
182         xor     %rsi,%rsi       # initialise properly.  XX do r8-r15 too?
183         cmp     $0,%rcx
184         # It's tempting to think 'cmov' for these assignments, but don't:
185         # cmov does a memory cycle whether or not it moves, succumbing to
186         # a classic buffer overrun bug if argv[] is "badly" placed.
187         je      Ldone
188         mov     0(%rbx),%rdx    # arg0
189         cmp     $1,%rcx
190         je      Ldone
191         mov     8(%rbx),%rdi    # arg1
192         cmp     $2,%rcx
193         je      Ldone
194         mov     16(%rbx),%rsi   # arg2
195 Ldone:  
196         shl     $(N_FIXNUM_TAG_BITS),%rcx       # (fixnumize num-args)
197         /* Registers rax, rcx, rdx, rdi, and rsi are now live. */
198         xor     %rbx,%rbx       # available
200         /* Alloc new frame. */
201         push    %rbp            # Dummy for return address
202         push    %rbp            # fp in save location S1
203         mov     %rsp,%rbp       # The current sp marks start of new frame.
204         sub     $8,%rsp         # Ensure 3 slots are allocated, two above.
206 Lcall:
207         call    *CLOSURE_FUN_OFFSET(%rax)
208         
209         /* If the function returned multiple values, the carry flag will be set.
210            Lose them */
211         jnc     LsingleValue    
212         mov     %rbx, %rsp
213 LsingleValue:   
215 /* Restore the stack, in case there was a stack change. */
216         pop     %rsp            # c-sp
218 /* Restore C regs */
219         pop     %r15
220         pop     %r14
221         pop     %r13
222         pop     %r12
223         pop     %rbx
225 /* FIXME Restore the NPX state. */
227         mov     %rdx,%rax       # c-val
228 #ifdef SUPPORT_FOMIT_FRAME_POINTER
229         mov     %r15,%rbp       # orig rbp
230         pop     %r15            # orig r15
231         add     $8,%rsp         # no need for saved (overridden) rbp
232 #else
233         leave
234 #endif
235         ret
236         SIZE(GNAME(call_into_lisp))
238 /* Our call-site does not take care of caller-saved xmm registers, so it
239  * falls to us spill them beforing hopping into C.
241  * We simply save all of them.
243  * (But for the sake of completeness, here is my understanding of the specs:)
244  *                     System V       Microsoft
245  * argument passing    xmm0-7         xmm0-3
246  * caller-saved        xmm8-15        xmm4-5
247  * callee-saved        -              xmm6-15
249  *  --DFL */
251 #define stkxmmsave(n) movaps %xmm##n, n*16(%rsp)
252 #define stkxmmload(n) movaps n*16(%rsp), %xmm##n
253 #define map_all_xmm(op) \
254         op(0);op(1);op(2);op(3);op(4);op(5);op(6);op(7); \
255     op(8);op(9);op(10);op(11);op(12);op(13);op(14);op(15);
257         .text
258         .align  align_16byte,0x90
259         .globl  GNAME(alloc_tramp)
260         TYPE(GNAME(alloc_tramp))
261 GNAME(alloc_tramp):
262         cld
263         push    %rbp            # Save old frame pointer.
264         mov     %rsp,%rbp       # Establish new frame.
265         and     $-32,%rsp
266         sub     $16*16,%rsp
267         map_all_xmm(stkxmmsave)
268         # Doing rax twice is to maintain 16-byte stack alignment.
269         push    %rax
270         push    %rax
271         push    %rcx
272         push    %rdx
273         push    %rsi
274         push    %rdi
275         push    %r8
276         push    %r9
277         push    %r10
278         push    %r11
279         # r12 through r15 are callee-saved
280         mov     16(%rbp),%rdi
281         call    GNAME(alloc)
282         mov     %rax,16(%rbp)
283         pop     %r11
284         pop     %r10
285         pop     %r9
286         pop     %r8
287         pop     %rdi
288         pop     %rsi
289         pop     %rdx
290         pop     %rcx
291         pop     %rax
292         pop     %rax # corresponds to "extra" push
293         map_all_xmm(stkxmmload)
294         mov     %rbp,%rsp
295         pop     %rbp
296         ret
297         SIZE(GNAME(alloc_tramp))
300  * fun-end breakpoint magic
301  */
304  * For an explanation of the magic involved in function-end
305  * breakpoints, see the implementation in ppc-assem.S.
306  */
308         .text
309         .globl  GNAME(fun_end_breakpoint_guts)
310         .align  align_16byte
311 GNAME(fun_end_breakpoint_guts):
312         /* Multiple Value return */
313         jc      multiple_value_return
314         /* Single value return: The eventual return will now use the
315            multiple values return convention but with a return values
316            count of one. */
317         mov     %rsp,%rbx       # Setup ebx - the ofp.
318         sub     $8,%rsp         # Allocate one stack slot for the return value
319         mov     $(1 << N_FIXNUM_TAG_BITS),%rcx          # Setup ecx for one return value.
320         mov     GSYM(NIL),%rdi  # default second value
321         mov     GSYM(NIL),%rsi  # default third value
322 multiple_value_return:
323         
324         .globl  GNAME(fun_end_breakpoint_trap)
325         .align  align_16byte,0x90
326 GNAME(fun_end_breakpoint_trap):
327         TRAP
328         .byte   trap_FunEndBreakpoint
329         hlt                     # We should never return here.
331         .globl  GNAME(fun_end_breakpoint_end)
332 GNAME(fun_end_breakpoint_end):
335         .globl  GNAME(do_pending_interrupt)
336         TYPE(GNAME(do_pending_interrupt))
337         .align  align_16byte,0x90
338 GNAME(do_pending_interrupt):
339         TRAP
340         .byte   trap_PendingInterrupt
341         ret
342         SIZE(GNAME(do_pending_interrupt))
344         .globl  GNAME(post_signal_tramp)
345         TYPE(GNAME(post_signal_tramp))
346         .align  align_16byte,0x90
347 GNAME(post_signal_tramp):
348         /* this is notionally the second half of a function whose first half
349          * doesn't exist.  This is where call_into_lisp returns when called 
350          * using return_to_lisp_function */
351         popq %r15
352         popq %r14
353         popq %r13
354         popq %r12
355         popq %r11
356         popq %r10
357         popq %r9
358         popq %r8
359         popq %rdi
360         popq %rsi
361         /* skip RBP and RSP */
362         popq %rbx
363         popq %rdx
364         popq %rcx
365         popq %rax
366         popfq
367         leave
368         ret
369         SIZE(GNAME(post_signal_tramp))
371 /* When LISP_FEATURE_C_STACK_IS_CONTROL_STACK, we cannot safely scrub
372  * the control stack from C, largely due to not knowing where the
373  * active stack frame ends.  On such platforms, we reimplement the
374  * core scrubbing logic in assembly, in this case here:
375  */
376         .text
377         .align  align_16byte,0x90
378         .globl GNAME(arch_scrub_control_stack)
379         TYPE(GNAME(arch_scrub_control_stack))
380 GNAME(arch_scrub_control_stack):
381         /* We are passed three parameters:
382          * A (struct thread *) in RDI,
383          * the address of the guard page in RSI, and
384          * the address of the hard guard page in RDX.
385          * We may trash RAX, RCX, and R8-R11 with impunity.
386          * [RSP] is our return address, [RSP-8] is the first
387          * stack slot to scrub. */
389         /* We start by setting up our scrub pointer in RAX, our
390          * guard page upper bound in R8, and our hard guard
391          * page upper bound in R9. */
392         lea     -8(%rsp), %rax
393 #ifdef LISP_FEATURE_DARWIN
394         mov     GSYM(GNAME(os_vm_page_size)),%r9
395 #else
396         mov     os_vm_page_size,%r9
397 #endif
398         lea     (%rsi,%r9), %r8
399         lea     (%rdx,%r9), %r9
401         /* Now we begin our main scrub loop. */
402 ascs_outer_loop:
404         /* If we're about to scrub the hard guard page, exit. */
405         cmp     %r9, %rax
406         jae     ascs_check_guard_page
407         cmp     %rax, %rdx
408         jbe     ascs_finished
410 ascs_check_guard_page:
411         /* If we're about to scrub the guard page, and the guard
412          * page is protected, exit. */
413         cmp     %r8, %rax
414         jae     ascs_clear_loop
415         cmp     %rax, %rsi
416         ja      ascs_clear_loop
417         cmpq    $(NIL), THREAD_CONTROL_STACK_GUARD_PAGE_PROTECTED_OFFSET(%rdi)
418         jne     ascs_finished
420         /* Clear memory backwards to the start of the (4KiB) page */
421 ascs_clear_loop:
422         movq    $0, (%rax)
423         test    $0xfff, %rax
424         lea     -8(%rax), %rax
425         jnz     ascs_clear_loop
427         /* If we're about to hit the hard guard page, exit. */
428         cmp     %r9, %rax
429         jae     ascs_finished
431         /* If the next (previous?) 4KiB page contains a non-zero
432          * word, continue scrubbing. */
433 ascs_check_loop:
434         testq   $-1, (%rax)
435         jnz     ascs_outer_loop
436         test    $0xfff, %rax
437         lea     -8(%rax), %rax
438         jnz     ascs_check_loop
440 ascs_finished:
441         ret
442         SIZE(GNAME(arch_scrub_control_stack))