1 /** 2 * Implementation of alloca() standard C routine. 3 * 4 * Copyright: Copyright Digital Mars 2000 - 2012. 5 * License: Distributed under the 6 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 7 * (See accompanying file LICENSE) 8 * Authors: Walter Bright 9 * Source: $(DRUNTIMESRC rt/_alloca.d) 10 */ 11 12 module rt.alloca; 13 14 version (Posix) 15 { 16 version = alloca; 17 } 18 else version (CRuntime_Microsoft) 19 { 20 version = alloca; 21 } 22 23 // Use DMC++'s alloca() for Win32 24 25 version (alloca) 26 { 27 28 /******************************************* 29 * Allocate data from the caller's stack frame. 30 * This is a 'magic' function that needs help from the compiler to 31 * work right, do not change its name, do not call it from other compilers. 32 * Input: 33 * nbytes number of bytes to allocate 34 * ECX address of variable with # of bytes in locals 35 * This is adjusted upon return to reflect the additional 36 * size of the stack frame. 37 * Returns: 38 * EAX allocated data, null if stack overflows 39 */ 40 41 extern (C) void* __alloca(int nbytes) 42 { 43 version (D_InlineAsm_X86) 44 { 45 asm 46 { 47 naked ; 48 mov EDX,ECX ; 49 mov EAX,4[ESP] ; // get nbytes 50 push EBX ; 51 push EDI ; 52 push ESI ; 53 54 add EAX,15 ; 55 and EAX,0xFFFFFFF0 ; // round up to 16 byte boundary 56 jnz Abegin ; 57 mov EAX,16 ; // minimum allocation is 16 58 Abegin: 59 mov ESI,EAX ; // ESI = nbytes 60 neg EAX ; 61 add EAX,ESP ; // EAX is now what the new ESP will be. 62 jae Aoverflow ; 63 } 64 version (Win32) 65 { 66 asm 67 { 68 // We need to be careful about the guard page 69 // Thus, for every 4k page, touch it to cause the OS to load it in. 70 mov ECX,EAX ; // ECX is new location for stack 71 mov EBX,ESI ; // EBX is size to "grow" stack 72 L1: 73 test [ECX+EBX],EBX ; // bring in page 74 sub EBX,0x1000 ; // next 4K page down 75 jae L1 ; // if more pages 76 test [ECX],EBX ; // bring in last page 77 } 78 } 79 asm 80 { 81 // Copy down to [ESP] the temps on the stack. 82 // The number of temps is (EBP - ESP - locals). 83 mov ECX,EBP ; 84 sub ECX,ESP ; 85 sub ECX,[EDX] ; // ECX = number of temps (bytes) to move. 86 add [EDX],ESI ; // adjust locals by nbytes for next call to alloca() 87 mov ESP,EAX ; // Set up new stack pointer. 88 add EAX,ECX ; // Return value = ESP + temps. 89 mov EDI,ESP ; // Destination of copy of temps. 90 add ESI,ESP ; // Source of copy. 91 shr ECX,2 ; // ECX to count of dwords in temps 92 // Always at least 4 (nbytes, EIP, ESI,and EDI). 93 rep ; 94 movsd ; 95 jmp done ; 96 97 Aoverflow: 98 // Overflowed the stack. Return null 99 xor EAX,EAX ; 100 101 done: 102 pop ESI ; 103 pop EDI ; 104 pop EBX ; 105 ret ; 106 } 107 } 108 else version (D_InlineAsm_X86_64) 109 { 110 version (Win64) 111 { 112 asm 113 { 114 /* RCX nbytes 115 * RDX address of variable with # of bytes in locals 116 * Must save registers RBX,RDI,RSI,R12..R15 117 */ 118 naked ; 119 push RBX ; 120 push RDI ; 121 push RSI ; 122 mov RAX,RCX ; // get nbytes 123 add RAX,15 ; 124 and AL,0xF0 ; // round up to 16 byte boundary 125 test RAX,RAX ; 126 jnz Abegin ; 127 mov RAX,16 ; // allow zero bytes allocation 128 Abegin: 129 mov RSI,RAX ; // RSI = nbytes 130 neg RAX ; 131 add RAX,RSP ; // RAX is now what the new RSP will be. 132 jae Aoverflow ; 133 134 // We need to be careful about the guard page 135 // Thus, for every 4k page, touch it to cause the OS to load it in. 136 mov RCX,RAX ; // RCX is new location for stack 137 mov RBX,RSI ; // RBX is size to "grow" stack 138 L1: 139 test [RCX+RBX],RBX ; // bring in page 140 sub RBX,0x1000 ; // next 4K page down 141 jae L1 ; // if more pages 142 test [RCX],RBX ; // bring in last page 143 144 // Copy down to [RSP] the temps on the stack. 145 // The number of temps is (RBP - RSP - locals). 146 mov RCX,RBP ; 147 sub RCX,RSP ; 148 sub RCX,[RDX] ; // RCX = number of temps (bytes) to move. 149 add [RDX],RSI ; // adjust locals by nbytes for next call to alloca() 150 mov RSP,RAX ; // Set up new stack pointer. 151 add RAX,RCX ; // Return value = RSP + temps. 152 mov RDI,RSP ; // Destination of copy of temps. 153 add RSI,RSP ; // Source of copy. 154 shr RCX,3 ; // RCX to count of qwords in temps 155 rep ; 156 movsq ; 157 jmp done ; 158 159 Aoverflow: 160 // Overflowed the stack. Return null 161 xor RAX,RAX ; 162 163 done: 164 pop RSI ; 165 pop RDI ; 166 pop RBX ; 167 ret ; 168 } 169 } 170 else 171 { 172 asm 173 { 174 /* Parameter is passed in RDI 175 * Must save registers RBX,R12..R15 176 */ 177 naked ; 178 mov RDX,RCX ; 179 mov RAX,RDI ; // get nbytes 180 add RAX,15 ; 181 and AL,0xF0 ; // round up to 16 byte boundary 182 test RAX,RAX ; 183 jnz Abegin ; 184 mov RAX,16 ; // allow zero bytes allocation 185 Abegin: 186 mov RSI,RAX ; // RSI = nbytes 187 neg RAX ; 188 add RAX,RSP ; // RAX is now what the new RSP will be. 189 jae Aoverflow ; 190 191 // Copy down to [RSP] the temps on the stack. 192 // The number of temps is (RBP - RSP - locals). 193 mov RCX,RBP ; 194 sub RCX,RSP ; 195 sub RCX,[RDX] ; // RCX = number of temps (bytes) to move. 196 add [RDX],RSI ; // adjust locals by nbytes for next call to alloca() 197 mov RSP,RAX ; // Set up new stack pointer. 198 add RAX,RCX ; // Return value = RSP + temps. 199 mov RDI,RSP ; // Destination of copy of temps. 200 add RSI,RSP ; // Source of copy. 201 shr RCX,3 ; // RCX to count of qwords in temps 202 rep ; 203 movsq ; 204 jmp done ; 205 206 Aoverflow: 207 // Overflowed the stack. Return null 208 xor RAX,RAX ; 209 210 done: 211 ret ; 212 } 213 } 214 } 215 else 216 static assert(0); 217 } 218 219 }