244 lines
5.9 KiB
ArmAsm
244 lines
5.9 KiB
ArmAsm
/**
|
|
* 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.
|
|
*/
|
|
|
|
/* The function prototype here is (essentially):
|
|
|
|
int __ms_v*scanf_internal (void *s,
|
|
void *format,
|
|
void *arg,
|
|
size_t count,
|
|
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
|
|
|
|
.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
|