Fix documentation
This commit is contained in:
1 parent
a317c07124
commit
ab21b3f30d
27 files changed
+2137
-1043
No files matched your search
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @file Architecture.cpp
|
||||
* @brief Per-architecture jump-patch backends for x86, x86-64, and ARM64.
|
||||
*/
|
||||
#include "Architecture.hpp"
|
||||
|
||||
#include <atomic>
|
||||
@@ -51,7 +55,8 @@
|
||||
* executing through the exact bytes being patched -- doing that in
|
||||
* general on a variable-length ISA needs a signal-handler-based retry
|
||||
* protocol (a much bigger mechanism, well beyond a dev-loop tool's
|
||||
* requirements). See the README for this precondition stated plainly.
|
||||
* requirements). See the "Limitations" section of the top-level README
|
||||
* for this precondition stated plainly.
|
||||
*/
|
||||
|
||||
namespace hot_reload::detail
|
||||
@@ -60,20 +65,30 @@ namespace hot_reload::detail
|
||||
{
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
|
||||
/// Size in bytes of the CET landing pad (`endbr64`) a function may start with.
|
||||
constexpr std::size_t kLandingPadBytes = 4;
|
||||
|
||||
/// Encoding of `endbr64`, the x86-64 CET indirect-branch landing pad.
|
||||
constexpr unsigned char kEndbr64[kLandingPadBytes] = {0xF3, 0x0F, 0x1E, 0xFA};
|
||||
// jmp qword ptr [rip+0]; <8-byte absolute address> -- reaches
|
||||
// any 64-bit address regardless of how far apart the old and
|
||||
// new modules were loaded, unlike a 5-byte relative jump
|
||||
// (E9 rel32) which only reaches +/-2GB. Verified byte-for-byte
|
||||
// against `as`/objdump output while building this library.
|
||||
|
||||
/// Size in bytes of the jump written over a function's entry:
|
||||
/// `jmp qword ptr [rip+0]` followed by an 8-byte absolute address. That reaches any
|
||||
/// 64-bit address regardless of how far apart the old and new modules were loaded,
|
||||
/// unlike a 5-byte relative jump (`E9 rel32`) which only reaches +/-2GB. Verified
|
||||
/// byte-for-byte against `as`/objdump output while building this library.
|
||||
constexpr std::size_t kJumpBytes = 14;
|
||||
|
||||
/// Whether the function at @p entry starts with an `endbr64` landing pad.
|
||||
/// @param entry The function's entry address (at least kLandingPadBytes readable bytes).
|
||||
/// @return True if the first bytes are `endbr64`.
|
||||
bool hasLandingPad(const unsigned char* entry)
|
||||
{
|
||||
return std::memcmp(entry, kEndbr64, kLandingPadBytes) == 0;
|
||||
}
|
||||
|
||||
/// Writes the x86-64 absolute jump at @p site, payload first and the opcode last.
|
||||
/// @param site Where the jump goes (just past the landing pad, if there is one).
|
||||
/// @param target Address the jump transfers control to.
|
||||
void writeJumpAt(unsigned char* site, const void* target)
|
||||
{
|
||||
std::uint64_t targetValue = 0;
|
||||
@@ -99,20 +114,29 @@ namespace hot_reload::detail
|
||||
|
||||
#elif defined(__i386__) || defined(_M_IX86)
|
||||
|
||||
/// Size in bytes of the CET landing pad (`endbr32`) a function may start with.
|
||||
constexpr std::size_t kLandingPadBytes = 4;
|
||||
|
||||
/// Encoding of `endbr32`, the 32-bit x86 CET indirect-branch landing pad.
|
||||
constexpr unsigned char kEndbr32[kLandingPadBytes] = {0xF3, 0x0F, 0x1E, 0xFB};
|
||||
// e9 rel32 -- a plain relative near jump. On 32-bit x86 the
|
||||
// entire address space fits in the signed 32-bit displacement
|
||||
// (mod 2^32 wraparound gives the right answer regardless of
|
||||
// "distance"), so unlike x86-64 there is no need for an
|
||||
// absolute/indirect form here.
|
||||
|
||||
/// Size in bytes of the jump written over a function's entry: `e9 rel32`, a plain
|
||||
/// relative near jump. On 32-bit x86 the entire address space fits in the signed 32-bit
|
||||
/// displacement (mod 2^32 wraparound gives the right answer regardless of "distance"),
|
||||
/// so unlike x86-64 there is no need for an absolute/indirect form here.
|
||||
constexpr std::size_t kJumpBytes = 5;
|
||||
|
||||
/// Whether the function at @p entry starts with an `endbr32` landing pad.
|
||||
/// @param entry The function's entry address (at least kLandingPadBytes readable bytes).
|
||||
/// @return True if the first bytes are `endbr32`.
|
||||
bool hasLandingPad(const unsigned char* entry)
|
||||
{
|
||||
return std::memcmp(entry, kEndbr32, kLandingPadBytes) == 0;
|
||||
}
|
||||
|
||||
/// Writes the x86 relative jump at @p site, displacement first and the opcode last.
|
||||
/// @param site Where the jump goes (just past the landing pad, if there is one).
|
||||
/// @param target Address the jump transfers control to.
|
||||
void writeJumpAt(unsigned char* site, const void* target)
|
||||
{
|
||||
std::int32_t rel32 = static_cast<std::int32_t>(
|
||||
@@ -128,35 +152,47 @@ namespace hot_reload::detail
|
||||
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
|
||||
/// Size in bytes of the BTI landing pad a function may start with (one instruction word).
|
||||
constexpr std::size_t kLandingPadBytes = 4;
|
||||
|
||||
// Matches any BTI variant (plain/C/J/JC): bits [31:6] are fixed
|
||||
// at 0b010101000000001001001, differing only in bits [6:5]
|
||||
// (the qualifier) -- equivalently, the low byte is one of
|
||||
// 0x1F/0x5F/0x9F/0xDF and the next 3 bytes are always
|
||||
// 24 03 D5. Verified with `as`/objdump for all 4 variants
|
||||
// while building this library.
|
||||
/// Whether the instruction word at @p entry is any BTI variant (plain/C/J/JC): bits
|
||||
/// [31:6] are fixed at 0b010101000000001001001, differing only in bits [6:5] (the
|
||||
/// qualifier) -- equivalently, the low byte is one of 0x1F/0x5F/0x9F/0xDF and the next 3
|
||||
/// bytes are always 24 03 D5. Verified with `as`/objdump for all 4 variants while
|
||||
/// building this library.
|
||||
/// @param entry The function's entry address (at least 4 readable bytes).
|
||||
/// @return True if the first instruction is a BTI landing pad.
|
||||
bool isBti(const unsigned char* entry)
|
||||
{
|
||||
return (entry[0] & 0x3Fu) == 0x1Fu && entry[1] == 0x24 && entry[2] == 0x03 && entry[3] == 0xD5;
|
||||
}
|
||||
|
||||
/// Whether the function at @p entry starts with a BTI landing pad.
|
||||
/// @param entry The function's entry address (at least kLandingPadBytes readable bytes).
|
||||
/// @return True if the first instruction is a BTI landing pad.
|
||||
bool hasLandingPad(const unsigned char* entry)
|
||||
{
|
||||
return isBti(entry);
|
||||
}
|
||||
|
||||
// ldr x17, #8 ; br x17 ; <8-byte absolute address>. x16/x17
|
||||
// are AArch64's designated "intra-procedure-call" scratch
|
||||
// registers (IP0/IP1) -- the AAPCS64 explicitly reserves them
|
||||
// for exactly this kind of linker/veneer-style long branch, so
|
||||
// clobbering them at a function's entry point, before any of
|
||||
// its real prologue has executed, is always safe. Byte values
|
||||
// verified with `as`/objdump while building this library.
|
||||
/// Size in bytes of the jump written over a function's entry:
|
||||
/// `ldr x17, #8 ; br x17 ; <8-byte absolute address>`. x16/x17 are AArch64's designated
|
||||
/// "intra-procedure-call" scratch registers (IP0/IP1) -- the AAPCS64 explicitly reserves
|
||||
/// them for exactly this kind of linker/veneer-style long branch, so clobbering them at
|
||||
/// a function's entry point, before any of its real prologue has executed, is always
|
||||
/// safe. Byte values verified with `as`/objdump while building this library.
|
||||
constexpr std::size_t kJumpBytes = 16;
|
||||
|
||||
/// Encoding of `ldr x17, #8` (loads the literal address stored 8 bytes further on).
|
||||
constexpr unsigned char kLdrX17Pc8[4] = {0x51, 0x00, 0x00, 0x58};
|
||||
|
||||
/// Encoding of `br x17` (branches to the address `ldr x17, #8` loaded).
|
||||
constexpr unsigned char kBrX17[4] = {0x20, 0x02, 0x1F, 0xD6};
|
||||
|
||||
/// Writes the ARM64 `ldr`/`br` pair plus literal address at @p site, payload first and
|
||||
/// the leading `ldr` last.
|
||||
/// @param site Where the jump goes (just past the landing pad, if there is one).
|
||||
/// @param target Address the jump transfers control to.
|
||||
void writeJumpAt(unsigned char* site, const void* target)
|
||||
{
|
||||
std::uint64_t targetValue = 0;
|
||||
|
||||
Reference in new issue
Block a user