Files
ww/cmd/w6l/pass.c
Hojun-Cho 2c33228b7e ww: rename toolchain to w-prefix + hare-style build/run/test driver
Plan 9-style w-prefix on the per-arch tools, disambiguating from the
real Plan 9 6c/6a/6l in ref/plan9front/:

    cmd/wwc/      → cmd/wcc/        libwwc.a → libwcc.a
    cmd/6{c,a,l}  → cmd/w6{c,a,l}   binary names too
    test/wwc/     → test/wcc/       6 test files w/ w6 prefix
    selfhost/cmd  mirror in lockstep
    bootstrap/amd64/{w6c,w6a,w6l}   snapshot binaries (gitignored)
    WW_6{C,A,L}   → WW_W6{C,A,L}    env-var overrides

Plan 9 source-tree refs ("Plan 9 6c shape", ref/plan9front/, etc.)
preserved. Hare-style driver, both C and ww sides:

    ww test [path]   discover *_test.ww in a directory module, run
                     each; single-file mode for `ww test foo.ww`
    Module-by-name   `ww build foo` resolves to foo.ww or foo/foo.ww
                     via search path (cwd : -I dirs : $WW_LIB)
    Default-to-cwd   `ww build` / `ww test` build the cwd module
    Run pass-through `ww run path arg1 arg2` reaches the program

lib/os: getcwd (79) and getdents64 (217) syscalls power `.` resolution
and directory enumeration on the ww side.

Makefile: wwstage tool deps now include lib/os/os.ww (+ lib/strconv
for wwdump_ww) so lib/* edits force their rebuild instead of leaving
stale binaries — surfaced when test 995 first failed against a stale
w6c_ww built before the lib/os additions.

Test 993 byte-identical parity gate (C-side ww vs ww-side ww_ww on a
build corpus) stays green; all 19 tests pass.
2026-05-11 13:49:27 +09:00

96 lines
2.6 KiB
C

/*
* 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 <stdio.h>
#include <string.h>
#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; /* already promoted */
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;
}
}
}
/* What remains undefined truly is undefined. */
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);
}
int
l_relocate(Lnk *l, u64 base)
{
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;
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, "w6l: unsupported reloc kind %d\n",
r->kind);
l->errs++;
}
}
return l->errs;
}