The wrapper was called flan.dev.ctor, and that is a name Flan can reach: (defn dev.ctor [] i32 7) mangles onto exactly it. The program compiles and runs as a release build and fails a dev build with a redefinition clang refuses -- loud, and only under LLVM with --dev, but mangle.ml's own comment exists to make it impossible rather than loud. The name is [Mangle.dev_ctor] now and starts with the dot no reader token can produce, beside .init-globals and .init-data. The colliding program builds and prints 7. Two comments in survey.sh, both of them reasoning rather than behaviour. The counts argument against a per-name -O0 list was no argument: excluding moves the counts just as much. What actually carries it is that dies_segv builds both programs at -O0 on both backends and asserts more than this sweep would. And dev-segv's park under --dev is a forever-list reason that happens to land on a program this list already covers, not a second reason for this list. FIX.org takes the sweep, and one thing the sweep cannot say: the two heap cases of bytes-copy.flan leak 24 bytes through flan_bytes_dup, measured with --leak-check=full, and both corpora are blind to it by policy -- detect_leaks=0 on one side and --leak-check=no on the other. The row proves the copy is in bounds and written. It says nothing about who frees it, and a green sweep should not be read as though it did.
63 lines
3.3 KiB
OCaml
63 lines
3.3 KiB
OCaml
(* The symbol names a Flan build puts into an object, spelled once.
|
|
|
|
Both backends emit the same names — that is not a nicety, it is the link:
|
|
an [--x86] host and a redefinition module built by LLVM bind against each
|
|
other, so [@"flan.cell.<n>"] has to be byte-for-byte the same string on
|
|
both sides or the dlopen fails and the piece served nothing. The macro
|
|
loader and the daemon's disassembler look up the same names from outside
|
|
the backends entirely.
|
|
|
|
So the prefixes live here, unquoted and without a sigil. Quoting is each
|
|
backend's own — LLVM writes [@"..."], the assembler writes ["..."] — and a
|
|
Flan name holds -, ?, > and /, which is why every emitted name is quoted
|
|
at all. This module only decides *which string* is quoted.
|
|
|
|
Not here: the ABI marker itself. [Emit.abi_marker] is ["flan.abi.llvm"] and
|
|
[X86.abi_marker] is ["flan.abi.x86"], and the two must stay distinct —
|
|
a crossed pair is refused at [dlopen] precisely because the marker one
|
|
image defines is not the one the other references. Sharing that string
|
|
would delete the mechanism. The *label* a module hangs its requirement on
|
|
is the other half of that mechanism and is shared, so it is here: see
|
|
[abi_require] below. *)
|
|
|
|
(* The prefix itself. It keeps the Flan [main] from colliding with C's, and
|
|
it is what makes every Flan symbol recognisable in a disassembly. *)
|
|
let prefix = "flan."
|
|
|
|
(* A function or a global. One namespace, because the language has one: a
|
|
[defn] and a [defonce] cannot share a name, so nothing here has to keep
|
|
them apart. The compiler's own names go through this too — [.init-globals]
|
|
and [.init-data] start with a dot no reader token can produce. *)
|
|
let sym n = prefix ^ n
|
|
|
|
(* The single constructor a dev build emits, which calls the runtime's two
|
|
enable entry points — the allocation registry and the crash handler — in
|
|
that order. It goes through [sym] with a leading dot for exactly the reason
|
|
that comment gives, and the reason is not decoration: the first spelling of
|
|
this was a plain [flan.dev.ctor], which is what [(defn dev.ctor [] i32 7)]
|
|
mangles to. That program compiles and runs as a release build and fails a
|
|
dev build with a redefinition clang refuses. A dot is what no reader token
|
|
can produce, so there is no Flan name that reaches this one. *)
|
|
let dev_ctor = prefix ^ ".dev-ctor"
|
|
|
|
(* A dev build's indirection cell: a mutable global holding the address of the
|
|
function that is currently this name's body. *)
|
|
let cell n = prefix ^ "cell." ^ n
|
|
|
|
(* The two module-local caches a name the host was never built with is reached
|
|
through — one for a function, one for a global. *)
|
|
let cellptr n = prefix ^ "cellp." ^ n
|
|
let globalptr n = prefix ^ "gp." ^ n
|
|
|
|
(* A compiled macro's entry point, which the expander dlsyms by this name out
|
|
of the module [Build.macro_module] wrote. *)
|
|
let macro n = prefix ^ "macro." ^ n
|
|
|
|
(* The datum a redefinition module puts its host's ABI marker into. Nothing
|
|
outside the module names it — the relocation against the marker is the
|
|
whole of what it does — but both backends emit it, so the string is spelled
|
|
once here rather than twice, beside every other name that has to read the
|
|
same on both sides. What it *holds* is each backend's own marker, and that
|
|
pair stays distinct; see the paragraph at the top. *)
|
|
let abi_require = prefix ^ "abi.require"
|