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

@@ -298,18 +298,9 @@ export fn main(argc: i32, argv: **u8) i32 = {
};
if (resolve(l) != 0) { return 1; };
// Static layout for relocation purposes. .data lands at the
// next page after .text; the dyn path overrides if its layout
// is different (text→text PC32 cancels the absolute VA so
// only the data delta matters here).
let textva: u64 = BASE + CODE_VA_OFF;
let datava: u64 = 0u64;
if (l.datalen > 0u64) {
let page: u64 = 4096u64;
let dataoff: u64 = (CODE_VA_OFF + l.textlen + page - 1u64) & ~(page - 1u64);
datava = BASE + dataoff;
};
if (relocate(l, textva, datava) != 0) { return 1; };
// Relocation is deferred to the emit functions — each path
// knows its own layout (textva, datava); the static and dyn
// paths place .data at different VAs.
let entrysym: *lsym = lookup(l, "_start");
if (entrysym == nil) { entrysym = lookup(l, "main"); }