1/** 2 * This file has no copyright assigned and is placed in the Public Domain. 3 * This file is part of the mingw-w64 runtime package. 4 * No warranty is given; refer to the file DISCLAIMER.PD within this package. 5 */ 6 7/* vsscanf, vswscanf, vfscanf, and vfwscanf all come here for i386 and arm. 8 9 The goal of this routine is to turn a call to v*scanf into a call to 10 s*scanf. This is needed because mingw-w64 uses msvcr100.dll, which doesn't 11 support the v*scanf functions instead of msvcr120.dll which does. 12 Unfortunately, there is no defined way to know exactly how big a va_list 13 is, so we use a hard-coded buffer. 14 15 I suppose a sufficiently-motivated person could try to parse the format 16 to figure out how many tokens there are... */ 17 18/* The function prototype here is (essentially): 19 20 int __ms_vsscanf_internal (void *s, 21 void *format, 22 void *arg, 23 void *func); 24 25 I say 'essentially' because passing a function pointer as void in ISO 26 is not supported. But in the end, I take the first parameter (which 27 may be a char *, a wchar_t *, or a FILE *) and put it into the newly 28 formed stack, and eventually call the address in func. */ 29 30#if defined (__x86_64__) 31 32 .text 33 .align 16 34 35 /* scl 2: C_EXT - External (public) symbol - covers globals and externs 36 type 32: DT_FCN - function returning T 37 */ 38 .def __argtos; .scl 2; .type 32; .endef 39 40 /* The max number of pointers we support. Must be an even number 41 to keep the 64bit stack 16byte aligned. Must not be less than 4. */ 42 .equ entries, 30 43 44 /* 64bit pointers are 8 bytes. */ 45 .equ sizeof, 8 46 47 /* Size of our buffer. */ 48 .equ iBytes, entries * sizeof 49 50 /* Stack space for first 2 args to s*scanf. */ 51 .equ iOffset, (2 * sizeof) 52 53 .seh_proc __argtos 54__argtos: 55 56 /* When we are done: 57 - s must be in rcx. That's where it is on entry. 58 - format must be in rdx. That's where it is on entry. 59 - The first pointer in arg must be in r8. arg is in r8 on entry. 60 - The second pointer in arg must be in r9. arg is in r8 on entry. 61 - The ($entries - 2) other pointers in arg must be on the stack, 62 starting 32bytes into rsp. */ 63 64 /* We need enough room to shadow (s + format) 65 + (enough room for all the other args). */ 66 subq $(iOffset + iBytes), %rsp 67 .seh_stackalloc iOffset + iBytes 68 69 .seh_endprologue 70 71 /* We are going to copy $entries pointers from arg to our 72 local stack. Except the first 2, since they will be 73 loaded in registers. */ 74 movq $entries - 2, %r10 /* # of ptrs to copy. */ 75 76 /* The first 32 bytes are in registers, but by spec, space 77 must still be reserved for them on the stack. Put the 78 rest of the pointers in the stack after that. */ 79 lea 32(%rsp), %r11 /* dst. */ 80 81.LOOP: 82 subq $1, %r10 83 84 /* Use 16 to skip over the first 2 pointers. */ 85 movq 16(%r8, %r10, 8), %rax 86 movq %rax, (%r11, %r10, 8) 87 jnz .LOOP 88 89 /* r9 contains the routine we are going to call. Since we are about to 90 overwrite it, move it somewhere safe. */ 91 movq %r9, %r10 92 93 /* The stack is now correctly populated, and so are rcx and rdx. 94 But we need to load the last 2 regs before making the call. */ 95 movq 0x8(%r8), %r9 /* 2nd dest location (may be garbage if only 1 arg). */ 96 movq (%r8), %r8 /* 1st dest location. */ 97 98 /* Make the call. */ 99 callq *%r10 100 101 addq $(iOffset + iBytes), %rsp 102 103 retq 104 .seh_endproc 105 106#elif defined (_X86_) 107 108 .text 109 .align 16 110 111 /* scl 2: C_EXT - External (public) symbol - covers globals and externs 112 type 32: DT_FCN - function returning T 113 */ 114 .def __argtos; .scl 2; .type 32; .endef 115 116 /* The max number of pointers we support. Must not be less than 1. */ 117 .equ entries, 30 118 119 /* 64bit pointers are 8 bytes. */ 120 .equ sizeof, 4 121 122 /* Size of our buffer. */ 123 .set iBytes, entries * sizeof 124 125 /* Stack space for first 2 args to s*scanf. */ 126 .equ iOffset, (2 * sizeof) 127 128__argtos: 129 pushl %ebp 130 movl %esp, %ebp 131 pushl %edi 132 133 /* Reserve enough stack space for everything. 134 135 Stack usage will look like: 136 4 bytes - s 137 4 bytes - format 138 (iBytes) bytes - variable # of parameters for sscanf (all ptrs). */ 139 140 subl $(iOffset + iBytes), %esp 141 142 /* Write out s and format where they need to be for the sscanf call. */ 143 movl 8(%ebp), %eax 144 movl %eax, (%esp) /* s. */ 145 movl 12(%ebp), %edx 146 movl %edx, 0x4(%esp) /* format. */ 147 148 /* We are going to copy $entries pointers from arg to our 149 local stack. */ 150 movl $entries, %ecx /* # of ptrs to copy. */ 151 lea iOffset(%esp), %edi /* dst. */ 152 movl 16(%ebp), %edx /* src. */ 153 154.LOOP: 155 subl $1, %ecx 156 157 movl (%edx, %ecx, 4), %eax 158 movl %eax, (%edi, %ecx, 4) 159 jnz .LOOP 160 161 /* The stack is now correctly populated. */ 162 163 /* Make the call. */ 164 call *20(%ebp) 165 166 /* Restore stack. */ 167 addl $(iOffset + iBytes), %esp 168 popl %edi 169 leave 170 171 ret 172 173#elif defined (__arm__) 174 175 .text 176 .align 2 177 .thumb_func 178 .globl __argtos 179 180__argtos: 181 push {r4-r7, lr} 182 sub sp, sp, #128 183 mov r12, r3 184 mov r4, sp 185 186 ldr r5, [r2], #4 187 ldr r6, [r2], #4 188 189 mov r3, #116 1901: ldr r7, [r2], #4 191 str r7, [r4], #4 192 subs r3, r3, #4 193 bne 1b 194 195 mov r2, r5 196 mov r3, r6 197 blx r12 198 add sp, sp, #128 199 pop {r4-r7, pc} 200 201#elif defined (__aarch64__) 202 203 .text 204 .align 2 205 .globl __argtos 206 207__argtos: 208 stp x29, x30, [sp, #-16]! 209 mov x29, sp 210 sub sp, sp, #256 211 mov x9, sp 212 mov x10, x2 213 mov x11, x3 214 215 ldr x2, [x10], #8 216 ldr x3, [x10], #8 217 ldr x4, [x10], #8 218 ldr x5, [x10], #8 219 ldr x6, [x10], #8 220 ldr x7, [x10], #8 221 222 mov x12, #240 2231: ldr x13, [x10], #8 224 str x13, [x9], #8 225 subs x12, x12, #8 226 b.ne 1b 227 228 blr x11 229 mov sp, x29 230 ldp x29, x30, [sp], #16 231 ret 232 233#endif 234