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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
|
// 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.
.intel_syntax noprefix
#include "unixasmmacros.inc"
#include "asmconstants.h"
#define real4 dword
#define real8 qword
//
// file: profile.cpp
// typedef struct _PROFILE_PLATFORM_SPECIFIC_DATA
// {
// FunctionID *functionId; // function ID comes in the r11 register
// void *rbp;
// void *probersp;
// void *ip;
// void *profiledRsp;
// UINT64 rax;
// LPVOID hiddenArg;
// UINT64 flt0;
// UINT64 flt1;
// UINT64 flt2;
// UINT64 flt3;
// UINT64 flt4;
// UINT64 flt5;
// UINT64 flt6;
// UINT64 flt7;
// UINT64 rdi;
// UINT64 rsi;
// UINT64 rdx;
// UINT64 rcx;
// UINT64 r8;
// UINT64 r9;
// UINT32 flags;
// } PROFILE_PLATFORM_SPECIFIC_DATA, *PPROFILE_PLATFORM_SPECIFIC_DATA;
//
.equ SIZEOF_PROFILE_PLATFORM_SPECIFIC_DATA, 0x8*22 + 0x8 // includes fudge to make FP_SPILL right
.equ SIZEOF_FP_ARG_SPILL, 0x10*2
.equ SIZEOF_STACK_FRAME, SIZEOF_PROFILE_PLATFORM_SPECIFIC_DATA + SIZEOF_FP_ARG_SPILL
.equ PROFILE_ENTER, 0x1
.equ PROFILE_LEAVE, 0x2
.equ PROFILE_TAILCALL, 0x4
// ***********************************************************
// NOTE:
//
// Register preservation scheme:
//
// Preserved:
// - all non-volatile registers
// - rax, rdx
// - xmm0, xmm1
//
// Not Preserved:
// - integer argument registers (rcx, rdx, r8, r9)
// - floating point argument registers (xmm1-3)
// - volatile integer registers (r10, r11)
// - volatile floating point registers (xmm4-5)
// - upper halves of ymm registers on AVX (which are volatile)
//
// ***********************************************************
// EXTERN_C void ProfileEnterNaked(FunctionIDOrClientID functionIDOrClientID, size_t profiledRsp);
// <NOTE>
//
// </NOTE>
NESTED_ENTRY ProfileEnterNaked, _TEXT, NoHandler
// Upon entry :
// r14 = clientInfo
// r15 = profiledRsp
push_nonvol_reg rax
lea rax, [rsp + 0x10] // caller rsp
mov r10, [rax - 0x8] // return address
push_argument_register rdx
alloc_stack SIZEOF_STACK_FRAME
// correctness of return value in structure doesn't matter for enter probe
// setup ProfilePlatformSpecificData structure
xor r11, r11 // nullify r11
mov [rsp + 0x0], r11 // r11 is null -- struct functionId field
save_reg_postrsp rbp, 0x8 // -- struct rbp field
mov [rsp + 0x10], rax // caller rsp -- struct probeRsp field
mov [rsp + 0x18], r10 // return address -- struct ip field
mov [rsp + 0x20], r15 // -- struct profiledRsp field
mov [rsp + 0x28], r11 // return value -- struct rax field
mov [rsp + 0x30], r11 // r11 is null -- struct hiddenArg field
movsd real8 ptr [rsp + 0x38], xmm0 // -- struct flt0 field
movsd real8 ptr [rsp + 0x40], xmm1 // -- struct flt1 field
movsd real8 ptr [rsp + 0x48], xmm2 // -- struct flt2 field
movsd real8 ptr [rsp + 0x50], xmm3 // -- struct flt3 field
movsd real8 ptr [rsp + 0x58], xmm4 // -- struct flt4 field
movsd real8 ptr [rsp + 0x60], xmm5 // -- struct flt5 field
movsd real8 ptr [rsp + 0x68], xmm6 // -- struct flt6 field
movsd real8 ptr [rsp + 0x70], xmm7 // -- struct flt7 field
mov [rsp + 0x78], rdi // -- struct rdi field
mov [rsp + 0x80], rsi // -- struct rsi field
mov [rsp + 0x88], rdx // -- struct rdx field
mov [rsp + 0x90], rcx // -- struct rcx field
mov [rsp + 0x98], r8 // -- struct r8 field
mov [rsp + 0xa0], r9 // -- struct r9 field
mov r10, 0x1 // PROFILE_ENTER
mov [rsp + 0xa8], r10d // -- struct flags field
// get aligned stack ptr (rsp + FRAME_SIZE) & (-16)
lea rax, [rsp + 0xb8]
and rax, -16
// we need to be able to restore the fp return register
// save fp return registers
movdqa [rax + 0x00], xmm0
movdqa [rax + 0x10], xmm1
END_PROLOGUE
// rdi already contains the clientInfo
mov rdi, r14
lea rsi, [rsp + 0x0]
call C_FUNC(ProfileEnter)
// restore fp return registers
lea rax, [rsp + 0xb8]
and rax, -16
movdqa xmm0, [rax + 0x00]
movdqa xmm1, [rax + 0x10]
// restore arg registers
mov rdi, [rsp + 0x78]
mov rsi, [rsp + 0x80]
mov rdx, [rsp + 0x88]
mov rcx, [rsp + 0x90]
mov r8, [rsp + 0x98]
mov r9, [rsp + 0xa0]
// begin epilogue
free_stack SIZEOF_STACK_FRAME
pop_argument_register rdx
pop_nonvol_reg rax
ret
NESTED_END ProfileEnterNaked, _TEXT
// EXTERN_C void ProfileLeaveNaked(FunctionIDOrClientID functionIDOrClientID, size_t profiledRsp);
// <NOTE>
//
// </NOTE>
NESTED_ENTRY ProfileLeaveNaked, _TEXT, NoHandler
// Upon entry :
// rdi = clientInfo
// rsi = profiledRsp
push_nonvol_reg rbx
lea rbx, [rsp + 0x10] // caller rsp
mov r10, [rbx - 0x8] // return address
// rdx should be saved here because it can be used for returning struct values
push_argument_register rdx
alloc_stack SIZEOF_STACK_FRAME
// correctness of argument registers in structure doesn't matter for leave probe
// setup ProfilePlatformSpecificData structure
xor r11, r11 // nullify r11
mov [rsp + 0x0], r11 // r11 is null -- struct functionId field
save_reg_postrsp rbp, 0x8 // -- struct rbp field
mov [rsp + 0x10], rbx // caller rsp -- struct probeRsp field
mov [rsp + 0x18], r10 // return address -- struct ip field
mov [rsp + 0x20], rsi // -- struct profiledRsp field
mov [rsp + 0x28], rax // return value -- struct rax field
mov [rsp + 0x30], r11 // r11 is null -- struct hiddenArg field
movsd real8 ptr [rsp + 0x38], xmm0 // -- struct flt0 field
movsd real8 ptr [rsp + 0x40], xmm1 // -- struct flt1 field
movsd real8 ptr [rsp + 0x48], xmm2 // -- struct flt2 field
movsd real8 ptr [rsp + 0x50], xmm3 // -- struct flt3 field
movsd real8 ptr [rsp + 0x58], xmm4 // -- struct flt4 field
movsd real8 ptr [rsp + 0x60], xmm5 // -- struct flt5 field
movsd real8 ptr [rsp + 0x68], xmm6 // -- struct flt6 field
movsd real8 ptr [rsp + 0x70], xmm7 // -- struct flt7 field
mov [rsp + 0x78], r11 // -- struct rdi field
mov [rsp + 0x80], r11 // -- struct rsi field
mov [rsp + 0x88], r11 // -- struct rdx field
mov [rsp + 0x90], r11 // -- struct rcx field
mov [rsp + 0x98], r11 // -- struct r8 field
mov [rsp + 0xa0], r11 // -- struct r9 field
mov r10, 0x2 // PROFILE_LEAVE
mov [rsp + 0xa8], r10d // flags -- struct flags field
// get aligned stack ptr (rsp + FRAME_SIZE) & (-16)
lea rax, [rsp + 0xb8]
and rax, -16
// we need to be able to restore the fp return register
// save fp return registers
movdqa [rax + 0x00], xmm0
movdqa [rax + 0x10], xmm1
END_PROLOGUE
// rdi already contains the clientInfo
lea rsi, [rsp + 0x0]
call C_FUNC(ProfileLeave)
// restore fp return registers
lea rax, [rsp + 0xb8]
and rax, -16
movdqa xmm0, [rax + 0x00]
movdqa xmm1, [rax + 0x10]
// restore int return register
mov rax, [rsp + 0x28]
// begin epilogue
free_stack SIZEOF_STACK_FRAME
pop_argument_register rdx
pop_nonvol_reg rbx
ret
NESTED_END ProfileLeaveNaked, _TEXT
// EXTERN_C void ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID, size_t profiledRsp);
// <NOTE>
//
// </NOTE>
NESTED_ENTRY ProfileTailcallNaked, _TEXT, NoHandler
// Upon entry :
// rdi = clientInfo
// rsi = profiledRsp
push_nonvol_reg rbx
lea rbx, [rsp + 0x10] // caller rsp
mov r10, [rbx - 0x8] // return address
// rdx should be saved here because it can be used for returning struct values
push_argument_register rdx
alloc_stack SIZEOF_STACK_FRAME
// correctness of argument registers in structure doesn't matter for tailcall probe
// setup ProfilePlatformSpecificData structure
xor r11, r11 // nullify r11
mov [rsp + 0x0], r11 // r11 is null -- struct functionId field
save_reg_postrsp rbp, 0x8 // -- struct rbp field
mov [rsp + 0x10], rbx // caller rsp -- struct probeRsp field
mov [rsp + 0x18], r10 // return address -- struct ip field
mov [rsp + 0x20], rsi // -- struct profiledRsp field
mov [rsp + 0x28], rax // return value -- struct rax field
mov [rsp + 0x30], r11 // r11 is null -- struct hiddenArg field
movsd real8 ptr [rsp + 0x38], xmm0 // -- struct flt0 field
movsd real8 ptr [rsp + 0x40], xmm1 // -- struct flt1 field
movsd real8 ptr [rsp + 0x48], xmm2 // -- struct flt2 field
movsd real8 ptr [rsp + 0x50], xmm3 // -- struct flt3 field
movsd real8 ptr [rsp + 0x58], xmm4 // -- struct flt4 field
movsd real8 ptr [rsp + 0x60], xmm5 // -- struct flt5 field
movsd real8 ptr [rsp + 0x68], xmm6 // -- struct flt6 field
movsd real8 ptr [rsp + 0x70], xmm7 // -- struct flt7 field
mov [rsp + 0x78], r11 // -- struct rdi field
mov [rsp + 0x80], r11 // -- struct rsi field
mov [rsp + 0x88], r11 // -- struct rdx field
mov [rsp + 0x90], r11 // -- struct rcx field
mov [rsp + 0x98], r11 // -- struct r8 field
mov [rsp + 0xa0], r11 // -- struct r9 field
mov r10, 0x2 // PROFILE_LEAVE
mov [rsp + 0xa8], r10d // flags -- struct flags field
// get aligned stack ptr (rsp + FRAME_SIZE) & (-16)
lea rax, [rsp + 0xc0]
and rax, -16
// we need to be able to restore the fp return register
// save fp return registers
movdqa [rax + 0x00], xmm0
movdqa [rax + 0x10], xmm1
END_PROLOGUE
// rdi already contains the clientInfo
lea rsi, [rsp + 0x0]
call C_FUNC(ProfileTailcall)
// restore fp return registers
lea rax, [rsp + 0xc0]
and rax, -16
movdqa xmm0, [rax + 0x00]
movdqa xmm1, [rax + 0x10]
// restore int return register
mov rax, [rsp + 0x28]
// begin epilogue
free_stack SIZEOF_STACK_FRAME
pop_argument_register rdx
pop_nonvol_reg rbx
ret
NESTED_END ProfileTailcallNaked, _TEXT
|