| /** |
| * 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, x64, arm32 and arm64. |
| |
| The goal of this routine is to turn a call to v*scanf into a call to |
| s*scanf. This is needed for pre-msvcr120 CRT libraries, which do not |
| support the v*scanf functions. |
| |
| The function prototype here is: |
| |
| int __argtos (void * restrict s, |
| const void * restrict format, |
| va_list arg, |
| size_t count, |
| int (*func)(void * restrict s, const void * restrict format, ...)); |
| |
| Where: |
| s - may be char *, a wchar_t *, or a FILE * (depending on a function) |
| format - is a char *, or a wchar_t * (depending on a function) |
| count - is the number of pointer-wide arguments from va_list arg which are |
| expanded as variadic arguments when calling 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 |
| |
| .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 (count - 2) other pointers in arg must be on the stack, |
| starting 32bytes into rsp. */ |
| |
| pushq %rbp |
| .seh_pushreg %rbp |
| movq %rsp, %rbp |
| .seh_setframe %rbp, 0 |
| |
| /* We need to always reserve space to shadow 4 parameters. */ |
| subq $32, %rsp |
| .seh_stackalloc 32 |
| .seh_endprologue |
| |
| movq 48(%rbp), %r10 /* func. */ |
| |
| /* We need enough room to shadow all the other args. |
| Except the first 2, since they will be loaded in registers. */ |
| cmpq $2, %r9 /* count. */ |
| jbe .SKIP |
| subq $2, %r9 /* # of ptrs to copy. */ |
| /* Calculate stack size (arg is 8byte) and keep the stack 16byte aligned. */ |
| leaq 8(, %r9, 8), %rax /* %rax = (%r9 + 1) * 8 */ |
| andq $-16, %rax |
| subq %rax, %rsp |
| |
| /* We are going to copy parameters from arg to our local stack. |
| 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, %r9 |
| |
| /* Use 16 to skip over the first 2 pointers. */ |
| movq 16(%r8, %r9, 8), %rax |
| movq %rax, (%r11, %r9, 8) |
| jnz .LOOP |
| |
| .SKIP: |
| /* 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 (may be garbage if no arg). */ |
| |
| /* Make the call. */ |
| callq *%r10 |
| |
| /* Restore stack. */ |
| movq %rbp, %rsp |
| |
| popq %rbp |
| 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 |
| |
| __argtos: |
| pushl %ebp |
| movl %esp, %ebp |
| pushl %edi |
| pushl %ebx |
| |
| /* Reserve enough stack space for everything. |
| |
| Stack usage will look like: |
| 4 bytes - s |
| 4 bytes - format |
| 4*count bytes - variable # of parameters for sscanf (all ptrs). */ |
| |
| movl 20(%ebp), %ebx /* count. */ |
| addl $2, %ebx /* s + format. */ |
| sall $2, %ebx /* (count + 2) * 4. */ |
| subl %ebx, %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 _count_ pointers from arg to our |
| local stack. */ |
| movl 20(%ebp), %ecx /* # of ptrs to copy. */ |
| testl %ecx, %ecx |
| jz .SKIP |
| lea 8(%esp), %edi /* dst. */ |
| movl 16(%ebp), %edx /* src. */ |
| |
| .LOOP: |
| subl $1, %ecx |
| |
| movl (%edx, %ecx, 4), %eax |
| movl %eax, (%edi, %ecx, 4) |
| jnz .LOOP |
| |
| .SKIP: |
| /* The stack is now correctly populated. */ |
| |
| /* Make the call. */ |
| call *24(%ebp) |
| |
| /* Restore stack. */ |
| addl %ebx, %esp |
| |
| popl %ebx |
| popl %edi |
| leave |
| |
| ret |
| |
| #elif defined (__arm__) |
| |
| .text |
| .align 2 |
| .thumb_func |
| .globl __argtos |
| |
| __argtos: |
| push {r4-r8, lr} |
| ldr r12, [sp, #24] |
| |
| ldr r5, [r2], #4 |
| ldr r6, [r2], #4 |
| |
| subs r3, r3, #2 |
| mov r8, #0 |
| ble 2f |
| |
| /* Round the number of entries to an even number, to maintain |
| * 8 byte stack alignment. */ |
| mov r8, r3 |
| add r8, r8, #1 |
| bic r8, r8, #1 |
| sub sp, sp, r8, lsl #2 |
| mov r4, sp |
| 1: ldr r7, [r2], #4 |
| subs r3, r3, #1 |
| str r7, [r4], #4 |
| bne 1b |
| |
| 2: |
| mov r2, r5 |
| mov r3, r6 |
| blx r12 |
| |
| add sp, sp, r8, lsl #2 |
| pop {r4-r8, pc} |
| |
| #elif defined (__aarch64__) |
| |
| .text |
| .align 2 |
| .globl __argtos |
| |
| __argtos: |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| mov x10, x2 |
| mov x11, x3 |
| mov x12, x4 |
| |
| ldr x2, [x10], #8 |
| ldr x3, [x10], #8 |
| ldr x4, [x10], #8 |
| ldr x5, [x10], #8 |
| ldr x6, [x10], #8 |
| ldr x7, [x10], #8 |
| |
| subs x11, x11, #6 |
| b.le 2f |
| |
| /* Round the number of entries to an even number, to maintain |
| * 16 byte stack alignment. */ |
| mov x13, x11 |
| add x13, x13, #1 |
| bic x13, x13, #1 |
| sub sp, sp, x13, lsl #3 |
| mov x9, sp |
| 1: ldr x13, [x10], #8 |
| subs x11, x11, #1 |
| str x13, [x9], #8 |
| b.ne 1b |
| |
| 2: |
| blr x12 |
| mov sp, x29 |
| ldp x29, x30, [sp], #16 |
| ret |
| |
| #endif |