/* * pass.c — resolution + relocation. After all objects are loaded: * * l_resolve : check that every symbol referenced by a relocation * is defined somewhere. Errors get logged. * l_relocate: with the final virtual base address known, walk the * relocation list and patch the .text bytes in place. * * Supported relocation kinds: PC32 (2), PLT32 (4). Both are PC-relative * 32-bit displacements; for static linking PLT32 collapses to PC32. */ #include "l.h" #include #include #define R_X86_64_PC32 2 #define R_X86_64_PLT32 4 int l_resolve(Lnk *l) { for (Lrel *r = l->rels; r; r = r->next) { if (r->sym == NULL) continue; if (!r->sym->defined) { fprintf(stderr, "6l: undefined reference to '%s'\n", r->sym->name); l->errs++; } } return l->errs; } static void patch_u32(u8 *p, u32 v) { p[0] = (u8)(v & 0xff); p[1] = (u8)((v >> 8) & 0xff); p[2] = (u8)((v >> 16) & 0xff); p[3] = (u8)((v >> 24) & 0xff); } int l_relocate(Lnk *l, u64 base) { for (Lrel *r = l->rels; r; r = r->next) { if (r->sym == NULL || !r->sym->defined) continue; switch (r->kind) { case R_X86_64_PC32: case R_X86_64_PLT32: { u64 site = base + r->off; i64 target = (i64)(base + r->sym->val); i64 rel = target - (i64)site + r->addend; patch_u32(l->text + r->off, (u32)(i32)rel); break; } default: fprintf(stderr, "6l: unsupported reloc kind %d\n", r->kind); l->errs++; } } return l->errs; }