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

@@ -28,8 +28,12 @@ typedef struct Lnk Lnk;
struct Lsym {
const char *name;
u64 val; /* offset within combined .text once linked */
u64 val; /* offset within combined .text (or .data when
* in_data=1) once linked */
int defined; /* 1 if a Lobj defines this symbol */
int in_data; /* 1 if defined in .data (writable globals);
* 0 means .text (the default). Mutually
* exclusive with is_dyn. */
Lobj *owner;
int idx_in_owner;
/* Dynamic-linking fields. Set by l_resolve when an undefined sym
@@ -57,6 +61,8 @@ struct Lobj {
u64 len;
u64 text_off; /* offset of .text in combined output */
u64 text_size;
u64 data_off; /* offset of .data in combined output */
u64 data_size; /* bytes contributed to combined .data (0 if none) */
Lobj *next;
};
@@ -76,6 +82,9 @@ struct Lnk {
Lrel *rels;
u8 *text; /* combined .text */
u64 textcap, textlen;
u8 *data; /* combined .data (writable). Empty unless any
* input .o has a .data PROGBITS section. */
u64 datacap, datalen;
int errs;
int dyn_n; /* number of symbols routed through PLT */
};
@@ -94,7 +103,11 @@ Lsym *l_intern(Lnk*, const char *name);
Lsym *l_lookup(Lnk*, const char *name);
/* pass.c */
int l_resolve(Lnk*);
int l_relocate(Lnk*, u64 base);
/* Patch relocations in l->text. text_va is the VA where .text will be
* mapped; data_va is the VA where .data will be mapped (pass 0 if no
* data symbols). PC32/PLT32 displacements between text symbols cancel
* the absolute VA, but data targets need the real data_va. */
int l_relocate(Lnk*, u64 text_va, u64 data_va);
/* out.c */
int l_emit_elf(Lnk*, FILE *out, u64 base, u64 entry);
/* dynout.c — emit a dynamic-linked ELF executable. Called by