/* * 989_datargate_run (#59, F15 c5) — w6a must loud-reject a DATAR relocation * whose slot was never defined by a prior DATAW, not silently drop the reloc. * * THE BUG (wwstage w6a only, cat-A silent wrong output under rc=0): asm.ww's * A_DATAR arm, when holder.defined==0 or holder.isdata==0, did `p = p.link; * continue;` with no diagnostic and no errs++ — so the R_X86_64_64 .data * relocation was silently dropped and a rc=0 .o was emitted with a zero-filled * pointer slot (a null pointer at link/runtime). The cstage twin (cmd/w6a/ * asm.c:363) printed a diagnostic + a->errs++, and main returns 1 before * opening the output, so no .o is written. THE FIX: emit a diagnostic and bump * a.errs (encode returns a.errs → main returns 1 before writing the .o). * * row | shape | result (cs & ww agree) * ----+-------------------------------+-------------------------------- * bad | DATAR on a slot with no DATAW | rc != 0, no .o written * ok | DATAW then DATAR on that slot | rc == 0, .o byte-identical (cs==ww) * * bad was RED pre-c5 on wwstage (rc=0, .o with the reloc silently dropped). * ok pins the defined-slot path: both stages rc=0 and a byte-identical .o. */ #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 *BAD = "TEXT f,$0\n\tRET\n\tDATAR x+0(SB), f(SB)\n"; static const char *OK = "TEXT f,$0\n\tRET\n" "DATAW x(SB),\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n" "\tDATAR x+0(SB), f(SB)\n"; static int write_file(const char *path, const char *body) { FILE *f = fopen(path, "wb"); if (!f) return -1; fputs(body, f); fclose(f); return 0; } /* Assemble `src` with `tool` into `obj` (removed first). Returns rc; sets * *exists to whether the .o was created. */ static int assemble(const char *tool, const char *src, const char *obj, int *exists) { char cmd[1024]; unlink(obj); snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", tool, obj, src); int rc = runwait(cmd); if (exists) *exists = (access(obj, F_OK) == 0); return rc; } int main(void) { const char *bin = getenv("BIN"); if (!bin) bin = "out/bin"; char absbin[1024]; if (bin[0] != '/') { char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); bin = absbin; } char ctool[1024], wtool[1024]; snprintf(ctool, sizeof ctool, "%s/w6a", bin); snprintf(wtool, sizeof wtool, "%s/w6a_ww", bin); int have_ww = (access(wtool, X_OK) == 0); if (!have_ww) fprintf(stderr, "datargate: skip wwstage (no %s)\n", wtool); char bads[64], oks[64], co[64], wo[64]; snprintf(bads, sizeof bads, "/tmp/datarg_bad_%d.s", getpid()); snprintf(oks, sizeof oks, "/tmp/datarg_ok_%d.s", getpid()); snprintf(co, sizeof co, "/tmp/datarg_c_%d.o", getpid()); snprintf(wo, sizeof wo, "/tmp/datarg_w_%d.o", getpid()); if (write_file(bads, BAD) || write_file(oks, OK)) return 1; int fail = 0, total = 0, ex; /* bad: both stages loud, no .o */ total++; if (assemble(ctool, bads, co, &ex) == 0 || ex) { fprintf(stderr, "datargate[cstage][bad]: rc=0/.o written on " "undefined DATAR slot\n"); fail++; } if (have_ww) { if (assemble(wtool, bads, wo, &ex) == 0 || ex) { fprintf(stderr, "datargate[wwstage][bad]: rc=0/.o written on " "undefined DATAR slot — reloc silently dropped (#59)\n"); fail++; } } /* ok: both stages rc=0, byte-identical .o */ total++; int crc = assemble(ctool, oks, co, &ex); if (crc != 0 || !ex) { fprintf(stderr, "datargate[cstage][ok]: rc=%d .o=%d\n", crc, ex); fail++; } if (have_ww) { int wrc = assemble(wtool, oks, wo, &ex); if (wrc != 0 || !ex) { fprintf(stderr, "datargate[wwstage][ok]: rc=%d .o=%d\n", wrc, ex); fail++; } char cmp[1024]; snprintf(cmp, sizeof cmp, "cmp -s %s %s", co, wo); if (runwait(cmp) != 0) { fprintf(stderr, "datargate[ok]: cs/ww .o differ (#59)\n"); fail++; } } unlink(bads); unlink(oks); unlink(co); unlink(wo); if (fail) { fprintf(stderr, "datargate_run: %d check(s) failed\n", fail); return 1; } printf("datargate_run: %d/%d ok\n", total, total); return 0; }