#include "l.h" #include #include #define R_X86_64_64 1 #define R_X86_64_PC32 2 #define R_X86_64_PLT32 4 int l_resolve(Lnk *l) { /* Initialise dynamic-linking fields. plt_idx and dynsym_idx * default to -1; l_intern sets is_dyn/dyn_lib to 0/NULL via * calloc, but we make the invariants explicit here for clarity. */ for (Lsym *s = l->syms; s; s = s->next) { s->plt_idx = -1; s->dynsym_idx = -1; } /* Promote each undefined sym that some Lso exports to "dynamic" * and hand it a PLT slot. Order is the iteration order over the * relocation list; that determines slot numbering and is stable * across runs (rels are pushed onto the head as objects load). */ for (Lrel *r = l->rels; r; r = r->next) { if (r->sym == NULL || r->sym->defined) continue; if (r->sym->is_dyn) continue; for (Lso *so = l->sos; so; so = so->next) { const char *ver = NULL; if (l_so_provides_v(so, r->sym->name, &ver)) { r->sym->is_dyn = 1; r->sym->dyn_lib = so; r->sym->dyn_version = ver; /* may be NULL */ r->sym->plt_idx = l->dyn_n++; break; } } } for (Lrel *r = l->rels; r; r = r->next) { if (r->sym == NULL) continue; if (!r->sym->defined && !r->sym->is_dyn) { fprintf(stderr, "w6l: 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); } static void patch_u64(u8 *p, u64 v) { for (int i = 0; i < 8; i++) p[i] = (u8)((v >> (i * 8)) & 0xff); } int l_relocate(Lnk *l, u64 text_va, u64 data_va) { for (Lrel *r = l->rels; r; r = r->next) { if (r->sym == NULL) continue; /* Dynamic syms are patched later, in l_emit_elf, once the * PLT's virtual address is known. */ if (r->sym->is_dyn) continue; if (!r->sym->defined) continue; u64 sym_va = r->sym->in_data ? data_va + r->sym->val : text_va + r->sym->val; switch (r->kind) { case R_X86_64_PC32: case R_X86_64_PLT32: { /* PC-relative 32-bit displacement; lands in .text. * For static linking PLT32 collapses to PC32. */ u64 site = text_va + r->off; i64 rel = (i64)sym_va - (i64)site + r->addend; patch_u32(l->text + r->off, (u32)(i32)rel); break; } case R_X86_64_64: { /* Absolute 64-bit: patch the 8-byte slot at the * given offset within the section. Currently only * used for data slots holding symbol addresses * (DATAR). */ u64 v = (u64)((i64)sym_va + r->addend); if (r->section == 1) { patch_u64(l->data + r->off, v); } else { patch_u64(l->text + r->off, v); } break; } default: fprintf(stderr, "w6l: unsupported reloc kind %d\n", r->kind); l->errs++; } } return l->errs; }