test: port the assembler input gates to ww
asmgate_test.ww absorbs 530_w6a_parsenum and 989_datargate_run: the strtoll-semantics identity rows plus the bare-minus reject against both assemblers with cross-stage .o byte-identity, and the undefined DATAR-slot loud reject (no .o written) with the defined-slot byte-identical ok path. The w6a_ww skip gates drop: the Make target declares both assemblers.
This commit is contained in:
2
Makefile
2
Makefile
@@ -396,7 +396,7 @@ ASM_WW_TARGETS = $(ASM_WW_TESTS:%=wwtest/%)
|
|||||||
# linker flag capacity, assembler input gates). Compiler/driver gates
|
# linker flag capacity, assembler input gates). Compiler/driver gates
|
||||||
# like test/sep: they run under test-compiler.
|
# like test/sep: they run under test-compiler.
|
||||||
OBJECT_WW_TESTS = test/object/elfobj_test.ww test/object/link_test.ww \
|
OBJECT_WW_TESTS = test/object/elfobj_test.ww test/object/link_test.ww \
|
||||||
test/object/archive_test.ww
|
test/object/archive_test.ww test/object/asmgate_test.ww
|
||||||
OBJECT_WW_TARGETS = $(OBJECT_WW_TESTS:%=wwtest/%)
|
OBJECT_WW_TARGETS = $(OBJECT_WW_TESTS:%=wwtest/%)
|
||||||
BOOTSTRAP_WRAPPER_SOURCES = test/wcc/950_selfcheck.c \
|
BOOTSTRAP_WRAPPER_SOURCES = test/wcc/950_selfcheck.c \
|
||||||
test/wcc/991_w6a_ww.c \
|
test/wcc/991_w6a_ww.c \
|
||||||
|
|||||||
156
test/object/asmgate_test.ww
Normal file
156
test/object/asmgate_test.ww
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package asmgate_test;
|
||||||
|
|
||||||
|
// Assembler input gates, w6a vs w6a_ww on hand-written asm the
|
||||||
|
// compiler never emits. Ports of the retired native carriers
|
||||||
|
// test/wcc/530_w6a_parsenum.c and 989_datargate_run.c; every
|
||||||
|
// assertion preserved.
|
||||||
|
//
|
||||||
|
// parsenum (530, F14 #62) — w6a_ww's parsenum must match the C
|
||||||
|
// twin's strtoll(s,end,0) (cmd/w6a/lex.c:30): `$ 5` skips the
|
||||||
|
// whitespace (→5), `$08` stops at the octal-invalid '8' (→0), and a
|
||||||
|
// bare `-(BP)` is a loud reject on BOTH stages. Identity rows
|
||||||
|
// (including the canonical control shapes w6c does emit) must
|
||||||
|
// produce byte-identical .o across the two assemblers.
|
||||||
|
//
|
||||||
|
// datargate (989, #59 F15 c5) — a DATAR against a slot never defined
|
||||||
|
// by DATAW is a loud reject on both stages with NO .o written (the
|
||||||
|
// pre-c5 wwstage silently dropped the R_X86_64_64 reloc under rc=0);
|
||||||
|
// the DATAW-then-DATAR shape assembles on both stages to a
|
||||||
|
// byte-identical .o (rule 10).
|
||||||
|
//
|
||||||
|
// Dropped C machinery, not assertions: the w6a_ww absent-tool skip
|
||||||
|
// gates (the Make target declares both assemblers) and per-file
|
||||||
|
// unlink accounting (testenv.clean).
|
||||||
|
|
||||||
|
import os;
|
||||||
|
import os.exec;
|
||||||
|
import strings;
|
||||||
|
import testenv;
|
||||||
|
import time;
|
||||||
|
|
||||||
|
fn fail(label: str, why: str) void = {
|
||||||
|
let m: str = strings.concat("asmgate FAIL: ", label, " -- ", why,
|
||||||
|
"\n");
|
||||||
|
os.write(2, m.ptr, m.len: u64);
|
||||||
|
assert(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
fn tmo() time.duration = {
|
||||||
|
return (240i64 * (time.second: i64)): time.duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -1 encodes an abnormal (non-EXIT) termination, never a valid code.
|
||||||
|
fn runcode(dir: str, name: str, argv: []str) i32 = {
|
||||||
|
let co: testenv.commandout;
|
||||||
|
testenv.runcommand(dir, dir, name, argv, tmo(), &co);
|
||||||
|
if (co.termination != exec.termination.EXIT) { return -1; };
|
||||||
|
return co.code;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn assemble(td: str, tool: str, tag: str, src: str, obj: str) i32 = {
|
||||||
|
let av: []str = [testenv.driver(tool), "-o", obj, src];
|
||||||
|
return runcode(td, tag, av);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- parsenum (530) ----------------------------------------------------
|
||||||
|
|
||||||
|
@test fn parsenum() void = {
|
||||||
|
let td: str = testenv.fresh();
|
||||||
|
let labels: []str = ["ws_after_dollar", "leading_zero",
|
||||||
|
"plain_imm", "plain_imm_eight", "hex_imm", "zero_imm",
|
||||||
|
"neg_indir", "pos_indir"];
|
||||||
|
// rows 0-1 are the strtoll edge shapes; the rest are the
|
||||||
|
// canonical controls w6c actually emits (no regression)
|
||||||
|
let texts: []str = [
|
||||||
|
"TEXT main,$16\n\tMOVQ\t$ 5, AX\n\tRET\n",
|
||||||
|
"TEXT main,$16\n\tMOVQ\t$08, AX\n\tRET\n",
|
||||||
|
"TEXT main,$16\n\tMOVQ\t$5, AX\n\tRET\n",
|
||||||
|
"TEXT main,$16\n\tMOVQ\t$8, AX\n\tRET\n",
|
||||||
|
"TEXT main,$16\n\tMOVQ\t$0x1f, AX\n\tRET\n",
|
||||||
|
"TEXT main,$16\n\tMOVQ\t$0, AX\n\tRET\n",
|
||||||
|
"TEXT main,$16\n\tMOVQ\t-8(BP), AX\n\tRET\n",
|
||||||
|
"TEXT main,$16\n\tMOVQ\t8(BP), AX\n\tRET\n",
|
||||||
|
];
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 8) {
|
||||||
|
let src: str = strings.concat(td, "/", labels[i], ".s");
|
||||||
|
let co: str = strings.concat(td, "/", labels[i], "_c.o");
|
||||||
|
let wo: str = strings.concat(td, "/", labels[i], "_w.o");
|
||||||
|
testenv.writefile(src, texts[i]);
|
||||||
|
if (assemble(td, "w6a", strings.concat("c_", labels[i]),
|
||||||
|
src, co) != 0) {
|
||||||
|
fail("parsenum", strings.concat(labels[i],
|
||||||
|
": cstage assemble failed"));
|
||||||
|
};
|
||||||
|
if (assemble(td, "w6a_ww", strings.concat("w_", labels[i]),
|
||||||
|
src, wo) != 0) {
|
||||||
|
fail("parsenum", strings.concat(labels[i],
|
||||||
|
": wwstage assemble failed"));
|
||||||
|
};
|
||||||
|
if (!testenv.same(testenv.readfile(co), testenv.readfile(wo))) {
|
||||||
|
fail("parsenum", strings.concat(labels[i],
|
||||||
|
": .o differ across assemblers"));
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// reject row: no digit after the sign — loud on both stages
|
||||||
|
let rsrc: str = strings.concat(td, "/bare_minus_indir.s");
|
||||||
|
testenv.writefile(rsrc, "TEXT main,$16\n\tMOVQ\t-(BP), AX\n\tRET\n");
|
||||||
|
if (assemble(td, "w6a", "c_bare_minus",
|
||||||
|
rsrc, strings.concat(td, "/bare_minus_c.o")) == 0) {
|
||||||
|
fail("parsenum", "bare_minus_indir: cstage accepted, want reject");
|
||||||
|
};
|
||||||
|
if (assemble(td, "w6a_ww", "w_bare_minus",
|
||||||
|
rsrc, strings.concat(td, "/bare_minus_w.o")) == 0) {
|
||||||
|
fail("parsenum", "bare_minus_indir: wwstage accepted, want reject");
|
||||||
|
};
|
||||||
|
testenv.clean(td);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- datargate (989) ---------------------------------------------------
|
||||||
|
|
||||||
|
@test fn datargate() void = {
|
||||||
|
let td: str = testenv.fresh();
|
||||||
|
let bads: str = strings.concat(td, "/bad.s");
|
||||||
|
let oks: str = strings.concat(td, "/ok.s");
|
||||||
|
testenv.writefile(bads,
|
||||||
|
"TEXT f,$0\n\tRET\n\tDATAR x+0(SB), f(SB)\n");
|
||||||
|
testenv.writefile(oks, strings.concat(
|
||||||
|
"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"));
|
||||||
|
|
||||||
|
// bad: both stages loud, and the reject must not write a .o
|
||||||
|
let tools: []str = ["w6a", "w6a_ww"];
|
||||||
|
let t: i32 = 0;
|
||||||
|
for (t < 2) {
|
||||||
|
let obj: str = strings.concat(td, "/bad_", tools[t], ".o");
|
||||||
|
if (assemble(td, tools[t], strings.concat("bad_", tools[t]),
|
||||||
|
bads, obj) == 0) {
|
||||||
|
fail("datargate", strings.concat(tools[t],
|
||||||
|
": rc=0 on an undefined DATAR slot (reloc dropped?)"));
|
||||||
|
};
|
||||||
|
if (testenv.exists(obj)) {
|
||||||
|
fail("datargate", strings.concat(tools[t],
|
||||||
|
": .o written on the reject path"));
|
||||||
|
};
|
||||||
|
t += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ok: both stages rc=0, .o present, byte-identical (rule 10)
|
||||||
|
let cobj: str = strings.concat(td, "/ok_c.o");
|
||||||
|
let wobj: str = strings.concat(td, "/ok_w.o");
|
||||||
|
if (assemble(td, "w6a", "ok_c", oks, cobj) != 0
|
||||||
|
|| !testenv.exists(cobj)) {
|
||||||
|
fail("datargate", "cstage failed the defined-slot path");
|
||||||
|
};
|
||||||
|
if (assemble(td, "w6a_ww", "ok_w", oks, wobj) != 0
|
||||||
|
|| !testenv.exists(wobj)) {
|
||||||
|
fail("datargate", "wwstage failed the defined-slot path");
|
||||||
|
};
|
||||||
|
if (!testenv.same(testenv.readfile(cobj), testenv.readfile(wobj))) {
|
||||||
|
fail("datargate", "cs/ww .o differ on the defined-slot path");
|
||||||
|
};
|
||||||
|
testenv.clean(td);
|
||||||
|
};
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* 530_w6a_parsenum — F14 #62: w6a's parsenum diverged from the C twin's
|
|
||||||
* strtoll(s,end,0) (cmd/w6a/lex.c:30) on three hand-written-asm edge
|
|
||||||
* shapes, all gate-blind (w6c emits the canonical $5 / $8 / -8(BP), never
|
|
||||||
* these). The fix aligns wwstage's assembler to strtoll semantics:
|
|
||||||
* (a) `$ 5` — leading whitespace after $: strtoll skips it (→5); ww
|
|
||||||
* had no skip and silently encoded imm 0.
|
|
||||||
* (b) `$08` — strtoll base-0 reads a leading 0 as octal and STOPS at
|
|
||||||
* '8' (→0); ww parsed it as decimal 8.
|
|
||||||
* (c) `-(BP)` — strtoll/cstage require a digit after the sign, so a bare
|
|
||||||
* `-(` is `unrecognised operand` (loud reject); ww silently
|
|
||||||
* accepted it as 0(BP).
|
|
||||||
*
|
|
||||||
* (a)/(b): both assemblers must emit a byte-identical .o.
|
|
||||||
* (c): both assemblers must FAIL (loud reject).
|
|
||||||
* Controls: the canonical $5 / $8 / -8(BP) shapes that w6c DOES emit must
|
|
||||||
* stay byte-identical (no regression).
|
|
||||||
*
|
|
||||||
* Drives w6a (cstage) and w6a_ww (wwstage) directly; gated on w6a_ww.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
static int
|
|
||||||
runwait(const char *cmd)
|
|
||||||
{
|
|
||||||
int rc = system(cmd);
|
|
||||||
if (rc == -1) return -1;
|
|
||||||
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* assemble `asm` with `tool` into `obj`; returns the build rc. */
|
|
||||||
static int
|
|
||||||
assemble(const char *tool, const char *asmtext, const char *obj, int i)
|
|
||||||
{
|
|
||||||
char src[64], cmd[1024];
|
|
||||||
snprintf(src, sizeof src, "/tmp/w6apn_%d_%d.s", getpid(), i);
|
|
||||||
FILE *f = fopen(src, "wb");
|
|
||||||
if (!f) return -2;
|
|
||||||
fputs(asmtext, f);
|
|
||||||
fclose(f);
|
|
||||||
snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", tool, obj, src);
|
|
||||||
int rc = runwait(cmd);
|
|
||||||
unlink(src);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
files_equal(const char *a, const char *b)
|
|
||||||
{
|
|
||||||
FILE *fa = fopen(a, "rb");
|
|
||||||
FILE *fb = fopen(b, "rb");
|
|
||||||
int eq = (fa && fb);
|
|
||||||
if (fa && fb) {
|
|
||||||
for (;;) {
|
|
||||||
int ca = fgetc(fa), cb = fgetc(fb);
|
|
||||||
if (ca != cb) { eq = 0; break; }
|
|
||||||
if (ca == EOF) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fa) fclose(fa);
|
|
||||||
if (fb) fclose(fb);
|
|
||||||
return eq;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct idrow { const char *label; const char *asmtext; };
|
|
||||||
|
|
||||||
/* shapes that must assemble byte-identically across the two assemblers. */
|
|
||||||
static const struct idrow idrows[] = {
|
|
||||||
{ "ws_after_dollar", "TEXT main,$16\n\tMOVQ\t$ 5, AX\n\tRET\n" },
|
|
||||||
{ "leading_zero", "TEXT main,$16\n\tMOVQ\t$08, AX\n\tRET\n" },
|
|
||||||
/* controls — the canonical shapes w6c actually emits. */
|
|
||||||
{ "plain_imm", "TEXT main,$16\n\tMOVQ\t$5, AX\n\tRET\n" },
|
|
||||||
{ "plain_imm_eight", "TEXT main,$16\n\tMOVQ\t$8, AX\n\tRET\n" },
|
|
||||||
{ "hex_imm", "TEXT main,$16\n\tMOVQ\t$0x1f, AX\n\tRET\n" },
|
|
||||||
{ "zero_imm", "TEXT main,$16\n\tMOVQ\t$0, AX\n\tRET\n" },
|
|
||||||
{ "neg_indir", "TEXT main,$16\n\tMOVQ\t-8(BP), AX\n\tRET\n" },
|
|
||||||
{ "pos_indir", "TEXT main,$16\n\tMOVQ\t8(BP), AX\n\tRET\n" },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* shapes both assemblers must reject. */
|
|
||||||
static const struct idrow rejrows[] = {
|
|
||||||
{ "bare_minus_indir", "TEXT main,$16\n\tMOVQ\t-(BP), AX\n\tRET\n" },
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (access(wtool, X_OK) != 0) {
|
|
||||||
fprintf(stderr, "w6a_parsenum: skip (no %s)\n", wtool);
|
|
||||||
printf("w6a_parsenum: skipped\n");
|
|
||||||
return 77;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nid = (int)(sizeof idrows / sizeof idrows[0]);
|
|
||||||
int nrej = (int)(sizeof rejrows / sizeof rejrows[0]);
|
|
||||||
int fail = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < nid; i++) {
|
|
||||||
char co[64], wo[64];
|
|
||||||
snprintf(co, sizeof co, "/tmp/w6apn_%d_%d_c.o", getpid(), i);
|
|
||||||
snprintf(wo, sizeof wo, "/tmp/w6apn_%d_%d_w.o", getpid(), i);
|
|
||||||
int cr = assemble(ctool, idrows[i].asmtext, co, i);
|
|
||||||
int wr = assemble(wtool, idrows[i].asmtext, wo, 1000 + i);
|
|
||||||
if (cr != 0 || wr != 0) {
|
|
||||||
fprintf(stderr, "w6a_parsenum[%s]: assemble failed "
|
|
||||||
"(c=%d w=%d)\n", idrows[i].label, cr, wr);
|
|
||||||
fail++;
|
|
||||||
} else if (!files_equal(co, wo)) {
|
|
||||||
fprintf(stderr, "w6a_parsenum[%s]: .o differ across "
|
|
||||||
"assemblers\n", idrows[i].label);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
unlink(co); unlink(wo);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < nrej; i++) {
|
|
||||||
char co[64], wo[64];
|
|
||||||
snprintf(co, sizeof co, "/tmp/w6apn_%d_r%d_c.o", getpid(), i);
|
|
||||||
snprintf(wo, sizeof wo, "/tmp/w6apn_%d_r%d_w.o", getpid(), i);
|
|
||||||
int cr = assemble(ctool, rejrows[i].asmtext, co, 2000 + i);
|
|
||||||
int wr = assemble(wtool, rejrows[i].asmtext, wo, 3000 + i);
|
|
||||||
if (cr == 0) {
|
|
||||||
fprintf(stderr, "w6a_parsenum[%s]: cstage accepted, "
|
|
||||||
"expected reject\n", rejrows[i].label);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
if (wr == 0) {
|
|
||||||
fprintf(stderr, "w6a_parsenum[%s]: wwstage accepted, "
|
|
||||||
"expected reject\n", rejrows[i].label);
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
unlink(co); unlink(wo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fail) {
|
|
||||||
fprintf(stderr, "w6a_parsenum: %d fixtures failed\n", fail);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("w6a_parsenum: %d/%d ok\n", nid + nrej, nid + nrej);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user