digitalmars.dip.ideas - watch Attribute for Hotpatchable Functions
- xoxorwr (60/60) Jun 12 Hey,
- Richard (Rikki) Andrew Cattermole (5/5) Jun 12 This can be done using a core.attribute attribute.
- xoxorwr (4/9) Jun 12 This sounds like a better idea, least intrusive option, a
- Guillaume Piolat (5/16) Jun 14 If we supported arm64ec (x86 code compiled into the ARM64X linker
- Quirin Schroll (4/9) Jun 19 This seems to be compiler-specific. It should probably be a
Hey,
I'm working on a dynamic hot reloading / binary patching
framework in D, and I've hit an issue with hooking very small
functions.
On x86_64, a safe absolute jump hook requires about 14 bytes:
```asm
jmp [rip+0]
dq target
```
But some functions compile to fewer than 14 bytes, so if I
overwrite their prologue, I can corrupt the `ret` instruction /
adjacent code.
Right now, the only workaround is manually padding them with
inline assembly, which is very inconvenient.
I'd like to propose a builtin function attribute, for example:
```d
watch
void foo() { }
```
This attribute would tell the compiler to make the function
hotpatch friendly by:
- disabling inlining
- emitting enough NOP padding at the function entry for a runtime
jump patch
On x86_64, this would mean reserving at least 14 bytes at the
start of the function.
The goal is to provide a standard, compiler supported way to mark
functions as safe targets for runtime patching or hot reloading,
without requiring manual assembly padding.
Example:
```diff
--- a/compiler/src/dmd/glue/package.d
+++ b/compiler/src/dmd/glue/package.d
-507,2 +507,6
Symbol* s = toSymbol(fd); // may set skipCodegen
func_t* f = s.Sfunc;
+
+ if (isHotpatchable(fd))
+ f.Fflags3 |= Fwatch;
+
```
```diff
--- a/compiler/src/dmd/backend/x86/cgcod.d
+++ b/compiler/src/dmd/backend/x86/cgcod.d
-628,2 +628,12
if (config.flags3 & CFG3ibt && !I16)
cdb.gen1(I32 ? ENDBR32 : ENDBR64);
+
+ if (funcsym_p.Sfunc.Fflags3 & Fwatch)
+ {
+ if (I64)
+ // 14 byte multibyte NOP for 64bit absolute JMP
+ cdb.genasm([0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00]);
+ else
+ // 8 byte multibyte NOP for 32bit relative JMP
+ cdb.genasm([0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00,
0x00, 0x00]);
+ }
```
Jun 12
This can be done using a core.attribute attribute. It is not something that should affect normal compilation, nor should it be common place. For llvm, it looks like the attribute is: patchable-function-entry set to a number like 5.
Jun 12
On Friday, 12 June 2026 at 13:05:03 UTC, Richard (Rikki) Andrew Cattermole wrote:This can be done using a core.attribute attribute. It is not something that should affect normal compilation, nor should it be common place. For llvm, it looks like the attribute is: patchable-function-entry set to a number like 5.This sounds like a better idea, least intrusive option, a compiler flag.
Jun 12
On Friday, 12 June 2026 at 13:11:59 UTC, xoxorwr wrote:On Friday, 12 June 2026 at 13:05:03 UTC, Richard (Rikki) Andrew Cattermole wrote:If we supported arm64ec (x86 code compiled into the ARM64X linker format), then each x86 function would have a similar prefix so that the JIT can do its work. IIRC "arm64ec" requires a similar function prologue as your case.This can be done using a core.attribute attribute. It is not something that should affect normal compilation, nor should it be common place. For llvm, it looks like the attribute is: patchable-function-entry set to a number like 5.This sounds like a better idea, least intrusive option, a compiler flag.
Jun 14
On Friday, 12 June 2026 at 12:58:53 UTC, xoxorwr wrote:I'm working on a dynamic hot reloading / binary patching framework in D, and I've hit an issue with hooking very small functions. […] I'd like to propose a builtin function attribute, for example:This seems to be compiler-specific. It should probably be a `pragma`, essentially for the same reason as inlining is controlled by a `pragma` and not an attribute.
Jun 19









Guillaume Piolat <first.name gmail.com> 