w6l: route writable globals into a second PT_LOAD

Second step toward top-level mutable `let`. The static path now loads
.data PROGBITS sections from input .o files, page-aligns them after
.text, and emits a second PT_LOAD (R+W) covering them. Relocations
targeting data symbols compute against the data VA; text→text
displacements still cancel the absolute VAs and stay correct.

Inputs without any .data keep the original single-PT_LOAD layout
byte-for-byte — 992 (selfhost w6l .o diff) and 995 (self-rebuild)
depend on that invariant.

Dynamic-link path (-l/-L) rejects .data for now with a clear error;
folding writable globals into the existing R+W segment alongside
.got.plt/.dynamic is a follow-up.
This commit is contained in:
2026-05-12 11:42:30 +09:00
parent 1b0955c97b
commit 38e0b6510a
8 changed files with 406 additions and 34 deletions

View File

@@ -115,7 +115,20 @@ main(int argc, char **argv)
if (l_load(&l, inputs[i]) != 0) return 1;
}
if (l_resolve(&l) != 0) return 1;
if (l_relocate(&l, base + 0x1000) != 0) return 1;
/* Layout for relocation purposes. The static path (out.c) uses
* text_va = base + 0x1000 and places .data at the next page after
* .text — these must agree with the layout in out.c. PC-relative
* displacements between .text symbols cancel the absolute VAs, so
* a dyn-path link whose data_va is "wrong" still relocates text→
* text correctly; text→data is currently rejected in dynout.c. */
u64 text_va = base + 0x1000;
u64 data_va = 0;
if (l.datalen > 0) {
u64 page = 0x1000;
u64 data_off = (0x1000 + l.textlen + page - 1) & ~(page - 1);
data_va = base + data_off;
}
if (l_relocate(&l, text_va, data_va) != 0) return 1;
Lsym *entry = l_lookup(&l, "_start");
if (entry == NULL || !entry->defined) entry = l_lookup(&l, "main");