/ 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