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:
@@ -84,6 +84,19 @@ emit_text(Lnk *l, const u8 *src, u64 n)
|
||||
l->textlen += n;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_data(Lnk *l, const u8 *src, u64 n)
|
||||
{
|
||||
if (l->datalen + n > l->datacap) {
|
||||
u64 nc = l->datacap ? l->datacap * 2 : 256;
|
||||
while (nc < l->datalen + n) nc *= 2;
|
||||
l->data = realloc(l->data, nc);
|
||||
l->datacap = nc;
|
||||
}
|
||||
memcpy(l->data + l->datalen, src, n);
|
||||
l->datalen += n;
|
||||
}
|
||||
|
||||
/* Internal: load a single ELF .o image already in memory. The caller
|
||||
* gives us the bytes (we own them) and a path tag for diagnostics.
|
||||
* If the bytes look like an archive (magic "!<arch>\n") we recurse
|
||||
@@ -116,12 +129,15 @@ elf_globals(const u8 *buf, u64 len)
|
||||
Ehdr *eh = (Ehdr *)buf;
|
||||
if (memcmp(eh->e_ident, "\x7f""ELF", 4) != 0) return NULL;
|
||||
Shdr *sh = (Shdr *)(buf + eh->e_shoff);
|
||||
int idx_text = -1, idx_symtab = -1;
|
||||
int idx_text = -1, idx_data = -1, idx_symtab = -1;
|
||||
const char *shstr = (const char *)(buf + sh[eh->e_shstrndx].sh_offset);
|
||||
for (u16 i = 0; i < eh->e_shnum; i++) {
|
||||
if (sh[i].sh_type == SHT_PROGBITS &&
|
||||
strcmp(shstr + sh[i].sh_name, ".text") == 0)
|
||||
idx_text = i;
|
||||
else if (sh[i].sh_type == SHT_PROGBITS &&
|
||||
strcmp(shstr + sh[i].sh_name, ".data") == 0)
|
||||
idx_data = i;
|
||||
else if (sh[i].sh_type == SHT_SYMTAB)
|
||||
idx_symtab = i;
|
||||
}
|
||||
@@ -131,12 +147,15 @@ elf_globals(const u8 *buf, u64 len)
|
||||
u64 nsyms = sh[idx_symtab].sh_size / sizeof(Sym64);
|
||||
const char *str = (const char *)(buf + sh[idx_strtab].sh_offset);
|
||||
|
||||
/* Include both .text and .data globals so archive members that
|
||||
* define a data global get pulled in when something references it. */
|
||||
char **out = calloc(nsyms + 1, sizeof *out);
|
||||
int n = 0;
|
||||
for (u64 i = 1; i < nsyms; i++) {
|
||||
if (symtab[i].st_shndx == 0) continue;
|
||||
if ((symtab[i].st_info >> 4) != 1) continue; /* STB_GLOBAL */
|
||||
if ((int)symtab[i].st_shndx != idx_text) continue;
|
||||
int sx = (int)symtab[i].st_shndx;
|
||||
if (sx != idx_text && sx != idx_data) continue;
|
||||
out[n++] = strdup(str + symtab[i].st_name);
|
||||
}
|
||||
out[n] = NULL;
|
||||
@@ -259,12 +278,15 @@ load_image(Lnk *l, const char *path, u8 *buf, u64 len)
|
||||
if (eh->e_shstrndx >= eh->e_shnum) { free(buf); return -1; }
|
||||
const char *shstr = (const char *)(buf + sh[eh->e_shstrndx].sh_offset);
|
||||
|
||||
/* find .text, .symtab, .strtab, .rela.text */
|
||||
int idx_text = -1, idx_symtab = -1, idx_strtab = -1, idx_rela = -1;
|
||||
/* find .text, .data (optional), .symtab, .strtab, .rela.text */
|
||||
int idx_text = -1, idx_data = -1, idx_symtab = -1, idx_strtab = -1;
|
||||
int idx_rela = -1;
|
||||
for (u16 i = 0; i < eh->e_shnum; i++) {
|
||||
const char *nm = shstr + sh[i].sh_name;
|
||||
if (sh[i].sh_type == SHT_PROGBITS && strcmp(nm, ".text") == 0)
|
||||
idx_text = i;
|
||||
else if (sh[i].sh_type == SHT_PROGBITS && strcmp(nm, ".data") == 0)
|
||||
idx_data = i;
|
||||
else if (sh[i].sh_type == SHT_SYMTAB)
|
||||
idx_symtab = i;
|
||||
else if (sh[i].sh_type == SHT_RELA && strcmp(nm, ".rela.text") == 0)
|
||||
@@ -283,11 +305,15 @@ load_image(Lnk *l, const char *path, u8 *buf, u64 len)
|
||||
ob->len = len;
|
||||
ob->text_off = l->textlen;
|
||||
ob->text_size = sh[idx_text].sh_size;
|
||||
ob->data_off = l->datalen;
|
||||
ob->data_size = (idx_data >= 0) ? sh[idx_data].sh_size : 0;
|
||||
ob->next = l->objs;
|
||||
l->objs = ob;
|
||||
|
||||
/* append .text */
|
||||
/* append .text and (if present) .data */
|
||||
emit_text(l, buf + sh[idx_text].sh_offset, sh[idx_text].sh_size);
|
||||
if (idx_data >= 0 && sh[idx_data].sh_size > 0)
|
||||
emit_data(l, buf + sh[idx_data].sh_offset, sh[idx_data].sh_size);
|
||||
|
||||
/* per-object: load symbols */
|
||||
Sym64 *symtab = (Sym64 *)(buf + sh[idx_symtab].sh_offset);
|
||||
@@ -300,8 +326,10 @@ load_image(Lnk *l, const char *path, u8 *buf, u64 len)
|
||||
const char *nm = str + symtab[i].st_name;
|
||||
if (nm[0] == '\0') continue;
|
||||
Lsym *gs = l_intern(l, nm);
|
||||
if (symtab[i].st_shndx != 0 /* SHN_UNDEF */
|
||||
&& symtab[i].st_shndx == idx_text) {
|
||||
int sx = (int)symtab[i].st_shndx;
|
||||
int in_text = (symtab[i].st_shndx != 0 && sx == idx_text);
|
||||
int in_data = (idx_data >= 0 && sx == idx_data);
|
||||
if (in_text || in_data) {
|
||||
if (gs->defined) {
|
||||
fprintf(stderr, "w6l: %s: duplicate symbol %s\n",
|
||||
path, nm);
|
||||
@@ -310,7 +338,12 @@ load_image(Lnk *l, const char *path, u8 *buf, u64 len)
|
||||
gs->defined = 1;
|
||||
gs->owner = ob;
|
||||
gs->idx_in_owner = (int)i;
|
||||
gs->val = ob->text_off + symtab[i].st_value;
|
||||
if (in_data) {
|
||||
gs->in_data = 1;
|
||||
gs->val = ob->data_off + symtab[i].st_value;
|
||||
} else {
|
||||
gs->val = ob->text_off + symtab[i].st_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
map[i] = gs;
|
||||
|
||||
Reference in New Issue
Block a user