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.
128 lines
3.0 KiB
Plaintext
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;
|
|
};
|