// selfhost/cmd/6l/pass.ww — port of cmd/6l/pass.c. // // Resolution + relocation. l_resolve flags every undefined symbol // referenced by a relocation. l_relocate walks the rel list and // patches the .text bytes in place once the final virtual base is // known. Supported relocation kinds: PC32 (=2), PLT32 (=4); both // are 32-bit PC-relative displacements (PLT32 == PC32 for static). use os; use sym; def R_X86_64_PC32: i32 = 2; def R_X86_64_PLT32: i32 = 4; export fn l_resolve(l: *lnk) i32 = { let r: *lrel = l.rels; for (r != nil) { if (r.sym != nil) { if (r.sym.defined == 0) { os.write(2, "6l: undefined reference to '".ptr, 28u64); let nm: str = r.sym.name; os.write(2, nm.ptr, nm.len: u64); os.write(2, "'\n".ptr, 2u64); l.errs += 1; }; }; r = r.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) { 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; };