fix(cpu): preserve TLS instruction boundaries after rel8 branches (#846)

This commit is contained in:
Foued Attar
2026-08-24 22:52:30 +02:00
committed by GitHub
parent 600fcde637
commit 51e5480049
2 changed files with 148 additions and 4 deletions
@@ -0,0 +1,75 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.Core.Cpu.Native;
using Xunit;
namespace SharpEmu.Libs.Tests.Cpu;
public sealed class TlsLoadPatchBoundaryTests
{
[Fact]
public void RejectsGtaShortJumpDisplacementAsTlsPrefix()
{
byte[] code =
[
0x90,
0xEB, 0x66,
0x66, 0x64, 0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00,
];
Assert.True(DirectExecutionBackend.IsTlsLoadCandidateInsideShortJump(code, candidateOffset: 2));
Assert.False(DirectExecutionBackend.IsTlsLoadCandidateInsideShortJump(code, candidateOffset: 3));
}
[Fact]
public void KeepsDreamingSarahTlsInstructionAfterBackwardJnz()
{
byte[] code =
[
0x48, 0x8B, 0x1C, 0xD0,
0x4C, 0x39, 0x2B,
0x0F, 0x84, 0x10, 0x01, 0x00, 0x00,
0x48, 0xFF, 0xC2,
0x48, 0x39, 0xD1,
0x75, 0xEB,
0x66, 0x66, 0x66, 0x64, 0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00,
];
Assert.False(DirectExecutionBackend.IsTlsLoadCandidateInsideShortJump(code, candidateOffset: 21));
}
[Theory]
[InlineData(0x70)]
[InlineData(0x7F)]
[InlineData(0xE0)]
[InlineData(0xE3)]
[InlineData(0xEB)]
public void KeepsTlsInstructionAfterRel8ControlFlow(byte opcode)
{
byte[] code =
[
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
opcode, 0xEB,
0x66, 0x64, 0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00,
];
Assert.False(DirectExecutionBackend.IsTlsLoadCandidateInsideShortJump(code, candidateOffset: 21));
}
[Fact]
public void Rel8OpcodeByteInsidePreviousInstructionDoesNotBypassGuard()
{
byte[] code =
[
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x6A, 0x75,
0xEB, 0x66,
0x66, 0x64, 0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00,
];
Assert.True(DirectExecutionBackend.IsTlsLoadCandidateInsideShortJump(code, candidateOffset: 21));
}
}