Change immobile space free pointers to alien vars
[sbcl.git] / src / runtime / x86-64-assem.S
blobcbc8062c6017d39f7ccf278b6b8aae4da03c43b3
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 #if POSITION_INDEPENDENT_ASM
37 #define PIC_CALL(x) x@PLT
38 #define PIC_VAR(x) x(%rip)
39 #else
40 #define PIC_CALL(x) x
41 #define PIC_VAR(x) x
42 #endif
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_4byte     4
48 #define align_8byte     8
49 #define align_16byte    16
50 #define align_32byte    32
51 #define align_page      32768
52 #else
53 #define align_4byte     2
54 #define align_8byte     3
55 #define align_16byte    4       
56 #define align_page      15
57 #endif                  
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
63  * other platforms.
64  */
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)
69 #else
70 #define TYPE(name)
71 #define SIZE(name)
72 #endif
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)
83 #define TRAP ud2
84 #else
85 #define TRAP int3
86 #endif
89  * More Apple assembler hacks
90  */
92 #if defined(LISP_FEATURE_DARWIN)
93 /* global symbol x86-64 sym(%rip) hack:*/
94 #define GSYM(name) name(%rip)
95 #else
96 #define GSYM(name) $name
97 #endif
99         
100         .text
101         .globl  GNAME(all_threads)
102         
103         .text   
104         .globl  GNAME(call_into_lisp_first_time)
105         TYPE(GNAME(call_into_lisp_first_time))
106                 
107 /* We don't worry too much about saving registers 
108  * here, because we never expect to return from the initial call to lisp 
109  * anyway */
110         
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
117 #else
118         movq    PIC_VAR(GNAME(all_threads)),%rax
119 #endif
120         mov     THREAD_CONTROL_STACK_END_OFFSET(%rax) ,%rsp
121         jmp     Lstack
123         .text   
124         .globl  GNAME(call_into_lisp)
125         TYPE(GNAME(call_into_lisp))
126                 
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
132  */
133 #ifdef LISP_FEATURE_WIN32
134 # define SUPPORT_FOMIT_FRAME_POINTER
135 #endif
136         .align  align_16byte,0x90
137 GNAME(call_into_lisp):
138 #ifdef SUPPORT_FOMIT_FRAME_POINTER
139         mov     %rbp,%rax
140 #endif
141         push    %rbp            # Save old frame pointer.
142         mov     %rsp,%rbp       # Establish new frame.
143 Lstack:
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. */
147         push    %r15
148         mov     %rax,%r15
149 #endif
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
154         push    %r14    #
155         push    %r15    #
157         mov     %rsp,%rbx       # remember current stack
158         push    %rbx            # Save entry stack on (maybe) new stack.
160         push    %rdi    # args from C
161         push    %rsi    #
162         push    %rdx    #
163 #ifdef LISP_FEATURE_SB_THREAD
164 # ifdef SUPPORT_FOMIT_FRAME_POINTER
165         mov     (%rbp),%rcx
166         sub     $32,%rsp
167         call    GNAME(carry_frame_pointer)
168         add     $32,%rsp
169         mov     %rax,(%rbp)
170 # endif
171 #ifdef LISP_FEATURE_GCC_TLS
172         movq    %fs:0, %rax
173         movq    GNAME(current_thread)@TPOFF(%rax), %r12
174 #else
175 #ifdef LISP_FEATURE_DARWIN
176         mov     GSYM(GNAME(specials)),%rdi
177 #else
178         mov     PIC_VAR(specials),%rdi
179 #endif
180         call    PIC_CALL(GNAME(pthread_getspecific))
181         mov     %rax,%r12
182 #endif
183 #endif
184         pop     %rcx    # num args
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?
191         cmp     $0,%rcx
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.
195         je      Ldone
196         mov     0(%rbx),%rdx    # arg0
197         cmp     $1,%rcx
198         je      Ldone
199         mov     8(%rbx),%rdi    # arg1
200         cmp     $2,%rcx
201         je      Ldone
202         mov     16(%rbx),%rsi   # arg2
203 Ldone:  
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.
214 Lcall:
215         call    *CLOSURE_FUN_OFFSET(%rax)
216         
217         /* If the function returned multiple values, the carry flag will be set.
218            Lose them */
219         jnc     LsingleValue    
220         mov     %rbx, %rsp
221 LsingleValue:   
223 /* Restore the stack, in case there was a stack change. */
224         pop     %rsp            # c-sp
226 /* Restore C regs */
227         pop     %r15
228         pop     %r14
229         pop     %r13
230         pop     %r12
231         pop     %rbx
233 /* FIXME Restore the NPX state. */
235         mov     %rdx,%rax       # c-val
236 #ifdef SUPPORT_FOMIT_FRAME_POINTER
237         mov     %r15,%rbp       # orig rbp
238         pop     %r15            # orig r15
239         add     $8,%rsp         # no need for saved (overridden) rbp
240 #else
241         leave
242 #endif
243         ret
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:)
252  *                     System V       Microsoft
253  * argument passing    xmm0-7         xmm0-3
254  * caller-saved        xmm8-15        xmm4-5
255  * callee-saved        -              xmm6-15
257  *  --DFL */
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);
265         .text
266         .align  align_16byte,0x90
267         .globl  GNAME(alloc_tramp)
268         TYPE(GNAME(alloc_tramp))
269 GNAME(alloc_tramp):
270         cld
271         push    %rbp            # Save old frame pointer.
272         mov     %rsp,%rbp       # Establish new frame.
273         and     $-32,%rsp
274         sub     $16*16,%rsp
275         map_all_xmm(stkxmmsave)
276         # Doing rax twice is to maintain 16-byte stack alignment.
277         push    %rax
278         push    %rax
279         push    %rcx
280         push    %rdx
281         push    %rsi
282         push    %rdi
283         push    %r8
284         push    %r9
285         push    %r10
286         push    %r11
287         # r12 through r15 are callee-saved
288         mov     16(%rbp),%rdi
289         call    GNAME(alloc)
290         mov     %rax,16(%rbp)
291         pop     %r11
292         pop     %r10
293         pop     %r9
294         pop     %r8
295         pop     %rdi
296         pop     %rsi
297         pop     %rdx
298         pop     %rcx
299         pop     %rax
300         pop     %rax # corresponds to "extra" push
301         map_all_xmm(stkxmmload)
302         mov     %rbp,%rsp
303         pop     %rbp
304         ret
305         SIZE(GNAME(alloc_tramp))
308         .align  align_16byte,0x90
309         .globl  GNAME(alloc_to_r11)
310         TYPE(GNAME(alloc_to_r11))
311 GNAME(alloc_to_r11):
312         cld
313         push    %rbp            # Save old frame pointer.
314         mov     %rsp,%rbp       # Establish new frame.
315         and     $-32,%rsp
316         sub     $16*16,%rsp
317         map_all_xmm(stkxmmsave)
318         # Doing rax twice is to maintain 16-byte stack alignment.
319         push    %rax
320         push    %rax
321         push    %rcx
322         push    %rdx
323         push    %rsi
324         push    %rdi
325         push    %r8
326         push    %r9
327         push    %r10
328         push    %r11
329         # r12 through r15 are callee-saved
330         mov     16(%rbp),%rdi
331         call    GNAME(alloc)
332         mov     %rax,%r11       # move to result register
333         pop     %rax            # dummy. %rax gets popped again later
334         pop     %r10
335         pop     %r9
336         pop     %r8
337         pop     %rdi
338         pop     %rsi
339         pop     %rdx
340         pop     %rcx
341         pop     %rax
342         pop     %rax # corresponds to "extra" push
343         map_all_xmm(stkxmmload)
344         mov     %rbp,%rsp
345         pop     %rbp
346         retq    $8              # remove 8 bytes from the stack
347         SIZE(GNAME(alloc_to_r11))
350  * fun-end breakpoint magic
351  */
354  * For an explanation of the magic involved in function-end
355  * breakpoints, see the implementation in ppc-assem.S.
356  */
358         .text
359         .globl  GNAME(fun_end_breakpoint_guts)
360         .align  align_16byte
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
366            count of one. */
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:
373         
374         .globl  GNAME(fun_end_breakpoint_trap)
375         .align  align_16byte,0x90
376 GNAME(fun_end_breakpoint_trap):
377         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):
389         TRAP
390         .byte   trap_PendingInterrupt
391         ret
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 */
401         popq %r15
402         popq %r14
403         popq %r13
404         popq %r12
405         popq %r11
406         popq %r10
407         popq %r9
408         popq %r8
409         popq %rdi
410         popq %rsi
411         /* skip RBP and RSP */
412         popq %rbx
413         popq %rdx
414         popq %rcx
415         popq %rax
416         popfq
417         leave
418         ret
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:
425  */
426         .text
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. */
442         lea     -8(%rsp), %rax
443 #ifdef LISP_FEATURE_DARWIN
444         mov     GSYM(GNAME(os_vm_page_size)),%r9
445 #else
446         mov     PIC_VAR(os_vm_page_size),%r9
447 #endif
448         lea     (%rsi,%r9), %r8
449         lea     (%rdx,%r9), %r9
451         /* Now we begin our main scrub loop. */
452 ascs_outer_loop:
454         /* If we're about to scrub the hard guard page, exit. */
455         cmp     %r9, %rax
456         jae     ascs_check_guard_page
457         cmp     %rax, %rdx
458         jbe     ascs_finished
460 ascs_check_guard_page:
461         /* If we're about to scrub the guard page, and the guard
462          * page is protected, exit. */
463         cmp     %r8, %rax
464         jae     ascs_clear_loop
465         cmp     %rax, %rsi
466         ja      ascs_clear_loop
467         cmpq    $(NIL), THREAD_CONTROL_STACK_GUARD_PAGE_PROTECTED_OFFSET(%rdi)
468         jne     ascs_finished
470         /* Clear memory backwards to the start of the (4KiB) page */
471 ascs_clear_loop:
472         movq    $0, (%rax)
473         test    $0xfff, %rax
474         lea     -8(%rax), %rax
475         jnz     ascs_clear_loop
477         /* If we're about to hit the hard guard page, exit. */
478         cmp     %r9, %rax
479         jae     ascs_finished
481         /* If the next (previous?) 4KiB page contains a non-zero
482          * word, continue scrubbing. */
483 ascs_check_loop:
484         testq   $-1, (%rax)
485         jnz     ascs_outer_loop
486         test    $0xfff, %rax
487         lea     -8(%rax), %rax
488         jnz     ascs_check_loop
490 ascs_finished:
491         ret
492         SIZE(GNAME(arch_scrub_control_stack))