selfhost/, cmd/, internal/ join the tree-wide sweep: every section banner dies (91 selfhost + the cmd C-style dividers -> 0); narration and stale contracts deleted (pre-#22 bundler notes, retired single-PT_LOAD and no-archive claims, superseded ABI tables); every ref/harec/qbe cite, task cite, encoding/ELF contract, and rule-10 twin pointer kept; lost lifetime/rationale lines restored where the sweep over-cut (elf_globals ownership, kwtab linear-scan). Comment- only proven: all five wwstage tool binaries byte-identical across the sweep; test-commit, test-byteid (161+1399, 0 pinned-divergent), and test-bootstrap (fixed point + 991-995 byte-id) all exit 0. The read-through banked 66 latent-bug leads (checkpoint).
125 lines
2.9 KiB
Plaintext
125 lines
2.9 KiB
Plaintext
// Port of cmd/w6l/pass.c.
|
|
//
|
|
// Supported relocation kinds: PC32 (=2), PLT32 (=4); both are 32-bit
|
|
// PC-relative displacements (PLT32 == PC32 for static).
|
|
|
|
package w6l;
|
|
|
|
import os;
|
|
import sym;
|
|
import dyn;
|
|
|
|
def R_X86_64_64: i32 = 1;
|
|
def R_X86_64_PC32: i32 = 2;
|
|
def R_X86_64_PLT32: i32 = 4;
|
|
|
|
export fn resolve(l: *lnk) i32 = {
|
|
// Initialise dynamic-linking sentinels. alloc(T{})! zeroes, so
|
|
// isdyn/dynlib start clean — but pltidx and dynsymidx
|
|
// must be -1, not 0.
|
|
let si: *lsym = l.syms;
|
|
for (si != nil) {
|
|
si.pltidx = -1;
|
|
si.dynsymidx = -1;
|
|
si = si.snext;
|
|
};
|
|
|
|
// Promote each undefined sym that some lso exports to dynamic
|
|
// and hand it a PLT slot. Iteration order over the relocation
|
|
// list determines slot numbering and is stable across runs.
|
|
let r: *lrel = l.rels;
|
|
for (r != nil) {
|
|
if (r.sym != nil) {
|
|
if (r.sym.defined == 0) {
|
|
if (r.sym.isdyn == 0) {
|
|
let so: *lso = l.sos;
|
|
for (so != nil) {
|
|
if (soprovides(so, r.sym.name) != 0) {
|
|
r.sym.isdyn = 1;
|
|
r.sym.dynlib = so;
|
|
r.sym.pltidx = l.dynn;
|
|
l.dynn += 1;
|
|
so = nil; // break
|
|
} else {
|
|
so = so.sonext;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
r = r.rnext;
|
|
};
|
|
|
|
// What remains undefined truly is undefined.
|
|
let r2: *lrel = l.rels;
|
|
for (r2 != nil) {
|
|
if (r2.sym != nil) {
|
|
if (r2.sym.defined == 0) {
|
|
if (r2.sym.isdyn == 0) {
|
|
os.write(2, "w6l: undefined reference to '".ptr, 28u64);
|
|
let nm: str = r2.sym.name;
|
|
os.write(2, nm.ptr, nm.len: u64);
|
|
os.write(2, "'\n".ptr, 2u64);
|
|
l.errs += 1;
|
|
};
|
|
};
|
|
};
|
|
r2 = r2.rnext;
|
|
};
|
|
return l.errs;
|
|
};
|
|
|
|
fn patchu32(p: *u8, v: u32) void = {
|
|
p[0] = (v & 255u32): u8;
|
|
p[1] = ((v >> 8u32) & 255u32): u8;
|
|
p[2] = ((v >> 16u32) & 255u32): u8;
|
|
p[3] = ((v >> 24u32) & 255u32): u8;
|
|
};
|
|
|
|
fn patchu64(p: *u8, v: u64) void = {
|
|
let i: i32 = 0;
|
|
for (i < 8) {
|
|
p[i] = ((v >> (i: u64 * 8u64)) & 255u64): u8;
|
|
i += 1;
|
|
};
|
|
};
|
|
|
|
export fn relocate(l: *lnk, textva: u64, datava: u64) i32 = {
|
|
let r: *lrel = l.rels;
|
|
for (r != nil) {
|
|
if (r.sym != nil) {
|
|
// Dynamic refs are patched later in dynout once the
|
|
// PLT vaddr is known.
|
|
if (r.sym.isdyn != 0) {
|
|
r = r.rnext;
|
|
continue;
|
|
};
|
|
if (r.sym.defined != 0) {
|
|
let symva: u64 = textva + r.sym.val;
|
|
if (r.sym.indata != 0) { symva = datava + r.sym.val; };
|
|
let k: i32 = r.kind;
|
|
switch (k) {
|
|
case R_X86_64_PC32,R_X86_64_PLT32:
|
|
let site: u64 = textva + r.off;
|
|
let rel: i64 = (symva: i64 - site: i64) + r.addend;
|
|
patchu32(l.text + r.off, rel: u32);
|
|
case R_X86_64_64:
|
|
// Absolute 64-bit. Currently used only
|
|
// for DATAR slots in .data.
|
|
let v: u64 = (symva: i64 + r.addend): u64;
|
|
if (r.section == 1) {
|
|
patchu64(l.data + r.off, v);
|
|
} else {
|
|
patchu64(l.text + r.off, v);
|
|
};
|
|
case:
|
|
os.write(2, "w6l: unsupported reloc kind\n".ptr, 27u64);
|
|
l.errs += 1;
|
|
};
|
|
};
|
|
};
|
|
r = r.rnext;
|
|
};
|
|
return l.errs;
|
|
};
|