diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Runtime/common/compiler/vcc/stack-vcc.asm | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Runtime/common/compiler/vcc/stack-vcc.asm')
-rw-r--r-- | src/VBox/Runtime/common/compiler/vcc/stack-vcc.asm | 639 |
1 files changed, 639 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/compiler/vcc/stack-vcc.asm b/src/VBox/Runtime/common/compiler/vcc/stack-vcc.asm new file mode 100644 index 00000000..edfd5750 --- /dev/null +++ b/src/VBox/Runtime/common/compiler/vcc/stack-vcc.asm @@ -0,0 +1,639 @@ +; $Id: stack-vcc.asm $ +;; @file +; IPRT - Stack related Visual C++ support routines. +; + +; +; Copyright (C) 2022-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%if 0 ; YASM's builtin SEH64 support doesn't cope well with code alignment, so use our own. + %define RT_ASM_WITH_SEH64 +%else + %define RT_ASM_WITH_SEH64_ALT +%endif +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%ifdef RT_ARCH_AMD64 + %include "iprt/win/context-amd64.mac" +%else + %include "iprt/win/context-x86.mac" +%endif + + +;********************************************************************************************************************************* +;* Structures and Typedefs * +;********************************************************************************************************************************* + +;; Variable descriptor. +struc RTC_VAR_DESC_T + .offFrame resd 1 + .cbVar resd 1 + alignb RTCCPTR_CB + .pszName RTCCPTR_RES 1 +endstruc + +;; Frame descriptor. +struc RTC_FRAME_DESC_T + .cVars resd 1 + alignb RTCCPTR_CB + .paVars RTCCPTR_RES 1 ; Array of RTC_VAR_DESC_T. +endstruc + +;; An alloca allocation. +struc RTC_ALLOCA_ENTRY_T + .uGuard1 resd 1 + .pNext RTCCPTR_RES 1 ; Misaligned. +%if ARCH_BITS == 32 + .pNextPad resd 1 +%endif + .cb RTCCPTR_RES 1 ; Misaligned. +%if ARCH_BITS == 32 + .cbPad resd 1 +%endif + .auGuard2 resd 3 +endstruc + +%ifdef RT_ARCH_X86 + %define FASTCALL_NAME(a_Name, a_cbArgs) $@ %+ a_Name %+ @ %+ a_cbArgs +%else + %define FASTCALL_NAME(a_Name, a_cbArgs) NAME(a_Name) +%endif + + +;********************************************************************************************************************************* +;* Defined Constants And Macros * +;********************************************************************************************************************************* +%define VARIABLE_MARKER_PRE 0xcccccccc +%define VARIABLE_MARKER_POST 0xcccccccc + +%define ALLOCA_FILLER_BYTE 0xcc +%define ALLOCA_FILLER_32 0xcccccccc + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BEGINDATA +GLOBALNAME __security_cookie + dd 0xdeadbeef + dd 0x0c00ffe0 + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BEGINCODE +extern NAME(rtVccStackVarCorrupted) +extern NAME(rtVccSecurityCookieMismatch) +extern NAME(rtVccRangeCheckFailed) +%ifdef RT_ARCH_X86 +extern NAME(rtVccCheckEspFailed) +%endif + + + +;; +; This just initializes a global and calls _RTC_SetErrorFuncW to NULL, and +; since we don't have either of those we have nothing to do here. +BEGINPROC _RTC_InitBase + SEH64_END_PROLOGUE + ret +ENDPROC _RTC_InitBase + + +;; +; Nothing to do here. +BEGINPROC _RTC_Shutdown + SEH64_END_PROLOGUE + ret +ENDPROC _RTC_Shutdown + + + + +;; +; Checks stack variable markers. +; +; This seems to be a regular C function in the CRT, but x86 is conveniently +; using the fastcall convention which makes it very similar to amd64. +; +; We try make this as sleek as possible, leaving all the trouble for when we +; find a corrupted stack variable and need to call a C function to complain. +; +; @param pStackFrame The caller RSP/ESP. [RCX/ECX] +; @param pFrameDesc Frame descriptor. [RDX/EDX] +; +ALIGNCODE(64) +BEGINPROC_RAW FASTCALL_NAME(_RTC_CheckStackVars, 8) + push xBP + SEH64_PUSH_xBP + SEH64_END_PROLOGUE + + ; + ; Load the variable count into eax and check that it's not zero. + ; + mov eax, [xDX + RTC_FRAME_DESC_T.cVars] + test eax, eax + jz .return + + ; + ; Make edx/rdx point to the current variable and xBP be the frame pointer. + ; The latter frees up xCX for scratch use and incidentally make stack access + ; go via SS instead of DS (mostly irrlevant in 64-bit and 32-bit mode). + ; + mov xDX, [xDX + RTC_FRAME_DESC_T.paVars] + mov xBP, xCX + + ; + ; Loop thru the variables and check that their markers/fences haven't be + ; trampled over. + ; +.next_var: + ; Marker before the variable. +%if ARCH_BITS == 64 + movsxd rcx, dword [xDX + RTC_VAR_DESC_T.offFrame] +%else + mov xCX, dword [xDX + RTC_VAR_DESC_T.offFrame] +%endif + cmp dword [xBP + xCX - 4], VARIABLE_MARKER_PRE + jne rtVccCheckStackVarsFailed + + ; Marker after the variable. + add ecx, dword [xDX + RTC_VAR_DESC_T.cbVar] +%if ARCH_BITS == 64 + movsxd rcx, ecx +%endif + cmp dword [xBP + xCX], VARIABLE_MARKER_POST + jne rtVccCheckStackVarsFailed + + ; + ; Advance to the next variable. + ; +.advance: + add xDX, RTC_VAR_DESC_T_size + dec eax + jnz .next_var + + ; + ; Return. + ; +.return: + pop xBP + ret +ENDPROC_RAW FASTCALL_NAME(_RTC_CheckStackVars, 8) + +; +; Sub-function for _RTC_CheckStackVars, for purposes of SEH64 unwinding. +; +; Note! While we consider this fatal and will terminate the application, the +; compiler guys do not seem to think it is all that horrible and will +; report failure, maybe do an int3, and then try continue execution. +; +BEGINPROC_RAW rtVccCheckStackVarsFailed + nop ;push xBP - done in parent function + SEH64_PUSH_xBP + mov xCX, xBP ; xCX = caller pStackFrame. xBP free to become frame pointer. + mov xBP, xSP + SEH64_SET_FRAME_xBP 0 + pushf + push xAX + SEH64_PUSH_GREG xAX + sub xSP, CONTEXT_SIZE + 20h + SEH64_ALLOCATE_STACK (CONTEXT_SIZE + 20h) + SEH64_END_PROLOGUE + + lea xAX, [xBP - CONTEXT_SIZE] + call NAME(rtVccCaptureContext) + + ; rtVccStackVarCorrupted(uint8_t *pbFrame, RTC_VAR_DESC_T const *pVar, PCONTEXT) +.again: +%ifdef RT_ARCH_AMD64 + lea r8, [xBP - CONTEXT_SIZE] +%else + lea xAX, [xBP - CONTEXT_SIZE] + mov [xSP + 8], xAX + mov [xSP + 4], xDX + mov [xSP], xCX +%endif + call NAME(rtVccStackVarCorrupted) + jmp .again +ENDPROC_RAW rtVccCheckStackVarsFailed + + +%ifdef RT_ARCH_X86 +;; +; Called to follow up on a 'CMP ESP, EBP' kind of instruction, +; expected to report failure if the compare failed. +; +; Note! While we consider this fatal and will terminate the application, the +; compiler guys do not seem to think it is all that horrible and will +; report failure, maybe do an int3, and then try continue execution. +; +ALIGNCODE(16) +BEGINPROC _RTC_CheckEsp + jne .unexpected_esp + ret + +.unexpected_esp: + push xBP + SEH64_PUSH_xBP + mov xBP, xSP + SEH64_SET_FRAME_xBP 0 + pushf + push xAX + SEH64_PUSH_GREG xAX + sub xSP, CONTEXT_SIZE + 20h + SEH64_ALLOCATE_STACK (CONTEXT_SIZE + 20h) + SEH64_END_PROLOGUE + + lea xAX, [xBP - CONTEXT_SIZE] + call NAME(rtVccCaptureContext) + + ; rtVccCheckEspFailed(PCONTEXT) +.again: + lea xAX, [xBP - CONTEXT_SIZE] +%ifdef RT_ARCH_AMD64 + mov xCX, xAX +%else + mov [xSP], xAX +%endif + call NAME(rtVccCheckEspFailed) + jmp .again + +ENDPROC _RTC_CheckEsp +%endif ; RT_ARCH_X86 + + + +;; +; Initialize an alloca allocation list entry and add it to it. +; +; When this is call, presumably _RTC_CheckStackVars2 is used to verify the frame. +; +; @param pNewEntry Pointer to the new entry. [RCX/ECX] +; @param cbEntry The entry size, including header. [RDX/EDX] +; @param ppHead Pointer to the list head pointer. [R8/stack] +; +ALIGNCODE(64) +BEGINPROC_RAW FASTCALL_NAME(_RTC_AllocaHelper, 12) + SEH64_END_PROLOGUE + + ; + ; Check that input isn't NULL or the size isn't zero. + ; + test xCX, xCX + jz .return + test xDX, xDX + jz .return +%if ARCH_BITS == 64 + test r8, r8 +%else + cmp dword [xSP + xCB], 0 +%endif + jz .return + + ; + ; Memset the memory to ALLOCA_FILLER + ; +%if ARCH_BITS == 64 + mov r10, rdi ; save rdi + mov r11, rcx ; save pNewEntry +%else + push xDI + push xCX + cld ; paranoia +%endif + + mov al, ALLOCA_FILLER_BYTE + mov xDI, xCX ; entry pointer + mov xCX, xDX ; entry size (in bytes) + rep stosb + +%if ARCH_BITS == 64 + mov rdi, r10 +%else + pop xCX + pop xDI +%endif + + ; + ; Fill in the entry and link it as onto the head of the chain. + ; +%if ARCH_BITS == 64 + mov [r11 + RTC_ALLOCA_ENTRY_T.cb], xDX + mov xAX, [r8] + mov [r11 + RTC_ALLOCA_ENTRY_T.pNext], xAX + mov [r8], r11 +%else + mov [xCX + RTC_ALLOCA_ENTRY_T.cb], xDX + mov xAX, [xSP + xCB] ; ppHead + mov xDX, [xAX] + mov [xCX + RTC_ALLOCA_ENTRY_T.pNext], xDX + mov [xAX], xCX +%endif + +.return: +%if ARCH_BITS == 64 + ret +%else + ret 4 +%endif +ENDPROC_RAW FASTCALL_NAME(_RTC_AllocaHelper, 12) + + +;; +; Checks if the security cookie ok, complaining and terminating if it isn't. +; +ALIGNCODE(16) +BEGINPROC_RAW FASTCALL_NAME(__security_check_cookie, 4) + SEH64_END_PROLOGUE + cmp xCX, [NAME(__security_cookie) xWrtRIP] + jne rtVccSecurityCookieFailed + ;; amd64 version checks if the top 16 bits are zero, we skip that for now. + ret +ENDPROC_RAW FASTCALL_NAME(__security_check_cookie, 4) + +; Sub-function for __security_check_cookie, for purposes of SEH64 unwinding. +BEGINPROC_RAW rtVccSecurityCookieFailed + push xBP + SEH64_PUSH_xBP + mov xBP, xSP + SEH64_SET_FRAME_xBP 0 + pushf + push xAX + SEH64_PUSH_GREG xAX + sub xSP, CONTEXT_SIZE + 20h + SEH64_ALLOCATE_STACK (CONTEXT_SIZE + 20h) + SEH64_END_PROLOGUE + + lea xAX, [xBP - CONTEXT_SIZE] + call NAME(rtVccCaptureContext) + + ; rtVccSecurityCookieMismatch(uCookie, PCONTEXT) +.again: +%ifdef RT_ARCH_AMD64 + lea xDX, [xBP - CONTEXT_SIZE] +%else + lea xAX, [xBP - CONTEXT_SIZE] + mov [xSP + 4], xAX + mov [xSP], xCX +%endif + call NAME(rtVccSecurityCookieMismatch) + jmp .again +ENDPROC_RAW rtVccSecurityCookieFailed + + +;; +; Generated when using /GS - buffer security checks - so, fatal. +; +; Doesn't seem to take any parameters. +; +BEGINPROC __report_rangecheckfailure + push xBP + SEH64_PUSH_xBP + mov xBP, xSP + SEH64_SET_FRAME_xBP 0 + pushf + push xAX + SEH64_PUSH_GREG xAX + sub xSP, CONTEXT_SIZE + 20h + SEH64_ALLOCATE_STACK (CONTEXT_SIZE + 20h) + SEH64_END_PROLOGUE + + lea xAX, [xBP - CONTEXT_SIZE] + call NAME(rtVccCaptureContext) + + ; rtVccRangeCheckFailed(PCONTEXT) +.again: + lea xAX, [xBP - CONTEXT_SIZE] +%ifdef RT_ARCH_AMD64 + mov xCX, xAX +%else + mov [xSP], xAX +%endif + call NAME(rtVccRangeCheckFailed) + jmp .again +ENDPROC __report_rangecheckfailure + + +%if 0 ; Currently not treating these as completely fatal, just like the + ; compiler guys do. I'm sure the compiler only generate these calls + ; if it thinks a variable could be used uninitialized, however I'm not + ; really sure if there is a runtime check in addition or if it's an + ; action that always will be taken in a code path deemed to be bad. + ; Judging from the warnings, the compile time analysis leave lots to be + ; desired (lots of false positives). +;; +; Not entirely sure how and when the compiler generates these. +; extern "C" void __cdecl _RTC_UninitUse(const char *pszVar) +BEGINPROC _RTC_UninitUse + push xBP + SEH64_PUSH_xBP + mov xBP, xSP + SEH64_SET_FRAME_xBP 0 + pushf + push xAX + SEH64_PUSH_GREG xAX + sub xSP, CONTEXT_SIZE + 20h + SEH64_ALLOCATE_STACK (CONTEXT_SIZE + 20h) + SEH64_END_PROLOGUE + + lea xAX, [xBP - CONTEXT_SIZE] + call NAME(rtVccCaptureContext) + + extern NAME(rtVccUninitializedVariableUse) + ; rtVccUninitializedVariableUse(const char *pszVar, PCONTEXT) +.again: +%ifdef RT_ARCH_AMD64 + lea xDX, [xBP - CONTEXT_SIZE] +%else + lea xAX, [xBP - CONTEXT_SIZE] + mov [xSP + xCB], xAX + mov xAX, [xBP + xCB * 2] + mov [xSP], xAX +%endif + call NAME(rtVccUninitializedVariableUse) + jmp .again +ENDPROC _RTC_UninitUse +%endif + +;; +; Internal worker that creates a CONTEXT record for the caller. +; +; This expects a old-style stack frame setup, with xBP as base, such that: +; xBP+xCB*1: Return address -> Rip/Eip +; xBP+xCB*0: Return xBP -> Rbp/Ebp +; xBP-xCB*1: EFLAGS -> EFlags +; xBP-xCB*2: Saved xAX -> Rax/Eax +; +; @param pCtx xAX Pointer to a CONTEXT structure. +; +BEGINPROC rtVccCaptureContext + SEH64_END_PROLOGUE + +%ifdef RT_ARCH_AMD64 + mov [xAX + CONTEXT.Rcx], rcx + mov [xAX + CONTEXT.Rdx], rdx + mov rcx, [xBP - xCB*2] + mov [xAX + CONTEXT.Rax], ecx + mov [xAX + CONTEXT.Rbx], rbx + lea rcx, [xBP + xCB*2] + mov [xAX + CONTEXT.Rsp], rcx + mov rdx, [xBP] + mov [xAX + CONTEXT.Rbp], rdx + mov [xAX + CONTEXT.Rdi], rdi + mov [xAX + CONTEXT.Rsi], rsi + mov [xAX + CONTEXT.R8], r8 + mov [xAX + CONTEXT.R9], r9 + mov [xAX + CONTEXT.R10], r10 + mov [xAX + CONTEXT.R11], r11 + mov [xAX + CONTEXT.R12], r12 + mov [xAX + CONTEXT.R13], r13 + mov [xAX + CONTEXT.R14], r14 + mov [xAX + CONTEXT.R15], r15 + + mov rcx, [xBP + xCB*1] + mov [xAX + CONTEXT.Rip], rcx + mov edx, [xBP - xCB*1] + mov [xAX + CONTEXT.EFlags], edx + + mov dx, ss + mov [xAX + CONTEXT.SegSs], dx + mov cx, cs + mov [xAX + CONTEXT.SegCs], cx + mov dx, ds + mov [xAX + CONTEXT.SegDs], dx + mov cx, es + mov [xAX + CONTEXT.SegEs], cx + mov dx, fs + mov [xAX + CONTEXT.SegFs], dx + mov cx, gs + mov [xAX + CONTEXT.SegGs], cx + + mov dword [xAX + CONTEXT.ContextFlags], CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS + + ; Clear stuff we didn't set. + xor edx, edx + mov [xAX + CONTEXT.P1Home], rdx + mov [xAX + CONTEXT.P2Home], rdx + mov [xAX + CONTEXT.P3Home], rdx + mov [xAX + CONTEXT.P4Home], rdx + mov [xAX + CONTEXT.P5Home], rdx + mov [xAX + CONTEXT.P6Home], rdx + mov [xAX + CONTEXT.MxCsr], edx + mov [xAX + CONTEXT.Dr0], rdx + mov [xAX + CONTEXT.Dr1], rdx + mov [xAX + CONTEXT.Dr2], rdx + mov [xAX + CONTEXT.Dr3], rdx + mov [xAX + CONTEXT.Dr6], rdx + mov [xAX + CONTEXT.Dr7], rdx + + mov ecx, CONTEXT_size - CONTEXT.FltSave + AssertCompile(((CONTEXT_size - CONTEXT.FltSave) % 8) == 0) +.again: + mov [xAX + CONTEXT.FltSave + xCX - 8], rdx + sub ecx, 8 + jnz .again + + ; Restore edx and ecx. + mov rcx, [xAX + CONTEXT.Rcx] + mov rdx, [xAX + CONTEXT.Rdx] + +%elifdef RT_ARCH_X86 + + mov [xAX + CONTEXT.Ecx], ecx + mov [xAX + CONTEXT.Edx], edx + mov ecx, [xBP - xCB*2] + mov [xAX + CONTEXT.Eax], ecx + mov [xAX + CONTEXT.Ebx], ebx + lea ecx, [xBP + xCB*2] + mov [xAX + CONTEXT.Esp], ecx + mov edx, [xBP] + mov [xAX + CONTEXT.Ebp], edx + mov [xAX + CONTEXT.Edi], edi + mov [xAX + CONTEXT.Esi], esi + + mov ecx, [xBP + xCB] + mov [xAX + CONTEXT.Eip], ecx + mov ecx, [xBP - xCB*1] + mov [xAX + CONTEXT.EFlags], ecx + + mov dx, ss + movzx edx, dx + mov [xAX + CONTEXT.SegSs], edx + mov cx, cs + movzx ecx, cx + mov [xAX + CONTEXT.SegCs], ecx + mov dx, ds + movzx edx, dx + mov [xAX + CONTEXT.SegDs], edx + mov cx, es + movzx ecx, cx + mov [xAX + CONTEXT.SegEs], ecx + mov dx, fs + movzx edx, dx + mov [xAX + CONTEXT.SegFs], edx + mov cx, gs + movzx ecx, cx + mov [xAX + CONTEXT.SegGs], ecx + + mov dword [xAX + CONTEXT.ContextFlags], CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS + + ; Clear stuff we didn't set. + xor edx, edx + mov [xAX + CONTEXT.Dr0], edx + mov [xAX + CONTEXT.Dr1], edx + mov [xAX + CONTEXT.Dr2], edx + mov [xAX + CONTEXT.Dr3], edx + mov [xAX + CONTEXT.Dr6], edx + mov [xAX + CONTEXT.Dr7], edx + + mov ecx, CONTEXT_size - CONTEXT.ExtendedRegisters +.again: + mov [xAX + CONTEXT.ExtendedRegisters + xCX - 4], edx + sub ecx, 4 + jnz .again + + ; Restore edx and ecx. + mov ecx, [xAX + CONTEXT.Ecx] + mov edx, [xAX + CONTEXT.Edx] + +%else + %error RT_ARCH +%endif + ret +ENDPROC rtVccCaptureContext + |