// selfhost/cmd/6l/pass.ww — port of cmd/6l/pass.c. // // Resolution + relocation. l_resolve flags every undefined symbol // referenced by a relocation, and promotes those provided by some // loaded .so to "dynamic" with a freshly-assigned PLT slot. // l_relocate walks the rel list and patches the .text bytes in place // once the final virtual base is known. Dynamic refs are deferred: // their site is patched later in dynout, once the PLT vaddr is known. // // Supported relocation kinds: PC32 (=2), PLT32 (=4); both are 32-bit // PC-relative displacements (PLT32 == PC32 for static). use os; use sym; use dyn; def R_X86_64_PC32: i32 = 2; def R_X86_64_PLT32: i32 = 4; export fn l_resolve(l: *lnk) i32 = { // Initialise dynamic-linking sentinels. amalloc zeroes, so // is_dyn/dyn_lib start clean — but plt_idx and dynsym_idx // must be -1, not 0. let si: *lsym = l.syms; for (si != nil) { si.plt_idx = -1; si.dynsym_idx = -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) { let sym: *lsym = r.sym; if (sym.is_dyn == 0) { let so: *lso = l.sos; for (so != nil) { if (l_so_provides(so, sym.name) != 0) { sym.is_dyn = 1; sym.dyn_lib = so; sym.plt_idx = l.dyn_n; l.dyn_n += 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.is_dyn == 0) { os.write(2, "6l: 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 patch_u32(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; }; export fn l_relocate(l: *lnk, base: 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.is_dyn != 0) { r = r.rnext; continue; }; if (r.sym.defined != 0) { let k: i32 = r.kind; if (k == R_X86_64_PC32) { let site: u64 = base + r.off; let target: i64 = (base + r.sym.val): i64; let rel: i64 = (target - site: i64) + r.addend; patch_u32(l.text + r.off, rel: u32); } else { if (k == R_X86_64_PLT32) { let site: u64 = base + r.off; let target: i64 = (base + r.sym.val): i64; let rel: i64 = (target - site: i64) + r.addend; patch_u32(l.text + r.off, rel: u32); } else { os.write(2, "6l: unsupported reloc kind\n".ptr, 27u64); l.errs += 1; };}; }; }; r = r.rnext; }; return l.errs; };