The first of the three things HANDOFF-x86-redef.md left: a function or a defvar the running process has no symbol for. ELF cannot grow one, so the address is asked for by string at install time -- flan_dev_cell for a cell, flan_dev_global for a global's storage -- and parked in a slot this module defines. The reference side is one new [loc] case and nothing else. [Lslot] loads the slot and answers [Reg (scratch, d)], which is exactly what [Lgot] already did with [Got] where this has [Sym]; every site that reaches a cell already double-loads, so no call site, no place expression and no [sym_loc] caller had to learn a third case. [fnctx.slot] is a second predicate rather than a widened [ext] because they answer different questions -- [ext] says "the host's, reach it through the GOT", [slot] says "nobody's yet, reach it through a slot I filled". It defaults to [fun _ -> None], so the whole-program path emits byte-identical output and the survey goes on being a structural check. flan_reload_install is now a function with a frame rather than a run of loads and stores, because it makes calls and a call on an unaligned stack faults inside glibc's movaps rather than anywhere a reader would look. Its shape is emit_globals_init's, down to owning the null transfer cell no caller hands it. A new global's declared value travels with it: flan_dev_global copies the image onto the allocation the first time the name is interned and ignores it after, which is where "a reload must not reset the state" lives. emit.ml folds that value into an LLVM constant and this file has no folder, so the image is a module-local buffer written by the initialiser lowered as ordinary code -- the same bargain emit_globals_data already documents. Republishing a defconst came free once the rest was there: one store of the new constant into the host's global, which is what emit.ml does. reload-v6.flan is new. v3's [extra] is declared zero, which calloc also gives, so a run-time-new global whose initial value never arrived would still pass; v6's [tuning] is 42 and the host prints 88. test_reload.ml's x86 section now runs all four modules against the same transcript the LLVM path is held to, and the refusal it used to assert is gone.
18 lines
614 B
Plaintext
18 lines
614 B
Plaintext
;;;; A run-time-new global with a value of its own, which is the half of the
|
|
;;;; new-name path that a zeroed defvar cannot measure: [flan_dev_global]
|
|
;;;; allocates with calloc, so a global declared zero looks right whether or
|
|
;;;; not its initial value travelled with the module. [tuning] is 42, and the
|
|
;;;; transcript is the number the host prints, so an image that never arrived
|
|
;;;; prints 4 rather than 88.
|
|
(defvar counter i64)
|
|
(defvar tuning i64 42)
|
|
|
|
(defn helper [x i64] i64 (* x 2))
|
|
|
|
(defn bump [] i64
|
|
(println "v6")
|
|
(set counter (+ counter tuning 1))
|
|
(helper counter))
|
|
|
|
(defn outer [] i64 (bump))
|