/ NSInvoke-x86.S
NSInvoke-x86.S
1 2 .text 3 .align 4, 0x90 4 .globl ___invoke__ 5 ___invoke__: 6 7 # void __invoke__(void (*msgSend)(...), 8 # void *retdata, 9 # marg_list args, 10 # size_t frame_length, 11 # const char *return_type) 12 13 #ifdef __i386__ 14 15 # Save retdata, scratch register, and return address. 16 push %ebp # Prologue 17 mov %esp, %ebp 18 push %edi 19 push %esi 20 push %edx 21 push %ebx 22 23 mov 12+8(%ebp), %eax #$eax = frame_length 24 mov 8+8(%ebp), %edx #$edx = args 25 26 mov %esp, %ebx 27 subl %eax, %esp #push the stack down 28 andl $-16, %esp #and align 29 30 Lpush: 31 movl -4(%eax,%edx), %edi 32 movl %edi, -4(%esp,%eax) 33 sub $4, %eax 34 test %eax, %eax 35 jne Lpush 36 37 mov 0+8(%ebp), %edi #$edi = msgSend 38 calll *%edi 39 40 mov 4+8(%ebp), %esi #$esi = retdata 41 42 mov %eax, (%esi) # copy the result (probably) into *retdata 43 44 #next, check to see if we need to put something else (ie something from 45 #the x87 registers or a 64-bit value) into *retdata instead. 46 47 mov 8+16(%ebp), %eax #$eax == return_type 48 mov (%eax), %al 49 cmpb $0x71, %al # if (returnType[0] == 'q') // int64_t 50 je Lsixtyfourret 51 cmpb $0x51, %al # if (returnType[0] == 'Q') // uint64_t 52 je Lsixtyfourret 53 cmpb $0x44, %al # if (returnType[0] == 'D') // long double 54 je Llongdoubleret 55 cmpb $0x64, %al # if (returnType[0] == 'd') // double 56 je Ldoubleret 57 cmpb $0x66, %al # if (returnType[0] == 'f') // float 58 jne Ldone 59 fstps (%esi) # this is how to get things out of x87. 60 # fstp pops and stores a certain length (determined by the suffix - 61 # s for float, l for double, t for long double - just go with it) 62 # in the location given (in this case *$esi) 63 jmp Ldone #then jump to to cleanup and return 64 Lsixtyfourret: 65 # just store edx too 66 mov %edx, 4(%esi) 67 jmp Ldone 68 Ldoubleret: 69 fstpl (%esi) 70 jmp Ldone 71 Llongdoubleret: 72 fstpt (%esi) 73 74 Ldone: 75 mov %ebx, %esp # restore stack! 76 pop %ebx 77 pop %edx 78 pop %esi 79 pop %edi 80 mov %ebp, %esp # Epilogue 81 pop %ebp 82 ret 83 84 #else // Now the x86-64 version 85 86 .cfi_startproc 87 .cfi_personality 155, ___objc_personality_v0 88 push %rbp # Prologue 89 .cfi_def_cfa_offset 16 90 .cfi_offset %rbp, -16 91 movq %rsp, %rbp 92 .cfi_def_cfa_register rbp 93 push %rdi 94 .cfi_offset %rdi, -24 95 push %rsi 96 .cfi_offset %rsi, -32 97 push %r8 98 .cfi_offset %r8, -40 99 movq %rdx, %rsi 100 101 subq %rcx, %rsp # Push the stack down 102 andq $-16, %rsp #and align 103 104 # Shift stack contents (frame_length/8) times, 105 # 8 bytes at a time 106 # TODO: More efficient than the Lpush loop 107 # in i386 assembly above 108 movq %rsp, %rdi 109 shrq $3, %rcx # frame_length /= 8 110 cld 111 rep movsq 112 113 # Copy args into registers 114 movq 0xb0(%rsp), %rax 115 movapd 0xa0(%rsp), %xmm7 116 movapd 0x90(%rsp), %xmm6 117 movapd 0x80(%rsp), %xmm5 118 movapd 0x70(%rsp), %xmm4 119 movapd 0x60(%rsp), %xmm3 120 movapd 0x50(%rsp), %xmm2 121 movapd 0x40(%rsp), %xmm1 122 movapd 0x30(%rsp), %xmm0 123 124 movq 0x28(%rsp), %r9 125 movq 0x20(%rsp), %r8 126 movq 0x18(%rsp), %rcx 127 movq 0x10(%rsp), %rdx 128 movq 8(%rsp), %rsi 129 movq (%rsp), %rdi 130 131 addq $224, %rsp 132 movq -8(%rbp), %r10 # call objc_msgSend 133 callq *%r10 134 135 movq -16(%rbp), %rsi # return value 136 movq -24(%rbp), %rcx 137 cmpb $0x44, %cl # if (returnType[0] == 'D') // long double 138 je Llongdoubleret 139 140 # double 141 movapd %xmm1, 32(%rsi) 142 movapd %xmm0, 16(%rsi) 143 144 # int128 145 movq %rdx, 8(%rsi) 146 movq %rax, (%rsi) 147 148 jmp Ldone 149 Llongdoubleret: 150 fstpt (%rsi) 151 Ldone: 152 movq %rbp, %rsp # Epilogue 153 pop %rbp 154 // .cfi_def_cfa rsp, 8 155 ret 156 .cfi_endproc 157 #endif 158 159