Table of Contents

Class InsertionPatch

Namespace
SkyrimForge
Assembly
SkyrimForge.dll

Inserts machine code at an address. The expected bytes become a jump to allocated memory, which runs the code and the displaced instructions, then jumps back.

public sealed class InsertionPatch : CodePatch
Inheritance
InsertionPatch
Inherited Members

Remarks

The allocated memory contains the displaced instructions, the code before or after them as Placement states, and a jump to the end of the expected bytes. The expected bytes past the displaced ones are not run, and the expected bytes past the jump become nops. The expected bytes and the displaced bytes each end on an instruction, and no branch elsewhere in the function lands inside the expected bytes. Apply(params ReadOnlySpan<CodePatch>) detects a direct branch in the function part the exception directory lists, not a branch through a jump table or a register.

The address of the code is not known when it is written, so the code is position-independent: no RIP-relative operand or relative branch in it refers outside it. It runs with the registers and stack the game left, and preserves every register, flag, and stack location the game reads afterward. Execution leaves it past its last byte, not through a return. It is copied without being decoded, so it may contain data.

A displaced instruction with an operand relative to its own address refers to a different address once moved, so Apply(params ReadOnlySpan<CodePatch>) throws. The exception is the displaced bytes being exactly one five-byte call, which becomes a call through an absolute address. A thread returning from that call returns into the allocated memory. Allocated memory has no unwind data, so an exception or a stack walk passing through a frame there is not unwound correctly.

Constructors

InsertionPatch(nint, BytePattern, ReadOnlySpan<byte>, int, DisplacedPlacement)

Creates a patch inserting code at address.

public InsertionPatch(nint address, BytePattern expected, ReadOnlySpan<byte> code, int displacedLength, DisplacedPlacement placement)

Parameters

address nint

The address of the first expected byte.

expected BytePattern

The bytes the code at address must match: the whole instructions replaced, at least five bytes.

code ReadOnlySpan<byte>

The machine code inserted. It is copied.

displacedLength int

How many of the expected bytes, from the first, run beside the code: 0 for none.

placement DisplacedPlacement

Whether the displaced instructions run before or after the code.

Exceptions

ArgumentOutOfRangeException

address is 0, expected is shorter than five bytes, code is empty, displacedLength is negative or greater than the length of expected, or placement is not a defined value.

ArgumentNullException

expected is null.

Properties

Code

The machine code inserted.

public ReadOnlyMemory<byte> Code { get; }

Property Value

ReadOnlyMemory<byte>

DisplacedLength

How many of the expected bytes, from the first, run beside the code.

public int DisplacedLength { get; }

Property Value

int

Placement

Whether the displaced instructions run before or after the code.

public DisplacedPlacement Placement { get; }

Property Value

DisplacedPlacement