darling-corefoundation/NSInvoke-x86.S
2017-02-28 17:50:29 +01:00

150 lines
3.2 KiB
ArmAsm

.text
.align 2, 0x90
.globl ___invoke__
___invoke__:
# void __invoke__(void (*msgSend)(...),
# void *retdata,
# marg_list args,
# size_t frame_length,
# const char *return_type)
#ifdef __i386__
# Save retdata, scratch register, and return address.
push %ebp # Prologue
mov %esp, %ebp
push %edi
push %esi
push %edx
push %ebx
mov 12+8(%ebp), %eax #$eax = frame_length
mov 8+8(%ebp), %edx #$edx = args
mov %esp, %ebx
subl %eax, %esp #push the stack down
andl $-16, %esp #and align
Lpush:
movl -4(%eax,%edx), %edi
movl %edi, -4(%esp,%eax)
sub $4, %eax
test %eax, %eax
jne Lpush
mov 0+8(%ebp), %edi #$edi = msgSend
calll *%edi
mov 4+8(%ebp), %esi #$esi = retdata
mov %eax, (%esi) # copy the result (probably) into *retdata
#next, check to see if we need to put something else (ie something from
#the x87 registers or a 64-bit value) into *retdata instead.
mov 8+16(%ebp), %eax #$eax == return_type
mov (%eax), %al
cmpb $0x71, %al # if (returnType[0] == 'q') // int64_t
je Lsixtyfourret
cmpb $0x51, %al # if (returnType[0] == 'Q') // uint64_t
je Lsixtyfourret
cmpb $0x44, %al # if (returnType[0] == 'D') // long double
je Llongdoubleret
cmpb $0x64, %al # if (returnType[0] == 'd') // double
je Ldoubleret
cmpb $0x66, %al # if (returnType[0] == 'f') // float
jne Ldone
fstps (%esi) # this is how to get things out of x87.
# fstp pops and stores a certain length (determined by the suffix -
# s for float, l for double, t for long double - just go with it)
# in the location given (in this case *$esi)
jmp Ldone #then jump to to cleanup and return
Lsixtyfourret:
# just store edx too
mov %edx, 4(%esi)
jmp Ldone
Ldoubleret:
fstpl (%esi)
jmp Ldone
Llongdoubleret:
fstpt (%esi)
Ldone:
mov %ebx, %esp # restore stack!
pop %ebx
pop %edx
pop %esi
pop %edi
mov %ebp, %esp # Epilogue
pop %ebp
ret
#else // Now the x86-64 version
push %rbp # Prologue
movq %rsp, %rbp
push %rdi
push %rsi
push %r8
movq %rdx, %rsi
subq %rcx, %rsp # Push the stack down
andq $-16, %rsp #and align
# Shift stack contents (frame_length/8) times,
# 8 bytes at a time
# TODO: More efficient than the Lpush loop
# in i386 assembly above
movq %rsp, %rdi
shrq $3, %rcx # frame_length /= 8
cld
rep movsq
# Copy args into registers
movq 0xb0(%rsp), %rax
movapd 0xa0(%rsp), %xmm7
movapd 0x90(%rsp), %xmm6
movapd 0x80(%rsp), %xmm5
movapd 0x70(%rsp), %xmm4
movapd 0x60(%rsp), %xmm3
movapd 0x50(%rsp), %xmm2
movapd 0x40(%rsp), %xmm1
movapd 0x30(%rsp), %xmm0
movq 0x28(%rsp), %r9
movq 0x20(%rsp), %r8
movq 0x18(%rsp), %rcx
movq 0x10(%rsp), %rdx
movq 8(%rsp), %rsi
movq (%rsp), %rdi
addq $224, %rsp
movq -8(%rbp), %r10 # call objc_msgSend
callq *%r10
movq -16(%rbp), %rsi # return value
movq -24(%rbp), %rcx
cmpb $0x44, %cl # if (returnType[0] == 'D') // long double
je Llongdoubleret
# double
movapd %xmm1, 32(%rsi)
movapd %xmm0, 16(%rsi)
# int128
movq %rdx, 8(%rsi)
movq %rax, (%rsi)
jmp Ldone
Llongdoubleret:
fstpt (%rsi)
Ldone:
movq %rbp, %rsp # Epilogue
pop %rbp
ret
#endif