/** @file | |
IA-32/x64 PatchInstructionX86() | |
Copyright (C) 2018, Intel Corporation. All rights reserved.<BR> | |
Copyright (C) 2018, Red Hat, Inc. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "BaseLibInternals.h" | |
/** | |
Patch the immediate operand of an IA32 or X64 instruction such that the byte, | |
word, dword or qword operand is encoded at the end of the instruction's | |
binary representation. | |
This function should be used to update object code that was compiled with | |
NASM from assembly source code. Example: | |
NASM source code: | |
mov eax, strict dword 0 ; the imm32 zero operand will be patched | |
ASM_PFX(gPatchCr3): | |
mov cr3, eax | |
C source code: | |
X86_ASSEMBLY_PATCH_LABEL gPatchCr3; | |
PatchInstructionX86 (gPatchCr3, AsmReadCr3 (), 4); | |
@param[out] InstructionEnd Pointer right past the instruction to patch. The | |
immediate operand to patch is expected to | |
comprise the trailing bytes of the instruction. | |
If InstructionEnd is closer to address 0 than | |
ValueSize permits, then ASSERT(). | |
@param[in] PatchValue The constant to write to the immediate operand. | |
The caller is responsible for ensuring that | |
PatchValue can be represented in the byte, word, | |
dword or qword operand (as indicated through | |
ValueSize); otherwise ASSERT(). | |
@param[in] ValueSize The size of the operand in bytes; must be 1, 2, | |
4, or 8. ASSERT() otherwise. | |
**/ | |
VOID | |
EFIAPI | |
PatchInstructionX86 ( | |
OUT X86_ASSEMBLY_PATCH_LABEL *InstructionEnd, | |
IN UINT64 PatchValue, | |
IN UINTN ValueSize | |
) | |
{ | |
// | |
// The equality ((UINTN)InstructionEnd == ValueSize) would assume a zero-size | |
// instruction at address 0; forbid it. | |
// | |
ASSERT ((UINTN)InstructionEnd > ValueSize); | |
switch (ValueSize) { | |
case 1: | |
ASSERT (PatchValue <= MAX_UINT8); | |
*((UINT8 *)(UINTN)InstructionEnd - 1) = (UINT8)PatchValue; | |
break; | |
case 2: | |
ASSERT (PatchValue <= MAX_UINT16); | |
WriteUnaligned16 ((UINT16 *)(UINTN)InstructionEnd - 1, (UINT16)PatchValue); | |
break; | |
case 4: | |
ASSERT (PatchValue <= MAX_UINT32); | |
WriteUnaligned32 ((UINT32 *)(UINTN)InstructionEnd - 1, (UINT32)PatchValue); | |
break; | |
case 8: | |
WriteUnaligned64 ((UINT64 *)(UINTN)InstructionEnd - 1, PatchValue); | |
break; | |
default: | |
ASSERT (FALSE); | |
} | |
} |