| /** | |
| * This file has no copyright assigned and is placed in the Public Domain. | |
| * This file is part of the mingw-w64 runtime package. | |
| * No warranty is given; refer to the file DISCLAIMER.PD within this package. | |
| */ | |
| /* vsscanf, vswscanf, vfscanf, and vfwscanf all come here for i386 and arm. | |
| The goal of this routine is to turn a call to v*scanf into a call to | |
| s*scanf. This is needed because mingw-w64 uses msvcr100.dll, which doesn't | |
| support the v*scanf functions instead of msvcr120.dll which does. | |
| Unfortunately, there is no defined way to know exactly how big a va_list | |
| is, so we use a hard-coded buffer. | |
| I suppose a sufficiently-motivated person could try to parse the format | |
| to figure out how many tokens there are... */ | |
| /* The function prototype here is (essentially): | |
| int __ms_vsscanf_internal (void *s, | |
| void *format, | |
| void *arg, | |
| void *func); | |
| I say 'essentially' because passing a function pointer as void in ISO | |
| is not supported. But in the end, I take the first parameter (which | |
| may be a char *, a wchar_t *, or a FILE *) and put it into the newly | |
| formed stack, and eventually call the address in func. */ | |
| #if defined (__x86_64__) | |
| .text | |
| .align 16 | |
| /* scl 2: C_EXT - External (public) symbol - covers globals and externs | |
| type 32: DT_FCN - function returning T | |
| */ | |
| .def __argtos; .scl 2; .type 32; .endef | |
| /* The max number of pointers we support. Must be an even number | |
| to keep the 64bit stack 16byte aligned. Must not be less than 4. */ | |
| .equ entries, 30 | |
| /* 64bit pointers are 8 bytes. */ | |
| .equ sizeof, 8 | |
| /* Size of our buffer. */ | |
| .equ iBytes, entries * sizeof | |
| /* Stack space for first 2 args to s*scanf. */ | |
| .equ iOffset, (2 * sizeof) | |
| .seh_proc __argtos | |
| __argtos: | |
| /* When we are done: | |
| - s must be in rcx. That's where it is on entry. | |
| - format must be in rdx. That's where it is on entry. | |
| - The first pointer in arg must be in r8. arg is in r8 on entry. | |
| - The second pointer in arg must be in r9. arg is in r8 on entry. | |
| - The ($entries - 2) other pointers in arg must be on the stack, | |
| starting 32bytes into rsp. */ | |
| /* We need enough room to shadow (s + format) | |
| + (enough room for all the other args). */ | |
| subq $(iOffset + iBytes), %rsp | |
| .seh_stackalloc iOffset + iBytes | |
| .seh_endprologue | |
| /* We are going to copy $entries pointers from arg to our | |
| local stack. Except the first 2, since they will be | |
| loaded in registers. */ | |
| movq $entries - 2, %r10 /* # of ptrs to copy. */ | |
| /* The first 32 bytes are in registers, but by spec, space | |
| must still be reserved for them on the stack. Put the | |
| rest of the pointers in the stack after that. */ | |
| lea 32(%rsp), %r11 /* dst. */ | |
| .LOOP: | |
| subq $1, %r10 | |
| /* Use 16 to skip over the first 2 pointers. */ | |
| movq 16(%r8, %r10, 8), %rax | |
| movq %rax, (%r11, %r10, 8) | |
| jnz .LOOP | |
| /* r9 contains the routine we are going to call. Since we are about to | |
| overwrite it, move it somewhere safe. */ | |
| movq %r9, %r10 | |
| /* The stack is now correctly populated, and so are rcx and rdx. | |
| But we need to load the last 2 regs before making the call. */ | |
| movq 0x8(%r8), %r9 /* 2nd dest location (may be garbage if only 1 arg). */ | |
| movq (%r8), %r8 /* 1st dest location. */ | |
| /* Make the call. */ | |
| callq *%r10 | |
| addq $(iOffset + iBytes), %rsp | |
| retq | |
| .seh_endproc | |
| #elif defined (_X86_) | |
| .text | |
| .align 16 | |
| /* scl 2: C_EXT - External (public) symbol - covers globals and externs | |
| type 32: DT_FCN - function returning T | |
| */ | |
| .def __argtos; .scl 2; .type 32; .endef | |
| /* The max number of pointers we support. Must not be less than 1. */ | |
| .equ entries, 30 | |
| /* 64bit pointers are 8 bytes. */ | |
| .equ sizeof, 4 | |
| /* Size of our buffer. */ | |
| .set iBytes, entries * sizeof | |
| /* Stack space for first 2 args to s*scanf. */ | |
| .equ iOffset, (2 * sizeof) | |
| __argtos: | |
| pushl %ebp | |
| movl %esp, %ebp | |
| pushl %edi | |
| /* Reserve enough stack space for everything. | |
| Stack usage will look like: | |
| 4 bytes - s | |
| 4 bytes - format | |
| (iBytes) bytes - variable # of parameters for sscanf (all ptrs). */ | |
| subl $(iOffset + iBytes), %esp | |
| /* Write out s and format where they need to be for the sscanf call. */ | |
| movl 8(%ebp), %eax | |
| movl %eax, (%esp) /* s. */ | |
| movl 12(%ebp), %edx | |
| movl %edx, 0x4(%esp) /* format. */ | |
| /* We are going to copy $entries pointers from arg to our | |
| local stack. */ | |
| movl $entries, %ecx /* # of ptrs to copy. */ | |
| lea iOffset(%esp), %edi /* dst. */ | |
| movl 16(%ebp), %edx /* src. */ | |
| .LOOP: | |
| subl $1, %ecx | |
| movl (%edx, %ecx, 4), %eax | |
| movl %eax, (%edi, %ecx, 4) | |
| jnz .LOOP | |
| /* The stack is now correctly populated. */ | |
| /* Make the call. */ | |
| call *20(%ebp) | |
| /* Restore stack. */ | |
| addl $(iOffset + iBytes), %esp | |
| popl %edi | |
| leave | |
| ret | |
| #elif defined (__arm__) | |
| .text | |
| .align 2 | |
| .thumb_func | |
| .globl __argtos | |
| __argtos: | |
| push {r4-r7, lr} | |
| sub sp, sp, #128 | |
| mov r12, r3 | |
| mov r4, sp | |
| ldr r5, [r2], #4 | |
| ldr r6, [r2], #4 | |
| mov r3, #116 | |
| 1: ldr r7, [r2], #4 | |
| str r7, [r4], #4 | |
| subs r3, r3, #4 | |
| bne 1b | |
| mov r2, r5 | |
| mov r3, r6 | |
| blx r12 | |
| add sp, sp, #128 | |
| pop {r4-r7, pc} | |
| #elif defined (__aarch64__) | |
| .text | |
| .align 2 | |
| .globl __argtos | |
| __argtos: | |
| stp x29, x30, [sp, #-16]! | |
| mov x29, sp | |
| sub sp, sp, #256 | |
| mov x9, sp | |
| mov x10, x2 | |
| mov x11, x3 | |
| ldr x2, [x10], #8 | |
| ldr x3, [x10], #8 | |
| ldr x4, [x10], #8 | |
| ldr x5, [x10], #8 | |
| ldr x6, [x10], #8 | |
| ldr x7, [x10], #8 | |
| mov x12, #240 | |
| 1: ldr x13, [x10], #8 | |
| str x13, [x9], #8 | |
| subs x12, x12, #8 | |
| b.ne 1b | |
| blr x11 | |
| mov sp, x29 | |
| ldp x29, x30, [sp], #16 | |
| ret | |
| #endif |