test: make dynamic linker parity observer self-contained
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
* Phase-8 marker for ET_DYN linking on the ww side: a green run means
|
||||
* the ww-side linker emits PT_INTERP/PT_DYNAMIC binaries byte-for-byte
|
||||
* identical to the C linker on the same inputs — i.e. the dynamic
|
||||
* linking story is fully ported.
|
||||
* linking story is fully ported. The input is generated privately so the
|
||||
* platform gate owns its complete source and artifact lifecycle.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -61,31 +62,70 @@ main(void)
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
|
||||
/* #93 sep layout: build the example via `ww build` into a
|
||||
* private /tmp stem (NOT next to the tracked example source), then
|
||||
* link <stem>.sepwork/__root.o — the self-contained single-package
|
||||
* object the flip emits in place of the old next-to-source .o. */
|
||||
char cmd[4096], mbstem[256], mbobj[320], co[64], wo[64];
|
||||
snprintf(mbstem, sizeof mbstem, "/tmp/wwld_%d_mb", getpid());
|
||||
snprintf(mbobj, sizeof mbobj, "%s.sepwork/__root.o", mbstem);
|
||||
snprintf(co, sizeof co, "/tmp/wwld_%d_c", getpid());
|
||||
snprintf(wo, sizeof wo, "/tmp/wwld_%d_w", getpid());
|
||||
const char *libdir = NULL;
|
||||
if (access("/usr/lib/libc.so.6", 0) == 0)
|
||||
libdir = "/usr/lib";
|
||||
else if (access("/lib/x86_64-linux-gnu/libc.so.6", 0) == 0)
|
||||
libdir = "/lib/x86_64-linux-gnu";
|
||||
else if (access("/lib64/libc.so.6", 0) == 0)
|
||||
libdir = "/lib64";
|
||||
if (libdir == NULL) {
|
||||
puts("w6l_ww-dyn: no libc.so.6 on this system — skipping");
|
||||
return 77;
|
||||
}
|
||||
|
||||
char td[] = "/tmp/wwld_XXXXXX";
|
||||
if (mkdtemp(td) == NULL) {
|
||||
perror("w6l_ww-dyn mkdtemp");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* #93 sep layout: build an explicit command source via `ww build`,
|
||||
* then independently link <stem>.sepwork/__root.o with both linkers.
|
||||
* The direct getpid call guarantees one dynamic libc relocation. */
|
||||
char cmd[4096], src[256], stem[256], scratch[320];
|
||||
char obj[384], co[256], wo[256];
|
||||
snprintf(src, sizeof src, "%s/dyn.ww", td);
|
||||
snprintf(stem, sizeof stem, "%s/built", td);
|
||||
snprintf(scratch, sizeof scratch, "%s.sepwork", stem);
|
||||
snprintf(obj, sizeof obj, "%s/__root.o", scratch);
|
||||
snprintf(co, sizeof co, "%s/c", td);
|
||||
snprintf(wo, sizeof wo, "%s/w", td);
|
||||
|
||||
int rc = 0;
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"cd %s/examples/mandelbrot && %s/ww build "
|
||||
"-o %s mandelbrot.ww -L /usr/lib -l c >/dev/null 2>&1",
|
||||
cwd, bin, mbstem);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: cannot build mandelbrot.o via C driver\n");
|
||||
FILE *f = fopen(src, "wb");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: cannot create generated source\n");
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
fputs("package main;\n"
|
||||
"@symbol(\"getpid\") fn cgetpid() i32;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tif (cgetpid() < 0) { return 1; };\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n", f);
|
||||
int writebad = ferror(f);
|
||||
if (fclose(f) != 0) writebad = 1;
|
||||
if (writebad) {
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: cannot write generated source\n");
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6l -o %s %s -L /usr/lib "
|
||||
"%s/ww build -o %s %s -L %s -l c >/dev/null 2>&1",
|
||||
bin, stem, src, libdir);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: cannot build generated command\n");
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6l -o %s %s -L %s "
|
||||
"-l c %s/out/lib/libwwrt.a 2>/dev/null",
|
||||
bin, co, mbobj, cwd);
|
||||
bin, co, obj, libdir, cwd);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: C w6l errored\n");
|
||||
rc = 1;
|
||||
@@ -93,9 +133,9 @@ main(void)
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6l_ww -o %s %s -L /usr/lib "
|
||||
"%s/w6l_ww -o %s %s -L %s "
|
||||
"-l c %s/out/lib/libwwrt.a 2>/dev/null",
|
||||
bin, wo, mbobj, cwd);
|
||||
bin, wo, obj, libdir, cwd);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: ww w6l errored\n");
|
||||
rc = 1;
|
||||
@@ -114,17 +154,28 @@ main(void)
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: C %zu vs ww %zu bytes\n",
|
||||
nc, nw);
|
||||
rc = 1;
|
||||
} else if (runwait(co) != 0 || runwait(wo) != 0) {
|
||||
fprintf(stderr, "w6l_ww-dyn FAIL: linked command did not run\n");
|
||||
rc = 1;
|
||||
} else {
|
||||
printf("w6l_ww-dyn: byte-identical to C w6l on mandelbrot "
|
||||
printf("w6l_ww-dyn: byte-identical to C w6l on generated command "
|
||||
"(PT_INTERP + PT_DYNAMIC + .rela.plt + .gnu.version_r, "
|
||||
"%zu bytes)\n", nc);
|
||||
}
|
||||
free(bc); free(bw);
|
||||
|
||||
cleanup:
|
||||
/* #93: `ww build` retains this exact caller-owned scratch tree. */
|
||||
snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork", mbstem);
|
||||
/* `ww build` retains this exact mkdtemp-owned scratch child. */
|
||||
snprintf(cmd, sizeof cmd, "rm -rf -- %s", scratch);
|
||||
int cleanfail = runwait(cmd) != 0;
|
||||
if (unlink(src) != 0 && errno != ENOENT) {
|
||||
perror(src);
|
||||
cleanfail = 1;
|
||||
}
|
||||
if (unlink(stem) != 0 && errno != ENOENT) {
|
||||
perror(stem);
|
||||
cleanfail = 1;
|
||||
}
|
||||
if (unlink(co) != 0 && errno != ENOENT) {
|
||||
perror(co);
|
||||
cleanfail = 1;
|
||||
@@ -133,8 +184,8 @@ cleanup:
|
||||
perror(wo);
|
||||
cleanfail = 1;
|
||||
}
|
||||
if (unlink(mbstem) != 0 && errno != ENOENT) {
|
||||
perror(mbstem);
|
||||
if (rmdir(td) != 0) {
|
||||
perror(td);
|
||||
cleanfail = 1;
|
||||
}
|
||||
if (cleanfail && rc == 0)
|
||||
|
||||
Reference in New Issue
Block a user