paavohtl Claude Opus 4.6 commited on
Commit
6124d55
·
1 Parent(s): 6eccc99

docs: document ECX preservation requirement for thiscall hook trampolines

Browse files
Files changed (1) hide show
  1. CLAUDE.md +1 -1
CLAUDE.md CHANGED
@@ -192,7 +192,7 @@ Hooks use the `minhook` crate. Two patterns:
192
  1. **Passthrough hook** (logging only): Call original via trampoline, log result. See `replacements/scheme.rs`.
193
  2. **Full replacement**: Reimplement the function in Rust, call WA functions via `wa_call` helpers. See `replacements/frontend.rs`.
194
 
195
- For `__usercall` functions, use a naked trampoline to capture register params before calling the Rust impl.
196
 
197
  3. **Vtable method replacement**: Use `vtable_replace!` to patch vtable slots at runtime. Write the replacement as `unsafe extern "thiscall" fn`. For base-class call-through, either save the original via `[ORIG_STATIC]` syntax, or call `broadcast_message()` for CTask::HandleMessage. See `replacements/task/cloud.rs`.
198
  4. **Trap hook** (`install_trap!`): For functions whose only caller is now ported Rust. Panics if called unexpectedly. Used for FireWeapon (0x51EE60) after WeaponRelease was ported.
 
192
  1. **Passthrough hook** (logging only): Call original via trampoline, log result. See `replacements/scheme.rs`.
193
  2. **Full replacement**: Reimplement the function in Rust, call WA functions via `wa_call` helpers. See `replacements/frontend.rs`.
194
 
195
+ For `__usercall` functions, use a naked trampoline to capture register params before calling the Rust impl. **ECX preservation**: The standard `reg = ecx` trampoline variants do NOT preserve ECX across the cdecl impl call. MSVC-generated callers often loop calling thiscall functions without re-setting ECX between iterations (relying on the original function preserving it). Use the `preserve_ecx` variant for thiscall hooks where callers may rely on ECX being preserved: `usercall_trampoline!(fn name; impl_fn = path; reg = ecx; stack_params = N; ret_bytes = "0xN"; preserve_ecx)`.
196
 
197
  3. **Vtable method replacement**: Use `vtable_replace!` to patch vtable slots at runtime. Write the replacement as `unsafe extern "thiscall" fn`. For base-class call-through, either save the original via `[ORIG_STATIC]` syntax, or call `broadcast_message()` for CTask::HandleMessage. See `replacements/task/cloud.rs`.
198
  4. **Trap hook** (`install_trap!`): For functions whose only caller is now ported Rust. Panics if called unexpectedly. Used for FireWeapon (0x51EE60) after WeaponRelease was ported.