1/* 2 Title: Assembly code routines for the poly system. 3 Author: David Matthews 4 Copyright (c) David C. J. Matthews 2000-2016 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License version 2.1 as published by the Free Software Foundation. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18*/ 19 20/* 21 This is the 64-bit gas version of the assembly code file. 22 There are separate versions of 32/64 and MAMS (Intel syntax) and 23 and GCC (gas syntax). 24*/ 25 26/* 27 Registers used :- 28 29 %rax: First argument to function. Result of function call. 30 %rbx: Second argument to function. 31 %rcx: General register 32 %rdx: Closure pointer in call. 33 %rbp: Points to memory used for extra registers 34 %rsi: General register. 35 %rdi: General register. 36 %rsp: Stack pointer. 37 %r8: Third argument to function 38 %r9: Fourth argument to function 39 %r10: Fifth argument to function 40 %r11: General register 41 %r12: General register 42 %r13: General register 43 %r14: General register 44 %r15: Memory allocation pointer 45*/ 46 47 48#include "config.h" 49#ifdef SYMBOLS_REQUIRE_UNDERSCORE 50#define EXTNAME(x) _##x 51#else 52#define EXTNAME(x) x 53#endif 54 55#ifdef __CYGWIN__ 56#define _WIN32 1 57#endif 58 59/* Macro to begin the hand-coded functions */ 60#ifdef MACOSX 61#define GLOBAL .globl 62#else 63#define GLOBAL .global 64#endif 65 66#define INLINE_ROUTINE(id) \ 67GLOBAL EXTNAME(id); \ 68EXTNAME(id): 69 70/* Extra entries on the C stack */ 71#define Fr_SavedMLSP -128 72 73#define Fr_Size 144 /* Must be multiple of 16 to get alignment correct */ 74 75/* This is the argument vector passed in to X86AsmSwitchToPoly 76 It is used to initialise the frame. A few values are updated 77 when ML returns. */ 78#define Arg_LocalMpointer 0x0 79#define Arg_HandlerRegister 0x8 80#define Arg_LocalMbottom 0x10 81#define Arg_StackLimit 0x18 82#define Arg_ExceptionPacket 0x20 /* Address of packet to raise */ 83#define Arg_RequestCode 0x28 /* Byte: Io function to call. */ 84#define Arg_ReturnReason 0x2a /* Byte: Reason for returning from ML. */ 85#define Arg_UnusedRestore 0x2b /* Byte: Full/partial restore */ 86#define Arg_SaveCStack 0x30 /* Current stack base */ 87#define Arg_ThreadId 0x38 /* My thread id */ 88#define Arg_StackPtr 0x40 /* Stack Pointer */ 89#define Arg_SaveRAX 0x68 90#define Arg_SaveRBX 0x70 91#define Arg_SaveRCX 0x78 92#define Arg_SaveRDX 0x80 93#define Arg_SaveRSI 0x88 94#define Arg_SaveRDI 0x90 95#define Arg_SaveR8 0x98 96#define Arg_SaveR9 0xa0 97#define Arg_SaveR10 0xa8 98#define Arg_SaveR11 0xb0 99#define Arg_SaveR12 0xb8 100#define Arg_SaveR13 0xc0 101#define Arg_SaveR14 0xc8 102#define Arg_SaveXMM0 0xd0 103#define Arg_SaveXMM1 0xd8 104#define Arg_SaveXMM2 0xe0 105#define Arg_SaveXMM3 0xe8 106#define Arg_SaveXMM4 0xf0 107#define Arg_SaveXMM5 0xf8 108#define Arg_SaveXMM6 0x100 109 110/* IO function numbers. These are functions that are called 111 to handle special cases in this code */ 112#include "sys.h" 113 114#define RETURN_HEAP_OVERFLOW 1 115#define RETURN_STACK_OVERFLOW 2 116#define RETURN_STACK_OVERFLOWEX 3 117#define RETURN_CALLBACK_RETURN 6 118#define RETURN_CALLBACK_EXCEPTION 7 119#define RETURN_RAISE_OVERFLOW 8 120#define RETURN_KILL_SELF 9 121 122# Mark the stack as non-executable when supported 123#ifdef HAVE_GNU_STACK 124.section .note.GNU-stack, "", @progbits 125#endif 126 127# 128# CODE STARTS HERE 129# 130 .text 131 132#define CALL_EXTRA(index) \ 133 pushq %rcx; \ 134 movb $index,Arg_ReturnReason(%rbp); \ 135 popq %rcx; \ 136 jmp SaveFullState; 137 138 139/* Load the registers from the ML stack and jump to the code. */ 140INLINE_ROUTINE(X86AsmSwitchToPoly) 141 pushq %rbp # Standard entry sequence 142/* If we're compiling with Mingw we're using Windows calling conventions. */ 143#ifdef _WIN32 144 movq %rcx,%rbp # Argument is in %rcx 145#else 146 movq %rdi,%rbp # Argument is in %rdi 147#endif 148 movq %rsp,Arg_SaveCStack(%rbp) 149 pushq %rbx 150 pushq %r12 151 pushq %r13 152 pushq %r14 153 pushq %r15 154#ifdef _WIN32 155 pushq %rdi # Callee save in Windows 156 pushq %rsi 157 subq $(Fr_Size-56),%rsp # Argument is already in %rcx 158#else 159 subq $(Fr_Size-40),%rsp 160#endif 161 162 movq Arg_LocalMpointer(%rbp),%r15 163 movq Arg_StackPtr(%rbp),%rsp # Set the new stack ptr 164 movq Arg_ExceptionPacket(%rbp),%rax 165 cmpq $1,%rax # Did we raise an exception? 166 jnz raisexLocal 167 168 movsd Arg_SaveXMM0(%rbp),%xmm0 169 movsd Arg_SaveXMM1(%rbp),%xmm1 170 movsd Arg_SaveXMM2(%rbp),%xmm2 171 movsd Arg_SaveXMM3(%rbp),%xmm3 172 movsd Arg_SaveXMM4(%rbp),%xmm4 173 movsd Arg_SaveXMM5(%rbp),%xmm5 174 movsd Arg_SaveXMM6(%rbp),%xmm6 175 movq Arg_SaveRAX(%rbp),%rax # Load the registers 176 movq Arg_SaveRBX(%rbp),%rbx 177 movq Arg_SaveRCX(%rbp),%rcx 178 movq Arg_SaveRDX(%rbp),%rdx 179 movq Arg_SaveRSI(%rbp),%rsi 180 movq Arg_SaveRDI(%rbp),%rdi 181 movq Arg_SaveR8(%rbp),%r8 182 movq Arg_SaveR9(%rbp),%r9 183 movq Arg_SaveR10(%rbp),%r10 184 movq Arg_SaveR11(%rbp),%r11 185 movq Arg_SaveR12(%rbp),%r12 186 movq Arg_SaveR13(%rbp),%r13 187 movq Arg_SaveR14(%rbp),%r14 188 cld # Clear this just in case 189 ret 190 191/* This is exactly the same as raisex but seems to be needed to work round a PIC problem. */ 192raisexLocal: 193 movq Arg_HandlerRegister(%rbp),%rcx # Get next handler into %rcx 194 jmp *(%rcx) 195 196/* Code to save the state and switch to C 197 This saves the full register state. */ 198SaveFullState: 199 movq %rax,Arg_SaveRAX(%rbp) 200 movq %rbx,Arg_SaveRBX(%rbp) 201 movq %rcx,Arg_SaveRCX(%rbp) 202 movq %rdx,Arg_SaveRDX(%rbp) 203 movq %rsi,Arg_SaveRSI(%rbp) 204 movq %rdi,Arg_SaveRDI(%rbp) 205 movsd %xmm0,Arg_SaveXMM0(%rbp) 206 movsd %xmm1,Arg_SaveXMM1(%rbp) 207 movsd %xmm2,Arg_SaveXMM2(%rbp) 208 movsd %xmm3,Arg_SaveXMM3(%rbp) 209 movsd %xmm4,Arg_SaveXMM4(%rbp) 210 movsd %xmm5,Arg_SaveXMM5(%rbp) 211 movsd %xmm6,Arg_SaveXMM6(%rbp) 212 movq %r8,Arg_SaveR8(%rbp) 213 movq %r9,Arg_SaveR9(%rbp) 214 movq %r10,Arg_SaveR10(%rbp) 215 movq %r11,Arg_SaveR11(%rbp) 216 movq %r12,Arg_SaveR12(%rbp) 217 movq %r13,Arg_SaveR13(%rbp) 218 movq %r14,Arg_SaveR14(%rbp) 219 movq %rsp,Arg_StackPtr(%rbp) 220 movq %r15,Arg_LocalMpointer(%rbp) # Save back heap pointer 221 movq Arg_SaveCStack(%rbp),%rsp # Restore C stack pointer 222#ifdef _WIN32 223 subq $56,%rsp 224 popq %rsi 225 popq %rdi 226#else 227 subq $40,%rsp 228#endif 229 popq %r15 # Restore callee-save registers 230 popq %r14 231 popq %r13 232 popq %r12 233 popq %rbx 234 popq %rbp 235 ret 236 237callExHeap: 238 CALL_EXTRA(RETURN_HEAP_OVERFLOW) 239callExStack: 240 CALL_EXTRA(RETURN_STACK_OVERFLOW) 241callExStackEx: 242 CALL_EXTRA(RETURN_STACK_OVERFLOWEX) 243callExRaiseOverflow: 244 CALL_EXTRA(RETURN_RAISE_OVERFLOW) 245 246 247/* Used when entering new code. The argument and closure are on the stack 248 in case there is a GC before we enter the code. */ 249INLINE_ROUTINE(X86AsmPopArgAndClosure) 250 popq %rdx 251 popq %rax 252 jmp *(%rdx) 253 254# This is used if the RTS sets up an exception. It's probably no longer relevant. 255INLINE_ROUTINE(X86AsmRaiseException) 256 movq Arg_HandlerRegister(%rbp),%rcx # Get next handler into %rcx 257 jmp *(%rcx) 258# Additional assembly code routines 259 260# RTS call to kill the current thread. 261INLINE_ROUTINE(X86AsmKillSelf) 262 CALL_EXTRA(RETURN_KILL_SELF) 263 264INLINE_ROUTINE(X86AsmCallbackReturn) 265 CALL_EXTRA(RETURN_CALLBACK_RETURN) 266 267INLINE_ROUTINE(X86AsmCallbackException) 268 CALL_EXTRA(RETURN_CALLBACK_EXCEPTION) 269 270INLINE_ROUTINE(X86AsmCallExtraRETURN_HEAP_OVERFLOW) 271 CALL_EXTRA(RETURN_HEAP_OVERFLOW) 272 273INLINE_ROUTINE(X86AsmCallExtraRETURN_STACK_OVERFLOW) 274 CALL_EXTRA(RETURN_STACK_OVERFLOW) 275 276INLINE_ROUTINE(X86AsmCallExtraRETURN_STACK_OVERFLOWEX) 277 CALL_EXTRA(RETURN_STACK_OVERFLOWEX) 278 279 280# This implements atomic addition in the same way as atomic_increment 281INLINE_ROUTINE(X86AsmAtomicIncrement) 282#ifdef _WIN32 283 movq %rcx,%rax # On Windows the argument is passed in %rcx 284#else 285 movq %rdi,%rax # On X86_64 the argument is passed in %rdi 286#endif 287# Use %rcx and %rax because they are volatile (unlike %rbx on X86/64/Unix) 288 movq $2,%rcx 289 lock xaddq %rcx,(%rax) 290 addq $2,%rcx 291 movq %rcx,%rax 292 ret 293 294