summaryrefslogtreecommitdiff
path: root/bridges/source/cpp_uno/msvc_win32_x86-64/codeSnippet.asm
blob: b1a4f73907fc6c928715f6f888093e8d6897f9a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
; -*- Mode: text; tab-width: 8; indent-tabs-mode: nil comment-column: 44; comment-start: ";; " comment-start-skip: ";; *" -*-

;; Version: MPL 1.1 / GPLv3+ / LGPLv3+
;;
;; The contents of this file are subject to the Mozilla Public License Version
;; 1.1 (the "License"); you may not use this file except in compliance with
;; the License or as specified alternatively below. You may obtain a copy of
;; the License at http://www.mozilla.org/MPL/
;;
;; Software distributed under the License is distributed on an "AS IS" basis,
;; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
;; for the specific language governing rights and limitations under the
;; License.
;;
;; The Initial Developer of the Original Code is
;;       Novell, Inc.
;; Portions created by the Initial Developer are Copyright (C) 2011
;; Novell, Inc. All Rights Reserved.
;;
;; Major Contributor(s):
;;       Tor Lillqvist <tml@iki.fi>
;; Portions created by Tor Lillqvist are Copyright (C) 2011 Tor Lillqvist. All Rights Reserved.
;;
;; For minor contributions see the git repository.
;;
;; Alternatively, the contents of this file may be used under the terms of
;; either the GNU General Public License Version 3 or later (the "GPLv3+"), or
;; the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
;; in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
;; instead of those above.

;; This is the template source code for the trampoline generated by
;; codeSnippet() in cpp2uno.cxx. codeSnippet() copies the code from
;; this function, modifying it as necessary in a few places. The
;; generated trampoline calls cpp_vtable_call() which then calls the
;; actual UNO function.

;; We keep this as a separate .asm file here so that it is easy to
;; modify, and we don't need to laborously enter machine code into
;; codeSnippet().

;; This is in a separate file for x86-64 as MSVC doesn't have in-line
;; assembly for x64.

;; Random web links and other documentation about low-level
;; implementation details for the C++/UNO bridge on x64 Windows kept
;; here:

;; Caolan's "Lazy Hackers Guide To Porting" is useful:
;; http://wiki.services.openoffice.org/wiki/Lazy_Hackers_Guide_To_Porting

;; As for details about the x64 Windows calling convention, register
;; usage, stack usage, exception handling etc, the official
;; documentation (?) on MSDN is a bit fragmented and split up into a
;; needlessly large number of short pages. But still:
;; http://msdn.microsoft.com/en-us/library/7kcdt6fy%28v=VS.90%29.aspx

;; Also see Raymond Chen's blog post:
;; http://blogs.msdn.com/b/oldnewthing/archive/2004/01/14/58579.aspx

;; This one is actually more readable: "Improving Automated Analysis
;; of Windows x64 Binaries": http://www.uninformed.org/?v=4&a=1

;; For exception handling and unwinding to work across the generated
;; functions (as I assume we want?), we would need call
;; RtlAddFunctionTable() (and RtlDeleteFunctionTable()). See Windows
;; SDK documentation.

;; Random interesting discussion threads:
;; http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/300bd6d3-9381-4d2d-8129-e48b392c05d8

;; Ken Johnson's blog http://www.nynaeve.net/ has much interesting
;; information, for instance:
;; http://www.nynaeve.net/?p=11

;; The code snippet generated is called from "normal" C++ code which
;; has no idea that it is calling dynamically generated code.

typelib_TypeClass_FLOAT equ 10
typelib_TypeClass_DOUBLE equ 11

extern cpp_vtable_call: proc

.code

;; Single instruction templates. For each register paramter, which can
;; be either in an integer or floating-point register, either of two
;; instruction sequences are used, either:
;;     mov qword ptr offset[rsp], reg
;;     nop
;; or:
;;     movsd qwort ptr offset[rsp], xmmreg
;;
;; The nop in the integer case is so that both are of equal length

fp_spill_templates:
public fp_spill_templates
    movsd qword ptr 32[rsp], xmm3
    movsd qword ptr 24[rsp], xmm2
    movsd qword ptr 16[rsp], xmm1
    movsd qword ptr 8[rsp], xmm0
fp_spill_templates_end:
public fp_spill_templates_end

;; The actual template function code here

trampoline_template proc

    ;; Spill our register parameters. In the x64 Windows calling
    ;; convention the caller always has stack space allocated
    ;; where the callee can spill register parameters.

    ;; The default is integer moves, that are replaced in the
    ;; generated code snippet with floating-point moves for
    ;; floating-point parameters.

    mov qword ptr 32[rsp], r9
    nop
    mov qword ptr 24[rsp], r8
    nop
    mov qword ptr 16[rsp], rdx
    nop
    mov qword ptr 8[rsp], rcx
    nop
trampoline_template_spill_end::
public trampoline_template_spill_end

    ;; Make stack frame. Re-align RSP at 16 bytes. We need just one
    ;; qword of stack for our own purposes: Where cpp_vtable_call()
    ;; will store the return value of the UNO callee. But we of course
    ;; must also allocate space for the functions we call (i.e., just
    ;; cpp_vtable_call()) to spill their register parameters.

    sub rsp, 40
trampoline_template_prolog_end::
public trampoline_template_prolog_end

    ;; Call cpp_vtable_call() with 3 parameters:

    ;; 1 (rcx): nFunctionIndex
    ;; 2 (rdx): nVtableOffset
    ;; 3 (r8): pointer to where to store return value, followed by our
    ;; return address (uninteresting to cpp_vtable_call()), followed
    ;; by our spilled register parameters, as stored above, followed
    ;; by the rest of our parameters, if any.

    mov rcx, 12345467890abcdeh              ;; nFunctionIndex, actual value generated from
                                            ;;  parameter to codeSnippet()
trampoline_template_function_index::
public trampoline_template_function_index

    mov rdx, 12345467890abcdeh               ;; nVtableOffset, ditto
trampoline_template_vtable_offset::
public trampoline_template_vtable_offset

    lea r8, 32[rsp]                         ;; Where cpp_vtable_call() will store the return value

    call cpp_vtable_call                    ;; Actual address generated by codeSnippet()

    ;; cpp_vtable_call() returns the typelib_TypeClass type of the
    ;; return value of the called UNO function

    cmp rax, typelib_TypeClass_FLOAT
    je Lfloat

    cmp rax, typelib_TypeClass_DOUBLE
    je Lfloat

    mov rax, qword ptr 32[rsp]
    jmp Lepilogue

Lfloat:
    movsd xmm0, qword ptr 32[rsp]

Lepilogue:
    add rsp, 40
    ret
trampoline_template_end::
public trampoline_template_end

trampoline_template endp

end

; vim:set shiftwidth=4 softtabstop=4 expandtab: