Papers
Topics
Authors
Recent
Search
2000 character limit reached

Attach-Stobj: Linking Abstract & Concrete Stobjs

Updated 7 July 2026
  • Attach-Stobj is a mechanism in ACL2 that connects an abstract stobj with its concrete counterpart using paired logic and execution functions governed by a correspondence relation.
  • It supports replaceable execution without recertifying proofs, facilitating efficient symbolic execution and performance optimization in models like ISA.
  • The design enforces atomicity and guard preservation, allowing multiple implementation strategies while maintaining stable logical reasoning.

Searching arXiv for the cited ACL2 papers to ground the article. Attach-Stobj denotes two closely related ACL2 ideas. In the earlier abstract-stobj literature, it is a useful description of how defabsstobj links a fast concrete single-threaded object to a logically simple abstract interface through paired :logic and :exec exports plus a correspondence relation (Goel et al., 2013). In later ACL2 terminology, attach-stobj is a feature that “first appeared in ACL2 Version 8.6 (October, 2024)” and allows an abstract stobj declared with :attachable t to execute using the :exec and :foundation of a separately defined implementation stobj, without recertifying the book that defines the original abstract stobj or theorems about it (Kaufmann et al., 25 Jul 2025). Across both senses, the central objective is stable logical reasoning over one state abstraction together with efficient or replaceable execution over another.

1. Conceptual basis in abstract stobjs

In ACL2, a stobj is a mutable object with applicative semantics that ACL2 executes efficiently while preserving logical soundness via a single-threadedness discipline. Concrete stobjs are introduced by defstobj; fields can have types, array constraints, and initial values, and the resulting representation is optimized for execution (Goel et al., 2013). The principal limitation described for concrete stobjs is that invariants are naturally field-wise: cross-field invariants are not expressible in the defstobj recognizer and instead appear as heavy guard obligations or hypotheses in theorems (Goel et al., 2013).

An abstract stobj, introduced by defabsstobj, provides an alternative logical representation and interface for an existing concrete stobj. Its exported operations have two views: :logic functions, used for reasoning, and :exec functions, used for execution. A correspondence predicate relates abstract and concrete states, and defabsstobj generates obligations ensuring that initial states correspond, exported operations preserve correspondence, and guards on abstract operations imply the guards of the concrete operations that will actually run (Goel et al., 2013).

This is the sense in which abstract stobjs realize an “Attach-Stobj” idea. The attachment is not logical equality, but a disciplined correspondence between two state representations. The abstract side can be small, sparse, and invariant-rich; the concrete side can be array-based, mutable, and optimized for raw Lisp execution. This separation yields faster execution, more efficient reasoning, support for symbolic simulation, and resilience of proof developments under concrete modeling optimization (Goel et al., 2013).

2. Formal mechanism of defabsstobj

The core defabsstobj pattern pairs a new abstract stobj name with an existing concrete stobj and specifies recognizers, creators, a correspondence function, and exports. A representative form is given as follows (Goel et al., 2013):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(defabsstobj ST
  :concrete st$c
  :recognizer (stp :logic st%%%%0%%%%cp)
  :creator    (create-st :logic create-st%%%%1%%%%c
                         :correspondence create-st{correspondence}
                         :preserved      create-st{preserved})
  :corr-fn st$corr
  :exports
    ((LOOKUP  :logic lookup%%%%2%%%%ci
              :correspondence lookup{correspondence}
              :guard-thm     lookup{guard-thm})
     (UPDATE  :logic update%%%%3%%%%ci
              :correspondence update{correspondence}
              :preserved      update{preserved}
              :guard-thm      update{guard-thm})
     (MISC    :logic misc%%%%4%%%%c
              :correspondence misc{correspondence})
     (UPDATE-MISC :logic update-misc%%%%5%%%%c
                  :correspondence update-misc{correspondence}
                  :preserved      update-misc{preserved})))

Before admitting such an event, one defines the abstract recognizer and creator, abstract operation specifications, the correspondence predicate, and the concrete side created by defstobj. What defabsstobj generates and requires includes {CORRESPONDENCE} theorems, {PRESERVED} theorems, and {GUARD-THM} theorems (Goel et al., 2013).

The correspondence can be expressed in a bisimulation-style form. Let ϕ(C,A)\phi(C,A) relate a concrete state CC to an abstract state AA. Then initialization requires ϕ(createC(),createA())\phi(\mathrm{create}_C(), \mathrm{create}_A()). For a reader ff, the requirement is that ϕ(C,A)\phi(C,A) implies equality of returned values. For an updater, the paper gives the update law in LaTeX form as

ϕ(C,A)ϕ(fC(C,x),fA(A,x)).\phi(C, A) \Rightarrow \phi(f_C(C, x), f_A(A, x)).

Recognizer preservation and guard transfer complete the discipline: the abstract recognizer must hold initially and be preserved by abstract updates, and abstract guards must entail the concrete guards needed by the executing :exec functions (Goel et al., 2013).

A representative example models abstract memory as an alist from indices to even naturals, with state represented as a cons (misc . mem-map), while execution uses a concrete array-based memc</code>.Thecorrespondenceassertsequalitybetweenconcretereadsandabstractlookupforeachaddressinrange,aswellasequalityofthemiscellaneousfield(<ahref="/papers/1304.7858"title=""rel="nofollow"dataturbo="false"class="assistantlink"xdataxtooltip.raw="">Goeletal.,2013</a>).Thisarrangementpermitsrichabstractinvariantssuchasallmemoryvaluesareevenwithoutforcingthoseinvariantstoberecheckedduringexecution.</p><h2class=paperheadingid=guardssinglethreadednessandatomicity>3.Guards,singlethreadedness,andatomicity</h2><p>Theexportsofanabstractstobjintroducestobjsignaturesthatenforcesinglethreadeduseoftheabstractstobj,whereasthelogical<code>c</code>. The correspondence asserts equality between concrete reads and abstract lookup for each address in range, as well as equality of the miscellaneous field (<a href="/papers/1304.7858" title="" rel="nofollow" data-turbo="false" class="assistant-link" x-data x-tooltip.raw="">Goel et al., 2013</a>). This arrangement permits rich abstract invariants such as “all memory values are even” without forcing those invariants to be rechecked during execution.</p> <h2 class='paper-heading' id='guards-single-threadedness-and-atomicity'>3. Guards, single-threadedness, and atomicity</h2> <p>The exports of an abstract stobj introduce stobj signatures that enforce single-threaded use of the abstract stobj, whereas the logical <code>a functions retain ordinary non-stobj signatures. This division is central to keeping proofs simple while maintaining executable discipline (Goel et al., 2013).

Guard handling is stricter than ordinary guard elision. Abstract functions may express high-level constraints such as index bounds or value parity, but defabsstobj requires proof that these imply the concrete guards of the underlying :exec functions. Even with guard-checking off, ACL2 always enforces guards for exported abstract stobj functions “to ensure compliant live stobj manipulation” (Goel et al., 2013). The abstract recognizer is defined to evaluate to T in raw Lisp when applied to a stobj, which avoids costly invariant checks at runtime while retaining logical strength for proofs (Goel et al., 2013).

A further issue is atomicity of executable exports. ACL2 6.0+ requires :protect t for any export whose :EXEC may be non-atomic. The stated pitfall is that an executable exported function performing multiple updates may be interrupted, for example by an error, leaving the stobj in a state that violates the abstract recognizer. In response, ACL2 inserts runtime checks and can signal an error, disabling certification for the session, if an incomplete export left the stobj unprotected (Goel et al., 2013). Syntactic analysis may allow omission of :protect t for obviously atomic exports, defined as those with at most one updater call (Goel et al., 2013).

These constraints are especially important when the abstract interface is intended to serve as the stable logical boundary for larger verification developments. Forgetting a {PRESERVED} theorem for an updater, misaligning field semantics between abstract and concrete states, or depending on execution of the abstract recognizer for runtime checking are all identified as common mistakes (Goel et al., 2013).

4. ISA modeling and symbolic execution

The best-known case study in the original abstract-stobj work is instruction-set architecture modeling for Y86/x86-32. The concrete processor stobj includes registers, EIP/PC, flags, and a space-efficient, two-level memory with on-demand allocation: mem-table, mem-array, and mem-array-next-addr (Goel et al., 2013). Concrete writes may resize the large memory array and rely on a well-formedness invariant good-memp enforced by the concrete recognizer (Goel et al., 2013).

For symbolic execution, the concrete-only model is problematic because the logical representation of stobjs is a massive list of fields and arrays. GL’s symbolic interpreter would need to construct an enormous mem-array list, causing value stack overflows and timeouts (Goel et al., 2013). The abstract x86-32 stobj addresses this by representing memory as a sparse record with initial value nil, using a recognizer defined with defun-sk:

CC0

Abstract memory write is correspondingly small:

CC1

The abstract stobj is exported with defabsstobj, including :protect t on the memory updater because the concrete executable write may be non-atomic (Goel et al., 2013). Memory correspondence is stated pointwise: for all in-range addresses, concrete read memci(i,C)</code>equalsabstractrecordlookup<code>g0(i,AbsMem(A))</code>(<ahref="/papers/1304.7858"title=""rel="nofollow"dataturbo="false"class="assistantlink"xdataxtooltip.raw="">Goeletal.,2013</a>).</p><p>Thisdesignsimplifiesrewritetheory.Arepresentativeunconditionalreadoverwritetheoremis:</p><p>ci(i, C)</code> equals abstract record lookup <code>g0(i, AbsMem(A))</code> (<a href="/papers/1304.7858" title="" rel="nofollow" data-turbo="false" class="assistant-link" x-data x-tooltip.raw="">Goel et al., 2013</a>).</p> <p>This design simplifies rewrite theory. A representative unconditional read-over-write theorem is:</p> <p>C$2

The practical consequence is that the Y86 “popcount” proof via GL symbolic execution succeeds on the abstract-stobj model in approximately 29 seconds on a 2.2 GHz Intel Core i7 / 8GB RAM under ACL2 6.0 and Clozure CL, with no auxiliary lemmas or custom clause processors, whereas the same style of GL proof failed for the concrete-only model because of massive mem-array lists causing stack overflow and timeouts (Goel et al., 2013).

5. The ACL2 8.6 attach-stobj feature

The later ACL2 feature attach-stobj formalizes a narrower but powerful notion of replaceable execution. It “first appeared in ACL2 Version 8.6 (October, 2024)” and allows different ACL2 sessions to specify different ways to execute operations on an attachable abstract stobj without recertifying the book that defines that stobj (Kaufmann et al., 25 Jul 2025). The mechanism is enabled by declaring the original stobj with :attachable t:

$C$3

An implementation stobj is then defined first, followed by an attachment event, followed by inclusion or definition of the attachable stobj:

$C$4

The required order is explicit: the implementation stobj must already be defined, and the attach-stobj event must precede the defabsstobj event that defines ST (Kaufmann et al., 25 Jul 2025). The key semantic operation is to “replace the :foundation and the :exec fields of the attachable stobj with those of its implementation” (Kaufmann et al., 25 Jul 2025).

This substitution changes execution only. Logical functions and theorems remain those of the attachable stobj, which is why existing book certifications remain valid (Kaufmann et al., 25 Jul 2025). The mechanism therefore supports “Mutable Objects with Several Implementations”: a single logical stobj can be executed through different implementation stobjs in different ACL2 sessions (Kaufmann et al., 25 Jul 2025).

A strict compatibility condition is imposed: the attachable and implementation stobjs must have “the same sequence of :logic functions,” meaning the same primitives in the same order (Kaufmann et al., 25 Jul 2025). Attachable abstract stobjs must still satisfy the usual abstract-stobj requirements, including complete :exec fields, even if those fields will later be overridden by attachment (Kaufmann et al., 25 Jul 2025).

6. Implementation architecture, nested stobjs, and performance trade-offs

Internally, attach-stobj populates a world table named attach-stobj-table, mapping an attachable stobj name to an implementation stobj name. Later, when the attachable stobj is defined, ACL2 recursively resolves the implementation by consulting this table (Kaufmann et al., 25 Jul 2025). The paper gives the internal lookup function as:

CC5

The core implementation function defabsstobj-fn1 then effectively invokes itself recursively when :attachable t is supplied, replacing :exec and :foundation after checking the identity of the logical interfaces (Kaufmann et al., 25 Jul 2025). Because abstract-stobj primitives are often macros, ACL2 also manages compilation carefully. Using two globals, ext-gens and ext-gen-barriers, ACL2 arranges that compiled code from a book should be ignored so that macroexpansion targets the attached implementation’s :exec functions at include-book time (Kaufmann et al., 25 Jul 2025).

The feature works in nested-stobj settings, including when the child is “whether concrete or abstract” (Kaufmann et al., 25 Jul 2025). A typical pattern is to attach a memory stobj implementation before defining a larger X86 stobj that includes the memory stobj as a child. The implementation stobj may also use :non-executable t if it will serve only as an implementation or only as a child or local stobj, thereby preventing creation of a global implementation stobj unless add-global-stobj is later used (Kaufmann et al., 25 Jul 2025).

The stated engineering trade-off is that execution with attachable stobjs is efficient because attach-stobj introduces no indirection, but compilation is performed at include-book time when existing compiled code is avoided (Kaufmann et al., 25 Jul 2025). The feature is illustrated through alternative memory models, specifically “symmetric” and “asymmetric” big memory implementations. For 100,000 writes of byte 1 to random addresses in a range of 2302^{30}, the symmetric model is reported as best for “high” writes, while the other two setups are best for “low” writes; attach-stobj allows one to retain theorems about the symmetric model and attach the asymmetric model for performance (Kaufmann et al., 25 Jul 2025).

The idea of attaching execution to an abstract state interface also appears in the integration of external incremental SAT solvers. In “Incremental SAT Library Integration Using Abstract Stobjs,” the solver is modeled as an abstract stobj named ipasir, whose logical state includes fields such as formula, assumption, new-clause, status, solution, solved-assumption, callback-count, and history (Swords, 2018). The logical model is used for proofs, while execution is realized through raw Lisp/CFFI wrappers to an external IPASIR solver library (Swords, 2018).

The paper explicitly notes that there is no literal attach-stobj primitive in that design. Instead, the executable versions of the abstract stobj’s exported functions are redefined to call into the external library, and one constrained function, ipasir-signature, uses defattach (Swords, 2018). The authors describe this as an “attach-stobj” pattern: defabsstobj provides the logical API, while the backend attaches raw executable bodies to exported abstract-stobj functions (Swords, 2018).

This example clarifies the boundaries between several ACL2 mechanisms. defattach attaches an executable function to a constrained function for execution, but it is function-oriented and does not address state, single-threadedness, or correspondence obligations (Goel et al., 2013). mbe and defexec provide :[LOGIC](https://www.emergentmind.com/topics/logic-02f6edfd-aeba-4f85-89f0-134bdf0a69a3) and :EXEC versions of the same function that are logically equal, whereas abstract stobjs allow :LOGIC and :EXEC components to correspond via a relation ϕ\phi rather than equality (Goel et al., 2013). Raw Lisp redefinitions are possible but are characterized as fragile and potentially threatening to soundness; abstract stobjs and, later, attach-stobj provide supported mechanisms with generated obligations or implementation checks (Goel et al., 2013).

A common misconception is to treat Attach-Stobj as a single ACL2 primitive throughout the literature. The source record supports a sharper distinction. In the 2013 work, “Attach-Stobj” is an apt description of the abstract-stobj discipline rather than a term used by the paper itself (Goel et al., 2013). In the 2025 extended abstract, attach-stobj is a specific ACL2 feature with concrete syntax, order-of-events constraints, world-table support, and session-specific execution substitution (Kaufmann et al., 25 Jul 2025). A plausible implication is that the later feature systematizes one important execution-substitution use case while preserving the broader abstract-stobj methodology that originally made such separation between logic and execution technically viable.

Definition Search Book Streamline Icon: https://streamlinehq.com
References (3)

Topic to Video (Beta)

No one has generated a video about this topic yet.

Whiteboard

No one has generated a whiteboard explanation for this topic yet.

Follow Topic

Get notified by email when new papers are published related to Attach-Stobj.