Files
ww/selfhost/cmd/w6l/pass.ww
Hojun-Cho 5006bf4fb9 w6l: link GNU long-name archive members; bad members fail the link
The archive walk skipped every member whose header name starts
with '/', which also dropped GNU long-name members (/N) -- any
member with a >15-char filename silently never linked. Only '/ '
(symbol index) and '//' (long-name table) are non-objects; /N
members index by content (names are never consulted). A member
that fails loadimage in the selective pull also stayed silently
unlinked with rc=0; it now reports and fails the link (rule 7).
wwstage w6l diagnostics ride the same .len idiom as the w6a sweep.
2026-08-09 01:07:19 +09:00

128 lines
3.0 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) {
let wm1: str = "w6l: undefined reference to '";
os.write(2, wm1.ptr, wm1.len: u64);
let nm: str = r2.sym.name;
os.write(2, nm.ptr, nm.len: u64);
let wm2: str = "'\n";
os.write(2, wm2.ptr, wm2.len: u64);
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:
let wm3: str = "w6l: unsupported reloc kind\n";
os.write(2, wm3.ptr, wm3.len: u64);
l.errs += 1;
};
};
};
r = r.rnext;
};
return l.errs;
};