kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 1604e6a34af780121e05fcdf883b8caf90295d8c
parent 7f8eab153bbe7861f2466909b1e0b71ad9488730
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 10 Jun 2026 07:56:22 -0700

fix(c_target): T1.3 — reject non-absolute data relocations

c_emit_data_symbol derived reloc width as (R_ABS32)?4:8 and rendered every
reloc as an absolute &sym pointer. A PC-relative / section-difference reloc
has no portable C spelling (pcrel is not a constant expression; a
sub-pointer-width address cannot be truncated into a 4-byte slot), and the
width logic mis-sized such slots. Per the design choice, reject any
non-absolute data reloc with a clear compiler_panic instead of silently
emitting a wrong slot. Only R_ABS32/R_ABS64 remain supported.

toy 96_data_relocations / 100_record_data_relocation exercise pcrel-in-data
on every backend, so they now carry a .cbackend.skip on the C path.
Documented in doc/CBACKEND.md.

test-cbackend: toy/C 159 pass/0 fail (96+100 skip as intended), parse/C
467/0. (The unrelated memory_grow_large/C failure is the pre-existing
memgrow bug, tracked separately and left parked.)

Diffstat:
Mdoc/CBACKEND.md | 10++++++++++
Mdoc/plan/TODO.md | 13-------------
Msrc/arch/c_target/c_emit.c | 13+++++++++++++
Atest/toy/cases/100_record_data_relocation.cbackend.skip | 1+
Atest/toy/cases/96_data_relocations.cbackend.skip | 1+
5 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/doc/CBACKEND.md b/doc/CBACKEND.md @@ -223,6 +223,16 @@ and linker resolve the references natively. The relocation slots are sorted by offset, and when any are present the struct is `__attribute__((packed))` so the field layout matches the original byte image exactly. +Only **absolute** data relocations (`R_ABS32` / `R_ABS64`) are emittable this +way, because the slot holds a real address-of value. A PC-relative or +section-difference relocation has no portable C spelling — a pcrel offset is not +a constant expression, and a sub-pointer-width address (e.g. an `@pcrel` into a +4-byte `i32` slot) cannot be truncated into its slot in standard C. The emitter +therefore `compiler_panic`s on any non-absolute data relocation rather than +silently mis-sizing the slot. Toy cases that exercise pcrel-in-data +(`96_data_relocations`, `100_record_data_relocation`) carry a `.cbackend.skip` +on the C path for this reason. + TLS delegates entirely to `_Thread_local`; the host compiler builds its own descriptor. On Mach-O, where TLS is split into a descriptor symbol plus a synthesized init symbol (see [OBJ.md](OBJ.md)), the emitter pulls the initial diff --git a/doc/plan/TODO.md b/doc/plan/TODO.md @@ -73,19 +73,6 @@ Add new deferred fixes below as they are discovered. which programs compile vs panic, so it must be a reviewed change, NOT folded into a dedup. Unblocks A.2 (below). -## Design-needed (not a quick fix) - -- **c_target data relocations (T1.3 / D.5).** `c_emit_data_symbol` - (`src/arch/c_target/c_emit.c:3846, 3911`) hardcodes reloc width `(kind==R_ABS32)?4:8` - and renders every reloc as an absolute pointer; a sub-pointer-width address reloc - (`@pcrel` into a 4-byte `i32` slot, e.g. toy tests 96/100) overflows the slot. - Root issue is fundamental: the C backend cannot put a real `&sym` (8 bytes) into a - 4-byte slot in portable C, and a true PC-relative/section-diff offset is not a C - constant expression. Needs a design decision: **either** reject such relocs - (`compiler_panic`) and mark tests 96/100 `SKIP` on `/C`, **or** emit runtime - init-time fixups. (A naive panic-on-non-absolute was tried and reverted — it broke - 96/100, which intentionally exercise pcrel-in-data on every backend incl. C.) - ## Deferred dedups & abstraction cleanups ("use the shared seam") - **A.2 — optimizer-path inline-asm dedup.** The three `aa_/x64_/rv_asm_block_native` diff --git a/src/arch/c_target/c_emit.c b/src/arch/c_target/c_emit.c @@ -3798,6 +3798,19 @@ static void c_emit_data_symbol(CTarget* t, ObjSymId id, const ObjSym* os) { } rs[k] = tmp; } + /* The C backend can only render an absolute address (&sym as a pointer + * value) into a data slot. A PC-relative or section-difference reloc is + * not a C constant expression, and a sub-pointer-width address cannot be + * truncated into its slot in portable C — reject those rather than + * silently mis-size the slot (the width logic below assumes ABS32/ABS64). */ + for (u32 i = 0; i < nrelocs; ++i) { + if (rs[i]->kind != R_ABS32 && rs[i]->kind != R_ABS64) + compiler_panic(t->c, (SrcLoc){0, 0, 0}, + "C target: unsupported non-absolute data relocation " + "(kind %u) targeting '%s'; the C backend emits only " + "absolute (R_ABS32/R_ABS64) data relocations", + (unsigned)rs[i]->kind, c_sym_name(t, rs[i]->sym)); + } } cbuf_puts(b, "struct "); diff --git a/test/toy/cases/100_record_data_relocation.cbackend.skip b/test/toy/cases/100_record_data_relocation.cbackend.skip @@ -0,0 +1 @@ +C backend rejects non-absolute (pcrel/section-diff) data relocations (T1.3): a PC-relative offset is not a C constant expression and cannot fit a sub-pointer-width slot in portable C. diff --git a/test/toy/cases/96_data_relocations.cbackend.skip b/test/toy/cases/96_data_relocations.cbackend.skip @@ -0,0 +1 @@ +C backend rejects non-absolute (pcrel/section-diff) data relocations (T1.3): a PC-relative offset is not a C constant expression and cannot fit a sub-pointer-width slot in portable C.