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 32-bit Unix version of the assembly code file. 22 There are separate versions of 32/64 and Windows (Intel syntax) 23 and Unix (gas syntax). 24*/ 25 26/* 27 Registers used :- 28 29 %%eax: First argument to function. Result of function call. 30 %%ebx: Second argument to function. 31 %%ecx: General register 32 %%edx: Closure pointer in call. 33 %%ebp: Points to memory used for extra registers 34 %%esi: General register. 35 %%edi: General register. 36 %%esp: Stack pointer. 37*/ 38 39 40#include "config.h" 41#ifdef SYMBOLS_REQUIRE_UNDERSCORE 42#define EXTNAME(x) _##x 43#else 44#define EXTNAME(x) x 45#endif 46 47# 48# Macro to begin the hand-coded functions 49# 50 51#ifdef MACOSX 52#define GLOBAL .globl 53#else 54#define GLOBAL .global 55#endif 56 57#define INLINE_ROUTINE(id) \ 58GLOBAL EXTNAME(id); \ 59EXTNAME(id): 60 61#define Fr_Size 56 62 63/* This is the argument vector passed in to X86AsmSwitchToPoly 64 It is used to initialise the frame. A few values are updated 65 when ML returns. */ 66#define Arg_LocalMpointer 0x0 67#define Arg_HandlerRegister 0x4 68#define Arg_LocalMbottom 0x8 69#define Arg_StackLimit 0xc 70#define Arg_ExceptionPacket 0x10 /* Address of packet to raise */ 71#define Arg_RequestCode 0x14 /* Byte: Io function to call. */ 72#define Arg_ReturnReason 0x16 /* Byte: Reason for returning from ML. */ 73#define Arg_FullRestore 0x17 /* Byte: Full/partial restore */ 74#define Arg_SaveCStack 0x18 /* Save C Stack pointer */ 75#define Arg_ThreadId 0x1c /* My thread id */ 76#define Arg_StackPtr 0x20 /* Stack Pointer */ 77#define Arg_SaveRAX 0x34 78#define Arg_SaveRBX 0x38 79#define Arg_SaveRCX 0x3c 80#define Arg_SaveRDX 0x40 81#define Arg_SaveRSI 0x44 82#define Arg_SaveRDI 0x48 83#define Arg_SaveFP 0x4c 84 85#define RETURN_HEAP_OVERFLOW 1 86#define RETURN_STACK_OVERFLOW 2 87#define RETURN_STACK_OVERFLOWEX 3 88#define RETURN_CALLBACK_RETURN 6 89#define RETURN_CALLBACK_EXCEPTION 7 90#define RETURN_KILL_SELF 9 91 92# Mark the stack as non-executable when supported 93#ifdef HAVE_GNU_STACK 94.section .note.GNU-stack, "", @progbits 95#endif 96 97# 98# CODE STARTS HERE 99# 100 .text 101 102#define CALL_EXTRA(index) \ 103 pushl %ecx; \ 104 movb $index,Arg_ReturnReason(%ebp); \ 105 popl %ecx; \ 106 jmp SaveFullState; 107 108/* Load the registers from the ML stack and jump to the code. 109 This is used to start ML code. 110 The argument is the address of the MemRegisters struct and goes into %rbp. 111 This is the general code for switching control to ML. There are a number of cases to consider: 112 1. Initial entry to root function or a new thread. Needs to load EDX at least. 113 2. Normal return from an RTS call. Could just do a simple return. 114 3. Exception raised in RTS call. 115 4. Callback from C to an ML function. In effect this is a coroutine. Similar to 1. 116 5. Return from "trap" i.e. Heap/Stack overflow. Stack-overflow can result in an exception 117 either because the stack can't be grown or because Interrupt has been raised. */ 118INLINE_ROUTINE(X86AsmSwitchToPoly) 119 pushl %ebp # Standard entry sequence 120 movl 8(%esp),%ebp # Address of argument vector 121 movl %esp,Arg_SaveCStack(%ebp) 122 pushl %ebx 123 pushl %edi 124 pushl %esi # Push callee-save registers 125 subl $(Fr_Size-12),%esp # Allocate frame 126 movl Arg_StackPtr(%ebp),%esp 127 movl Arg_ExceptionPacket(%ebp),%eax 128 cmpl $1,%eax # Did we raise an exception? 129 jnz raisexlocal 130 FRSTOR Arg_SaveFP(%ebp) 131 movl Arg_SaveRAX(%ebp),%eax # Load the registers 132 movl Arg_SaveRBX(%ebp),%ebx # Load the registers 133 movl Arg_SaveRCX(%ebp),%ecx 134 movl Arg_SaveRDX(%ebp),%edx 135 movl Arg_SaveRSI(%ebp),%esi 136 movl Arg_SaveRDI(%ebp),%edi 137 cld # Clear this just in case 138 ret 139 140 141/* Code to save the state and switch to C 142 This saves the full register state. */ 143SaveFullState: 144 movl %eax,Arg_SaveRAX(%ebp) 145 movl %ebx,Arg_SaveRBX(%ebp) 146 movl %ecx,Arg_SaveRCX(%ebp) 147 movl %edx,Arg_SaveRDX(%ebp) 148 movl %esi,Arg_SaveRSI(%ebp) 149 movl %edi,Arg_SaveRDI(%ebp) 150 fnsave Arg_SaveFP(%ebp) # Save FP state. Also resets the state so... 151 fldcw Arg_SaveFP(%ebp) # ...load because we need the same rounding mode in the RTS 152 movl %esp,Arg_StackPtr(%ebp) # Save ML stack pointer 153 movl Arg_SaveCStack(%ebp),%esp # Restore C stack pointer 154 subl $12,%esp # Sp is just before the registers 155 popl %esi 156 popl %edi 157 popl %ebx 158 popl %ebp 159 ret 160 161INLINE_ROUTINE(X86AsmCallExtraRETURN_HEAP_OVERFLOW) 162 CALL_EXTRA(RETURN_HEAP_OVERFLOW) 163 164INLINE_ROUTINE(X86AsmCallExtraRETURN_STACK_OVERFLOW) 165 CALL_EXTRA(RETURN_STACK_OVERFLOW) 166 167INLINE_ROUTINE(X86AsmCallExtraRETURN_STACK_OVERFLOWEX) 168 CALL_EXTRA(RETURN_STACK_OVERFLOWEX) 169 170/* Used when entering new code. The argument and closure are on the stack 171 in case there is a GC before we enter the code. */ 172INLINE_ROUTINE(X86AsmPopArgAndClosure) 173 popl %edx 174 popl %eax 175 jmp *(%edx) 176 177INLINE_ROUTINE(X86AsmRaiseException) 178raisexlocal: 179 movl Arg_HandlerRegister(%ebp),%ecx # Get next handler into %rcx 180 jmp *(%ecx) 181 182# Additional assembly code routines 183 184# RTS call to kill the current thread. 185INLINE_ROUTINE(X86AsmKillSelf) 186 CALL_EXTRA(RETURN_KILL_SELF) 187 188INLINE_ROUTINE(X86AsmCallbackReturn) 189 CALL_EXTRA(RETURN_CALLBACK_RETURN) 190 191INLINE_ROUTINE(X86AsmCallbackException) 192 CALL_EXTRA(RETURN_CALLBACK_EXCEPTION) 193 194# This implements atomic addition in the same way as atomic_increment 195INLINE_ROUTINE(X86AsmAtomicIncrement) 196#ifndef HOSTARCHITECTURE_X86_64 197 movl 4(%esp),%eax 198#else 199 movl %edi,%eax # On X86_64 the argument is passed in %edi 200#endif 201# Use %ecx and %eax because they are volatile (unlike %ebx on X86/64/Unix) 202 movl $2,%ecx 203 lock; xaddl %ecx,(%eax) 204 addl $2,%ecx 205 movl %ecx,%eax 206 ret 207 208