From 0e0ee4052877d277ad912b9d35b8849a884a89e1 Mon Sep 17 00:00:00 2001 From: agra Date: Tue, 16 Jun 2026 09:05:15 +0300 Subject: [PATCH] =?UTF-8?q?docs(asm):=20symbol=20refs=20are=20portable=20?= =?UTF-8?q?=E2=80=94=20explain=20the=20auto-:c=20mechanism?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates the symbol-operand guide: x86 now uses the same plain %[fn] as aarch64, and a 'How the portability works' note explains the mechanism (compiler auto-injects LLVM's :c modifier for "s" operands, equivalent to GCC :P/%P0 for x86 calls, no-op on aarch64, overridable). Drops the stale per-arch :P guidance; checkpoint updated. --- current/CHECKPOINT-ASM.md | 13 ++++++++++--- docs/inline-assembly.md | 32 ++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/current/CHECKPOINT-ASM.md b/current/CHECKPOINT-ASM.md index cd8c1b0..c600c58 100644 --- a/current/CHECKPOINT-ASM.md +++ b/current/CHECKPOINT-ASM.md @@ -372,9 +372,16 @@ Orthogonal: **issue 0137** (no-`main` segfault). arches: 1657 read-write (`"incq ${0}","=r,0"`), 1658 indirect (`"movq $$42, ${0}","=*m"`(ptr elementtype)), 1659 symbol (`"call ${2:P}"`, direct call). x86 templates validated by cross-emitting an object (integrated assembler accepts; - objdump confirms 1659's direct `call` reloc). **Note:** x86 direct calls need - the `P` operand modifier (`%[fn:P]`); aarch64 `bl %[fn]` needs none. Pure - additive locks. `zig build test` green (668 corpus, 446 unit). + objdump confirms 1659's direct `call` reloc). Pure additive locks. `zig build + test` green (668 corpus, 446 unit). +- (symbol portability) made `%[fn]` portable across arches — `renderAsmTemplate` + auto-injects LLVM's `:c` modifier (`${N}`→`${N:c}`) for symbol (`"s"`) operands + lacking an explicit modifier (`asmNamedIsSymbol` helper). Without it x86 renders + `$cb` (a bad `call` target needing a hand-written `:P`); aarch64 unaffected. + Verified `:c` ≡ `:P` for x86-64 calls (both → `R_X86_64_PLT32`). Explicit + `%[fn:X]` still wins (escape hatch). 1659 dropped its `:P` → same plain `%[fn]` + as aarch64 1656; both IRs regen to `${N:c}`. `zig build test` green (668 corpus, + 446 unit). ## Known issues - **0138** — RESOLVED. `@const` (address-of a `::` comptime constant) yielded a diff --git a/docs/inline-assembly.md b/docs/inline-assembly.md index 2ad6d98..a85dff4 100644 --- a/docs/inline-assembly.md +++ b/docs/inline-assembly.md @@ -79,20 +79,11 @@ ASM, } ``` -Two reasons to prefer this over passing a function *pointer* in a plain -`"r"` register and using an indirect `blr`/`call *`: - -- **One fewer indirection** — a direct PC-relative branch, no pointer - load into a register, and a predictable (non-indirect) branch. -- **Portable** — the backend emits the correctly-mangled name, so you - don't hardcode the macOS leading underscore. - -On **x86_64**, a direct `call` to a symbol operand needs the `P` -("call-target") operand modifier — `%[name:P]` (the GCC `%P0` idiom): +The same `%[fn]` works on **x86_64** — just the branch mnemonic differs: ```sx return asm volatile { - "call %[fn:P]", // x86_64 — note the :P modifier + "call %[fn]", // x86_64 — same portable %[fn] [ret] "={rax}" -> i64, "{rdi}" = n, [fn] "s" = cb, @@ -100,7 +91,24 @@ return asm volatile { }; ``` -aarch64 `bl %[fn]` needs no modifier. +Two reasons to prefer this over passing a function *pointer* in a plain +`"r"` register and using an indirect `blr`/`call *`: + +- **One fewer indirection** — a direct PC-relative branch, no pointer + load into a register, and a predictable (non-indirect) branch. +- **Portable** — `%[fn]` is the same on every target; the backend emits + the correctly-mangled name, so you never hardcode the macOS leading + underscore *or* a per-arch operand modifier. + +**How the portability works.** A bare `%[fn]` would render differently +per target — on x86 the symbol prints as `$cb` (an immediate `$`-prefix +that `call` rejects), while aarch64 prints it bare. So for a symbol (`"s"`) +operand the compiler **auto-injects LLVM's `:c` operand modifier** (`%[fn]` +→ `${N:c}`, "print the constant with no punctuation"). `:c` prints the +plain symbol on every target — equivalent to the GCC `:P`/`%P0` call-target +idiom on x86 (both emit the same `R_X86_64_PLT32` relocation) and a no-op +on aarch64. You can still override it with an explicit `%[fn:X]` if you +ever need a different rendering, but for a call/branch you never should. The callee needs a stable, externally-linked symbol — i.e. `export` (which also gives it the C ABI). A plain or `callconv(.c)`-only function