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
|
;; Licensed to the .NET Foundation under one or more agreements.
;; The .NET Foundation licenses this file to you under the MIT license.
;; See the LICENSE file in the project root for more information.
#include "kxarm.h"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DATA SECTIONS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DATAAREA
g_vtableResolveCallback DCD 0 ; The vtableresolve method
EXPORT g_vtableResolveCallback
g_universalTransition DCD 0 ; The address of Redhawk's UniversalTransition thunk
#define VTableThunkSize 0x20
;; TODO - do something similar to Redhawk's asmoffsets to compute the value at compile time
#define EETypeVTableOffset 0x14
#define PointerSize 4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ConstrainedCall Support Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TEXTAREA
;;
;; Note: The "__jmpstub__" prefix is used to indicate to debugger
;; that it must step-through this stub when it encounters it while
;; stepping.
;;
;; Returns the size of the pre-generated thunks
;; int VTableResolver_Init(IntPtr *__jmpstub__VTableResolverSlot0,
;; IntPtr vtableResolveCallback,
;; IntPtr universalTransition,
;; int *slotCount)
;;
LEAF_ENTRY VTableResolver_Init
ldr r12, __jmpstub__VTableSlot000
add r12, r12, 1 ; Add thumb bit
str r12, [r0]
ldr r12, =g_vtableResolveCallback
str r1, [r12]
ldr r12, =g_universalTransition
str r2, [r12]
mov r12, 100 ; This file defines 100 slot helpers
str r12, [r3]
mov r0, VTableThunkSize ; Each thunk is VTableThunkSize in bytes
bx lr
LEAF_END VTableResolver_Init
;; void* VTableResolver_GetCommonCallingStub()
;; - Get the address of the common calling stub
LEAF_ENTRY VTableResolver_GetCommonCallingStub
ldr r0, __jmpstub__VTableResolver_CommonCallingStub
bx lr
LEAF_END VTableResolver_GetCommonCallingStub
;;
;; __jmpstub__VTableResolver_CommonCallingStub(?)
;; Used when we dynamically need a VTableResolver not pre-generated
;;
;; sp-4 contains a pointer to a VTableResolverStruct
;; struct VTableResolverStruct
;; {
;; int offsetFromStartOfEETypePtr;
;; IntPtr VTableThunkAddress;
;; };
;;
LEAF_ENTRY __jmpstub__VTableResolver_CommonCallingStub
;; Custom calling convention:
;; red zone has pointer to the VTableResolverStruct
;; Copy red zone value into r12 so that the PROLOG_PUSH doesn't destroy it
PROLOG_NOP ldr r12, [sp, #-4]
PROLOG_PUSH {r3}
PROLOG_PUSH {r1-r2}
ldr r2, [r0]
;; r2 is the EEType pointer add the VTableOffset + slot_number * pointer size to get the vtable entry
;; compare the that value to the address of the thunk being executed and if the values are equal then
;; call to the resolver otherwise call the method
ldr r1, [r12]
;; r1 is the offset from start of EEType to interesting slot
ldr r3, [r2,r1]
;; r3 is now the function pointer in the vtable
ldr r2,[r12,#4]
;; is now the address of the function pointer that serves as the entry point for this particular instantiation
;; of __jmpstub__VTableResolver_CommonCallingStub
cmp r2,r3
beq __jmpstub__JumpToVTableResolver
mov r12,r3 ; Move the target function pointer to r12
EPILOG_POP {r1,r2}
EPILOG_POP {r3}
EPILOG_BRANCH_REG r12
LEAF_END __jmpstub__VTableResolver_CommonCallingStub
;; stub for dispatch will come in with r1 set to EETypeVTableOffset + ($slot_number * PointerSize),
;; and r1, r2 and r3 of the function we really want to call pushed on the stack
LEAF_ENTRY __jmpstub__JumpToVTableResolver
mov r3, r1
POP {r1,r2}
str r3, [sp, #-4] ; Store slot number into red zone at appropriate spot
POP {r3}
ldr r12, =g_vtableResolveCallback
ldr r12, [r12]
str r12, [sp, #-4] ; Store vtable resolve callback into red zone
ldr r12, =g_universalTransition
ldr r12, [r12]
bx r12
LEAF_END __jmpstub__VTableResolver_Init
MACRO
VTableThunkDecl $name, $slot_number
ALIGN 16 ; The alignment here forces the thunks to be the same size which gives all of the macros the same size and allows us to index
LEAF_ENTRY __jmpstub__$name
;; rcx is the this pointer to the call being made
PUSH {r3}
PUSH {r1,r2} ; Push r1,r2
ldr r2, [r0]
;; r2 is the EEType pointer add the VTableOffset + slot_number * pointer size to get the vtable entry
;; compare the that value to the address of the thunk being executed and if the values are equal then
;; call to the resolver otherwise call the method
mov r1, EETypeVTableOffset + ($slot_number * PointerSize)
ldr r3, [r2,r1]
; r3 is now the function pointer in the vtable
ldr r2,=__jmpstub__$name
cmp r2,r3
beq JumpVTableResolver$name
mov r12,r3 ; Move the target function pointer to r12 before popping r2 and r3. We used r3 instead of r12 here so that
; we could use the 2 byte thumb instructions and the whole thunk could fit in less than 32 bytes
POP {r1,r2,r3}
bx r12
JumpVTableResolver$name
b __jmpstub__JumpToVTableResolver
LEAF_END __jmpstub__$name
MEND
MACRO
VTableThunkDeclTen $slotnumberDecimal
VTableThunkDecl VTableSlot$slotnumberDecimal0,$slotnumberDecimal0
VTableThunkDecl VTableSlot$slotnumberDecimal1,$slotnumberDecimal1
VTableThunkDecl VTableSlot$slotnumberDecimal2,$slotnumberDecimal2
VTableThunkDecl VTableSlot$slotnumberDecimal3,$slotnumberDecimal3
VTableThunkDecl VTableSlot$slotnumberDecimal4,$slotnumberDecimal4
VTableThunkDecl VTableSlot$slotnumberDecimal5,$slotnumberDecimal5
VTableThunkDecl VTableSlot$slotnumberDecimal6,$slotnumberDecimal6
VTableThunkDecl VTableSlot$slotnumberDecimal7,$slotnumberDecimal7
VTableThunkDecl VTableSlot$slotnumberDecimal8,$slotnumberDecimal8
VTableThunkDecl VTableSlot$slotnumberDecimal9,$slotnumberDecimal9
MEND
MACRO
VTableThunkDeclHundred $slotnumberPerHundred
VTableThunkDeclTen $slotnumberPerHundred0
VTableThunkDeclTen $slotnumberPerHundred1
VTableThunkDeclTen $slotnumberPerHundred2
VTableThunkDeclTen $slotnumberPerHundred3
VTableThunkDeclTen $slotnumberPerHundred4
VTableThunkDeclTen $slotnumberPerHundred5
VTableThunkDeclTen $slotnumberPerHundred6
VTableThunkDeclTen $slotnumberPerHundred7
VTableThunkDeclTen $slotnumberPerHundred8
VTableThunkDeclTen $slotnumberPerHundred9
MEND
VTableThunkDeclHundred 0
END
|