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
|
; 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.
; ==++==
;
;
; ==--==
; ***********************************************************************
; File: TlsGetters.asm, see history in jithelp.asm
;
; Notes: These TlsGetters (GetAppDomain(), GetThread()) are implemented
; in a generic fashion, but might be patched at runtime to contain
; a much faster implementation which goes straight to the TLS for
; the Thread* or AppDomain*.
;
; Note that the macro takes special care to not have these become
; non-unwindable after the patching has overwritten the prologue of
; the generic getter.
; ***********************************************************************
include AsmMacros.inc
include asmconstants.inc
; Min amount of stack space that a nested function should allocate.
MIN_SIZE equ 28h
; These generic TLS getters are used for GetThread() and GetAppDomain(), they do a little
; extra work to ensure that certain registers are preserved, those include the following
; volatile registers
;
; rcx
; rdx
; r8
; r9
; r10
; r11
;
; The return value is in rax as usual
;
; They DO NOT save scratch flowing point registers, if you need those you need to save them.
ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
GetThreadGenericFullCheck equ ?GetThreadGenericFullCheck@@YAPEAVThread@@XZ
extern GetThreadGenericFullCheck:proc
endif ; ENABLE_GET_THREAD_GENERIC_FULL_CHECK
; Creates a generic TLS getter using the value from TLS slot gTLSIndex. Set GenerateGetThread
; when using this macro to generate GetThread, as that will cause special code to be generated which
; enables additional debug-only checking, such as enforcement of EE_THREAD_NOT_REQUIRED contracts
GenerateOptimizedTLSGetter macro name, GenerateGetThread
extern g&name&TLSIndex:dword
extern __imp_TlsGetValue:qword
SIZEOF_PUSHED_ARGS equ 10h
NESTED_ENTRY Get&name&Generic, _TEXT
push_vol_reg r10
push_vol_reg r11
alloc_stack MIN_SIZE
; save argument registers in shadow space
save_reg_postrsp rcx, MIN_SIZE + 8h + SIZEOF_PUSHED_ARGS
save_reg_postrsp rdx, MIN_SIZE + 10h + SIZEOF_PUSHED_ARGS
save_reg_postrsp r8, MIN_SIZE + 18h + SIZEOF_PUSHED_ARGS
save_reg_postrsp r9, MIN_SIZE + 20h + SIZEOF_PUSHED_ARGS
END_PROLOGUE
ifdef _DEBUG
cmp dword ptr [g&name&TLSIndex], -1
jnz @F
int 3
@@:
endif ; _DEBUG
CALL_GET_THREAD_GENERIC_FULL_CHECK=0
ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
if GenerateGetThread
; Generating the GetThread() tlsgetter, and GetThreadGenericFullCheck is
; defined in C (in threads.cpp). So we'll want to delegate directly to
; GetThreadGenericFullCheck, which may choose to do additional checking, such
; as enforcing EE_THREAD_NOT_REQUIRED contracts
CALL_GET_THREAD_GENERIC_FULL_CHECK=1
endif ; GenerateGetThread
endif ; ENABLE_GET_THREAD_GENERIC_FULL_CHECK
if CALL_GET_THREAD_GENERIC_FULL_CHECK
call GetThreadGenericFullCheck
else
; Not generating the GetThread() tlsgetter (or there is no GetThreadGenericFullCheck
; to call), so do nothing special--just look up the value stored at TLS slot gTLSIndex
mov ecx, [g&name&TLSIndex]
call [__imp_TlsGetValue]
endif
; restore arguments from shadow space
mov rcx, [rsp + MIN_SIZE + 8h + SIZEOF_PUSHED_ARGS]
mov rdx, [rsp + MIN_SIZE + 10h + SIZEOF_PUSHED_ARGS]
mov r8, [rsp + MIN_SIZE + 18h + SIZEOF_PUSHED_ARGS]
mov r9, [rsp + MIN_SIZE + 20h + SIZEOF_PUSHED_ARGS]
; epilog
add rsp, MIN_SIZE
pop r11
pop r10
ret
NESTED_END Get&name&Generic, _TEXT
endm
GenerateOptimizedTLSGetter Thread, 1
GenerateOptimizedTLSGetter AppDomain, 0
end
|