Soo, uuhhh, I was just bored on a train. And "I have no idea what I'm doing" applies rather heavily.
But... I just ported: <https://nullprogram.com/blog/2016/03/31/> to Nim to try it out for this. To my utter surprise it actually works. I'm pretty sure it's _not_ a good idea to use this for testing, but it's fun, haha. import posix proc foo(s: string, x: int) = echo "Hello ", s, " id ", x proc bar(s: string, x: int) = echo "Hax0r you! ", s, " id ", x * 123 type Instr {.union.} = object bytes: array[8, byte] value: uint64 proc hotpatchImpl*(target, replacement: pointer) = # YOLO who needs alignment #doAssert (cast[ByteAddress](target) and ByteAddress(0x07)) == 0 var page = cast[pointer](cast[ByteAddress](target) and (not 0xfff)) doAssert mprotect(page, 4096, PROT_WRITE or PROT_EXEC) == 0 let rel = cast[ByteAddress](replacement) - cast[ByteAddress](target) - 5 var instr = Instr(bytes: [0xe9.byte, (rel shr 0).byte, (rel shr 8).byte, (rel shr 16).byte, (rel shr 24).byte, 0, 0, 0]) cast[ptr uint64](target)[] = instr.value doAssert mprotect(page, 4096, PROT_EXEC) == 0 template hotpatch*(target, replacement: untyped): untyped = hotpatchImpl(cast[pointer](target), cast[pointer](replacement)) foo("world", 1) hotpatch(foo, bar) foo("world", 1) import strutils proc myParse(s: string): int = 1337 hotpatch(parseInt, myParse) echo "12".parseInt() Run (or see here that it actually works: <https://play.nim-lang.org/#ix=40DX>
