OLD | NEW |
(Empty) | |
| 1 ; Copyright 2015 The Crashpad Authors. All rights reserved. |
| 2 ; |
| 3 ; Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 ; you may not use this file except in compliance with the License. |
| 5 ; You may obtain a copy of the License at |
| 6 ; |
| 7 ; http://www.apache.org/licenses/LICENSE-2.0 |
| 8 ; |
| 9 ; Unless required by applicable law or agreed to in writing, software |
| 10 ; distributed under the License is distributed on an "AS IS" BASIS, |
| 11 ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 ; See the License for the specific language governing permissions and |
| 13 ; limitations under the License. |
| 14 |
| 15 ; Detect ml64 assembling for x86_64 by checking for rax. |
| 16 ifdef rax |
| 17 _M_X64 equ 1 |
| 18 else |
| 19 _M_IX86 equ 1 |
| 20 endif |
| 21 |
| 22 ifdef _M_IX86 |
| 23 .586 |
| 24 .XMM |
| 25 .model flat |
| 26 endif |
| 27 |
| 28 offsetof macro structure, field |
| 29 exitm <structure.&field> |
| 30 endm |
| 31 |
| 32 ; The CONTEXT structure definitions that follow are based on those in <winnt.h>. |
| 33 ; Field names are prefixed (as in c_Rax) to avoid colliding with the predefined |
| 34 ; register names (such as Rax). |
| 35 |
| 36 ifdef _M_IX86 |
| 37 |
| 38 CONTEXT_i386 equ 10000h |
| 39 CONTEXT_CONTROL equ CONTEXT_i386 or 1h |
| 40 CONTEXT_INTEGER equ CONTEXT_i386 or 2h |
| 41 CONTEXT_SEGMENTS equ CONTEXT_i386 or 4h |
| 42 CONTEXT_FLOATING_POINT equ CONTEXT_i386 or 8h |
| 43 CONTEXT_DEBUG_REGISTERS equ CONTEXT_i386 or 10h |
| 44 CONTEXT_EXTENDED_REGISTERS equ CONTEXT_i386 or 20h |
| 45 CONTEXT_XSTATE equ CONTEXT_i386 or 40h |
| 46 |
| 47 MAXIMUM_SUPPORTED_EXTENSION equ 512 |
| 48 |
| 49 CONTEXT struct |
| 50 c_ContextFlags dword ? |
| 51 |
| 52 c_Dr0 dword ? |
| 53 c_Dr1 dword ? |
| 54 c_Dr2 dword ? |
| 55 c_Dr3 dword ? |
| 56 c_Dr6 dword ? |
| 57 c_Dr7 dword ? |
| 58 |
| 59 struct c_FloatSave |
| 60 f_ControlWord dword ? |
| 61 f_StatusWord dword ? |
| 62 f_TagWord dword ? |
| 63 f_ErrorOffset dword ? |
| 64 f_ErrorSelector dword ? |
| 65 f_DataOffset dword ? |
| 66 f_DataSelector dword ? |
| 67 f_RegisterArea byte 80 dup(?) |
| 68 |
| 69 union |
| 70 f_Spare0 dword ? ; As in FLOATING_SAVE_AREA. |
| 71 f_Cr0NpxState dword ? ; As in WOW64_FLOATING_SAVE_AREA. |
| 72 ends |
| 73 ends |
| 74 |
| 75 c_SegGs dword ? |
| 76 c_SegFs dword ? |
| 77 c_SegEs dword ? |
| 78 c_SegDs dword ? |
| 79 |
| 80 c_Edi dword ? |
| 81 c_Esi dword ? |
| 82 c_Ebx dword ? |
| 83 c_Edx dword ? |
| 84 c_Ecx dword ? |
| 85 c_Eax dword ? |
| 86 |
| 87 c_Ebp dword ? |
| 88 |
| 89 c_Eip dword ? |
| 90 c_SegCs dword ? |
| 91 |
| 92 c_EFlags dword ? |
| 93 |
| 94 c_Esp dword ? |
| 95 c_SegSs dword ? |
| 96 |
| 97 c_ExtendedRegisters byte MAXIMUM_SUPPORTED_EXTENSION dup(?) |
| 98 CONTEXT ends |
| 99 |
| 100 elseifdef _M_X64 |
| 101 |
| 102 M128A struct 16 |
| 103 m_Low qword ? |
| 104 m_High qword ? |
| 105 M128A ends |
| 106 |
| 107 CONTEXT_AMD64 equ 100000h |
| 108 CONTEXT_CONTROL equ CONTEXT_AMD64 or 1h |
| 109 CONTEXT_INTEGER equ CONTEXT_AMD64 or 2h |
| 110 CONTEXT_SEGMENTS equ CONTEXT_AMD64 or 4h |
| 111 CONTEXT_FLOATING_POINT equ CONTEXT_AMD64 or 8h |
| 112 CONTEXT_DEBUG_REGISTERS equ CONTEXT_AMD64 or 10h |
| 113 CONTEXT_XSTATE equ CONTEXT_AMD64 or 40h |
| 114 |
| 115 CONTEXT struct 16 |
| 116 c_P1Home qword ? |
| 117 c_P2Home qword ? |
| 118 c_P3Home qword ? |
| 119 c_P4Home qword ? |
| 120 c_P5Home qword ? |
| 121 c_P6Home qword ? |
| 122 |
| 123 c_ContextFlags dword ? |
| 124 c_MxCsr dword ? |
| 125 |
| 126 c_SegCs word ? |
| 127 c_SegDs word ? |
| 128 c_SegEs word ? |
| 129 c_SegFs word ? |
| 130 c_SegGs word ? |
| 131 c_SegSs word ? |
| 132 |
| 133 c_EFlags dword ? |
| 134 |
| 135 c_Dr0 qword ? |
| 136 c_Dr1 qword ? |
| 137 c_Dr2 qword ? |
| 138 c_Dr3 qword ? |
| 139 c_Dr6 qword ? |
| 140 c_Dr7 qword ? |
| 141 |
| 142 c_Rax qword ? |
| 143 c_Rcx qword ? |
| 144 c_Rdx qword ? |
| 145 c_Rbx qword ? |
| 146 c_Rsp qword ? |
| 147 c_Rbp qword ? |
| 148 c_Rsi qword ? |
| 149 c_Rdi qword ? |
| 150 c_R8 qword ? |
| 151 c_R9 qword ? |
| 152 c_R10 qword ? |
| 153 c_R11 qword ? |
| 154 c_R12 qword ? |
| 155 c_R13 qword ? |
| 156 c_R14 qword ? |
| 157 c_R15 qword ? |
| 158 |
| 159 c_Rip qword ? |
| 160 |
| 161 union |
| 162 struct c_FltSave |
| 163 f_ControlWord word ? |
| 164 f_StatusWord word ? |
| 165 f_TagWord byte ? |
| 166 f_Reserved1 byte ? |
| 167 f_ErrorOpcode word ? |
| 168 f_ErrorOffset dword ? |
| 169 f_ErrorSelector word ? |
| 170 f_Reserved2 word ? |
| 171 f_DataOffset dword ? |
| 172 f_DataSelector word ? |
| 173 f_Reserved3 word ? |
| 174 f_MxCsr dword ? |
| 175 f_MxCsr_Mask dword ? |
| 176 f_FloatRegisters M128A 8 dup(<?>) |
| 177 f_XmmRegisters M128A 16 dup(<?>) |
| 178 f_Reserved4 byte 96 dup(?) |
| 179 ends |
| 180 struct |
| 181 fx_Header M128A 2 dup(<?>) |
| 182 fx_Legacy M128A 8 dup(<?>) |
| 183 fx_Xmm0 M128A <?> |
| 184 fx_Xmm1 M128A <?> |
| 185 fx_Xmm2 M128A <?> |
| 186 fx_Xmm3 M128A <?> |
| 187 fx_Xmm4 M128A <?> |
| 188 fx_Xmm5 M128A <?> |
| 189 fx_Xmm6 M128A <?> |
| 190 fx_Xmm7 M128A <?> |
| 191 fx_Xmm8 M128A <?> |
| 192 fx_Xmm9 M128A <?> |
| 193 fx_Xmm10 M128A <?> |
| 194 fx_Xmm11 M128A <?> |
| 195 fx_Xmm12 M128A <?> |
| 196 fx_Xmm13 M128A <?> |
| 197 fx_Xmm14 M128A <?> |
| 198 fx_Xmm15 M128A <?> |
| 199 ends |
| 200 ends |
| 201 |
| 202 c_VectorRegister M128A 26 dup(<?>) |
| 203 c_VectorControl qword ? |
| 204 |
| 205 c_DebugControl qword ? |
| 206 c_LastBranchToRip qword ? |
| 207 c_LastBranchFromRip qword ? |
| 208 c_LastExceptionToRip qword ? |
| 209 c_LastExceptionFromRip qword ? |
| 210 CONTEXT ends |
| 211 |
| 212 endif |
| 213 |
| 214 ; namespace crashpad { |
| 215 ; void CaptureContext(CONTEXT* context) |
| 216 ; } // namespace crashpad |
| 217 ifdef _M_IX86 |
| 218 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPAU_CONTEXT@@@Z |
| 219 elseifdef _M_X64 |
| 220 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z |
| 221 endif |
| 222 |
| 223 _TEXT segment |
| 224 public CAPTURECONTEXT_SYMBOL |
| 225 |
| 226 ifdef _M_IX86 |
| 227 |
| 228 CAPTURECONTEXT_SYMBOL proc |
| 229 |
| 230 push ebp |
| 231 mov ebp, esp |
| 232 |
| 233 ; pushfd first, because some instructions affect eflags. eflags will be in |
| 234 ; [ebp-4]. |
| 235 pushfd |
| 236 |
| 237 ; Save the original value of ebx, and use ebx to hold the CONTEXT* argument. |
| 238 ; The original value of ebx will be in [ebp-8]. |
| 239 push ebx |
| 240 mov ebx, [ebp+8] |
| 241 |
| 242 ; General-purpose registers whose values haven’t changed can be captured |
| 243 ; directly. |
| 244 mov [ebx.CONTEXT].c_Edi, edi |
| 245 mov [ebx.CONTEXT].c_Esi, esi |
| 246 mov [ebx.CONTEXT].c_Edx, edx |
| 247 mov [ebx.CONTEXT].c_Ecx, ecx |
| 248 mov [ebx.CONTEXT].c_Eax, eax |
| 249 |
| 250 ; Now that the original value of edx has been saved, it can be repurposed to |
| 251 ; hold other registers’ values. |
| 252 |
| 253 ; The original ebx was saved on the stack above. |
| 254 mov edx, dword ptr [ebp-8] |
| 255 mov [ebx.CONTEXT].c_Ebx, edx |
| 256 |
| 257 ; The original ebp was saved on the stack in this function’s prologue. |
| 258 mov edx, dword ptr [ebp] |
| 259 mov [ebx.CONTEXT].c_Ebp, edx |
| 260 |
| 261 ; eip can’t be accessed directly, but the return address saved on the stack |
| 262 ; by the call instruction that reached this function can be used. |
| 263 mov edx, dword ptr [ebp+4] |
| 264 mov [ebx.CONTEXT].c_Eip, edx |
| 265 |
| 266 ; The original eflags was saved on the stack above. |
| 267 mov edx, dword ptr [ebp-4] |
| 268 mov [ebx.CONTEXT].c_EFlags, edx |
| 269 |
| 270 ; esp was saved in ebp in this function’s prologue, but the caller’s esp is 8 |
| 271 ; more than this value: 4 for the original ebp saved on the stack in this |
| 272 ; function’s prologue, and 4 for the return address saved on the stack by the |
| 273 ; call instruction that reached this function. |
| 274 lea edx, [ebp+8] |
| 275 mov [ebx.CONTEXT].c_Esp, edx |
| 276 |
| 277 ; The segment registers are 16 bits wide, but CONTEXT declares them as |
| 278 ; unsigned 32-bit values, so zero the top half. |
| 279 xor edx, edx |
| 280 mov dx, gs |
| 281 mov [ebx.CONTEXT].c_SegGs, edx |
| 282 mov dx, fs |
| 283 mov [ebx.CONTEXT].c_SegFs, edx |
| 284 mov dx, es |
| 285 mov [ebx.CONTEXT].c_SegEs, edx |
| 286 mov dx, ds |
| 287 mov [ebx.CONTEXT].c_SegDs, edx |
| 288 mov dx, cs |
| 289 mov [ebx.CONTEXT].c_SegCs, edx |
| 290 mov dx, ss |
| 291 mov [ebx.CONTEXT].c_SegSs, edx |
| 292 |
| 293 ; Prepare for the string move that will populate the ExtendedRegisters area, |
| 294 ; or the string store that will zero it. |
| 295 cld |
| 296 |
| 297 ; Use cpuid 1 to check whether fxsave is supported. If it is, perform it |
| 298 ; before fnsave because fxsave is a less-destructive operation. |
| 299 mov esi, ebx |
| 300 mov eax, 1 |
| 301 cpuid |
| 302 mov ebx, esi |
| 303 |
| 304 test edx, 01000000 ; FXSR |
| 305 jnz $FXSave |
| 306 |
| 307 ; fxsave is not supported. Set ContextFlags to not include |
| 308 ; CONTEXT_EXTENDED_REGISTERS, and zero the ExtendedRegisters area. |
| 309 mov [ebx.CONTEXT].c_ContextFlags, CONTEXT_i386 or \ |
| 310 CONTEXT_CONTROL or \ |
| 311 CONTEXT_INTEGER or \ |
| 312 CONTEXT_SEGMENTS or \ |
| 313 CONTEXT_FLOATING_POINT |
| 314 lea edi, [ebx.CONTEXT].c_ExtendedRegisters |
| 315 xor eax, eax |
| 316 mov ecx, MAXIMUM_SUPPORTED_EXTENSION / sizeof(dword) ; 128 |
| 317 rep stosd |
| 318 jmp $FXSaveDone |
| 319 |
| 320 $FXSave: |
| 321 ; fxsave is supported. Set ContextFlags to include CONTEXT_EXTENDED_REGISTERS. |
| 322 mov [ebx.CONTEXT].c_ContextFlags, CONTEXT_i386 or \ |
| 323 CONTEXT_CONTROL or \ |
| 324 CONTEXT_INTEGER or \ |
| 325 CONTEXT_SEGMENTS or \ |
| 326 CONTEXT_FLOATING_POINT or \ |
| 327 CONTEXT_EXTENDED_REGISTERS |
| 328 |
| 329 ; fxsave requires a 16 byte-aligned destination memory area. Nothing |
| 330 ; guarantees the alignment of a CONTEXT structure, so create a temporary |
| 331 ; aligned fxsave destination on the stack. |
| 332 and esp, 0fffffff0h |
| 333 sub esp, MAXIMUM_SUPPORTED_EXTENSION |
| 334 |
| 335 ; Zero out the temporary fxsave area before performing the fxsave. Some of the |
| 336 ; fxsave area may not be written by fxsave, and some is definitely not written |
| 337 ; by fxsave. |
| 338 mov edi, esp |
| 339 xor eax, eax |
| 340 mov ecx, MAXIMUM_SUPPORTED_EXTENSION / sizeof(dword) ; 128 |
| 341 rep stosd |
| 342 |
| 343 fxsave [esp] |
| 344 |
| 345 ; Copy the temporary fxsave area into the CONTEXT structure. |
| 346 lea edi, [ebx.CONTEXT].c_ExtendedRegisters |
| 347 mov esi, esp |
| 348 mov ecx, MAXIMUM_SUPPORTED_EXTENSION / sizeof(dword) ; 128 |
| 349 rep movsd |
| 350 |
| 351 ; Free the stack space used for the temporary fxsave area. |
| 352 lea esp, [ebp-8] |
| 353 |
| 354 ; TODO(mark): AVX/xsave support. |
| 355 ; https://code.google.com/p/crashpad/issues/detail?id=58 |
| 356 |
| 357 $FXSaveDone: |
| 358 ; fnsave reinitializes the FPU with an implicit finit operation, so use frstor |
| 359 ; to restore the original state. |
| 360 fnsave [ebx.CONTEXT].c_FloatSave |
| 361 frstor [ebx.CONTEXT].c_FloatSave |
| 362 |
| 363 ; cr0 is inaccessible from user code, and this field would not be used anyway. |
| 364 mov [ebx.CONTEXT].c_FloatSave.f_Cr0NpxState, 0 |
| 365 |
| 366 ; The debug registers can’t be read from user code, so zero them out in the |
| 367 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are |
| 368 ; present. |
| 369 mov [ebx.CONTEXT].c_Dr0, 0 |
| 370 mov [ebx.CONTEXT].c_Dr1, 0 |
| 371 mov [ebx.CONTEXT].c_Dr2, 0 |
| 372 mov [ebx.CONTEXT].c_Dr3, 0 |
| 373 mov [ebx.CONTEXT].c_Dr6, 0 |
| 374 mov [ebx.CONTEXT].c_Dr7, 0 |
| 375 |
| 376 ; Clean up by restoring clobbered registers, even those considered volatile |
| 377 ; by the ABI, so that the captured context represents the state at this |
| 378 ; function’s exit. |
| 379 mov edi, [ebx.CONTEXT].c_Edi |
| 380 mov esi, [ebx.CONTEXT].c_Esi |
| 381 mov edx, [ebx.CONTEXT].c_Edx |
| 382 mov ecx, [ebx.CONTEXT].c_Ecx |
| 383 mov eax, [ebx.CONTEXT].c_Eax |
| 384 pop ebx |
| 385 popfd |
| 386 |
| 387 pop ebp |
| 388 |
| 389 ret |
| 390 |
| 391 CAPTURECONTEXT_SYMBOL endp |
| 392 |
| 393 elseifdef _M_X64 |
| 394 |
| 395 CAPTURECONTEXT_SYMBOL proc frame |
| 396 |
| 397 push rbp |
| 398 .pushreg rbp |
| 399 mov rbp, rsp |
| 400 .setframe rbp, 0 |
| 401 |
| 402 ; Note that 16-byte stack alignment is not maintained because this function |
| 403 ; does not call out to any other. |
| 404 |
| 405 ; pushfq first, because some instructions affect rflags. rflags will be in |
| 406 ; [rbp-8]. |
| 407 pushfq |
| 408 .allocstack 8 |
| 409 .endprolog |
| 410 |
| 411 mov [rcx.CONTEXT].c_ContextFlags, CONTEXT_AMD64 or \ |
| 412 CONTEXT_CONTROL or \ |
| 413 CONTEXT_INTEGER or \ |
| 414 CONTEXT_SEGMENTS or \ |
| 415 CONTEXT_FLOATING_POINT |
| 416 |
| 417 ; General-purpose registers whose values haven’t changed can be captured |
| 418 ; directly. |
| 419 mov [rcx.CONTEXT].c_Rax, rax |
| 420 mov [rcx.CONTEXT].c_Rdx, rdx |
| 421 mov [rcx.CONTEXT].c_Rbx, rbx |
| 422 mov [rcx.CONTEXT].c_Rsi, rsi |
| 423 mov [rcx.CONTEXT].c_Rdi, rdi |
| 424 mov [rcx.CONTEXT].c_R8, r8 |
| 425 mov [rcx.CONTEXT].c_R9, r9 |
| 426 mov [rcx.CONTEXT].c_R10, r10 |
| 427 mov [rcx.CONTEXT].c_R11, r11 |
| 428 mov [rcx.CONTEXT].c_R12, r12 |
| 429 mov [rcx.CONTEXT].c_R13, r13 |
| 430 mov [rcx.CONTEXT].c_R14, r14 |
| 431 mov [rcx.CONTEXT].c_R15, r15 |
| 432 |
| 433 ; Because of the calling convention, there’s no way to recover the value of |
| 434 ; the caller’s rcx as it existed prior to calling this function. This |
| 435 ; function captures a snapshot of the register state at its return, which |
| 436 ; involves rcx containing a pointer to its first argument. |
| 437 mov [rcx.CONTEXT].c_Rcx, rcx |
| 438 |
| 439 ; Now that the original value of rax has been saved, it can be repurposed to |
| 440 ; hold other registers’ values. |
| 441 |
| 442 ; Save mxcsr. This is duplicated in context->FltSave.MxCsr, saved by fxsave |
| 443 ; below. |
| 444 stmxcsr [rcx.CONTEXT].c_MxCsr |
| 445 |
| 446 ; Segment registers. |
| 447 mov [rcx.CONTEXT].c_SegCs, cs |
| 448 mov [rcx.CONTEXT].c_SegDs, ds |
| 449 mov [rcx.CONTEXT].c_SegEs, es |
| 450 mov [rcx.CONTEXT].c_SegFs, fs |
| 451 mov [rcx.CONTEXT].c_SegGs, gs |
| 452 mov [rcx.CONTEXT].c_SegSs, ss |
| 453 |
| 454 ; The original rflags was saved on the stack above. Note that the CONTEXT |
| 455 ; structure only stores eflags, the low 32 bits. The high 32 bits in rflags |
| 456 ; are reserved. |
| 457 mov rax, qword ptr [rbp-8] |
| 458 mov [rcx.CONTEXT].c_EFlags, eax |
| 459 |
| 460 ; rsp was saved in rbp in this function’s prologue, but the caller’s rsp is |
| 461 ; 16 more than this value: 8 for the original rbp saved on the stack in this |
| 462 ; function’s prologue, and 8 for the return address saved on the stack by the |
| 463 ; call instruction that reached this function. |
| 464 lea rax, [rbp+16] |
| 465 mov [rcx.CONTEXT].c_Rsp, rax |
| 466 |
| 467 ; The original rbp was saved on the stack in this function’s prologue. |
| 468 mov rax, qword ptr [rbp] |
| 469 mov [rcx.CONTEXT].c_Rbp, rax |
| 470 |
| 471 ; rip can’t be accessed directly, but the return address saved on the stack by |
| 472 ; the call instruction that reached this function can be used. |
| 473 mov rax, qword ptr [rbp+8] |
| 474 mov [rcx.CONTEXT].c_Rip, rax |
| 475 |
| 476 ; Zero out the fxsave area before performing the fxsave. Some of the fxsave |
| 477 ; area may not be written by fxsave, and some is definitely not written by |
| 478 ; fxsave. This also zeroes out the rest of the CONTEXT structure to its end, |
| 479 ; including the unused VectorRegister and VectorControl fields, and the debug |
| 480 ; control register fields. |
| 481 mov rbx, rcx |
| 482 cld |
| 483 lea rdi, [rcx.CONTEXT].c_FltSave |
| 484 xor rax, rax |
| 485 mov rcx, (sizeof(CONTEXT) - offsetof(CONTEXT, c_FltSave)) / \ |
| 486 sizeof(qword) ; 122 |
| 487 rep stosq |
| 488 mov rcx, rbx |
| 489 |
| 490 ; Save the floating point (including SSE) state. The CONTEXT structure is |
| 491 ; declared as 16-byte-aligned, which is correct for this operation. |
| 492 fxsave [rcx.CONTEXT].c_FltSave |
| 493 |
| 494 ; TODO(mark): AVX/xsave support. |
| 495 ; https://code.google.com/p/crashpad/issues/detail?id=58 |
| 496 |
| 497 ; The register parameter home address fields aren’t used, so zero them out. |
| 498 mov [rcx.CONTEXT].c_P1Home, 0 |
| 499 mov [rcx.CONTEXT].c_P2Home, 0 |
| 500 mov [rcx.CONTEXT].c_P3Home, 0 |
| 501 mov [rcx.CONTEXT].c_P4Home, 0 |
| 502 mov [rcx.CONTEXT].c_P5Home, 0 |
| 503 mov [rcx.CONTEXT].c_P6Home, 0 |
| 504 |
| 505 ; The debug registers can’t be read from user code, so zero them out in the |
| 506 ; CONTEXT structure. context->ContextFlags doesn’t indicate that they are |
| 507 ; present. |
| 508 mov [rcx.CONTEXT].c_Dr0, 0 |
| 509 mov [rcx.CONTEXT].c_Dr1, 0 |
| 510 mov [rcx.CONTEXT].c_Dr2, 0 |
| 511 mov [rcx.CONTEXT].c_Dr3, 0 |
| 512 mov [rcx.CONTEXT].c_Dr6, 0 |
| 513 mov [rcx.CONTEXT].c_Dr7, 0 |
| 514 |
| 515 ; Clean up by restoring clobbered registers, even those considered volatile by |
| 516 ; the ABI, so that the captured context represents the state at this |
| 517 ; function’s exit. |
| 518 mov rax, [rcx.CONTEXT].c_Rax |
| 519 mov rbx, [rcx.CONTEXT].c_Rbx |
| 520 mov rdi, [rcx.CONTEXT].c_Rdi |
| 521 popfq |
| 522 |
| 523 pop rbp |
| 524 |
| 525 ret |
| 526 |
| 527 CAPTURECONTEXT_SYMBOL endp |
| 528 |
| 529 endif |
| 530 |
| 531 _TEXT ends |
| 532 end |
OLD | NEW |