test: port the archive-driven linker observers to ww
archive_test.ww absorbs 610_arch and 632_w6l_manyflags: archive
member selectivity through a load-bearing undefined @symbol extern
(link exit 0, run exit 7), and the -L capacity table {1,64,65,100,
128} against both w6l and w6l_ww with an ET_EXEC check per leg. ar is
/usr/bin/ar via runcommand; the junk -L flags are real argv entries
instead of a 16KB shell string.
This commit is contained in:
3
Makefile
3
Makefile
@@ -395,7 +395,8 @@ ASM_WW_TARGETS = $(ASM_WW_TESTS:%=wwtest/%)
|
||||
# layout, program-header split and BSS trim, archive selectivity,
|
||||
# linker flag capacity, assembler input gates). Compiler/driver gates
|
||||
# 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
|
||||
OBJECT_WW_TARGETS = $(OBJECT_WW_TESTS:%=wwtest/%)
|
||||
BOOTSTRAP_WRAPPER_SOURCES = test/wcc/950_selfcheck.c \
|
||||
test/wcc/991_w6a_ww.c \
|
||||
|
||||
169
test/object/archive_test.ww
Normal file
169
test/object/archive_test.ww
Normal file
@@ -0,0 +1,169 @@
|
||||
package archive_test;
|
||||
|
||||
// Archive-driven w6l observers (host ar). Ports of the retired native
|
||||
// carriers test/wcc/610_arch.c and 632_w6l_manyflags.c; every
|
||||
// assertion preserved.
|
||||
//
|
||||
// selectivity (610) — libfoo.a holds a needed member and a member
|
||||
// referencing an undefined extern; the link succeeds (exit 0) because
|
||||
// w6l pulls ONLY the needed member — pulling lib_bad would fail with
|
||||
// an undefined reference to this_symbol_does_not_exist — and the
|
||||
// binary runs with exit 7. The bad member's @symbol extern is the
|
||||
// discriminator; keep it verbatim.
|
||||
//
|
||||
// manyflags (632, drain F-C) — -L/-l arrays must be sized by argc,
|
||||
// not a fixed 64-slot cap. -lfoo resolves only through the FINAL real
|
||||
// -L placed after N-1 junk dirs, so a successful link (exit 0 +
|
||||
// ELF64 ET_EXEC output) proves the Nth -L was honoured. N table
|
||||
// {1, 64, 65, 100, 128}; N=65 is the exact pre-fix overflow slot.
|
||||
// Both w6l and w6l_ww are driven (the w6l_ww leg was ungated in the
|
||||
// carrier too).
|
||||
//
|
||||
// Dropped C machinery, not assertions: wwtestpkg.h package-clause
|
||||
// injection, the 16KB shell-command buffer (argv is a real vector
|
||||
// here), and per-file unlink accounting (testenv.clean).
|
||||
|
||||
import os;
|
||||
import os.exec;
|
||||
import strconv;
|
||||
import strings;
|
||||
import testenv;
|
||||
import time;
|
||||
|
||||
fn fail(label: str, why: str) void = {
|
||||
let m: str = strings.concat("archive 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;
|
||||
};
|
||||
|
||||
// itos returns a view into a static buffer; dup materializes it.
|
||||
fn dec(n: i32) str = {
|
||||
return strings.dup(strconv.itos(n: int, strconv.base.DEC));
|
||||
};
|
||||
|
||||
// w6c + w6a on one package-main source; leaves <stem>.o next to it.
|
||||
fn compile(td: str, stem: str, body: str) void = {
|
||||
let src: str = strings.concat(td, "/", stem, ".ww");
|
||||
let asmf: str = strings.concat(td, "/", stem, ".s");
|
||||
let obj: str = strings.concat(td, "/", stem, ".o");
|
||||
testenv.writefile(src, body);
|
||||
let cav: []str = [testenv.driver("w6c"), "-o", asmf, src];
|
||||
if (runcode(td, strings.concat("c_", stem), cav) != 0) {
|
||||
fail(stem, "w6c failed");
|
||||
};
|
||||
let aav: []str = [testenv.driver("w6a"), "-o", obj, asmf];
|
||||
if (runcode(td, strings.concat("a_", stem), aav) != 0) {
|
||||
fail(stem, "w6a failed");
|
||||
};
|
||||
};
|
||||
|
||||
// ---- selectivity (610) -------------------------------------------------
|
||||
|
||||
@test fn selectivity() void = {
|
||||
let td: str = testenv.fresh();
|
||||
compile(td, "lib_good", strings.concat("package main;\n",
|
||||
"export fn f1() i32 = { return 7; };\n"));
|
||||
// defines f2 but also references an undefined extern — the
|
||||
// discriminator: pulling this member makes the link fail
|
||||
compile(td, "lib_bad", strings.concat("package main;\n",
|
||||
"@symbol(\"this_symbol_does_not_exist\") fn bogus() i32;\n",
|
||||
"export fn f2() i32 = { return bogus(); };\n"));
|
||||
// the plain prototype declares f1 in the same (main) module, so
|
||||
// the call resolves to main.f1 — matching lib_good's definition
|
||||
compile(td, "m", strings.concat("package main;\n",
|
||||
"fn f1() i32;\n",
|
||||
"fn main() i32 = { return f1(); };\n"));
|
||||
|
||||
let lib: str = strings.concat(td, "/libfoo.a");
|
||||
let arav: []str = ["/usr/bin/ar", "rcs", lib,
|
||||
strings.concat(td, "/lib_good.o"),
|
||||
strings.concat(td, "/lib_bad.o")];
|
||||
if (runcode(td, "ar", arav) != 0) { fail("selectivity", "ar failed"); };
|
||||
|
||||
let exe: str = strings.concat(td, "/m");
|
||||
let start: str = strings.concat(testenv.repo(),
|
||||
"/out/obj/rt/start.o");
|
||||
let lav: []str = [testenv.driver("w6l"), "-o", exe,
|
||||
strings.concat(td, "/m.o"), start, lib];
|
||||
let co: testenv.commandout;
|
||||
testenv.runcommand(td, td, "link", lav, tmo(), &co);
|
||||
if (co.termination != exec.termination.EXIT || co.code != 0) {
|
||||
fail("selectivity", strings.concat(
|
||||
"link failed (bad member pulled?): ", co.stderr));
|
||||
};
|
||||
|
||||
let rav: []str = [exe];
|
||||
if (runcode(td, "run_m", rav) != 7) {
|
||||
fail("selectivity", "exit != 7");
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
// ---- manyflags (632) ---------------------------------------------------
|
||||
|
||||
fn linkwith(td: str, lnk: str, n: i32) void = {
|
||||
let tag: str = strings.concat(lnk, "_", dec(n));
|
||||
let exe: str = strings.concat(td, "/x_", tag);
|
||||
let av: []str = alloc([], 8u64)!;
|
||||
append(av, testenv.driver(lnk));
|
||||
append(av, "-o");
|
||||
append(av, exe);
|
||||
append(av, strings.concat(td, "/m.o"));
|
||||
let i: i32 = 1;
|
||||
for (i < n) {
|
||||
append(av, strings.concat("-L/nonexist/wwfc_d", dec(i)));
|
||||
i += 1;
|
||||
};
|
||||
append(av, strings.concat("-L", td));
|
||||
append(av, "-lfoo");
|
||||
if (runcode(td, strings.concat("lnk_", tag), av) != 0) {
|
||||
fail("manyflags", strings.concat(lnk, " nflags=", dec(n),
|
||||
" link failed (Nth -L not honoured)"));
|
||||
};
|
||||
let o: str = testenv.readfile(exe);
|
||||
if (o.len < 64 || o[0] != 0x7fu8 || o[1] != 0x45u8
|
||||
|| o[2] != 0x4cu8 || o[3] != 0x46u8) {
|
||||
fail("manyflags", strings.concat(lnk, " nflags=", dec(n),
|
||||
" output not an ELF"));
|
||||
};
|
||||
// ET_EXEC == 2 (Ehdr e_type at 16, LE u16)
|
||||
if (testenv.leu16(o, 16) != 2u64) {
|
||||
fail("manyflags", strings.concat(lnk, " nflags=", dec(n),
|
||||
" output not ET_EXEC"));
|
||||
};
|
||||
};
|
||||
|
||||
@test fn manyflags() void = {
|
||||
let td: str = testenv.fresh();
|
||||
// a standalone main.o (no undefs) + an unrelated archived foo.o
|
||||
compile(td, "m", strings.concat("package main;\n",
|
||||
"fn main() i32 = { return 42; };\n"));
|
||||
compile(td, "f", strings.concat("package main;\n",
|
||||
"export fn foo() i32 = { return 7; };\n"));
|
||||
let arav: []str = ["/usr/bin/ar", "rcs",
|
||||
strings.concat(td, "/libfoo.a"),
|
||||
strings.concat(td, "/f.o")];
|
||||
if (runcode(td, "ar", arav) != 0) { fail("manyflags", "ar failed"); };
|
||||
|
||||
let counts: []i32 = [1, 64, 65, 100, 128];
|
||||
let i: i32 = 0;
|
||||
for (i < 5) {
|
||||
linkwith(td, "w6l_ww", counts[i]);
|
||||
linkwith(td, "w6l", counts[i]);
|
||||
i += 1;
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 610_arch — archive selectivity. Build two .o files into an archive
|
||||
* where one defines a symbol main needs, and the other references an
|
||||
* undefined external. Linking should pull only the needed member;
|
||||
* the other one's bad reference must NOT cause a link error.
|
||||
*
|
||||
* If w6l were still pulling all members, this test would fail with
|
||||
* "undefined reference to 'this_symbol_does_not_exist'".
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include "wwtestpkg.h"
|
||||
|
||||
static int run(const char *cmd) { return system(cmd); }
|
||||
|
||||
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 dir[64];
|
||||
snprintf(dir, sizeof dir, "/tmp/wwarch_%d", getpid());
|
||||
if (mkdir(dir, 0755) != 0) {
|
||||
perror(dir);
|
||||
return 1;
|
||||
}
|
||||
int result = 1;
|
||||
|
||||
/* lib_good.ww — defines f1() (→ main.f1 under strict-package #24a) */
|
||||
char path[256];
|
||||
snprintf(path, sizeof path, "%s/lib_good.ww", dir);
|
||||
FILE *f = fopen(path, "wb");
|
||||
if (!f) { perror(path); goto cleanup; }
|
||||
wwtest_fputs("export fn f1() i32 = { return 7; };", f);
|
||||
if (fclose(f) != 0) { perror(path); goto cleanup; }
|
||||
|
||||
/* lib_bad.ww — defines f2() but also references an undefined extern */
|
||||
snprintf(path, sizeof path, "%s/lib_bad.ww", dir);
|
||||
f = fopen(path, "wb");
|
||||
if (!f) { perror(path); goto cleanup; }
|
||||
wwtest_fputs("@symbol(\"this_symbol_does_not_exist\") fn bogus() i32;\n"
|
||||
"export fn f2() i32 = { return bogus(); };", f);
|
||||
if (fclose(f) != 0) { perror(path); goto cleanup; }
|
||||
|
||||
/* main.ww — calls f1, NOT f2. The plain prototype declares f1 in the
|
||||
* same (main) module, so the call resolves to main.f1 — matching
|
||||
* lib_good's moduled definition (no @symbol bare-pin needed). */
|
||||
snprintf(path, sizeof path, "%s/m.ww", dir);
|
||||
f = fopen(path, "wb");
|
||||
if (!f) { perror(path); goto cleanup; }
|
||||
wwtest_fputs("fn f1() i32;\n"
|
||||
"fn main() i32 = { return f1(); };", f);
|
||||
if (fclose(f) != 0) { perror(path); goto cleanup; }
|
||||
|
||||
char cmd[2048];
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"set -e; cd %s && %s/w6c -o lib_good.s lib_good.ww && "
|
||||
"%s/w6c -o lib_bad.s lib_bad.ww && "
|
||||
"%s/w6a -o lib_good.o lib_good.s && %s/w6a -o lib_bad.o lib_bad.s && "
|
||||
"ar rcs libfoo.a lib_good.o lib_bad.o && "
|
||||
"%s/w6c -o m.s m.ww && %s/w6a -o m.o m.s",
|
||||
dir, bin, bin, bin, bin, bin, bin);
|
||||
if (run(cmd) != 0) {
|
||||
fprintf(stderr, "build failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Find start.o for the runtime */
|
||||
char startobj[256];
|
||||
snprintf(startobj, sizeof startobj, "%s/../obj/rt/start.o", bin);
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s/w6l -o %s/m %s/m.o %s %s/libfoo.a 2>%s/link.err",
|
||||
bin, dir, dir, startobj, dir, dir);
|
||||
if (run(cmd) != 0) {
|
||||
char errpath[300];
|
||||
snprintf(errpath, sizeof errpath, "%s/link.err", dir);
|
||||
FILE *e = fopen(errpath, "r");
|
||||
if (e) {
|
||||
char buf[512]; size_t r = fread(buf, 1, sizeof buf - 1, e); buf[r]='\0'; fclose(e);
|
||||
fprintf(stderr, "link failed:\n%s\n", buf);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
char exepath[256];
|
||||
snprintf(exepath, sizeof exepath, "%s/m", dir);
|
||||
int rc = run(exepath);
|
||||
if (WIFEXITED(rc) && WEXITSTATUS(rc) == 7) {
|
||||
result = 0;
|
||||
} else {
|
||||
fprintf(stderr, "arch: unexpected exit\n");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
snprintf(path, sizeof path, "%s/lib_good.ww", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/lib_bad.ww", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/m.ww", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/lib_good.s", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/lib_bad.s", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/lib_good.o", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/lib_bad.o", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/libfoo.a", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/m.s", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/m.o", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/m", dir); unlink(path);
|
||||
snprintf(path, sizeof path, "%s/link.err", dir); unlink(path);
|
||||
if (rmdir(dir) != 0) {
|
||||
perror(dir);
|
||||
result = 1;
|
||||
}
|
||||
if (result == 0)
|
||||
printf("arch: ok (only needed archive member pulled)\n");
|
||||
return result;
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* 632_w6l_manyflags — w6l -L/-l arrays must be sized by argc, not a
|
||||
* fixed 64-slot cap (drain F-C). The 65th -L used to write past the
|
||||
* allocation: `libdirs[nlibdirs] = ...` with no bound check, corrupting
|
||||
* the heap and dropping the flag.
|
||||
*
|
||||
* Behavioural discriminator: make a -L past slot 64 LOAD-BEARING. We
|
||||
* build libfoo.a in a real directory and reach it ONLY via the Nth -L,
|
||||
* preceded by N-1 junk dirs. w6l errors `cannot find -lfoo` unless it
|
||||
* can locate the archive, so a successful link (exit 0 + ET_EXEC) proves
|
||||
* the Nth -L was honoured. N is a table {1, 64, 65, 100, 128}; pre-fix,
|
||||
* N=65 (the slot exactly one past the 64-element array) reliably fails
|
||||
* to round-trip and the link errors — verified by rebuilding the pre-fix
|
||||
* w6l_ww. Both stages are driven for parity.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include "wwtestpkg.h"
|
||||
|
||||
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
|
||||
runwait(const char *cmd)
|
||||
{
|
||||
int rc = system(cmd);
|
||||
if (rc == -1) return -1;
|
||||
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* link `obj` with linker `lnk`, resolving -lfoo through `libdir` placed
|
||||
* as the Nth (last) -L after nflags-1 junk dirs. Returns the linker's
|
||||
* exit code; on success also fails (-1) if the output isn't an ET_EXEC
|
||||
* ELF — proving the archive was actually located and linked. */
|
||||
static int
|
||||
linkwith(const char *lnk, const char *obj, const char *libdir, int nflags)
|
||||
{
|
||||
char exe[128];
|
||||
snprintf(exe, sizeof exe, "%s/wwfc_x", libdir);
|
||||
|
||||
char junk[8192];
|
||||
size_t off = 0;
|
||||
for (int i = 1; i < nflags; i++)
|
||||
off += snprintf(junk + off, sizeof junk - off,
|
||||
" -L/nonexist/wwfc_d%d", i);
|
||||
|
||||
char cmd[16384];
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"%s -o %s %s%s -L%s -lfoo 2>/dev/null",
|
||||
lnk, exe, obj, junk, libdir);
|
||||
int rc = runwait(cmd);
|
||||
if (rc != 0) goto cleanup;
|
||||
|
||||
FILE *f = fopen(exe, "rb");
|
||||
if (!f) {
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
unsigned char hdr[20];
|
||||
int ok = fread(hdr, 1, sizeof hdr, f) == sizeof hdr;
|
||||
fclose(f);
|
||||
if (!ok || memcmp(hdr, "\x7f""ELF", 4) != 0) {
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
unsigned short etype = (unsigned short)hdr[16]
|
||||
| ((unsigned short)hdr[17] << 8);
|
||||
if (etype != 2) rc = -1; /* ET_EXEC */
|
||||
|
||||
cleanup:
|
||||
if (unlink(exe) != 0 && errno != ENOENT) {
|
||||
perror(exe);
|
||||
if (rc == 0) rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = absbin();
|
||||
if (!bin) return 1;
|
||||
|
||||
char src[128], asmf[128], obj[128];
|
||||
char fsrc[128], fasm[128], fobj[128];
|
||||
char libdir[64], lib[128], cmd[1024];
|
||||
int pid = getpid();
|
||||
snprintf(libdir, sizeof libdir, "/tmp/wwfc_%d_lib", pid);
|
||||
if (mkdir(libdir, 0755) != 0) {
|
||||
perror(libdir);
|
||||
return 1;
|
||||
}
|
||||
int result = 1;
|
||||
snprintf(src, sizeof src, "%s/m.ww", libdir);
|
||||
snprintf(asmf, sizeof asmf, "%s/m.s", libdir);
|
||||
snprintf(obj, sizeof obj, "%s/m.o", libdir);
|
||||
snprintf(fsrc, sizeof fsrc, "%s/f.ww", libdir);
|
||||
snprintf(fasm, sizeof fasm, "%s/f.s", libdir);
|
||||
snprintf(fobj, sizeof fobj, "%s/f.o", libdir);
|
||||
snprintf(lib, sizeof lib, "%s/libfoo.a", libdir);
|
||||
|
||||
/* a standalone main.o (no undefs) + an unrelated archived foo.o. */
|
||||
FILE *f = fopen(src, "wb");
|
||||
if (!f) { perror(src); goto cleanup; }
|
||||
wwtest_fputs("fn main() i32 = { return 42; };", f);
|
||||
if (fclose(f) != 0) { perror(src); goto cleanup; }
|
||||
f = fopen(fsrc, "wb");
|
||||
if (!f) { perror(fsrc); goto cleanup; }
|
||||
wwtest_fputs("export fn foo() i32 = { return 7; };", f);
|
||||
if (fclose(f) != 0) { perror(fsrc); goto cleanup; }
|
||||
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s", bin, asmf, src);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "w6c main failed\n"); goto cleanup; }
|
||||
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s", bin, obj, asmf);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "w6a main failed\n"); goto cleanup; }
|
||||
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s", bin, fasm, fsrc);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "w6c foo failed\n"); goto cleanup; }
|
||||
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s", bin, fobj, fasm);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "w6a foo failed\n"); goto cleanup; }
|
||||
snprintf(cmd, sizeof cmd, "ar rcs %s %s", lib, fobj);
|
||||
if (runwait(cmd) != 0) { fprintf(stderr, "ar failed\n"); goto cleanup; }
|
||||
|
||||
int counts[] = { 1, 64, 65, 100, 128 };
|
||||
int fail = 0;
|
||||
for (int i = 0; i < (int)(sizeof counts / sizeof counts[0]); i++) {
|
||||
int n = counts[i];
|
||||
char wlnk[2048], clnk[2048];
|
||||
snprintf(wlnk, sizeof wlnk, "%s/w6l_ww", bin);
|
||||
snprintf(clnk, sizeof clnk, "%s/w6l", bin);
|
||||
int wrc = linkwith(wlnk, obj, libdir, n);
|
||||
int crc = linkwith(clnk, obj, libdir, n);
|
||||
if (wrc != 0) {
|
||||
fprintf(stderr, "FAIL: w6l_ww nflags=%d link rc=%d "
|
||||
"(65th-style -L not honoured → heap overflow)\n",
|
||||
n, wrc);
|
||||
fail++;
|
||||
}
|
||||
if (crc != 0) {
|
||||
fprintf(stderr, "FAIL: w6l (cstage) nflags=%d link rc=%d\n",
|
||||
n, crc);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
fprintf(stderr, "w6l_manyflags: %d failure(s)\n", fail);
|
||||
goto cleanup;
|
||||
}
|
||||
result = 0;
|
||||
|
||||
cleanup:
|
||||
{
|
||||
int cleanfail = 0;
|
||||
if (unlink(src) != 0 && errno != ENOENT) {
|
||||
perror(src); cleanfail = 1;
|
||||
}
|
||||
if (unlink(asmf) != 0 && errno != ENOENT) {
|
||||
perror(asmf); cleanfail = 1;
|
||||
}
|
||||
if (unlink(obj) != 0 && errno != ENOENT) {
|
||||
perror(obj); cleanfail = 1;
|
||||
}
|
||||
if (unlink(fsrc) != 0 && errno != ENOENT) {
|
||||
perror(fsrc); cleanfail = 1;
|
||||
}
|
||||
if (unlink(fasm) != 0 && errno != ENOENT) {
|
||||
perror(fasm); cleanfail = 1;
|
||||
}
|
||||
if (unlink(fobj) != 0 && errno != ENOENT) {
|
||||
perror(fobj); cleanfail = 1;
|
||||
}
|
||||
if (unlink(lib) != 0 && errno != ENOENT) {
|
||||
perror(lib); cleanfail = 1;
|
||||
}
|
||||
char exe[128];
|
||||
snprintf(exe, sizeof exe, "%s/wwfc_x", libdir);
|
||||
if (unlink(exe) != 0 && errno != ENOENT) {
|
||||
perror(exe);
|
||||
cleanfail = 1;
|
||||
}
|
||||
if (rmdir(libdir) != 0) {
|
||||
perror(libdir);
|
||||
cleanfail = 1;
|
||||
}
|
||||
if (cleanfail && result == 0) result = 1;
|
||||
}
|
||||
if (result != 0) return result;
|
||||
printf("w6l_manyflags: -L past slot 64 honoured by both stages "
|
||||
"(1/64/65/100/128 flags)\n");
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user