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
addressnintThe address of the first expected byte.
expectedBytePatternThe bytes the code at
addressmust match: the whole instructions replaced, at least five bytes.codeReadOnlySpan<byte>The machine code inserted. It is copied.
displacedLengthintHow many of the expected bytes, from the first, run beside the code: 0 for none.
placementDisplacedPlacementWhether the displaced instructions run before or after the code.
Exceptions
- ArgumentOutOfRangeException
addressis 0,expectedis shorter than five bytes,codeis empty,displacedLengthis negative or greater than the length ofexpected, orplacementis not a defined value.- ArgumentNullException
expectedisnull.
Properties
Code
The machine code inserted.
public ReadOnlyMemory<byte> Code { get; }
Property Value
DisplacedLength
How many of the expected bytes, from the first, run beside the code.
public int DisplacedLength { get; }
Property Value
Placement
Whether the displaced instructions run before or after the code.
public DisplacedPlacement Placement { get; }