w6l+selfhost: dynamic-link + .data — shared R+W segment

.data now lives at the end of the dyn-path R+W PT_LOAD, just after
.dynamic. The single segment covers .got.plt + .dynamic + .data; its
filesz drops trailing zeros (BSS) while memsz spans the full extent.

Relocation moves from main.c into each emit function so the static
and dynamic paths use their own data_va — text→data refs land on the
right VA regardless of path. Removes the early-error in dynout.c
that previously refused any .data with -l/-L.

Tests: 810_dyn gains two new dyn+.data fixtures (mutable read+write
of an i32, plus a zero-init i64 verifying the BSS scan still produces
a valid p_filesz<p_memsz under the shared segment).
This commit is contained in:
2026-05-12 13:50:09 +09:00
parent 2480f4c272
commit a9b804935c
8 changed files with 150 additions and 82 deletions

View File

@@ -115,20 +115,9 @@ main(int argc, char **argv)
if (l_load(&l, inputs[i]) != 0) return 1;
}
if (l_resolve(&l) != 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;
/* Relocation is deferred to the emit functions — each path knows
* its own layout (text_va, data_va), and the static and dynamic
* paths place .data at different VAs. */
Lsym *entry = l_lookup(&l, "_start");
if (entry == NULL || !entry->defined) entry = l_lookup(&l, "main");