selfhost/cmd/w6l: drop l_* prefix from exports + snake fields/helpers

This commit is contained in:
2026-05-11 14:34:11 +09:00
parent f250bcfb3a
commit fce0a54d62
8 changed files with 334 additions and 370 deletions

View File

@@ -123,8 +123,8 @@ fn d_basename(p: *u8) *u8 = {
// ---- file slurp --------------------------------------------------------
fn read_all_so(path_cs: *u8) (*u8, u64) = {
let fd: i32 = os.open(path_cs, os.O_RDONLY, 0i32);
fn readallso(path: *u8) (*u8, u64) = {
let fd: i32 = os.open(path, os.O_RDONLY, 0i32);
if (fd < 0) { return nil, 0u64; };
let n: i64 = os.filesize(fd);
if (n < 0i64) { os.close(fd); return nil, 0u64; };
@@ -137,11 +137,11 @@ fn read_all_so(path_cs: *u8) (*u8, u64) = {
// ---- verdef helpers ----------------------------------------------------
// vd_name_at — walk verdef records and return the name (as *u8 into
// vdnameat — walk verdef records and return the name (as *u8 into
// the .so's verstr buffer) for the entry whose vd_ndx == ndx. The name
// is the first Verdaux's vda_name (subsequent auxes are predecessor
// names). Returns nil if no entry matches.
fn vd_name_at(buf: *u8, verdef_off: u64, verdef_size: u64,
fn vdnameat(buf: *u8, verdef_off: u64, verdef_size: u64,
verstr: *u8, ndx: u16) *u8 = {
let off: u64 = 0u64;
for (off < verdef_size) {
@@ -162,10 +162,10 @@ fn vd_name_at(buf: *u8, verdef_off: u64, verdef_size: u64,
// ---- entry points ------------------------------------------------------
export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
export fn loadso(l: *lnk, path: *u8) i32 = {
let buf: *u8;
let blen: u64;
buf, blen = read_all_so(path_cs);
buf, blen = readallso(path);
if (buf == nil) {
os.write(2, "w6l: cannot read .so\n".ptr, 20u64);
return -1;
@@ -174,22 +174,22 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
os.write(2, "w6l: short ELF\n".ptr, 14u64);
return -1;
};
if (buf[0u64] != 127u8) { return so_err("not ELF"); };
if (buf[1u64] != 69u8) { return so_err("not ELF"); };
if (buf[2u64] != 76u8) { return so_err("not ELF"); };
if (buf[3u64] != 70u8) { return so_err("not ELF"); };
if (buf[4u64] != 2u8) { return so_err("not ELFCLASS64"); };
if (buf[0u64] != 127u8) { return soerr("not ELF"); };
if (buf[1u64] != 69u8) { return soerr("not ELF"); };
if (buf[2u64] != 76u8) { return soerr("not ELF"); };
if (buf[3u64] != 70u8) { return soerr("not ELF"); };
if (buf[4u64] != 2u8) { return soerr("not ELFCLASS64"); };
if (d_u16(buf, EH_EMACHINE) != EM_X86_64_SO) {
return so_err("not amd64");
return soerr("not amd64");
};
if (d_u16(buf, EH_ETYPE) != ET_DYN_SO) {
return so_err("not ET_DYN");
return soerr("not ET_DYN");
};
let shoff: u64 = d_u64(buf, EH_SHOFF);
let shnum: u32 = d_u16(buf, EH_SHNUM): u32;
if (shoff == 0u64) { return so_err("stripped .so unsupported"); };
if (shnum == 0u32) { return so_err("stripped .so unsupported"); };
if (shoff == 0u64) { return soerr("stripped .so unsupported"); };
if (shnum == 0u32) { return soerr("stripped .so unsupported"); };
// Locate the four sections we care about.
let idx_dynsym: i32 = -1;
@@ -207,7 +207,7 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
i += 1u32;
};
if (idx_dynsym < 0) {
return so_err("no .dynsym");
return soerr("no .dynsym");
};
let dynsym_sh: u64 = shoff + (idx_dynsym: u64) * SH_SIZE;
@@ -250,7 +250,7 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
};
};
if (soname_cs == nil) {
soname_cs = d_basename(path_cs);
soname_cs = d_basename(path);
};
// Versym is one u16 per dynsym entry.
@@ -277,9 +277,9 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
};
// Build the lso. Exports are appended in dynsym order so
// l_so_provides_v's first-match semantics match the C version.
// soprovides_v's first-match semantics match the C version.
let so: *lso = amalloc(l.a, 64u64): *lso;
so.path = d_cstr_to_str(l.a, path_cs);
so.path = d_cstr_to_str(l.a, path);
so.soname = d_cstr_to_str(l.a, soname_cs);
so.exports = nil;
let tail: *lexport = nil;
@@ -325,7 +325,7 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
vername_cs = nil;
} else {
if (verstr != nil) {
let nm: *u8 = vd_name_at(buf, verdef_off, verdef_size, verstr, vidx);
let nm: *u8 = vdnameat(buf, verdef_off, verdef_size, verstr, vidx);
vername_cs = nm;
};
}; }; };
@@ -358,34 +358,34 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
return 0;
};
fn so_err(msg: str) i32 = {
fn soerr(msg: str) i32 = {
os.write(2, "w6l: ".ptr, 4u64);
os.write(2, msg.ptr, msg.len: u64);
os.write(2, "\n".ptr, 1u64);
return -1;
};
// l_so_provides — 1 if so exports name, 0 otherwise.
export fn l_so_provides(so: *lso, name: str) i32 = {
// soprovides — 1 if so exports name, 0 otherwise.
export fn soprovides(so: *lso, name: str) i32 = {
if (so == nil) { return 0; };
let e: *lexport = so.exports;
for (e != nil) {
if (s_eq(e.name, name)) { return 1; };
if (streq(e.name, name)) { return 1; };
e = e.enext;
};
return 0;
};
// l_so_version — the version of so's export named `name`, or an empty
// soversion — the version of so's export named `name`, or an empty
// str (ptr=nil, len=0) if the export is unversioned or not present.
export fn l_so_version(so: *lso, name: str) str = {
export fn soversion(so: *lso, name: str) str = {
let result: str;
result.ptr = nil;
result.len = 0i32;
if (so == nil) { return result; };
let e: *lexport = so.exports;
for (e != nil) {
if (s_eq(e.name, name)) {
if (streq(e.name, name)) {
result.ptr = e.version.ptr;
result.len = e.version.len;
return result;
@@ -395,12 +395,4 @@ export fn l_so_version(so: *lso, name: str) str = {
return result;
};
fn s_eq(a: str, b: str) bool = {
if (a.len != b.len) { return false; };
let i: i32 = 0;
for (i < a.len) {
if (a[i] != b[i]) { return false; };
i += 1;
};
return true;
};
// `streq` lives in sym.ww — same bundle, single definition.

View File

@@ -23,10 +23,10 @@
// [dynamic_off] .dynamic (writable; covered by PT_DYNAMIC)
//
// cgen workaround notes:
// - Two-level field assignments through pointers (e.g. r.sym.is_dyn = 1)
// - Two-level field assignments through pointers (e.g. r.sym.isdyn = 1)
// silently fail in the current wwstage cgen. We bind the inner
// pointer to a local first: `let sym = r.sym; sym.is_dyn = 1;`
// - Tuple returns of (i32, str) drop the str payload. l_so_version
// pointer to a local first: `let sym = r.sym; sym.isdyn = 1;`
// - Tuple returns of (i32, str) drop the str payload. soversion
// returns a plain str instead.
// - `def NAME: str = "...";` produces a bogus str (len ends up adding
// to an offset accumulator). We use a fn returning the literal.
@@ -175,19 +175,19 @@ fn str_eq_d(a: str, b: str) bool = {
// ---- main entry --------------------------------------------------------
export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let a: *arena = l.a;
let n: i32 = l.dyn_n;
let n: i32 = l.dynn;
let nu: u64 = n: u64;
// ---- collect dyn syms into a plt_idx-indexed array ----
let dynsyms: **lsym = amalloc(a, nu * 8u64): **lsym;
let s: *lsym = l.syms;
for (s != nil) {
if (s.is_dyn != 0) {
if (s.plt_idx >= 0) {
if (s.plt_idx < n) {
dynsyms[s.plt_idx] = s;
if (s.isdyn != 0) {
if (s.pltidx >= 0) {
if (s.pltidx < n) {
dynsyms[s.pltidx] = s;
};
};
};
@@ -214,7 +214,7 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let j: i32 = 0;
for (j < n) {
let dsm: *lsym = dynsyms[j];
let dl: *lso = dsm.dyn_lib;
let dl: *lso = dsm.dynlib;
if (dl == so) { used = 1; j = n; }
else { j += 1; };
};
@@ -254,10 +254,10 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let j: i32 = 0;
for (j < n) {
let dsm: *lsym = dynsyms[j];
let dl: *lso = dsm.dyn_lib;
let dl: *lso = dsm.dynlib;
if (dl == cur_so) {
let nm0: str = dsm.name;
let dv: str = l_so_version(cur_so, nm0);
let dv: str = soversion(cur_so, nm0);
if (dv.len > 0) {
has = 1; j = n;
} else { j += 1; };
@@ -270,10 +270,10 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let jj: i32 = 0;
for (jj < n) {
let dsm2: *lsym = dynsyms[jj];
let dl2: *lso = dsm2.dyn_lib;
let dl2: *lso = dsm2.dynlib;
if (dl2 == cur_so) {
let nm2: str = dsm2.name;
let vname: str = l_so_version(cur_so, nm2);
let vname: str = soversion(cur_so, nm2);
if (vname.len > 0) {
let seen: i32 = 0;
let k: i32 = 0;
@@ -387,9 +387,9 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
pi = 0;
for (pi < n) {
let dsm3: *lsym = dynsyms[pi];
let dl3: *lso = dsm3.dyn_lib;
let dl3: *lso = dsm3.dynlib;
let nm3: str = dsm3.name;
let vname: str = l_so_version(dl3, nm3);
let vname: str = soversion(dl3, nm3);
if (vname.len == 0) {
d_wr16(versym_for, (pi: u64) * 2u64, VER_NDX_GLOBAL_D);
} else {
@@ -630,7 +630,7 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
for (r != nil) {
if (r.sym != nil) {
let rsym: *lsym = r.sym;
if (rsym.is_dyn != 0) {
if (rsym.isdyn != 0) {
if (r.kind != R_X86_64_PC32_D) {
if (r.kind != R_X86_64_PLT32_D) {
os.write(2, "w6l: dynamic reloc kind unsupported\n".ptr, 35u64);
@@ -638,7 +638,7 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
};
};
let site: u64 = text_va + r.off;
let stub: u64 = plt_va + (rsym.plt_idx: u64) * PLT_STUB_BYTES_D;
let stub: u64 = plt_va + (rsym.pltidx: u64) * PLT_STUB_BYTES_D;
let disp: i64 = (stub: i64) - (site: i64) + r.addend;
d_wr32(l.text, r.off, (disp: i32): u32);
};

View File

@@ -326,15 +326,15 @@ type lsym = struct {
val: u64, // offset within combined .text once linked
defined: i32, // 1 if some lobj defines this symbol
owner: *lobj,
idx_in_owner: i32,
// Dynamic-linking fields. Set by l_resolve when an undefined sym
// is provided by some loaded lso. plt_idx and dynsym_idx default
// to -1 (set explicitly by l_resolve, not by amalloc-zeroing).
is_dyn: i32,
dyn_lib: *lso,
dyn_version: str, // matched export's version; len 0 if none
plt_idx: i32,
dynsym_idx: i32,
idxinowner: i32,
// Dynamic-linking fields. Set by resolve when an undefined sym
// is provided by some loaded lso. pltidx and dynsymidx default
// to -1 (set explicitly by resolve, not by amalloc-zeroing).
isdyn: i32,
dynlib: *lso,
dynversion: str, // matched export's version; len 0 if none
pltidx: i32,
dynsymidx: i32,
snext: *lsym,
};
@@ -350,14 +350,14 @@ type lobj = struct {
path: str,
buf: *u8, // object bytes
len: u64,
text_off: u64, // offset of .text in combined output
text_size: u64,
textoff: u64, // offset of .text in combined output
textsize: u64,
onext: *lobj,
};
// lexport — one entry per GLOBAL/WEAK symbol exported by a loaded .so.
// Stored as a chain in the order the .so's dynsym presents them, so
// l_so_provides_v's first-match semantics agree with the C version.
// soprovides_v's first-match semantics agree with the C version.
type lexport = struct {
name: str,
version: str, // len 0 for unversioned globals
@@ -381,7 +381,7 @@ type lnk = struct {
textcap: u64,
textlen: u64,
errs: i32,
dyn_n: i32, // number of syms routed through PLT
dynn: i32, // number of syms routed through PLT
};
fn streq(a: str, b: str) bool = {
@@ -394,7 +394,7 @@ fn streq(a: str, b: str) bool = {
return true;
};
export fn l_intern(l: *lnk, name: str) *lsym = {
export fn intern(l: *lnk, name: str) *lsym = {
let s: *lsym = l.syms;
for (s != nil) {
if (streq(s.name, name)) { return s; };
@@ -407,7 +407,7 @@ export fn l_intern(l: *lnk, name: str) *lsym = {
return n;
};
export fn l_lookup(l: *lnk, name: str) *lsym = {
export fn lookup(l: *lnk, name: str) *lsym = {
let s: *lsym = l.syms;
for (s != nil) {
if (streq(s.name, name)) { return s; };
@@ -493,8 +493,8 @@ def RELA_ADDEND: u64 = 16u64;
// ---- file slurp --------------------------------------------------------
fn read_all(path_cs: *u8) (*u8, u64) = {
let fd: i32 = os.open(path_cs, os.O_RDONLY, 0i32);
fn readall(path: *u8) (*u8, u64) = {
let fd: i32 = os.open(path, os.O_RDONLY, 0i32);
if (fd < 0) { return nil, 0u64; };
let n: i64 = os.filesize(fd);
if (n < 0i64) { os.close(fd); return nil, 0u64; };
@@ -507,7 +507,7 @@ fn read_all(path_cs: *u8) (*u8, u64) = {
// ---- text buffer growth ------------------------------------------------
fn emit_text(l: *lnk, src: *u8, n: u64) void = {
fn emittext(l: *lnk, src: *u8, n: u64) void = {
if (l.textlen + n > l.textcap) {
let nc: u64 = l.textcap;
if (nc == 0u64) { nc = 4096u64; };
@@ -540,7 +540,7 @@ fn cstrlen(p: *u8) u64 = {
return n;
};
fn cstr_eq(p: *u8, lit: str) bool = {
fn cstreq(p: *u8, lit: str) bool = {
let n: u64 = lit.len: u64;
let i: u64 = 0u64;
for (i < n) {
@@ -552,8 +552,8 @@ fn cstr_eq(p: *u8, lit: str) bool = {
return true;
};
// Build a ww str from a NUL-terminated *u8 (for passing to l_intern).
fn cstr_to_str(a: *arena, p: *u8) str = {
// Build a ww str from a NUL-terminated *u8 (for passing to intern).
fn cstrtostr(a: *arena, p: *u8) str = {
let n: u64 = cstrlen(p);
return astrndup(a, p, n);
};
@@ -577,7 +577,7 @@ type armember = struct {
mnext: *armember,
};
fn is_archive(p: *u8, len: u64) bool = {
fn isarchive(p: *u8, len: u64) bool = {
if (len < 8u64) { return false; };
if (p[0u64] != 33u8) { return false; }; // '!'
if (p[1u64] != 60u8) { return false; }; // '<'
@@ -590,8 +590,8 @@ fn is_archive(p: *u8, len: u64) bool = {
return true;
};
// ar_field — parse a space-padded decimal integer of width n.
fn ar_field(p: *u8, n: u64) u64 = {
// arfield — parse a space-padded decimal integer of width n.
fn arfield(p: *u8, n: u64) u64 = {
let v: u64 = 0u64;
let i: u64 = 0u64;
for (i < n) {
@@ -604,10 +604,10 @@ fn ar_field(p: *u8, n: u64) u64 = {
return v;
};
// elf_globals — return a linked list of names of globally-defined
// elfglobals — return a linked list of names of globally-defined
// (STB_GLOBAL) symbols whose section is `.text`. Names are arena
// copies, so the source ELF buffer can be freed afterward.
fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = {
if (len < EHDR_SIZE) { return nil; };
if (buf[0u64] != 127u8) { return nil; };
if (buf[1u64] != 69u8) { return nil; };
@@ -630,7 +630,7 @@ fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
let sh_name: u32 = rd_u32(buf, sh_off + SHDR_NAME);
let nm: *u8 = shstr + (sh_name: u64);
if (sh_type == SHT_PROGBITS: u32) {
if (cstr_eq(nm, ".text")) { idx_text = i: i32; };
if (cstreq(nm, ".text")) { idx_text = i: i32; };
};
if (sh_type == SHT_SYMTAB: u32) { idx_symtab = i: i32; };
i += 1u32;
@@ -662,7 +662,7 @@ fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
if ((st_shndx: i32) == idx_text) {
let nm_p: *u8 = strtab + (st_name: u64);
if (nm_p[0u64] != 0u8) {
let nm: str = cstr_to_str(a, nm_p);
let nm: str = cstrtostr(a, nm_p);
let de: *defent = amalloc(a, 32u64): *defent;
de.name = nm;
de.dnext = head;
@@ -676,13 +676,13 @@ fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
return head;
};
// member_defines_undef — true if any of m's defined globals matches a
// memberdefinesundef — true if any of m's defined globals matches a
// currently-undefined symbol in the linker's symbol table. Names not
// already interned are uninteresting (the link doesn't need them yet).
fn member_defines_undef(l: *lnk, m: *armember) bool = {
fn memberdefinesundef(l: *lnk, m: *armember) bool = {
let de: *defent = m.defs;
for (de != nil) {
let s: *lsym = l_lookup(l, de.name);
let s: *lsym = lookup(l, de.name);
if (s != nil) {
if (s.defined == 0) { return true; };
};
@@ -691,17 +691,17 @@ fn member_defines_undef(l: *lnk, m: *armember) bool = {
return false;
};
// load_archive — port of cmd/w6l/obj.c:load_archive.
// loadarchive — port of cmd/w6l/obj.c:load_archive.
//
// Pass 1 indexes every regular member. Pass 2 iteratively pulls in any
// member that supplies a currently-undefined symbol; each pull may
// introduce fresh undefs, so we loop until quiescent.
fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
fn loadarchive(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
let head: *armember = nil;
let tail: *armember = nil;
let pos: u64 = 8u64; // past "!<arch>\n"
for (pos + 60u64 <= len) {
let hdr_size: u64 = ar_field(buf + pos + 48u64, 10u64);
let hdr_size: u64 = arfield(buf + pos + 48u64, 10u64);
let hdr_end: u64 = pos + 60u64;
if (hdr_end + hdr_size > len) { break; };
let first: u8 = buf[pos];
@@ -717,7 +717,7 @@ fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
i += 1u64;
};
m.data = mb;
m.defs = elf_globals(l.a, mb, hdr_size);
m.defs = elfglobals(l.a, mb, hdr_size);
m.loaded = 0;
m.mnext = nil;
if (head == nil) { head = m; }
@@ -734,8 +734,8 @@ fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let m: *armember = head;
for (m != nil) {
if (m.loaded == 0) {
if (member_defines_undef(l, m)) {
if (load_image(l, path_cs, m.data, m.size) == 0) {
if (memberdefinesundef(l, m)) {
if (loadimage(l, path, m.data, m.size) == 0) {
m.loaded = 1;
changed = 1;
};
@@ -749,21 +749,21 @@ fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
// ---- main loader -------------------------------------------------------
export fn l_load(l: *lnk, path_cs: *u8) i32 = {
export fn load(l: *lnk, path: *u8) i32 = {
let bufp: *u8;
let buflen: u64;
bufp, buflen = read_all(path_cs);
bufp, buflen = readall(path);
if (bufp == nil) {
os.write(2, "w6l: cannot read object\n".ptr, 23u64);
return -1;
};
if (is_archive(bufp, buflen)) {
return load_archive(l, path_cs, bufp, buflen);
if (isarchive(bufp, buflen)) {
return loadarchive(l, path, bufp, buflen);
};
return load_image(l, path_cs, bufp, buflen);
return loadimage(l, path, bufp, buflen);
};
fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
if (len < EHDR_SIZE) { return -1; };
// magic: 0x7f, 'E', 'L', 'F'
if (buf[0u64] != 127u8) { return -1; };
@@ -792,11 +792,11 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let sh_name: u32 = rd_u32(buf, sh_off + SHDR_NAME);
let nm: *u8 = shstr + (sh_name: u64);
if (sh_type == SHT_PROGBITS: u32) {
if (cstr_eq(nm, ".text")) { idx_text = i: i32; };
if (cstreq(nm, ".text")) { idx_text = i: i32; };
};
if (sh_type == SHT_SYMTAB: u32) { idx_symtab = i: i32; };
if (sh_type == SHT_RELA: u32) {
if (cstr_eq(nm, ".rela.text")) { idx_rela = i: i32; };
if (cstreq(nm, ".rela.text")) { idx_rela = i: i32; };
};
i += 1u32;
};
@@ -825,16 +825,16 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
// Track this object.
let ob: *lobj = amalloc(l.a, 64u64): *lobj;
ob.path = cstr_to_str(l.a, path_cs);
ob.path = cstrtostr(l.a, path);
ob.buf = buf;
ob.len = len;
ob.text_off = l.textlen;
ob.text_size = text_size;
ob.textoff = l.textlen;
ob.textsize = text_size;
ob.onext = l.objs;
l.objs = ob;
// Append .text bytes to the combined image.
emit_text(l, buf + text_off, text_size);
emittext(l, buf + text_off, text_size);
// Walk symbols. We don't keep a per-object map[] of *lsym. Instead
// the reloc loop re-walks symtab and re-interns by name. Simpler
@@ -847,8 +847,8 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let st_value: u64 = rd_u64(buf, sym_p + SYM_VALUE);
let nm_p: *u8 = strtab + (st_name: u64);
if (nm_p[0u64] != 0u8) {
let nm: str = cstr_to_str(l.a, nm_p);
let gs: *lsym = l_intern(l, nm);
let nm: str = cstrtostr(l.a, nm_p);
let gs: *lsym = intern(l, nm);
if (st_shndx != 0u16) {
if ((st_shndx: i32) == idx_text) {
if (gs.defined != 0) {
@@ -857,8 +857,8 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
} else {
gs.defined = 1;
gs.owner = ob;
gs.idx_in_owner = si: i32;
gs.val = ob.text_off + st_value;
gs.idxinowner = si: i32;
gs.val = ob.textoff + st_value;
};
};
};
@@ -881,7 +881,7 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let r_sym_idx: u32 = (r_info >> 32u64): u32;
let r_kind: i32 = ((r_info & 4294967295u64): u32): i32;
let nr: *lrel = amalloc(l.a, 48u64): *lrel;
nr.off = ob.text_off + r_off;
nr.off = ob.textoff + r_off;
nr.kind = r_kind;
nr.addend = r_addend: i64;
// Look up the referenced sym by name (re-walk symtab).
@@ -890,8 +890,8 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let s_name: u32 = rd_u32(buf, s_p + SYM_NAME);
let s_nm: *u8 = strtab + (s_name: u64);
if (s_nm[0u64] != 0u8) {
let nm: str = cstr_to_str(l.a, s_nm);
nr.sym = l_intern(l, nm);
let nm: str = cstrtostr(l.a, s_nm);
nr.sym = intern(l, nm);
};
};
nr.rnext = l.rels;
@@ -1028,8 +1028,8 @@ fn d_basename(p: *u8) *u8 = {
// ---- file slurp --------------------------------------------------------
fn read_all_so(path_cs: *u8) (*u8, u64) = {
let fd: i32 = os.open(path_cs, os.O_RDONLY, 0i32);
fn readallso(path: *u8) (*u8, u64) = {
let fd: i32 = os.open(path, os.O_RDONLY, 0i32);
if (fd < 0) { return nil, 0u64; };
let n: i64 = os.filesize(fd);
if (n < 0i64) { os.close(fd); return nil, 0u64; };
@@ -1042,11 +1042,11 @@ fn read_all_so(path_cs: *u8) (*u8, u64) = {
// ---- verdef helpers ----------------------------------------------------
// vd_name_at — walk verdef records and return the name (as *u8 into
// vdnameat — walk verdef records and return the name (as *u8 into
// the .so's verstr buffer) for the entry whose vd_ndx == ndx. The name
// is the first Verdaux's vda_name (subsequent auxes are predecessor
// names). Returns nil if no entry matches.
fn vd_name_at(buf: *u8, verdef_off: u64, verdef_size: u64,
fn vdnameat(buf: *u8, verdef_off: u64, verdef_size: u64,
verstr: *u8, ndx: u16) *u8 = {
let off: u64 = 0u64;
for (off < verdef_size) {
@@ -1067,10 +1067,10 @@ fn vd_name_at(buf: *u8, verdef_off: u64, verdef_size: u64,
// ---- entry points ------------------------------------------------------
export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
export fn loadso(l: *lnk, path: *u8) i32 = {
let buf: *u8;
let blen: u64;
buf, blen = read_all_so(path_cs);
buf, blen = readallso(path);
if (buf == nil) {
os.write(2, "w6l: cannot read .so\n".ptr, 20u64);
return -1;
@@ -1079,22 +1079,22 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
os.write(2, "w6l: short ELF\n".ptr, 14u64);
return -1;
};
if (buf[0u64] != 127u8) { return so_err("not ELF"); };
if (buf[1u64] != 69u8) { return so_err("not ELF"); };
if (buf[2u64] != 76u8) { return so_err("not ELF"); };
if (buf[3u64] != 70u8) { return so_err("not ELF"); };
if (buf[4u64] != 2u8) { return so_err("not ELFCLASS64"); };
if (buf[0u64] != 127u8) { return soerr("not ELF"); };
if (buf[1u64] != 69u8) { return soerr("not ELF"); };
if (buf[2u64] != 76u8) { return soerr("not ELF"); };
if (buf[3u64] != 70u8) { return soerr("not ELF"); };
if (buf[4u64] != 2u8) { return soerr("not ELFCLASS64"); };
if (d_u16(buf, EH_EMACHINE) != EM_X86_64_SO) {
return so_err("not amd64");
return soerr("not amd64");
};
if (d_u16(buf, EH_ETYPE) != ET_DYN_SO) {
return so_err("not ET_DYN");
return soerr("not ET_DYN");
};
let shoff: u64 = d_u64(buf, EH_SHOFF);
let shnum: u32 = d_u16(buf, EH_SHNUM): u32;
if (shoff == 0u64) { return so_err("stripped .so unsupported"); };
if (shnum == 0u32) { return so_err("stripped .so unsupported"); };
if (shoff == 0u64) { return soerr("stripped .so unsupported"); };
if (shnum == 0u32) { return soerr("stripped .so unsupported"); };
// Locate the four sections we care about.
let idx_dynsym: i32 = -1;
@@ -1112,7 +1112,7 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
i += 1u32;
};
if (idx_dynsym < 0) {
return so_err("no .dynsym");
return soerr("no .dynsym");
};
let dynsym_sh: u64 = shoff + (idx_dynsym: u64) * SH_SIZE;
@@ -1155,7 +1155,7 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
};
};
if (soname_cs == nil) {
soname_cs = d_basename(path_cs);
soname_cs = d_basename(path);
};
// Versym is one u16 per dynsym entry.
@@ -1182,9 +1182,9 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
};
// Build the lso. Exports are appended in dynsym order so
// l_so_provides_v's first-match semantics match the C version.
// soprovides_v's first-match semantics match the C version.
let so: *lso = amalloc(l.a, 64u64): *lso;
so.path = d_cstr_to_str(l.a, path_cs);
so.path = d_cstr_to_str(l.a, path);
so.soname = d_cstr_to_str(l.a, soname_cs);
so.exports = nil;
let tail: *lexport = nil;
@@ -1230,7 +1230,7 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
vername_cs = nil;
} else {
if (verstr != nil) {
let nm: *u8 = vd_name_at(buf, verdef_off, verdef_size, verstr, vidx);
let nm: *u8 = vdnameat(buf, verdef_off, verdef_size, verstr, vidx);
vername_cs = nm;
};
}; }; };
@@ -1263,34 +1263,34 @@ export fn l_load_so(l: *lnk, path_cs: *u8) i32 = {
return 0;
};
fn so_err(msg: str) i32 = {
fn soerr(msg: str) i32 = {
os.write(2, "w6l: ".ptr, 4u64);
os.write(2, msg.ptr, msg.len: u64);
os.write(2, "\n".ptr, 1u64);
return -1;
};
// l_so_provides — 1 if so exports name, 0 otherwise.
export fn l_so_provides(so: *lso, name: str) i32 = {
// soprovides — 1 if so exports name, 0 otherwise.
export fn soprovides(so: *lso, name: str) i32 = {
if (so == nil) { return 0; };
let e: *lexport = so.exports;
for (e != nil) {
if (s_eq(e.name, name)) { return 1; };
if (streq(e.name, name)) { return 1; };
e = e.enext;
};
return 0;
};
// l_so_version — the version of so's export named `name`, or an empty
// soversion — the version of so's export named `name`, or an empty
// str (ptr=nil, len=0) if the export is unversioned or not present.
export fn l_so_version(so: *lso, name: str) str = {
export fn soversion(so: *lso, name: str) str = {
let result: str;
result.ptr = nil;
result.len = 0i32;
if (so == nil) { return result; };
let e: *lexport = so.exports;
for (e != nil) {
if (s_eq(e.name, name)) {
if (streq(e.name, name)) {
result.ptr = e.version.ptr;
result.len = e.version.len;
return result;
@@ -1300,15 +1300,7 @@ export fn l_so_version(so: *lso, name: str) str = {
return result;
};
fn s_eq(a: str, b: str) bool = {
if (a.len != b.len) { return false; };
let i: i32 = 0;
for (i < a.len) {
if (a[i] != b[i]) { return false; };
i += 1;
};
return true;
};
// `streq` lives in sym.ww — same bundle, single definition.
// selfhost/cmd/w6l/pass.ww — port of cmd/w6l/pass.c.
//
@@ -1329,14 +1321,14 @@ use dyn;
def R_X86_64_PC32: i32 = 2;
def R_X86_64_PLT32: i32 = 4;
export fn l_resolve(l: *lnk) i32 = {
export fn resolve(l: *lnk) i32 = {
// Initialise dynamic-linking sentinels. amalloc zeroes, so
// is_dyn/dyn_lib start clean — but plt_idx and dynsym_idx
// isdyn/dynlib start clean — but pltidx and dynsymidx
// must be -1, not 0.
let si: *lsym = l.syms;
for (si != nil) {
si.plt_idx = -1;
si.dynsym_idx = -1;
si.pltidx = -1;
si.dynsymidx = -1;
si = si.snext;
};
@@ -1348,14 +1340,14 @@ export fn l_resolve(l: *lnk) i32 = {
if (r.sym != nil) {
if (r.sym.defined == 0) {
let sym: *lsym = r.sym;
if (sym.is_dyn == 0) {
if (sym.isdyn == 0) {
let so: *lso = l.sos;
for (so != nil) {
if (l_so_provides(so, sym.name) != 0) {
sym.is_dyn = 1;
sym.dyn_lib = so;
sym.plt_idx = l.dyn_n;
l.dyn_n += 1;
if (soprovides(so, sym.name) != 0) {
sym.isdyn = 1;
sym.dynlib = so;
sym.pltidx = l.dynn;
l.dynn += 1;
so = nil; // break
} else {
so = so.sonext;
@@ -1372,7 +1364,7 @@ export fn l_resolve(l: *lnk) i32 = {
for (r2 != nil) {
if (r2.sym != nil) {
if (r2.sym.defined == 0) {
if (r2.sym.is_dyn == 0) {
if (r2.sym.isdyn == 0) {
os.write(2, "w6l: undefined reference to '".ptr, 28u64);
let nm: str = r2.sym.name;
os.write(2, nm.ptr, nm.len: u64);
@@ -1386,20 +1378,20 @@ export fn l_resolve(l: *lnk) i32 = {
return l.errs;
};
fn patch_u32(p: *u8, v: u32) void = {
fn patchu32(p: *u8, v: u32) void = {
p[0] = (v & 255u32): u8;
p[1] = ((v >> 8u32) & 255u32): u8;
p[2] = ((v >> 16u32) & 255u32): u8;
p[3] = ((v >> 24u32) & 255u32): u8;
};
export fn l_relocate(l: *lnk, base: u64) i32 = {
export fn relocate(l: *lnk, base: u64) i32 = {
let r: *lrel = l.rels;
for (r != nil) {
if (r.sym != nil) {
// Dynamic refs are patched later in dynout once the
// PLT vaddr is known.
if (r.sym.is_dyn != 0) {
if (r.sym.isdyn != 0) {
r = r.rnext;
continue;
};
@@ -1409,12 +1401,12 @@ export fn l_relocate(l: *lnk, base: u64) i32 = {
let site: u64 = base + r.off;
let target: i64 = (base + r.sym.val): i64;
let rel: i64 = (target - site: i64) + r.addend;
patch_u32(l.text + r.off, rel: u32);
patchu32(l.text + r.off, rel: u32);
} else { if (k == R_X86_64_PLT32) {
let site: u64 = base + r.off;
let target: i64 = (base + r.sym.val): i64;
let rel: i64 = (target - site: i64) + r.addend;
patch_u32(l.text + r.off, rel: u32);
patchu32(l.text + r.off, rel: u32);
} else {
os.write(2, "w6l: unsupported reloc kind\n".ptr, 27u64);
l.errs += 1;
@@ -1451,10 +1443,10 @@ export fn l_relocate(l: *lnk, base: u64) i32 = {
// [dynamic_off] .dynamic (writable; covered by PT_DYNAMIC)
//
// cgen workaround notes:
// - Two-level field assignments through pointers (e.g. r.sym.is_dyn = 1)
// - Two-level field assignments through pointers (e.g. r.sym.isdyn = 1)
// silently fail in the current wwstage cgen. We bind the inner
// pointer to a local first: `let sym = r.sym; sym.is_dyn = 1;`
// - Tuple returns of (i32, str) drop the str payload. l_so_version
// pointer to a local first: `let sym = r.sym; sym.isdyn = 1;`
// - Tuple returns of (i32, str) drop the str payload. soversion
// returns a plain str instead.
// - `def NAME: str = "...";` produces a bogus str (len ends up adding
// to an offset accumulator). We use a fn returning the literal.
@@ -1603,19 +1595,19 @@ fn str_eq_d(a: str, b: str) bool = {
// ---- main entry --------------------------------------------------------
export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let a: *arena = l.a;
let n: i32 = l.dyn_n;
let n: i32 = l.dynn;
let nu: u64 = n: u64;
// ---- collect dyn syms into a plt_idx-indexed array ----
let dynsyms: **lsym = amalloc(a, nu * 8u64): **lsym;
let s: *lsym = l.syms;
for (s != nil) {
if (s.is_dyn != 0) {
if (s.plt_idx >= 0) {
if (s.plt_idx < n) {
dynsyms[s.plt_idx] = s;
if (s.isdyn != 0) {
if (s.pltidx >= 0) {
if (s.pltidx < n) {
dynsyms[s.pltidx] = s;
};
};
};
@@ -1642,7 +1634,7 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let j: i32 = 0;
for (j < n) {
let dsm: *lsym = dynsyms[j];
let dl: *lso = dsm.dyn_lib;
let dl: *lso = dsm.dynlib;
if (dl == so) { used = 1; j = n; }
else { j += 1; };
};
@@ -1682,10 +1674,10 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let j: i32 = 0;
for (j < n) {
let dsm: *lsym = dynsyms[j];
let dl: *lso = dsm.dyn_lib;
let dl: *lso = dsm.dynlib;
if (dl == cur_so) {
let nm0: str = dsm.name;
let dv: str = l_so_version(cur_so, nm0);
let dv: str = soversion(cur_so, nm0);
if (dv.len > 0) {
has = 1; j = n;
} else { j += 1; };
@@ -1698,10 +1690,10 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
let jj: i32 = 0;
for (jj < n) {
let dsm2: *lsym = dynsyms[jj];
let dl2: *lso = dsm2.dyn_lib;
let dl2: *lso = dsm2.dynlib;
if (dl2 == cur_so) {
let nm2: str = dsm2.name;
let vname: str = l_so_version(cur_so, nm2);
let vname: str = soversion(cur_so, nm2);
if (vname.len > 0) {
let seen: i32 = 0;
let k: i32 = 0;
@@ -1815,9 +1807,9 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
pi = 0;
for (pi < n) {
let dsm3: *lsym = dynsyms[pi];
let dl3: *lso = dsm3.dyn_lib;
let dl3: *lso = dsm3.dynlib;
let nm3: str = dsm3.name;
let vname: str = l_so_version(dl3, nm3);
let vname: str = soversion(dl3, nm3);
if (vname.len == 0) {
d_wr16(versym_for, (pi: u64) * 2u64, VER_NDX_GLOBAL_D);
} else {
@@ -2058,7 +2050,7 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
for (r != nil) {
if (r.sym != nil) {
let rsym: *lsym = r.sym;
if (rsym.is_dyn != 0) {
if (rsym.isdyn != 0) {
if (r.kind != R_X86_64_PC32_D) {
if (r.kind != R_X86_64_PLT32_D) {
os.write(2, "w6l: dynamic reloc kind unsupported\n".ptr, 35u64);
@@ -2066,7 +2058,7 @@ export fn l_emit_dyn_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
};
};
let site: u64 = text_va + r.off;
let stub: u64 = plt_va + (rsym.plt_idx: u64) * PLT_STUB_BYTES_D;
let stub: u64 = plt_va + (rsym.pltidx: u64) * PLT_STUB_BYTES_D;
let disp: i64 = (stub: i64) - (site: i64) + r.addend;
d_wr32(l.text, r.off, (disp: i32): u32);
};
@@ -2196,31 +2188,31 @@ def TEXT_OFF: u64 = 4096u64; // 0x1000
// ---- little-endian byte writers ----------------------------------------
fn wr_u16(buf: *u8, off: u64, v: u16) void = {
fn wru16(buf: *u8, off: u64, v: u16) void = {
buf[off] = (v & 255u16): u8;
buf[off + 1u64] = ((v >> 8u16) & 255u16): u8;
};
fn wr_u32(buf: *u8, off: u64, v: u32) void = {
fn wru32(buf: *u8, off: u64, v: u32) void = {
buf[off] = (v & 255u32): u8;
buf[off + 1u64] = ((v >> 8u32) & 255u32): u8;
buf[off + 2u64] = ((v >> 16u32) & 255u32): u8;
buf[off + 3u64] = ((v >> 24u32) & 255u32): u8;
};
fn wr_u64(buf: *u8, off: u64, v: u64) void = {
wr_u32(buf, off, (v & 4294967295u64): u32);
wr_u32(buf, off + 4u64, ((v >> 32u64) & 4294967295u64): u32);
fn wru64(buf: *u8, off: u64, v: u64) void = {
wru32(buf, off, (v & 4294967295u64): u32);
wru32(buf, off + 4u64, ((v >> 32u64) & 4294967295u64): u32);
};
// ---- emit ---------------------------------------------------------------
export fn l_emit_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
// Dispatch: any loaded shared object plus any dynamic ref means
// we owe the loader a real PT_INTERP/PT_DYNAMIC binary.
if (l.sos != nil) {
if (l.dyn_n > 0) {
return l_emit_dyn_elf(l, fd, base, entry);
if (l.dynn > 0) {
return emitdynelf(l, fd, base, entry);
};
};
@@ -2237,29 +2229,29 @@ export fn l_emit_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
hdr[4u64] = ELFCLASS64;
hdr[5u64] = ELFDATA2LSB;
hdr[6u64] = EV_CURRENT: u8;
wr_u16(hdr, 16u64, ET_EXEC); // e_type
wr_u16(hdr, 18u64, EM_X86_64_W); // e_machine
wr_u32(hdr, 20u64, EV_CURRENT); // e_version
wr_u64(hdr, 24u64, entry); // e_entry
wr_u64(hdr, 32u64, 64u64); // e_phoff = sizeof(Ehdr)
wr_u64(hdr, 40u64, 0u64); // e_shoff
wr_u32(hdr, 48u64, 0u32); // e_flags
wr_u16(hdr, 52u64, 64u16); // e_ehsize
wr_u16(hdr, 54u64, 56u16); // e_phentsize
wr_u16(hdr, 56u64, 1u16); // e_phnum
wr_u16(hdr, 58u64, 0u16); // e_shentsize
wr_u16(hdr, 60u64, 0u16); // e_shnum
wr_u16(hdr, 62u64, 0u16); // e_shstrndx
wru16(hdr, 16u64, ET_EXEC); // e_type
wru16(hdr, 18u64, EM_X86_64_W); // e_machine
wru32(hdr, 20u64, EV_CURRENT); // e_version
wru64(hdr, 24u64, entry); // e_entry
wru64(hdr, 32u64, 64u64); // e_phoff = sizeof(Ehdr)
wru64(hdr, 40u64, 0u64); // e_shoff
wru32(hdr, 48u64, 0u32); // e_flags
wru16(hdr, 52u64, 64u16); // e_ehsize
wru16(hdr, 54u64, 56u16); // e_phentsize
wru16(hdr, 56u64, 1u16); // e_phnum
wru16(hdr, 58u64, 0u16); // e_shentsize
wru16(hdr, 60u64, 0u16); // e_shnum
wru16(hdr, 62u64, 0u16); // e_shstrndx
// --- Phdr (56 bytes) at offset 64 ---
wr_u32(hdr, 64u64, PT_LOAD); // p_type
wr_u32(hdr, 68u64, PF_R | PF_X); // p_flags
wr_u64(hdr, 72u64, 0u64); // p_offset
wr_u64(hdr, 80u64, base); // p_vaddr
wr_u64(hdr, 88u64, base); // p_paddr
wr_u64(hdr, 96u64, filesz); // p_filesz
wr_u64(hdr, 104u64, filesz); // p_memsz
wr_u64(hdr, 112u64, TEXT_OFF); // p_align
wru32(hdr, 64u64, PT_LOAD); // p_type
wru32(hdr, 68u64, PF_R | PF_X); // p_flags
wru64(hdr, 72u64, 0u64); // p_offset
wru64(hdr, 80u64, base); // p_vaddr
wru64(hdr, 88u64, base); // p_paddr
wru64(hdr, 96u64, filesz); // p_filesz
wru64(hdr, 104u64, filesz); // p_memsz
wru64(hdr, 112u64, TEXT_OFF); // p_align
// Write [0..0x1000) then .text.
let n1: i64 = os.writefull(fd, hdr, TEXT_OFF);
@@ -2296,17 +2288,7 @@ fn mklnk(a: *arena) *lnk = {
return l;
};
fn cstreq(a: *u8, lit: str) bool = {
let n: u64 = lit.len: u64;
let i: u64 = 0u64;
for (i < n) {
let li: i32 = i: i32;
if (a[i] != lit[li]) { return false; };
i += 1u64;
};
if (a[i] != 0u8) { return false; };
return true;
};
// `cstreq` lives in obj.ww — same bundle, single definition.
// `cstrlen` lives in obj.ww — same bundle, single definition.
@@ -2549,12 +2531,12 @@ export fn main(argc: i32, argv: **u8) i32 = {
let l: *lnk = mklnk(a);
// Seed _start so libwwrt-style start.o is recognised as wanted.
l_intern(l, "_start");
intern(l, "_start");
// Load positional inputs first (preserving order).
let k: i32 = 0;
for (k < ninputs) {
if (l_load(l, inputs[k]) != 0) {
if (load(l, inputs[k]) != 0) {
return 1;
};
k += 1;
@@ -2573,19 +2555,19 @@ export fn main(argc: i32, argv: **u8) i32 = {
return 1;
};
if (isso(p) != 0) {
if (l_load_so(l, p) != 0) { return 1; };
if (loadso(l, p) != 0) { return 1; };
} else {
if (l_load(l, p) != 0) { return 1; };
if (load(l, p) != 0) { return 1; };
};
lf += 1;
};
if (l_resolve(l) != 0) { return 1; };
if (l_relocate(l, BASE + CODE_VA_OFF) != 0) { return 1; };
if (resolve(l) != 0) { return 1; };
if (relocate(l, BASE + CODE_VA_OFF) != 0) { return 1; };
let entrysym: *lsym = l_lookup(l, "_start");
if (entrysym == nil) { entrysym = l_lookup(l, "main"); }
else { if (entrysym.defined == 0) { entrysym = l_lookup(l, "main"); }; };
let entrysym: *lsym = lookup(l, "_start");
if (entrysym == nil) { entrysym = lookup(l, "main"); }
else { if (entrysym.defined == 0) { entrysym = lookup(l, "main"); }; };
if (entrysym == nil) {
os.write(2, "w6l: no _start or main symbol\n".ptr, 29u64);
return 1;
@@ -2603,7 +2585,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
};
let entryva: u64 = BASE + CODE_VA_OFF + entrysym.val;
let rc: i32 = l_emit_elf(l, fd, BASE, entryva);
let rc: i32 = emitelf(l, fd, BASE, entryva);
os.close(fd);
return rc;
};

View File

@@ -23,17 +23,7 @@ fn mklnk(a: *arena) *lnk = {
return l;
};
fn cstreq(a: *u8, lit: str) bool = {
let n: u64 = lit.len: u64;
let i: u64 = 0u64;
for (i < n) {
let li: i32 = i: i32;
if (a[i] != lit[li]) { return false; };
i += 1u64;
};
if (a[i] != 0u8) { return false; };
return true;
};
// `cstreq` lives in obj.ww — same bundle, single definition.
// `cstrlen` lives in obj.ww — same bundle, single definition.
@@ -276,12 +266,12 @@ export fn main(argc: i32, argv: **u8) i32 = {
let l: *lnk = mklnk(a);
// Seed _start so libwwrt-style start.o is recognised as wanted.
l_intern(l, "_start");
intern(l, "_start");
// Load positional inputs first (preserving order).
let k: i32 = 0;
for (k < ninputs) {
if (l_load(l, inputs[k]) != 0) {
if (load(l, inputs[k]) != 0) {
return 1;
};
k += 1;
@@ -300,19 +290,19 @@ export fn main(argc: i32, argv: **u8) i32 = {
return 1;
};
if (isso(p) != 0) {
if (l_load_so(l, p) != 0) { return 1; };
if (loadso(l, p) != 0) { return 1; };
} else {
if (l_load(l, p) != 0) { return 1; };
if (load(l, p) != 0) { return 1; };
};
lf += 1;
};
if (l_resolve(l) != 0) { return 1; };
if (l_relocate(l, BASE + CODE_VA_OFF) != 0) { return 1; };
if (resolve(l) != 0) { return 1; };
if (relocate(l, BASE + CODE_VA_OFF) != 0) { return 1; };
let entrysym: *lsym = l_lookup(l, "_start");
if (entrysym == nil) { entrysym = l_lookup(l, "main"); }
else { if (entrysym.defined == 0) { entrysym = l_lookup(l, "main"); }; };
let entrysym: *lsym = lookup(l, "_start");
if (entrysym == nil) { entrysym = lookup(l, "main"); }
else { if (entrysym.defined == 0) { entrysym = lookup(l, "main"); }; };
if (entrysym == nil) {
os.write(2, "w6l: no _start or main symbol\n".ptr, 29u64);
return 1;
@@ -330,7 +320,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
};
let entryva: u64 = BASE + CODE_VA_OFF + entrysym.val;
let rc: i32 = l_emit_elf(l, fd, BASE, entryva);
let rc: i32 = emitelf(l, fd, BASE, entryva);
os.close(fd);
return rc;
};

View File

@@ -75,8 +75,8 @@ def RELA_ADDEND: u64 = 16u64;
// ---- file slurp --------------------------------------------------------
fn read_all(path_cs: *u8) (*u8, u64) = {
let fd: i32 = os.open(path_cs, os.O_RDONLY, 0i32);
fn readall(path: *u8) (*u8, u64) = {
let fd: i32 = os.open(path, os.O_RDONLY, 0i32);
if (fd < 0) { return nil, 0u64; };
let n: i64 = os.filesize(fd);
if (n < 0i64) { os.close(fd); return nil, 0u64; };
@@ -89,7 +89,7 @@ fn read_all(path_cs: *u8) (*u8, u64) = {
// ---- text buffer growth ------------------------------------------------
fn emit_text(l: *lnk, src: *u8, n: u64) void = {
fn emittext(l: *lnk, src: *u8, n: u64) void = {
if (l.textlen + n > l.textcap) {
let nc: u64 = l.textcap;
if (nc == 0u64) { nc = 4096u64; };
@@ -122,7 +122,7 @@ fn cstrlen(p: *u8) u64 = {
return n;
};
fn cstr_eq(p: *u8, lit: str) bool = {
fn cstreq(p: *u8, lit: str) bool = {
let n: u64 = lit.len: u64;
let i: u64 = 0u64;
for (i < n) {
@@ -134,8 +134,8 @@ fn cstr_eq(p: *u8, lit: str) bool = {
return true;
};
// Build a ww str from a NUL-terminated *u8 (for passing to l_intern).
fn cstr_to_str(a: *arena, p: *u8) str = {
// Build a ww str from a NUL-terminated *u8 (for passing to intern).
fn cstrtostr(a: *arena, p: *u8) str = {
let n: u64 = cstrlen(p);
return astrndup(a, p, n);
};
@@ -159,7 +159,7 @@ type armember = struct {
mnext: *armember,
};
fn is_archive(p: *u8, len: u64) bool = {
fn isarchive(p: *u8, len: u64) bool = {
if (len < 8u64) { return false; };
if (p[0u64] != 33u8) { return false; }; // '!'
if (p[1u64] != 60u8) { return false; }; // '<'
@@ -172,8 +172,8 @@ fn is_archive(p: *u8, len: u64) bool = {
return true;
};
// ar_field — parse a space-padded decimal integer of width n.
fn ar_field(p: *u8, n: u64) u64 = {
// arfield — parse a space-padded decimal integer of width n.
fn arfield(p: *u8, n: u64) u64 = {
let v: u64 = 0u64;
let i: u64 = 0u64;
for (i < n) {
@@ -186,10 +186,10 @@ fn ar_field(p: *u8, n: u64) u64 = {
return v;
};
// elf_globals — return a linked list of names of globally-defined
// elfglobals — return a linked list of names of globally-defined
// (STB_GLOBAL) symbols whose section is `.text`. Names are arena
// copies, so the source ELF buffer can be freed afterward.
fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = {
if (len < EHDR_SIZE) { return nil; };
if (buf[0u64] != 127u8) { return nil; };
if (buf[1u64] != 69u8) { return nil; };
@@ -212,7 +212,7 @@ fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
let sh_name: u32 = rd_u32(buf, sh_off + SHDR_NAME);
let nm: *u8 = shstr + (sh_name: u64);
if (sh_type == SHT_PROGBITS: u32) {
if (cstr_eq(nm, ".text")) { idx_text = i: i32; };
if (cstreq(nm, ".text")) { idx_text = i: i32; };
};
if (sh_type == SHT_SYMTAB: u32) { idx_symtab = i: i32; };
i += 1u32;
@@ -244,7 +244,7 @@ fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
if ((st_shndx: i32) == idx_text) {
let nm_p: *u8 = strtab + (st_name: u64);
if (nm_p[0u64] != 0u8) {
let nm: str = cstr_to_str(a, nm_p);
let nm: str = cstrtostr(a, nm_p);
let de: *defent = amalloc(a, 32u64): *defent;
de.name = nm;
de.dnext = head;
@@ -258,13 +258,13 @@ fn elf_globals(a: *arena, buf: *u8, len: u64) *defent = {
return head;
};
// member_defines_undef — true if any of m's defined globals matches a
// memberdefinesundef — true if any of m's defined globals matches a
// currently-undefined symbol in the linker's symbol table. Names not
// already interned are uninteresting (the link doesn't need them yet).
fn member_defines_undef(l: *lnk, m: *armember) bool = {
fn memberdefinesundef(l: *lnk, m: *armember) bool = {
let de: *defent = m.defs;
for (de != nil) {
let s: *lsym = l_lookup(l, de.name);
let s: *lsym = lookup(l, de.name);
if (s != nil) {
if (s.defined == 0) { return true; };
};
@@ -273,17 +273,17 @@ fn member_defines_undef(l: *lnk, m: *armember) bool = {
return false;
};
// load_archive — port of cmd/w6l/obj.c:load_archive.
// loadarchive — port of cmd/w6l/obj.c:load_archive.
//
// Pass 1 indexes every regular member. Pass 2 iteratively pulls in any
// member that supplies a currently-undefined symbol; each pull may
// introduce fresh undefs, so we loop until quiescent.
fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
fn loadarchive(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
let head: *armember = nil;
let tail: *armember = nil;
let pos: u64 = 8u64; // past "!<arch>\n"
for (pos + 60u64 <= len) {
let hdr_size: u64 = ar_field(buf + pos + 48u64, 10u64);
let hdr_size: u64 = arfield(buf + pos + 48u64, 10u64);
let hdr_end: u64 = pos + 60u64;
if (hdr_end + hdr_size > len) { break; };
let first: u8 = buf[pos];
@@ -299,7 +299,7 @@ fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
i += 1u64;
};
m.data = mb;
m.defs = elf_globals(l.a, mb, hdr_size);
m.defs = elfglobals(l.a, mb, hdr_size);
m.loaded = 0;
m.mnext = nil;
if (head == nil) { head = m; }
@@ -316,8 +316,8 @@ fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let m: *armember = head;
for (m != nil) {
if (m.loaded == 0) {
if (member_defines_undef(l, m)) {
if (load_image(l, path_cs, m.data, m.size) == 0) {
if (memberdefinesundef(l, m)) {
if (loadimage(l, path, m.data, m.size) == 0) {
m.loaded = 1;
changed = 1;
};
@@ -331,21 +331,21 @@ fn load_archive(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
// ---- main loader -------------------------------------------------------
export fn l_load(l: *lnk, path_cs: *u8) i32 = {
export fn load(l: *lnk, path: *u8) i32 = {
let bufp: *u8;
let buflen: u64;
bufp, buflen = read_all(path_cs);
bufp, buflen = readall(path);
if (bufp == nil) {
os.write(2, "w6l: cannot read object\n".ptr, 23u64);
return -1;
};
if (is_archive(bufp, buflen)) {
return load_archive(l, path_cs, bufp, buflen);
if (isarchive(bufp, buflen)) {
return loadarchive(l, path, bufp, buflen);
};
return load_image(l, path_cs, bufp, buflen);
return loadimage(l, path, bufp, buflen);
};
fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
if (len < EHDR_SIZE) { return -1; };
// magic: 0x7f, 'E', 'L', 'F'
if (buf[0u64] != 127u8) { return -1; };
@@ -374,11 +374,11 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let sh_name: u32 = rd_u32(buf, sh_off + SHDR_NAME);
let nm: *u8 = shstr + (sh_name: u64);
if (sh_type == SHT_PROGBITS: u32) {
if (cstr_eq(nm, ".text")) { idx_text = i: i32; };
if (cstreq(nm, ".text")) { idx_text = i: i32; };
};
if (sh_type == SHT_SYMTAB: u32) { idx_symtab = i: i32; };
if (sh_type == SHT_RELA: u32) {
if (cstr_eq(nm, ".rela.text")) { idx_rela = i: i32; };
if (cstreq(nm, ".rela.text")) { idx_rela = i: i32; };
};
i += 1u32;
};
@@ -407,16 +407,16 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
// Track this object.
let ob: *lobj = amalloc(l.a, 64u64): *lobj;
ob.path = cstr_to_str(l.a, path_cs);
ob.path = cstrtostr(l.a, path);
ob.buf = buf;
ob.len = len;
ob.text_off = l.textlen;
ob.text_size = text_size;
ob.textoff = l.textlen;
ob.textsize = text_size;
ob.onext = l.objs;
l.objs = ob;
// Append .text bytes to the combined image.
emit_text(l, buf + text_off, text_size);
emittext(l, buf + text_off, text_size);
// Walk symbols. We don't keep a per-object map[] of *lsym. Instead
// the reloc loop re-walks symtab and re-interns by name. Simpler
@@ -429,8 +429,8 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let st_value: u64 = rd_u64(buf, sym_p + SYM_VALUE);
let nm_p: *u8 = strtab + (st_name: u64);
if (nm_p[0u64] != 0u8) {
let nm: str = cstr_to_str(l.a, nm_p);
let gs: *lsym = l_intern(l, nm);
let nm: str = cstrtostr(l.a, nm_p);
let gs: *lsym = intern(l, nm);
if (st_shndx != 0u16) {
if ((st_shndx: i32) == idx_text) {
if (gs.defined != 0) {
@@ -439,8 +439,8 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
} else {
gs.defined = 1;
gs.owner = ob;
gs.idx_in_owner = si: i32;
gs.val = ob.text_off + st_value;
gs.idxinowner = si: i32;
gs.val = ob.textoff + st_value;
};
};
};
@@ -463,7 +463,7 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let r_sym_idx: u32 = (r_info >> 32u64): u32;
let r_kind: i32 = ((r_info & 4294967295u64): u32): i32;
let nr: *lrel = amalloc(l.a, 48u64): *lrel;
nr.off = ob.text_off + r_off;
nr.off = ob.textoff + r_off;
nr.kind = r_kind;
nr.addend = r_addend: i64;
// Look up the referenced sym by name (re-walk symtab).
@@ -472,8 +472,8 @@ fn load_image(l: *lnk, path_cs: *u8, buf: *u8, len: u64) i32 = {
let s_name: u32 = rd_u32(buf, s_p + SYM_NAME);
let s_nm: *u8 = strtab + (s_name: u64);
if (s_nm[0u64] != 0u8) {
let nm: str = cstr_to_str(l.a, s_nm);
nr.sym = l_intern(l, nm);
let nm: str = cstrtostr(l.a, s_nm);
nr.sym = intern(l, nm);
};
};
nr.rnext = l.rels;

View File

@@ -24,31 +24,31 @@ def TEXT_OFF: u64 = 4096u64; // 0x1000
// ---- little-endian byte writers ----------------------------------------
fn wr_u16(buf: *u8, off: u64, v: u16) void = {
fn wru16(buf: *u8, off: u64, v: u16) void = {
buf[off] = (v & 255u16): u8;
buf[off + 1u64] = ((v >> 8u16) & 255u16): u8;
};
fn wr_u32(buf: *u8, off: u64, v: u32) void = {
fn wru32(buf: *u8, off: u64, v: u32) void = {
buf[off] = (v & 255u32): u8;
buf[off + 1u64] = ((v >> 8u32) & 255u32): u8;
buf[off + 2u64] = ((v >> 16u32) & 255u32): u8;
buf[off + 3u64] = ((v >> 24u32) & 255u32): u8;
};
fn wr_u64(buf: *u8, off: u64, v: u64) void = {
wr_u32(buf, off, (v & 4294967295u64): u32);
wr_u32(buf, off + 4u64, ((v >> 32u64) & 4294967295u64): u32);
fn wru64(buf: *u8, off: u64, v: u64) void = {
wru32(buf, off, (v & 4294967295u64): u32);
wru32(buf, off + 4u64, ((v >> 32u64) & 4294967295u64): u32);
};
// ---- emit ---------------------------------------------------------------
export fn l_emit_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
// Dispatch: any loaded shared object plus any dynamic ref means
// we owe the loader a real PT_INTERP/PT_DYNAMIC binary.
if (l.sos != nil) {
if (l.dyn_n > 0) {
return l_emit_dyn_elf(l, fd, base, entry);
if (l.dynn > 0) {
return emitdynelf(l, fd, base, entry);
};
};
@@ -65,29 +65,29 @@ export fn l_emit_elf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
hdr[4u64] = ELFCLASS64;
hdr[5u64] = ELFDATA2LSB;
hdr[6u64] = EV_CURRENT: u8;
wr_u16(hdr, 16u64, ET_EXEC); // e_type
wr_u16(hdr, 18u64, EM_X86_64_W); // e_machine
wr_u32(hdr, 20u64, EV_CURRENT); // e_version
wr_u64(hdr, 24u64, entry); // e_entry
wr_u64(hdr, 32u64, 64u64); // e_phoff = sizeof(Ehdr)
wr_u64(hdr, 40u64, 0u64); // e_shoff
wr_u32(hdr, 48u64, 0u32); // e_flags
wr_u16(hdr, 52u64, 64u16); // e_ehsize
wr_u16(hdr, 54u64, 56u16); // e_phentsize
wr_u16(hdr, 56u64, 1u16); // e_phnum
wr_u16(hdr, 58u64, 0u16); // e_shentsize
wr_u16(hdr, 60u64, 0u16); // e_shnum
wr_u16(hdr, 62u64, 0u16); // e_shstrndx
wru16(hdr, 16u64, ET_EXEC); // e_type
wru16(hdr, 18u64, EM_X86_64_W); // e_machine
wru32(hdr, 20u64, EV_CURRENT); // e_version
wru64(hdr, 24u64, entry); // e_entry
wru64(hdr, 32u64, 64u64); // e_phoff = sizeof(Ehdr)
wru64(hdr, 40u64, 0u64); // e_shoff
wru32(hdr, 48u64, 0u32); // e_flags
wru16(hdr, 52u64, 64u16); // e_ehsize
wru16(hdr, 54u64, 56u16); // e_phentsize
wru16(hdr, 56u64, 1u16); // e_phnum
wru16(hdr, 58u64, 0u16); // e_shentsize
wru16(hdr, 60u64, 0u16); // e_shnum
wru16(hdr, 62u64, 0u16); // e_shstrndx
// --- Phdr (56 bytes) at offset 64 ---
wr_u32(hdr, 64u64, PT_LOAD); // p_type
wr_u32(hdr, 68u64, PF_R | PF_X); // p_flags
wr_u64(hdr, 72u64, 0u64); // p_offset
wr_u64(hdr, 80u64, base); // p_vaddr
wr_u64(hdr, 88u64, base); // p_paddr
wr_u64(hdr, 96u64, filesz); // p_filesz
wr_u64(hdr, 104u64, filesz); // p_memsz
wr_u64(hdr, 112u64, TEXT_OFF); // p_align
wru32(hdr, 64u64, PT_LOAD); // p_type
wru32(hdr, 68u64, PF_R | PF_X); // p_flags
wru64(hdr, 72u64, 0u64); // p_offset
wru64(hdr, 80u64, base); // p_vaddr
wru64(hdr, 88u64, base); // p_paddr
wru64(hdr, 96u64, filesz); // p_filesz
wru64(hdr, 104u64, filesz); // p_memsz
wru64(hdr, 112u64, TEXT_OFF); // p_align
// Write [0..0x1000) then .text.
let n1: i64 = os.writefull(fd, hdr, TEXT_OFF);

View File

@@ -17,14 +17,14 @@ use dyn;
def R_X86_64_PC32: i32 = 2;
def R_X86_64_PLT32: i32 = 4;
export fn l_resolve(l: *lnk) i32 = {
export fn resolve(l: *lnk) i32 = {
// Initialise dynamic-linking sentinels. amalloc zeroes, so
// is_dyn/dyn_lib start clean — but plt_idx and dynsym_idx
// isdyn/dynlib start clean — but pltidx and dynsymidx
// must be -1, not 0.
let si: *lsym = l.syms;
for (si != nil) {
si.plt_idx = -1;
si.dynsym_idx = -1;
si.pltidx = -1;
si.dynsymidx = -1;
si = si.snext;
};
@@ -36,14 +36,14 @@ export fn l_resolve(l: *lnk) i32 = {
if (r.sym != nil) {
if (r.sym.defined == 0) {
let sym: *lsym = r.sym;
if (sym.is_dyn == 0) {
if (sym.isdyn == 0) {
let so: *lso = l.sos;
for (so != nil) {
if (l_so_provides(so, sym.name) != 0) {
sym.is_dyn = 1;
sym.dyn_lib = so;
sym.plt_idx = l.dyn_n;
l.dyn_n += 1;
if (soprovides(so, sym.name) != 0) {
sym.isdyn = 1;
sym.dynlib = so;
sym.pltidx = l.dynn;
l.dynn += 1;
so = nil; // break
} else {
so = so.sonext;
@@ -60,7 +60,7 @@ export fn l_resolve(l: *lnk) i32 = {
for (r2 != nil) {
if (r2.sym != nil) {
if (r2.sym.defined == 0) {
if (r2.sym.is_dyn == 0) {
if (r2.sym.isdyn == 0) {
os.write(2, "w6l: undefined reference to '".ptr, 28u64);
let nm: str = r2.sym.name;
os.write(2, nm.ptr, nm.len: u64);
@@ -74,20 +74,20 @@ export fn l_resolve(l: *lnk) i32 = {
return l.errs;
};
fn patch_u32(p: *u8, v: u32) void = {
fn patchu32(p: *u8, v: u32) void = {
p[0] = (v & 255u32): u8;
p[1] = ((v >> 8u32) & 255u32): u8;
p[2] = ((v >> 16u32) & 255u32): u8;
p[3] = ((v >> 24u32) & 255u32): u8;
};
export fn l_relocate(l: *lnk, base: u64) i32 = {
export fn relocate(l: *lnk, base: u64) i32 = {
let r: *lrel = l.rels;
for (r != nil) {
if (r.sym != nil) {
// Dynamic refs are patched later in dynout once the
// PLT vaddr is known.
if (r.sym.is_dyn != 0) {
if (r.sym.isdyn != 0) {
r = r.rnext;
continue;
};
@@ -97,12 +97,12 @@ export fn l_relocate(l: *lnk, base: u64) i32 = {
let site: u64 = base + r.off;
let target: i64 = (base + r.sym.val): i64;
let rel: i64 = (target - site: i64) + r.addend;
patch_u32(l.text + r.off, rel: u32);
patchu32(l.text + r.off, rel: u32);
} else { if (k == R_X86_64_PLT32) {
let site: u64 = base + r.off;
let target: i64 = (base + r.sym.val): i64;
let rel: i64 = (target - site: i64) + r.addend;
patch_u32(l.text + r.off, rel: u32);
patchu32(l.text + r.off, rel: u32);
} else {
os.write(2, "w6l: unsupported reloc kind\n".ptr, 27u64);
l.errs += 1;

View File

@@ -10,15 +10,15 @@ type lsym = struct {
val: u64, // offset within combined .text once linked
defined: i32, // 1 if some lobj defines this symbol
owner: *lobj,
idx_in_owner: i32,
// Dynamic-linking fields. Set by l_resolve when an undefined sym
// is provided by some loaded lso. plt_idx and dynsym_idx default
// to -1 (set explicitly by l_resolve, not by amalloc-zeroing).
is_dyn: i32,
dyn_lib: *lso,
dyn_version: str, // matched export's version; len 0 if none
plt_idx: i32,
dynsym_idx: i32,
idxinowner: i32,
// Dynamic-linking fields. Set by resolve when an undefined sym
// is provided by some loaded lso. pltidx and dynsymidx default
// to -1 (set explicitly by resolve, not by amalloc-zeroing).
isdyn: i32,
dynlib: *lso,
dynversion: str, // matched export's version; len 0 if none
pltidx: i32,
dynsymidx: i32,
snext: *lsym,
};
@@ -34,14 +34,14 @@ type lobj = struct {
path: str,
buf: *u8, // object bytes
len: u64,
text_off: u64, // offset of .text in combined output
text_size: u64,
textoff: u64, // offset of .text in combined output
textsize: u64,
onext: *lobj,
};
// lexport — one entry per GLOBAL/WEAK symbol exported by a loaded .so.
// Stored as a chain in the order the .so's dynsym presents them, so
// l_so_provides_v's first-match semantics agree with the C version.
// soprovides_v's first-match semantics agree with the C version.
type lexport = struct {
name: str,
version: str, // len 0 for unversioned globals
@@ -65,7 +65,7 @@ type lnk = struct {
textcap: u64,
textlen: u64,
errs: i32,
dyn_n: i32, // number of syms routed through PLT
dynn: i32, // number of syms routed through PLT
};
fn streq(a: str, b: str) bool = {
@@ -78,7 +78,7 @@ fn streq(a: str, b: str) bool = {
return true;
};
export fn l_intern(l: *lnk, name: str) *lsym = {
export fn intern(l: *lnk, name: str) *lsym = {
let s: *lsym = l.syms;
for (s != nil) {
if (streq(s.name, name)) { return s; };
@@ -91,7 +91,7 @@ export fn l_intern(l: *lnk, name: str) *lsym = {
return n;
};
export fn l_lookup(l: *lnk, name: str) *lsym = {
export fn lookup(l: *lnk, name: str) *lsym = {
let s: *lsym = l.syms;
for (s != nil) {
if (streq(s.name, name)) { return s; };