[DynInst_API:] [dyninst/dyninst] 12fe1a: dyninstAPI: fix -fipa-ra caller register clobber


Date: Wed, 08 Jul 2026 22:54:24 -0700
From: bbiiggppiigg <noreply@xxxxxxxxxx>
Subject: [DynInst_API:] [dyninst/dyninst] 12fe1a: dyninstAPI: fix -fipa-ra caller register clobber
  Branch: refs/heads/bbiiggppiigg/ipa-ra-caller-saved-clobber
  Home:   https://github.com/dyninst/dyninst
  Commit: 12fe1a11cca688807160f4dfd8325226b21e0c52
      https://github.com/dyninst/dyninst/commit/12fe1a11cca688807160f4dfd8325226b21e0c52
  Author: wuxx1279 <bbiiggppiigg@xxxxxxxxx>
  Date:   2026-07-09 (Thu, 09 Jul 2026)

  Changed paths:
    M dyninstAPI/src/emit-x86.C

  Log Message:
  -----------
  dyninstAPI: fix -fipa-ra caller register clobber

GCC -fipa-ra (on at -O2, aggressive under LTO) narrows a callee's
clobber set from the caller's point of view whenever the callee's body
is fully visible and the call cannot be interposed. A direct caller may
then keep a value in a caller-saved register live across the call
because the callee provably never writes that register. Instrumenting
such a callee's entry breaks this contract: dyninst's intra-procedural
liveness sees the register dead inside the callee, the base trampoline
does not preserve it, and the inserted snippet (a standard-ABI call)
clobbers it -- silently corrupting the caller. Observed on an
LTO-built SPEC CPU 2017 gcc: fold_builtin_inf keeps &local in %rsi
across a call to the plain local function real_inf (which only writes
{rax,rcx,rdx,rdi}); instrumenting every function entry destroys %rsi
and the caller SIGSEGVs on a subsequent rep movsl.

The existing guard (PR #2288) only covers GCC local clones
(.isra/.constprop/... suffixes, Symbol::isClone), but -fipa-ra applies
to ANY local callee, clone or not. Extend the conservative-save gate in
shouldSaveReg with isLocalFunc(), which fires when:

- any of the function's symbols has SL_LOCAL linkage; or
- the function has no symbol in the binary at all: functions discovered
  by parsing (ParseAPI src() != HINT -- recursive traversal, gap
  heuristics, on-demand) get a synthesized "targXXX" symbol with
  SL_GLOBAL linkage, so the linkage check alone would wrongly take the
  fast path. In stripped binaries the affected local callees are
  precisely the ones whose symbols are gone, and a missing symbol says
  nothing about the ABI actually used at its call sites.

Global (interposable) functions keep the existing liveness-based
pruning; the check short-circuits before any per-register work.

Verified: the SPEC gcc reproducer runs to completion instrumented
(previously SIGSEGV); deepsjeng shows no regression.

Co-Authored-By: Claude Fable 5 <noreply@xxxxxxxxxxxxx>



To unsubscribe from these emails, change your notification settings at https://github.com/dyninst/dyninst/settings/notifications
[← Prev in Thread] Current Thread [Next in Thread→]
  • [DynInst_API:] [dyninst/dyninst] 12fe1a: dyninstAPI: fix -fipa-ra caller register clobber, bbiiggppiigg <=