/* * 992_w6l_ww — phase-10 marker for the ww-side w6l port. * * Diffs the C-built `w6l` against the ww-built `w6l_ww` on a corpus of * link inputs. Both must produce byte-identical static ELF binaries. * The corpus mixes: * - a single .o input (no archive resolution) * - a .o + libwwrt.a link, exercising the SysV `ar` two-pass loader * * Any divergence is a port bug in selfhost/cmd/w6l/. */ #include #include #include #include #include static int runwait(const char *cmd) { int rc = system(cmd); if (rc == -1) return -1; if (WIFEXITED(rc)) return WEXITSTATUS(rc); return 1; } static const char * absbin(void) { const char *b = getenv("BIN"); if (!b) b = "out/bin"; if (b[0] == '/') return b; static char buf[2048]; char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return NULL; snprintf(buf, sizeof buf, "%s/%s", cwd, b); return buf; } static int slurp(const char *path, char **outbuf, size_t *outlen) { FILE *f = fopen(path, "rb"); if (!f) return -1; fseek(f, 0, SEEK_END); long n = ftell(f); fseek(f, 0, SEEK_SET); if (n < 0) { fclose(f); return -1; } char *b = malloc((size_t)n + 1); if (!b) { fclose(f); return -1; } if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; } b[n] = '\0'; fclose(f); *outbuf = b; *outlen = (size_t)n; return 0; } /* link `inputs` (space-separated, the caller's responsibility to quote) * with both linkers, compare bytes. */ static int diff_one(const char *bin, const char *label, const char *inputs) { char co[64], wo[64], cmd[4096]; snprintf(co, sizeof co, "/tmp/wwl_%d_c", getpid()); snprintf(wo, sizeof wo, "/tmp/wwl_%d_w", getpid()); snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s 2>/dev/null", bin, co, inputs); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww FAIL: C w6l errored on %s\n", label); unlink(co); return -1; } snprintf(cmd, sizeof cmd, "%s/w6l_ww -o %s %s 2>/dev/null", bin, wo, inputs); if (runwait(cmd) != 0) { fprintf(stderr, "w6l_ww FAIL: ww w6l errored on %s\n", label); unlink(co); unlink(wo); return -1; } char *bc = NULL, *bw = NULL; size_t nc = 0, nw = 0; int rc = 0; if (slurp(co, &bc, &nc) < 0 || slurp(wo, &bw, &nw) < 0) { fprintf(stderr, "w6l_ww FAIL: cannot read output for %s\n", label); rc = -1; } else if (nc != nw || memcmp(bc, bw, nc) != 0) { fprintf(stderr, "w6l_ww FAIL: %s — C %zu vs ww %zu bytes\n", label, nc, nw); rc = -1; } free(bc); free(bw); unlink(co); unlink(wo); return rc; } int main(void) { const char *bin = absbin(); if (!bin) return 1; char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; struct { const char *label; const char *inputs_fmt; /* %s = cwd */ } cases[] = { /* Real bootstrap-style links: every selfhost main.o paired * with libwwrt.a. Exercises both the .o code path and the * archive two-pass loader (rt_malloc / rt_syscall / rt_abort * are pulled from libwwrt.a as undefs are encountered). */ { "wwdump+libwwrt", "%s/selfhost/cmd/wwdump/main.o %s/out/lib/libwwrt.a" }, { "w6a+libwwrt", "%s/selfhost/cmd/w6a/main.o %s/out/lib/libwwrt.a" }, { "w6l+libwwrt", "%s/selfhost/cmd/w6l/main.o %s/out/lib/libwwrt.a" }, { NULL, NULL }, }; int fail = 0; int n = 0; for (int i = 0; cases[i].label; i++) { char inputs[2048]; snprintf(inputs, sizeof inputs, cases[i].inputs_fmt, cwd, cwd); if (diff_one(bin, cases[i].label, inputs) != 0) fail++; n++; } if (fail) { fprintf(stderr, "w6l_ww: %d/%d diff(s) failed\n", fail, n); return 1; } printf("w6l_ww: byte-identical to C w6l on %d corpus links " "(.o + libwwrt.a archive resolution)\n", n); return 0; }