Skip to content

feat: call-boundary ABI framework with strict clobber semantics#76

Merged
NaC-L merged 2 commits intomainfrom
feature/call-boundary-abi
Mar 26, 2026
Merged

feat: call-boundary ABI framework with strict clobber semantics#76
NaC-L merged 2 commits intomainfrom
feature/call-boundary-abi

Conversation

@NaC-L
Copy link
Copy Markdown
Owner

@NaC-L NaC-L commented Mar 26, 2026

Summary

Cross-ABI call-boundary framework that models what happens at non-inlineable call instructions (indirect calls, import thunks, outlined targets).

Changes

New: AbiCallContract.hpp

  • AbiKind: x64_msvc, x86_cdecl/stdcall/fastcall, unknown
  • CallModelMode: strict (default, clobbers volatile) / compat (preserves all)
  • CallEffects: arg regs, return regs, volatile set, stack cleanup, memory effect
  • RegSet<Register>: fixed-capacity register set for ABI specs
  • Structured diagnostics ([call-abi] prefix at every call site)

Modified: lift_call (Semantics_ControlFlow.ipp)

  • applyPostCallEffects: writes RAX = result, clobbers volatile regs in strict mode
  • emittedExternalCall flag: skips Unflatten path when CreateCall was emitted
  • Import thunk detection (FF 25jmp [IAT]): auto-outlines DLL imports
  • Speculative inlining scaffolding (disabled, opt-in via maxCallInlineBudget)

Bug fixes

  • parseArgs(nullptr) duplicated RDI (18 values for 16 type slots)
  • Unknown calls in lift_call never assigned RAX = call result
  • callFunctionIR now routes through applyPostCallEffects

Tests

  • call_abi_compat_preserves_volatile: R10 survives, RAX = result
  • call_abi_strict_clobbers_volatile: R10 = undef, RBX preserved
  • call_abi_default_is_strict: verifies strict is the default

Verification

  • All baseline (90+), semantic (23/23), micro (15/15) tests pass
  • Determinism: 34 golden files match
  • VMP 3.8.1 target: identical a + b + c deobfuscation (14K instructions, 1629 blocks)
  • call r9 (function pointer) binary: correct CreateCall + ABI effects + continuation

Open work

Speculative inlining policy for distinguishing VM handler calls from library calls — see #75

…nlining scaffolding

Cross-ABI call contract (AbiCallContract.hpp):
- AbiKind enum (x64_msvc, x86_cdecl/stdcall/fastcall, unknown)
- CallModelMode: strict (default) clobbers volatile regs, compat preserves all
- CallEffects: arg regs, return regs, volatile set, stack cleanup, memory effect
- Pre-built descriptors for x64 MSVC and x86 calling conventions
- Structured diagnostics at every call site ([call-abi] prefix)

Call-site semantics (lift_call):
- applyPostCallEffects: assigns RAX=result, clobbers volatile in strict mode
- emittedExternalCall flag: skips Unflatten inlining when CreateCall emitted
- Import thunk detection (FF 25 jmp [IAT]): auto-outlines DLL imports
- shouldOutlineCall hook: extensible policy for inline/outline decisions

Bug fixes:
- parseArgs(nullptr) duplicated RDI (18 values for 16-type slots) — now 16 GPRs + memory ptr
- Unknown calls in lift_call never assigned RAX = call result — now they do
- callFunctionIR routed through applyPostCallEffects for consistency

Speculative inlining (disabled by default, opt-in via maxCallInlineBudget):
- Budget-limited call inlining with bail-out to CreateCall + ABI effects
- Worklist trimming on bail-out restores pre-call continuation
- Works mechanically but needs smarter trigger policy (see open issue)

Tests:
- call_abi_compat_preserves_volatile: R10 survives, RAX = result
- call_abi_strict_clobbers_volatile: R10 = undef, RBX preserved, RAX = result
- call_abi_default_is_strict: verifies strict is the default
- All existing baseline (90+), semantic (23/23), micro (15) tests pass
- VMP 3.8.1 target produces identical a+b+c deobfuscation
Documents the unsolved problem of distinguishing real function calls
(library, CRT) from obfuscation call gadgets (VM handlers, push+ret).

Current state: import thunks auto-detected, speculative budget mechanism
built but disabled. Needs call-depth scoped policy or hybrid approach.

See .github/SPECULATIVE_INLINE_ISSUE.md for full analysis and proposals.
@NaC-L NaC-L merged commit 317e6b7 into main Mar 26, 2026
4 checks passed
@NaC-L NaC-L deleted the feature/call-boundary-abi branch March 26, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants