// 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 main; import os; 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; };