selfhost/cmd/w6l: strip *arena cascade (γ-4)
amalloc has 0 callers post-γ-2; the *arena threaded through w6l's mklnk/resolvelib/cstrtostr/elfglobals/dcstrtostr and the lnk.a field are vestigial. Drop `import mem;` from sym/main/obj/dyn/dynout, remove lnk.a struct field, strip *arena from the five signatures, update 13 call sites. Drop a dead `let a: *arena = l.a;` in dynout. Comments at pass.ww/obj.ww/main.ww retidied to match post-strip reality. main.combined.ww auto-regenerated. Verified 132/132 incl. 992_w6l_ww + 996_dyn_ww + 995_self_rebuild byte-identity.
This commit is contained in:
@@ -12,7 +12,6 @@ package w6l;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -107,7 +106,7 @@ fn dcstrlen(p: *u8) u64 = {
|
|||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn dcstrtostr(a: *arena, p: *u8) str = {
|
fn dcstrtostr(p: *u8) str = {
|
||||||
let n: u64 = dcstrlen(p);
|
let n: u64 = dcstrlen(p);
|
||||||
let view: str;
|
let view: str;
|
||||||
view.ptr = p;
|
view.ptr = p;
|
||||||
@@ -295,7 +294,7 @@ export fn loadso(l: *lnk, path: *u8) i32 = {
|
|||||||
|
|
||||||
// Build the lso. Exports are appended in dynsym order so
|
// Build the lso. Exports are appended in dynsym order so
|
||||||
// soprovides_v's first-match semantics match the C version.
|
// soprovides_v's first-match semantics match the C version.
|
||||||
let so: *lso = alloc(lso { path = dcstrtostr(l.a, path), soname = dcstrtostr(l.a, sonamecs) })!;
|
let so: *lso = alloc(lso { path = dcstrtostr(path), soname = dcstrtostr(sonamecs) })!;
|
||||||
let tail: *lexport = nil;
|
let tail: *lexport = nil;
|
||||||
|
|
||||||
let si: u64 = 1u64;
|
let si: u64 = 1u64;
|
||||||
@@ -347,9 +346,9 @@ export fn loadso(l: *lnk, path: *u8) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (keep != 0) {
|
if (keep != 0) {
|
||||||
let e: *lexport = alloc(lexport { name = dcstrtostr(l.a, nmp) })!;
|
let e: *lexport = alloc(lexport { name = dcstrtostr(nmp) })!;
|
||||||
if (vernamecs != nil) {
|
if (vernamecs != nil) {
|
||||||
e.version = dcstrtostr(l.a, vernamecs);
|
e.version = dcstrtostr(vernamecs);
|
||||||
};
|
};
|
||||||
if (tail == nil) {
|
if (tail == nil) {
|
||||||
so.exports = e;
|
so.exports = e;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ package w6l;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
// ELF constants
|
// ELF constants
|
||||||
@@ -170,7 +169,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
// Placed after .dynamic so the segment is one contiguous run;
|
// Placed after .dynamic so the segment is one contiguous run;
|
||||||
// relocate runs from here so the dyn layout's datava lands in
|
// relocate runs from here so the dyn layout's datava lands in
|
||||||
// patched offsets.
|
// patched offsets.
|
||||||
let a: *arena = l.a;
|
|
||||||
let n: i32 = l.dynn;
|
let n: i32 = l.dynn;
|
||||||
let nu: u64 = n: u64;
|
let nu: u64 = n: u64;
|
||||||
|
|
||||||
|
|||||||
@@ -750,98 +750,6 @@ package rt;
|
|||||||
// a future task (task #39). ref/hare/rt/malloc.ha:27.
|
// a future task (task #39). ref/hare/rt/malloc.ha:27.
|
||||||
@symbol("rt_malloc") export fn malloc(n: u64) *void;
|
@symbol("rt_malloc") export fn malloc(n: u64) *void;
|
||||||
|
|
||||||
// selfhost/cmd/wcc/mem.ww — port of cmd/wcc/mem.c.
|
|
||||||
//
|
|
||||||
// Bump arena allocator. Backed by the runtime page allocator
|
|
||||||
// (rt_malloc / rt_free), no libc. Each chunk is mmap'd; when the
|
|
||||||
// current chunk runs out we link a fresh one. Freeing the arena
|
|
||||||
// unmaps the chain.
|
|
||||||
//
|
|
||||||
// Memory handed out is 16-byte aligned. The C version under
|
|
||||||
// cmd/wcc/ is retained until the three-stage bootstrap diffs clean.
|
|
||||||
|
|
||||||
package wcc;
|
|
||||||
|
|
||||||
import os;
|
|
||||||
import rt;
|
|
||||||
|
|
||||||
def ALIGN: u64 = 16u64;
|
|
||||||
def INIT_CHUNK: u64 = 65536u64;
|
|
||||||
def MAX_CHUNK: u64 = 4194304u64;
|
|
||||||
def ARENA_SZ: u64 = 48u64; // sizeof(arena), kept in sync below
|
|
||||||
|
|
||||||
type arena = struct {
|
|
||||||
buf: *u8,
|
|
||||||
off: u64,
|
|
||||||
cap: u64,
|
|
||||||
next: *arena,
|
|
||||||
total: u64,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn roundup(n: u64, a: u64) u64 = {
|
|
||||||
return (n + a - 1u64) & ~(a - 1u64);
|
|
||||||
};
|
|
||||||
|
|
||||||
export fn newarena() *arena = {
|
|
||||||
let a: *arena = rt.malloc(ARENA_SZ): *arena;
|
|
||||||
a.buf = rt.malloc(INIT_CHUNK): *u8;
|
|
||||||
a.off = 0u64;
|
|
||||||
a.cap = INIT_CHUNK;
|
|
||||||
a.next = nil;
|
|
||||||
a.total = 0u64;
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grow: link a fresh chunk in front of the head. We push the old
|
|
||||||
// chunk into `next` so the head always describes the current bump
|
|
||||||
// region. Chunk size doubles up to MAX_CHUNK.
|
|
||||||
fn grow(a: *arena, need: u64) bool = {
|
|
||||||
let want: u64 = a.cap * 2u64;
|
|
||||||
if (want < need) { want = need; };
|
|
||||||
if (want > MAX_CHUNK) { want = MAX_CHUNK; };
|
|
||||||
if (want < need) { return false; }; // single allocation too big
|
|
||||||
|
|
||||||
let old: *arena = rt.malloc(ARENA_SZ): *arena;
|
|
||||||
old.buf = a.buf;
|
|
||||||
old.off = a.off;
|
|
||||||
old.cap = a.cap;
|
|
||||||
old.next = a.next;
|
|
||||||
old.total = 0u64;
|
|
||||||
|
|
||||||
a.buf = rt.malloc(want): *u8;
|
|
||||||
a.off = 0u64;
|
|
||||||
a.cap = want;
|
|
||||||
a.next = old;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
export fn amalloc(a: *arena, n: u64) *void = {
|
|
||||||
let need: u64 = roundup(n, ALIGN);
|
|
||||||
if (need > a.cap - a.off) {
|
|
||||||
if (!grow(a, need)) { return nil; };
|
|
||||||
};
|
|
||||||
let p: *u8 = a.buf + a.off;
|
|
||||||
a.off += need;
|
|
||||||
a.total += need;
|
|
||||||
// Zero the region. Plan 9 amalloc zeroes; we mirror that here so
|
|
||||||
// the checker can assume freshly allocated nodes start at 0.
|
|
||||||
let i: u64 = 0u64;
|
|
||||||
for (i < need) {
|
|
||||||
p[i] = 0u8;
|
|
||||||
i += 1u64;
|
|
||||||
};
|
|
||||||
return p: *void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export fn freearena(a: *arena) void = {
|
|
||||||
for (a != nil) {
|
|
||||||
let next: *arena = a.next;
|
|
||||||
os.free(a.buf: *void, a.cap);
|
|
||||||
os.free(a: *void, ARENA_SZ);
|
|
||||||
a = next;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// selfhost/cmd/w6l/sym.ww — port of cmd/w6l/sym.c.
|
// selfhost/cmd/w6l/sym.ww — port of cmd/w6l/sym.c.
|
||||||
//
|
//
|
||||||
// Linker symbol table. Singly-linked list, usually a few hundred
|
// Linker symbol table. Singly-linked list, usually a few hundred
|
||||||
@@ -849,8 +757,6 @@ export fn freearena(a: *arena) void = {
|
|||||||
|
|
||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import mem;
|
|
||||||
|
|
||||||
type lsym = struct {
|
type lsym = struct {
|
||||||
name: str,
|
name: str,
|
||||||
val: u64, // offset within combined .text (or .data when
|
val: u64, // offset within combined .text (or .data when
|
||||||
@@ -907,7 +813,6 @@ type lso = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type lnk = struct {
|
type lnk = struct {
|
||||||
a: *arena,
|
|
||||||
objs: *lobj,
|
objs: *lobj,
|
||||||
sos: *lso,
|
sos: *lso,
|
||||||
syms: *lsym,
|
syms: *lsym,
|
||||||
@@ -2899,7 +2804,6 @@ package w6l;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -3045,7 +2949,7 @@ fn cstrlen(p: *u8) u64 = {
|
|||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
// pathstr — view a NUL-terminated *u8 as a str. Bridges argv/arena
|
// pathstr — view a NUL-terminated *u8 as a str. Bridges argv-style
|
||||||
// callers to lib/os entrypoints (str post-task-#23). Shared with
|
// callers to lib/os entrypoints (str post-task-#23). Shared with
|
||||||
// main.ww and dyn.ww via the w6l bundle.
|
// main.ww and dyn.ww via the w6l bundle.
|
||||||
fn pathstr(p: *u8) str = {
|
fn pathstr(p: *u8) str = {
|
||||||
@@ -3068,7 +2972,7 @@ fn cstreq(p: *u8, lit: str) bool = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Build a ww str from a NUL-terminated *u8 (for passing to intern).
|
// Build a ww str from a NUL-terminated *u8 (for passing to intern).
|
||||||
fn cstrtostr(a: *arena, p: *u8) str = {
|
fn cstrtostr(p: *u8) str = {
|
||||||
let n: u64 = cstrlen(p);
|
let n: u64 = cstrlen(p);
|
||||||
let view: str;
|
let view: str;
|
||||||
view.ptr = p;
|
view.ptr = p;
|
||||||
@@ -3088,7 +2992,7 @@ type defent = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type armember = struct {
|
type armember = struct {
|
||||||
data: *u8, // arena copy of the member's ELF bytes
|
data: *u8, // owned heap copy of the member's ELF bytes
|
||||||
size: u64,
|
size: u64,
|
||||||
defs: *defent, // linked list of defined globals
|
defs: *defent, // linked list of defined globals
|
||||||
loaded: i32,
|
loaded: i32,
|
||||||
@@ -3123,9 +3027,9 @@ fn arfield(p: *u8, n: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// elfglobals — 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
|
// (STB_GLOBAL) symbols whose section is `.text`. Names are owned
|
||||||
// copies, so the source ELF buffer can be freed afterward.
|
// heap copies, so the source ELF buffer can be freed afterward.
|
||||||
fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = {
|
fn elfglobals(buf: *u8, len: u64) *defent = {
|
||||||
if (len < EHDR_SIZE) { return nil; };
|
if (len < EHDR_SIZE) { return nil; };
|
||||||
if (buf[0u64] != 127u8) { return nil; };
|
if (buf[0u64] != 127u8) { return nil; };
|
||||||
if (buf[1u64] != 69u8) { return nil; };
|
if (buf[1u64] != 69u8) { return nil; };
|
||||||
@@ -3189,7 +3093,7 @@ fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = {
|
|||||||
if (intext || indt) {
|
if (intext || indt) {
|
||||||
let nmp: *u8 = strtab + (stname: u64);
|
let nmp: *u8 = strtab + (stname: u64);
|
||||||
if (nmp[0u64] != 0u8) {
|
if (nmp[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(a, nmp);
|
let nm: str = cstrtostr(nmp);
|
||||||
let de: *defent = alloc(defent { name = nm, dnext = head })!;
|
let de: *defent = alloc(defent { name = nm, dnext = head })!;
|
||||||
head = de;
|
head = de;
|
||||||
};
|
};
|
||||||
@@ -3242,7 +3146,7 @@ fn loadarchive(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
i += 1u64;
|
i += 1u64;
|
||||||
};
|
};
|
||||||
m.data = mb;
|
m.data = mb;
|
||||||
m.defs = elfglobals(l.a, mb, hdrsize);
|
m.defs = elfglobals(mb, hdrsize);
|
||||||
if (head == nil) { head = m; }
|
if (head == nil) { head = m; }
|
||||||
else { tail.mnext = m; };
|
else { tail.mnext = m; };
|
||||||
tail = m;
|
tail = m;
|
||||||
@@ -3360,7 +3264,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
|
|
||||||
// Track this object.
|
// Track this object.
|
||||||
let ob: *lobj = alloc(lobj {
|
let ob: *lobj = alloc(lobj {
|
||||||
path = cstrtostr(l.a, path),
|
path = cstrtostr(path),
|
||||||
buf = buf,
|
buf = buf,
|
||||||
len = len,
|
len = len,
|
||||||
textoff = l.textlen,
|
textoff = l.textlen,
|
||||||
@@ -3391,7 +3295,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
let stvalue: u64 = rdu64(buf, symp + SYM_VALUE);
|
let stvalue: u64 = rdu64(buf, symp + SYM_VALUE);
|
||||||
let nmp: *u8 = strtab + (stname: u64);
|
let nmp: *u8 = strtab + (stname: u64);
|
||||||
if (nmp[0u64] != 0u8) {
|
if (nmp[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(l.a, nmp);
|
let nm: str = cstrtostr(nmp);
|
||||||
let gs: *lsym = intern(l, nm);
|
let gs: *lsym = intern(l, nm);
|
||||||
if (stshndx != 0u16) {
|
if (stshndx != 0u16) {
|
||||||
let intext: bool = (stshndx: i32) == idxtext;
|
let intext: bool = (stshndx: i32) == idxtext;
|
||||||
@@ -3455,7 +3359,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
||||||
let snm: *u8 = strtab + (sname: u64);
|
let snm: *u8 = strtab + (sname: u64);
|
||||||
if (snm[0u64] != 0u8) {
|
if (snm[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(l.a, snm);
|
let nm: str = cstrtostr(snm);
|
||||||
nr.sym = intern(l, nm);
|
nr.sym = intern(l, nm);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -3491,7 +3395,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
||||||
let snm: *u8 = strtab + (sname: u64);
|
let snm: *u8 = strtab + (sname: u64);
|
||||||
if (snm[0u64] != 0u8) {
|
if (snm[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(l.a, snm);
|
let nm: str = cstrtostr(snm);
|
||||||
nr.sym = intern(l, nm);
|
nr.sym = intern(l, nm);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -3517,7 +3421,6 @@ package w6l;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -3612,7 +3515,7 @@ fn dcstrlen(p: *u8) u64 = {
|
|||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn dcstrtostr(a: *arena, p: *u8) str = {
|
fn dcstrtostr(p: *u8) str = {
|
||||||
let n: u64 = dcstrlen(p);
|
let n: u64 = dcstrlen(p);
|
||||||
let view: str;
|
let view: str;
|
||||||
view.ptr = p;
|
view.ptr = p;
|
||||||
@@ -3800,7 +3703,7 @@ export fn loadso(l: *lnk, path: *u8) i32 = {
|
|||||||
|
|
||||||
// Build the lso. Exports are appended in dynsym order so
|
// Build the lso. Exports are appended in dynsym order so
|
||||||
// soprovides_v's first-match semantics match the C version.
|
// soprovides_v's first-match semantics match the C version.
|
||||||
let so: *lso = alloc(lso { path = dcstrtostr(l.a, path), soname = dcstrtostr(l.a, sonamecs) })!;
|
let so: *lso = alloc(lso { path = dcstrtostr(path), soname = dcstrtostr(sonamecs) })!;
|
||||||
let tail: *lexport = nil;
|
let tail: *lexport = nil;
|
||||||
|
|
||||||
let si: u64 = 1u64;
|
let si: u64 = 1u64;
|
||||||
@@ -3852,9 +3755,9 @@ export fn loadso(l: *lnk, path: *u8) i32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (keep != 0) {
|
if (keep != 0) {
|
||||||
let e: *lexport = alloc(lexport { name = dcstrtostr(l.a, nmp) })!;
|
let e: *lexport = alloc(lexport { name = dcstrtostr(nmp) })!;
|
||||||
if (vernamecs != nil) {
|
if (vernamecs != nil) {
|
||||||
e.version = dcstrtostr(l.a, vernamecs);
|
e.version = dcstrtostr(vernamecs);
|
||||||
};
|
};
|
||||||
if (tail == nil) {
|
if (tail == nil) {
|
||||||
so.exports = e;
|
so.exports = e;
|
||||||
@@ -3934,7 +3837,7 @@ def R_X86_64_PC32: i32 = 2;
|
|||||||
def R_X86_64_PLT32: i32 = 4;
|
def R_X86_64_PLT32: i32 = 4;
|
||||||
|
|
||||||
export fn resolve(l: *lnk) i32 = {
|
export fn resolve(l: *lnk) i32 = {
|
||||||
// Initialise dynamic-linking sentinels. amalloc zeroes, so
|
// Initialise dynamic-linking sentinels. alloc(T{})! zeroes, so
|
||||||
// isdyn/dynlib start clean — but pltidx and dynsymidx
|
// isdyn/dynlib start clean — but pltidx and dynsymidx
|
||||||
// must be -1, not 0.
|
// must be -1, not 0.
|
||||||
let si: *lsym = l.syms;
|
let si: *lsym = l.syms;
|
||||||
@@ -4074,7 +3977,6 @@ package w6l;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
// ELF constants
|
// ELF constants
|
||||||
@@ -4218,7 +4120,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
|||||||
// Placed after .dynamic so the segment is one contiguous run;
|
// Placed after .dynamic so the segment is one contiguous run;
|
||||||
// relocate runs from here so the dyn layout's datava lands in
|
// relocate runs from here so the dyn layout's datava lands in
|
||||||
// patched offsets.
|
// patched offsets.
|
||||||
let a: *arena = l.a;
|
|
||||||
let n: i32 = l.dynn;
|
let n: i32 = l.dynn;
|
||||||
let nu: u64 = n: u64;
|
let nu: u64 = n: u64;
|
||||||
|
|
||||||
@@ -4996,7 +4897,6 @@ package main;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import sym;
|
import sym;
|
||||||
import obj;
|
import obj;
|
||||||
import dyn;
|
import dyn;
|
||||||
@@ -5006,8 +4906,8 @@ import out;
|
|||||||
def BASE: u64 = 4194304u64; // 0x400000
|
def BASE: u64 = 4194304u64; // 0x400000
|
||||||
def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000
|
def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000
|
||||||
|
|
||||||
fn mklnk(a: *arena) *lnk = {
|
fn mklnk() *lnk = {
|
||||||
let l: *lnk = alloc(lnk { a = a })!;
|
let l: *lnk = alloc(lnk { })!;
|
||||||
return l;
|
return l;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -5114,9 +5014,9 @@ fn islinkable(path: *u8) bool = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Walk libdirs[0..n) trying lib<name>.so, then lib<name>.so.{0..8},
|
// Walk libdirs[0..n) trying lib<name>.so, then lib<name>.so.{0..8},
|
||||||
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
// then lib<name>.a. Return a heap-allocated NUL-terminated path on
|
||||||
// nil on miss.
|
// success, nil on miss.
|
||||||
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
fn resolvelib(name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||||
let bufp: []u8 = alloc([], 1024u64)!;
|
let bufp: []u8 = alloc([], 1024u64)!;
|
||||||
bufp.len = 1024;
|
bufp.len = 1024;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
@@ -5254,8 +5154,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
let a: *arena = newarena();
|
let l: *lnk = mklnk();
|
||||||
let l: *lnk = mklnk(a);
|
|
||||||
|
|
||||||
// Seed _start so libwwrt-style start.o is recognised as wanted.
|
// Seed _start so libwwrt-style start.o is recognised as wanted.
|
||||||
intern(l, "_start");
|
intern(l, "_start");
|
||||||
@@ -5273,7 +5172,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
// objects register their exports.
|
// objects register their exports.
|
||||||
let lf: i32 = 0;
|
let lf: i32 = 0;
|
||||||
for (lf < nlflags) {
|
for (lf < nlflags) {
|
||||||
let p: *u8 = resolvelib(a, lflags[lf], libdirs.ptr, nlibdirs);
|
let p: *u8 = resolvelib(lflags[lf], libdirs.ptr, nlibdirs);
|
||||||
if (p == nil) {
|
if (p == nil) {
|
||||||
os.write(2, "w6l: cannot find -l".ptr, 18u64);
|
os.write(2, "w6l: cannot find -l".ptr, 18u64);
|
||||||
let nm: *u8 = lflags[lf];
|
let nm: *u8 = lflags[lf];
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ package main;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import sym;
|
import sym;
|
||||||
import obj;
|
import obj;
|
||||||
import dyn;
|
import dyn;
|
||||||
@@ -20,8 +19,8 @@ import out;
|
|||||||
def BASE: u64 = 4194304u64; // 0x400000
|
def BASE: u64 = 4194304u64; // 0x400000
|
||||||
def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000
|
def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000
|
||||||
|
|
||||||
fn mklnk(a: *arena) *lnk = {
|
fn mklnk() *lnk = {
|
||||||
let l: *lnk = alloc(lnk { a = a })!;
|
let l: *lnk = alloc(lnk { })!;
|
||||||
return l;
|
return l;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -128,9 +127,9 @@ fn islinkable(path: *u8) bool = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Walk libdirs[0..n) trying lib<name>.so, then lib<name>.so.{0..8},
|
// Walk libdirs[0..n) trying lib<name>.so, then lib<name>.so.{0..8},
|
||||||
// then lib<name>.a. Return arena-owned NUL-terminated path on success,
|
// then lib<name>.a. Return a heap-allocated NUL-terminated path on
|
||||||
// nil on miss.
|
// success, nil on miss.
|
||||||
fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
fn resolvelib(name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = {
|
||||||
let bufp: []u8 = alloc([], 1024u64)!;
|
let bufp: []u8 = alloc([], 1024u64)!;
|
||||||
bufp.len = 1024;
|
bufp.len = 1024;
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
@@ -268,8 +267,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
let a: *arena = newarena();
|
let l: *lnk = mklnk();
|
||||||
let l: *lnk = mklnk(a);
|
|
||||||
|
|
||||||
// Seed _start so libwwrt-style start.o is recognised as wanted.
|
// Seed _start so libwwrt-style start.o is recognised as wanted.
|
||||||
intern(l, "_start");
|
intern(l, "_start");
|
||||||
@@ -287,7 +285,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
// objects register their exports.
|
// objects register their exports.
|
||||||
let lf: i32 = 0;
|
let lf: i32 = 0;
|
||||||
for (lf < nlflags) {
|
for (lf < nlflags) {
|
||||||
let p: *u8 = resolvelib(a, lflags[lf], libdirs.ptr, nlibdirs);
|
let p: *u8 = resolvelib(lflags[lf], libdirs.ptr, nlibdirs);
|
||||||
if (p == nil) {
|
if (p == nil) {
|
||||||
os.write(2, "w6l: cannot find -l".ptr, 18u64);
|
os.write(2, "w6l: cannot find -l".ptr, 18u64);
|
||||||
let nm: *u8 = lflags[lf];
|
let nm: *u8 = lflags[lf];
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ package w6l;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import mem;
|
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
import sym;
|
||||||
|
|
||||||
@@ -158,7 +157,7 @@ fn cstrlen(p: *u8) u64 = {
|
|||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
// pathstr — view a NUL-terminated *u8 as a str. Bridges argv/arena
|
// pathstr — view a NUL-terminated *u8 as a str. Bridges argv-style
|
||||||
// callers to lib/os entrypoints (str post-task-#23). Shared with
|
// callers to lib/os entrypoints (str post-task-#23). Shared with
|
||||||
// main.ww and dyn.ww via the w6l bundle.
|
// main.ww and dyn.ww via the w6l bundle.
|
||||||
fn pathstr(p: *u8) str = {
|
fn pathstr(p: *u8) str = {
|
||||||
@@ -181,7 +180,7 @@ fn cstreq(p: *u8, lit: str) bool = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Build a ww str from a NUL-terminated *u8 (for passing to intern).
|
// Build a ww str from a NUL-terminated *u8 (for passing to intern).
|
||||||
fn cstrtostr(a: *arena, p: *u8) str = {
|
fn cstrtostr(p: *u8) str = {
|
||||||
let n: u64 = cstrlen(p);
|
let n: u64 = cstrlen(p);
|
||||||
let view: str;
|
let view: str;
|
||||||
view.ptr = p;
|
view.ptr = p;
|
||||||
@@ -201,7 +200,7 @@ type defent = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type armember = struct {
|
type armember = struct {
|
||||||
data: *u8, // arena copy of the member's ELF bytes
|
data: *u8, // owned heap copy of the member's ELF bytes
|
||||||
size: u64,
|
size: u64,
|
||||||
defs: *defent, // linked list of defined globals
|
defs: *defent, // linked list of defined globals
|
||||||
loaded: i32,
|
loaded: i32,
|
||||||
@@ -236,9 +235,9 @@ fn arfield(p: *u8, n: u64) u64 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// elfglobals — 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
|
// (STB_GLOBAL) symbols whose section is `.text`. Names are owned
|
||||||
// copies, so the source ELF buffer can be freed afterward.
|
// heap copies, so the source ELF buffer can be freed afterward.
|
||||||
fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = {
|
fn elfglobals(buf: *u8, len: u64) *defent = {
|
||||||
if (len < EHDR_SIZE) { return nil; };
|
if (len < EHDR_SIZE) { return nil; };
|
||||||
if (buf[0u64] != 127u8) { return nil; };
|
if (buf[0u64] != 127u8) { return nil; };
|
||||||
if (buf[1u64] != 69u8) { return nil; };
|
if (buf[1u64] != 69u8) { return nil; };
|
||||||
@@ -302,7 +301,7 @@ fn elfglobals(a: *arena, buf: *u8, len: u64) *defent = {
|
|||||||
if (intext || indt) {
|
if (intext || indt) {
|
||||||
let nmp: *u8 = strtab + (stname: u64);
|
let nmp: *u8 = strtab + (stname: u64);
|
||||||
if (nmp[0u64] != 0u8) {
|
if (nmp[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(a, nmp);
|
let nm: str = cstrtostr(nmp);
|
||||||
let de: *defent = alloc(defent { name = nm, dnext = head })!;
|
let de: *defent = alloc(defent { name = nm, dnext = head })!;
|
||||||
head = de;
|
head = de;
|
||||||
};
|
};
|
||||||
@@ -355,7 +354,7 @@ fn loadarchive(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
i += 1u64;
|
i += 1u64;
|
||||||
};
|
};
|
||||||
m.data = mb;
|
m.data = mb;
|
||||||
m.defs = elfglobals(l.a, mb, hdrsize);
|
m.defs = elfglobals(mb, hdrsize);
|
||||||
if (head == nil) { head = m; }
|
if (head == nil) { head = m; }
|
||||||
else { tail.mnext = m; };
|
else { tail.mnext = m; };
|
||||||
tail = m;
|
tail = m;
|
||||||
@@ -473,7 +472,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
|
|
||||||
// Track this object.
|
// Track this object.
|
||||||
let ob: *lobj = alloc(lobj {
|
let ob: *lobj = alloc(lobj {
|
||||||
path = cstrtostr(l.a, path),
|
path = cstrtostr(path),
|
||||||
buf = buf,
|
buf = buf,
|
||||||
len = len,
|
len = len,
|
||||||
textoff = l.textlen,
|
textoff = l.textlen,
|
||||||
@@ -504,7 +503,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
let stvalue: u64 = rdu64(buf, symp + SYM_VALUE);
|
let stvalue: u64 = rdu64(buf, symp + SYM_VALUE);
|
||||||
let nmp: *u8 = strtab + (stname: u64);
|
let nmp: *u8 = strtab + (stname: u64);
|
||||||
if (nmp[0u64] != 0u8) {
|
if (nmp[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(l.a, nmp);
|
let nm: str = cstrtostr(nmp);
|
||||||
let gs: *lsym = intern(l, nm);
|
let gs: *lsym = intern(l, nm);
|
||||||
if (stshndx != 0u16) {
|
if (stshndx != 0u16) {
|
||||||
let intext: bool = (stshndx: i32) == idxtext;
|
let intext: bool = (stshndx: i32) == idxtext;
|
||||||
@@ -568,7 +567,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
||||||
let snm: *u8 = strtab + (sname: u64);
|
let snm: *u8 = strtab + (sname: u64);
|
||||||
if (snm[0u64] != 0u8) {
|
if (snm[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(l.a, snm);
|
let nm: str = cstrtostr(snm);
|
||||||
nr.sym = intern(l, nm);
|
nr.sym = intern(l, nm);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -604,7 +603,7 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
|||||||
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
||||||
let snm: *u8 = strtab + (sname: u64);
|
let snm: *u8 = strtab + (sname: u64);
|
||||||
if (snm[0u64] != 0u8) {
|
if (snm[0u64] != 0u8) {
|
||||||
let nm: str = cstrtostr(l.a, snm);
|
let nm: str = cstrtostr(snm);
|
||||||
nr.sym = intern(l, nm);
|
nr.sym = intern(l, nm);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def R_X86_64_PC32: i32 = 2;
|
|||||||
def R_X86_64_PLT32: i32 = 4;
|
def R_X86_64_PLT32: i32 = 4;
|
||||||
|
|
||||||
export fn resolve(l: *lnk) i32 = {
|
export fn resolve(l: *lnk) i32 = {
|
||||||
// Initialise dynamic-linking sentinels. amalloc zeroes, so
|
// Initialise dynamic-linking sentinels. alloc(T{})! zeroes, so
|
||||||
// isdyn/dynlib start clean — but pltidx and dynsymidx
|
// isdyn/dynlib start clean — but pltidx and dynsymidx
|
||||||
// must be -1, not 0.
|
// must be -1, not 0.
|
||||||
let si: *lsym = l.syms;
|
let si: *lsym = l.syms;
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
package w6l;
|
package w6l;
|
||||||
|
|
||||||
import mem;
|
|
||||||
|
|
||||||
type lsym = struct {
|
type lsym = struct {
|
||||||
name: str,
|
name: str,
|
||||||
val: u64, // offset within combined .text (or .data when
|
val: u64, // offset within combined .text (or .data when
|
||||||
@@ -63,7 +61,6 @@ type lso = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type lnk = struct {
|
type lnk = struct {
|
||||||
a: *arena,
|
|
||||||
objs: *lobj,
|
objs: *lobj,
|
||||||
sos: *lso,
|
sos: *lso,
|
||||||
syms: *lsym,
|
syms: *lsym,
|
||||||
|
|||||||
Reference in New Issue
Block a user