diff --git a/lib/build.ml b/lib/build.ml index 7a64ab3..d5383c4 100644 --- a/lib/build.ml +++ b/lib/build.ml @@ -744,18 +744,20 @@ let executable ?(opts = default) ?(csrcs = []) ?(lflags = []) ?(pnames = []) by this backend — and the module that would redefine through them arrives with the lane that writes it. - That lane inherits one thing this comment should say out loud rather than - leave for it to find. [x86.ml]'s header licenses its own calling - convention on the grounds that a dev build is compiled entirely by it and - a release build entirely by LLVM, so the two never meet in one process. - Publishing a cell an LLVM-built module can store into is the first thing - that could make that false: the two conventions agree on scalars and - disagree on every aggregate, so an [Emit.redefinition] module dlopened - into an [--x86] host would be correct until the first redefined function - took or returned a struct. Nothing in the toolchain does that today — - [flan reload] and [flan dev] both build host and module through LLVM — - and the fix when something does is to emit the module through this - backend too, not to grow a classifier. *) + [X86.redefinition] is that lane, and it has landed, so the paragraph this + comment used to end with — that no counterpart existed — is no longer + true. What remains true is why it had to be written here rather than + borrowed from LLVM. [x86.ml]'s header licenses its own calling convention + on the grounds that a dev build is compiled entirely by it and a release + build entirely by LLVM, so the two never meet in one process. Publishing + a cell an LLVM-built module can store into is the first thing that could + make that false: the two conventions agree on scalars and disagree on + every aggregate, so an [Emit.redefinition] module dlopened into an + [--x86] host is correct until the first redefined function takes or + returns a struct. That pair is now refused at [dlopen] by a marker symbol + each backend defines and each backend's module references — see [shared] + below — rather than left to die at the call. The answer was to emit the + module through this backend too, and never to grow a classifier. *) (* [--debug] used to be in this list too. It is not any more: [x86.ml] emits a compile unit, a subprogram per function and a line table, all written out as bytes because [.loc] cannot work against a file whose instructions @@ -911,12 +913,17 @@ let shared ?(opts = default) ~ir ~out () : timing = than it is is worse than none. It catches a caller holding one option record and reaching for the wrong builder. It does not catch a caller holding two and picking the wrong one — the crossed pair that was measured - segfaulting passes this check and still segfaults, because it hands an - LLVM record to the LLVM builder and simply loads the result into an x86 - host. [flan reload] is precisely that caller. The complete answer is a - marker symbol the host defines and a module references, so the loader - refuses the pair at dlopen rather than the processor refusing it at a - call. See docs/handoffs/HANDOFF-x86-aggregates.md. *) + segfaulting passes this check, because it hands an LLVM record to the LLVM + builder and simply loads the result into an x86 host. [flan reload] is + precisely that caller, and it is why this guard was never the whole + answer. The whole answer is the marker symbol: a dev build defines + [flan.abi.x86] or [flan.abi.llvm] according to which backend emitted it, + each backend's redefinition module holds a pointer to its own, and the + loader has to resolve that pointer while it maps the object — so a crossed + pair is refused at [dlopen], naming both backends, before any new body + runs. That landed; this check is the cheap first line rather than the only + one. See docs/handoffs/HANDOFF-x86-aggregates.md and + docs/handoffs/HANDOFF-x86-abi-marker.md. *) if opts.x86 then failwith "--x86: Build.shared is the LLVM redefinition path, and an --x86 host \