w6l: link GNU long-name archive members; bad members fail the link

The archive walk skipped every member whose header name starts
with '/', which also dropped GNU long-name members (/N) -- any
member with a >15-char filename silently never linked. Only '/ '
(symbol index) and '//' (long-name table) are non-objects; /N
members index by content (names are never consulted). A member
that fails loadimage in the selective pull also stayed silently
unlinked with rc=0; it now reports and fails the link (rule 7).
wwstage w6l diagnostics ride the same .len idiom as the w6a sweep.
This commit is contained in:
2026-08-09 01:07:19 +09:00
parent 4fe2e25da4
commit 5006bf4fb9
5 changed files with 58 additions and 14 deletions

View File

@@ -185,7 +185,16 @@ load_archive(Lnk *l, const char *path, u8 *buf, u64 len)
u64 size = ar_field(hdr + 48, 10);
u64 hdr_end = pos + 60;
if (hdr_end + size > len) break;
if (hdr[0] != '/' && hdr[0] != 0 && hdr[0] != ' ') {
/* '/'-led names: '/ ' is the symbol index and '//' the GNU
* long-name table — neither is an object. '/N' (digits) IS
* a real member whose name lives in that table; names are
* never consulted here, so index it by content. Pre-fix
* every long-named (>15 char) member was silently skipped
* and its definitions never linked. */
int special = (hdr[0] == '/'
&& (hdr[1] == ' ' || hdr[1] == '/'))
|| hdr[0] == 0 || hdr[0] == ' ';
if (!special) {
ArMember *m = calloc(1, sizeof *m);
m->size = size;
m->data = malloc((size_t)size);
@@ -213,6 +222,14 @@ load_archive(Lnk *l, const char *path, u8 *buf, u64 len)
if (load_image(l, path, copy, m->size) == 0) {
m->loaded = 1;
changed = 1;
} else {
/* a member that fails to parse must fail
* the link, not stay silently unlinked
* (rule 7). Consumed either way. */
fprintf(stderr,
"w6l: %s: bad archive member\n", path);
l->errs++;
m->loaded = 1;
}
}
}