1/* 2 Title: Assembly code routines for the poly system. 3 Author: David Matthews 4 Copyright (c) David C. J. Matthews 2000-2020 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 16 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_TrapHandlerEntry 0x34 78#define Arg_SaveRAX 0x38 79#define Arg_SaveRBX 0x3c 80#define Arg_SaveRCX 0x40 81#define Arg_SaveRDX 0x44 82#define Arg_SaveRSI 0x48 83#define Arg_SaveRDI 0x4c 84#define Arg_SaveFP 0x50 85 86#define RETURN_HEAP_OVERFLOW 1 87#define RETURN_STACK_OVERFLOW 2 88#define RETURN_STACK_OVERFLOWEX 3 89 90# Mark the stack as non-executable when supported 91#if (defined(__linux__) && defined(__ELF__)) 92.section .note.GNU-stack, "", @progbits 93#endif 94 95# 96# CODE STARTS HERE 97# 98 .text 99 100#define CALL_EXTRA(index) \ 101 movb $index,Arg_ReturnReason(%ebp); \ 102 jmp CallTrapHandler; 103 104/* Enter ML code. This is now only ever used to start a new thread. 105 It is probably unnecessary to save the callee-save regs or load the ML regs. */ 106INLINE_ROUTINE(X86AsmSwitchToPoly) 107 pushl %ebp # Standard entry sequence 108 movl 8(%esp),%ebp # Address of argument vector 109 pushl %ebx 110 pushl %edi 111 pushl %esi # Push callee-save registers 112 subl $(Fr_Size-12),%esp # Allocate frame 113 movl %esp,Arg_SaveCStack(%ebp) 114 movl Arg_StackPtr(%ebp),%esp 115 FRSTOR Arg_SaveFP(%ebp) 116 movl Arg_SaveRAX(%ebp),%eax # Load the registers 117 movl Arg_SaveRBX(%ebp),%ebx # Load the registers 118 movl Arg_SaveRCX(%ebp),%ecx 119 movl Arg_SaveRDX(%ebp),%edx 120 movl Arg_SaveRSI(%ebp),%esi 121 movl Arg_SaveRDI(%ebp),%edi 122 cld # Clear this just in case 123 jmp *(%edx) 124 125 126/* Save all the registers and enter the trap handler. 127 It is probably unnecessary to save the FP state now. */ 128CallTrapHandler: 129 movl %eax,Arg_SaveRAX(%ebp) 130 movl %ebx,Arg_SaveRBX(%ebp) 131 movl %ecx,Arg_SaveRCX(%ebp) 132 movl %edx,Arg_SaveRDX(%ebp) 133 movl %esi,Arg_SaveRSI(%ebp) 134 movl %edi,Arg_SaveRDI(%ebp) 135 fnsave Arg_SaveFP(%ebp) # Save FP state. Also resets the state so... 136 fldcw Arg_SaveFP(%ebp) # ...load because we need the same rounding mode in the RTS 137 movl %esp,Arg_StackPtr(%ebp) # Save ML stack pointer 138 movl Arg_SaveCStack(%ebp),%esp # Restore C stack pointer 139 subl $12,%esp # Align stack ptr - GCC prefers this 140 pushl Arg_ThreadId(%ebp) 141 calll *Arg_TrapHandlerEntry(%ebp) 142 addl $16,%esp 143 movl Arg_StackPtr(%ebp),%esp 144 movl Arg_ExceptionPacket(%ebp),%eax 145 cmpl $1,%eax # Did we raise an exception? 146 jnz raisexlocal 147 FRSTOR Arg_SaveFP(%ebp) 148 movl Arg_SaveRAX(%ebp),%eax # Load the registers 149 movl Arg_SaveRBX(%ebp),%ebx # Load the registers 150 movl Arg_SaveRCX(%ebp),%ecx 151 movl Arg_SaveRDX(%ebp),%edx 152 movl Arg_SaveRSI(%ebp),%esi 153 movl Arg_SaveRDI(%ebp),%edi 154 cld # Clear this just in case 155 ret 156 157raisexlocal: 158 movl Arg_HandlerRegister(%ebp),%ecx # Get next handler into %rcx 159 jmp *(%ecx) 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# Additional assembly code routines 171 172# This implements atomic addition in the same way as atomic_increment 173INLINE_ROUTINE(X86AsmAtomicDecrement) 174#ifndef HOSTARCHITECTURE_X86_64 175 movl 4(%esp),%eax 176#else 177 movl %edi,%eax # On X86_64 the argument is passed in %edi 178#endif 179# Use %ecx and %eax because they are volatile (unlike %ebx on X86/64/Unix) 180 movl $-2,%ecx 181 lock; xaddl %ecx,(%eax) 182 subl $2,%ecx 183 movl %ecx,%eax 184 ret 185 186