Fix a rounding error in TAN type derivation.
[sbcl.git] / src / runtime / x86-64-assem.S
blob2d879d2f633cf5d11a8eeb97dea238d42b0c4b42
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 #include "genesis/sbcl.h"
22 #include "validate.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
32 #else
33 #define GNAME(var) _##var
34 #endif
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
40 #else
41 #define LOAD_PIC_VAR(x,dest) mov GNAME(x)@GOTPCREL(%rip), dest ; mov (dest), dest
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_16byte    16
48 #else
49 #define align_16byte    4
50 #endif
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
56  * other platforms.
57  */
58 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
59 #define TYPE(name) .type name,@function
60 #define SIZE(name) .size name,.-name
61 #else
62 #define TYPE(name)
63 #define SIZE(name)
64 #endif
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
69 #else
70 #define TRAP int3
71 #endif
73 #define CARD_TABLE_REG %r12
74 #define THREAD_BASE_REG %r13
76 #ifdef LISP_FEATURE_WIN32
77 #define CARG1 %rcx
78 #define CARG2 %rdx
79 #define CARG3 %r8
80 #else
81 #define CARG1 %rdi
82 #define CARG2 %rsi
83 #define CARG3 %rdx
84 #endif
85         
86 #ifdef LISP_FEATURE_OS_THREAD_STACK
87         .text
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.
94         */
95         push    %rbp
96         mov     %rsp,%rbp
98         mov     THREAD_CONTROL_STACK_END_OFFSET(CARG1),%rsp
100 #ifdef LISP_FEATURE_WIN32       
101         /* _chkstk() is called at some unknown points and is
102            expecting that
103         */
104         mov     THREAD_CONTROL_STACK_START_OFFSET(CARG1), %rax
105         movq    %rax, %gs:16
106 #endif
107         call    *CARG2
109         mov     %rbp, %rsp
110         pop     %rbp
111         ret
112         SIZE(GNAME(funcall1_switching_stack))
113 #endif
115         .text
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
121  * anyway */
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
130         jmp     Lstack
132         .text
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
141  */
142 #ifdef LISP_FEATURE_WIN32
143 # define SUPPORT_FOMIT_FRAME_POINTER
144 #endif
145         .align  align_16byte,0x90
146 GNAME(call_into_lisp_):
147 #ifdef SUPPORT_FOMIT_FRAME_POINTER
148         mov     %rbp,%rax
149 #endif
150         push    %rbp            # Save old frame pointer.
151         mov     %rsp,%rbp       # Establish new frame.
152 Lstack:
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. */
156         push    %r15
157         mov     %rax,%r15
158 #endif
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
163         push    %r14    #
164         push    %r15    #
165         push    %rdi    # args from C
166         push    %rsi    #
167         push    %rdx    #
168         movq    %rcx, THREAD_BASE_REG
169         pop     %rcx    # num args
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?
178         cmp     $2,%rcx
179         je      Ltwo
180         cmp     $1,%rcx
181         je      Lone
182         jl      Lzero
183         mov     16(%rbx),%rsi   # arg2
184 Ltwo:   mov     8(%rbx),%rdi    # arg1
185 Lone:   mov     0(%rbx),%rdx    # arg0
186 Lzero:
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.
195 Lcall:
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.
200            Lose them */
201         jnc     LsingleValue
202         mov     %rbx, %rsp
203 LsingleValue:
205 /* Restore C regs */
206         pop     %r15
207         pop     %r14
208         pop     %r13
209         pop     %r12
210         pop     %rbx
212 /* FIXME Restore the NPX state. */
214         mov     %rdx,%rax       # c-val
215 #ifdef SUPPORT_FOMIT_FRAME_POINTER
216         mov     %r15,%rbp       # orig rbp
217         pop     %r15            # orig r15
218         add     $8,%rsp         # no need for saved (overridden) rbp
219 #else
220         leave
221 #endif
222         ret
223         SIZE(GNAME(call_into_lisp_))
225         .text
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
231    rdi arg1
232    rsi arg2
233    rdx arg0
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
243         push    %r14    #
244         push    %r15    #
245 #ifdef LISP_FEATURE_SB_THREAD
246         mov     %rcx, THREAD_BASE_REG
247 #else
248         LOAD_PIC_VAR(all_threads, THREAD_BASE_REG)
249 #endif
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
255         mov     %rsp,%rbp
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)
260 /* Restore C regs */
261         pop     %r15
262         pop     %r14
263         pop     %r13
264         pop     %r12
265         pop     %rbx
267         leave
269         ret
270         SIZE(GNAME(funcall_alien_callback))
273  * fun-end breakpoint magic
274  */
277  * For an explanation of the magic involved in function-end
278  * breakpoints, see the implementation in ppc-assem.S.
279  */
281         .text
282         .globl  GNAME(fun_end_breakpoint_guts)
283         .align  align_16byte
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
289            count of one. */
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):
300         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):
312         TRAP
313         .byte   trap_PendingInterrupt
314         ret
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):
322         TRAP
323         .byte   trap_GlobalSafepoint
324         ret
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):
331         TRAP
332         .byte   trap_CspSafepoint
333         ret
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):
341         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 */
352         popq %r15
353         popq %r14
354         popq %r13
355         popq %r12
356         popq %r11
357         popq %r10
358         popq %r9
359         popq %r8
360         popq %rdi
361         popq %rsi
362         /* skip RBP and RSP */
363         popq %rbx
364         popq %rdx
365         popq %rcx
366         popq %rax
367         popfq
368         leave
369         ret
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:
376  */
377         .text
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. */
393         lea     -8(%rsp), %rax
394 #ifdef LISP_FEATURE_WIN32
395         LOAD_PIC_VAR(win32_page_size, %r9)
396 #else
397         LOAD_PIC_VAR(os_vm_page_size, %r9)
398 #endif
399         lea     (%rsi,%r9), %r8
400         lea     (%rdx,%r9), %r9
402         /* Now we begin our main scrub loop. */
403 ascs_outer_loop:
405         /* If we're about to scrub the hard guard page, exit. */
406         cmp     %r9, %rax
407         jae     ascs_check_guard_page
408         cmp     %rax, %rdx
409         jbe     ascs_finished
411 ascs_check_guard_page:
412         /* If we're about to scrub the guard page, and the guard
413          * page is protected, exit. */
414         cmp     %r8, %rax
415         jae     ascs_clear_loop
416         cmp     %rax, %rsi
417         ja      ascs_clear_loop
418         /* test state_word.control_stack_guard_page_protected */
419         cmpb    $0, THREAD_STATE_WORD_OFFSET(%rdi)
420         jne     ascs_finished
422         /* Clear memory backwards to the start of the (4KiB) page */
423 ascs_clear_loop:
424         movq    $0, (%rax)
425         test    $0xfff, %rax
426         lea     -8(%rax), %rax
427         jnz     ascs_clear_loop
429         /* If we're about to hit the hard guard page, exit. */
430         cmp     %r9, %rax
431         jae     ascs_finished
433         /* If the next (previous?) 4KiB page contains a non-zero
434          * word, continue scrubbing. */
435 ascs_check_loop:
436         testq   $-1, (%rax)
437         jnz     ascs_outer_loop
438         test    $0xfff, %rax
439         lea     -8(%rax), %rax
440         jnz     ascs_check_loop
442 ascs_finished:
443         ret
444         SIZE(GNAME(arch_scrub_control_stack))