toolchain: banner purge + WHY-only comment sweep (rule 8)
selfhost/, cmd/, internal/ join the tree-wide sweep: every section banner dies (91 selfhost + the cmd C-style dividers -> 0); narration and stale contracts deleted (pre-#22 bundler notes, retired single-PT_LOAD and no-archive claims, superseded ABI tables); every ref/harec/qbe cite, task cite, encoding/ELF contract, and rule-10 twin pointer kept; lost lifetime/rationale lines restored where the sweep over-cut (elf_globals ownership, kwtab linear-scan). Comment- only proven: all five wwstage tool binaries byte-identical across the sweep; test-commit, test-byteid (161+1399, 0 pinned-divergent), and test-bootstrap (fixed point + 991-995 byte-id) all exit 0. The read-through banked 66 latent-bug leads (checkpoint).
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
// selfhost/cmd/w6l/dyn.ww — port of cmd/w6l/dyn.c.
|
||||
// Port of cmd/w6l/dyn.c.
|
||||
//
|
||||
// Load a shared object (ET_DYN) so the linker knows which symbols it
|
||||
// exports and which DT_NEEDED entry to record. We do not pull bytes
|
||||
// from the .so; the dynamic loader maps it at runtime.
|
||||
//
|
||||
// Each call appends one lso to lnk->sos. l_so_provides_v answers
|
||||
// "does this .so export the named symbol, and at which version?" —
|
||||
// l_resolve uses that to promote unresolved references to dynamic.
|
||||
|
||||
package w6l;
|
||||
|
||||
@@ -72,8 +68,6 @@ def VD_NEXT: u64 = 16u64;
|
||||
def VA_NAME: u64 = 0u64;
|
||||
def VA_NEXT: u64 = 4u64;
|
||||
|
||||
// ---- little-endian byte readers ---------------------------------------
|
||||
|
||||
fn du16(p: *u8, off: u64) u16 = {
|
||||
let b0: u16 = p[off]: u16;
|
||||
let b1: u16 = p[off + 1u64]: u16;
|
||||
@@ -98,8 +92,6 @@ fn di64(p: *u8, off: u64) i64 = {
|
||||
return du64(p, off): i64;
|
||||
};
|
||||
|
||||
// ---- C-string helpers --------------------------------------------------
|
||||
|
||||
fn dcstrlen(p: *u8) u64 = {
|
||||
let n: u64 = 0u64;
|
||||
for (p[n] != 0u8) { n += 1u64; };
|
||||
@@ -114,7 +106,6 @@ fn dcstrtostr(p: *u8) str = {
|
||||
return strings.dup(view);
|
||||
};
|
||||
|
||||
// basename: scan for last '/' and return pointer past it.
|
||||
fn dbasename(p: *u8) *u8 = {
|
||||
let n: u64 = dcstrlen(p);
|
||||
let i: u64 = n;
|
||||
@@ -127,8 +118,6 @@ fn dbasename(p: *u8) *u8 = {
|
||||
return p;
|
||||
};
|
||||
|
||||
// ---- file slurp --------------------------------------------------------
|
||||
|
||||
fn slurpso(path: *u8) (*u8, u64) = {
|
||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { return nil, 0u64; };
|
||||
@@ -151,8 +140,6 @@ fn slurpso(path: *u8) (*u8, u64) = {
|
||||
return buf.ptr, n: u64;
|
||||
};
|
||||
|
||||
// ---- verdef helpers ----------------------------------------------------
|
||||
|
||||
// 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
|
||||
@@ -176,8 +163,6 @@ fn vdnameat(buf: *u8, verdefoff: u64, verdefsize: u64,
|
||||
return nil;
|
||||
};
|
||||
|
||||
// ---- entry points ------------------------------------------------------
|
||||
|
||||
export fn loadso(l: *lnk, path: *u8) i32 = {
|
||||
let buf: *u8;
|
||||
let blen: u64;
|
||||
@@ -207,7 +192,6 @@ export fn loadso(l: *lnk, path: *u8) i32 = {
|
||||
if (shoff == 0u64) { return soerr("stripped .so unsupported"); };
|
||||
if (shnum == 0u32) { return soerr("stripped .so unsupported"); };
|
||||
|
||||
// Locate the four sections we care about.
|
||||
let idxdynsym: i32 = -1;
|
||||
let idxdynamic: i32 = -1;
|
||||
let idxversym: i32 = -1;
|
||||
@@ -292,8 +276,8 @@ export fn loadso(l: *lnk, path: *u8) i32 = {
|
||||
verstr = buf + vstroff;
|
||||
};
|
||||
|
||||
// Build the lso. Exports are appended in dynsym order so
|
||||
// soprovides_v's first-match semantics match the C version.
|
||||
// Exports are appended in dynsym order so soprovides_v's
|
||||
// first-match semantics match the C version.
|
||||
let so: *lso = alloc(lso { path = dcstrtostr(path), soname = dcstrtostr(sonamecs) })!;
|
||||
let tail: *lexport = nil;
|
||||
|
||||
@@ -371,7 +355,6 @@ fn soerr(msg: str) i32 = {
|
||||
return -1;
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// selfhost/cmd/w6l/dynout.ww — port of cmd/w6l/dynout.c.
|
||||
// Port of cmd/w6l/dynout.c.
|
||||
//
|
||||
// Emit a dynamic-linked ELF executable. The shape is the simplest
|
||||
// valid one: PT_INTERP + PT_DYNAMIC + DT_BIND_NOW so the loader
|
||||
@@ -29,7 +29,6 @@ import rt;
|
||||
import strings;
|
||||
import sym;
|
||||
|
||||
// ELF constants
|
||||
def ET_EXEC_D: u16 = 2u16;
|
||||
def EM_X86_64_D: u16 = 62u16;
|
||||
def EV_CURRENT_D: u32 = 1u32;
|
||||
@@ -75,8 +74,6 @@ def PAGE: u64 = 4096u64;
|
||||
|
||||
def INTERP: str = "/lib64/ld-linux-x86-64.so.2";
|
||||
|
||||
// ---- byte writers ------------------------------------------------------
|
||||
|
||||
fn dwr8(buf: *u8, off: u64, v: u8) void = {
|
||||
buf[off] = v;
|
||||
};
|
||||
@@ -106,8 +103,6 @@ fn dwri32(buf: *u8, off: u64, v: i32) void = {
|
||||
dwr32(buf, off, v: u32);
|
||||
};
|
||||
|
||||
// ---- byte readers ------------------------------------------------------
|
||||
|
||||
fn drdu16(p: *u8, off: u64) u16 = {
|
||||
let b0: u16 = p[off]: u16;
|
||||
let b1: u16 = p[off + 1u64]: u16;
|
||||
@@ -153,8 +148,6 @@ fn alignup(off: u64, a: u64) u64 = {
|
||||
return (off + a - 1u64) & ~(a - 1u64);
|
||||
};
|
||||
|
||||
// ---- main entry --------------------------------------------------------
|
||||
|
||||
export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
// .data shares the R+W PT_LOAD with .got.plt and .dynamic.
|
||||
// Placed after .dynamic so the segment is one contiguous run;
|
||||
@@ -163,7 +156,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
let n: i32 = l.dynn;
|
||||
let nu: u64 = n: u64;
|
||||
|
||||
// ---- collect dyn syms into a plt_idx-indexed array ----
|
||||
let dynsyms: []*lsym = alloc([], nu)!;
|
||||
let s: *lsym = l.syms;
|
||||
for (s != nil) {
|
||||
@@ -185,7 +177,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
i += 1;
|
||||
};
|
||||
|
||||
// ---- collect used .so's (in l.sos order) ----
|
||||
// Used .so's are collected in l.sos order.
|
||||
let maxsos: i32 = 0;
|
||||
let so: *lso = l.sos;
|
||||
for (so != nil) { maxsos += 1; so = so.sonext; };
|
||||
@@ -208,7 +200,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
so = so.sonext;
|
||||
};
|
||||
|
||||
// ---- build flat version table grouped by vlib ----
|
||||
// Flat version table grouped by vlib:
|
||||
// vlib_sos_idx[k] = sos_used index for vlib k.
|
||||
// vlib_first[k] = ver index of first version under vlib k.
|
||||
// vlib_count[k] = number of versions under vlib k.
|
||||
@@ -301,7 +293,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
vi += 1;
|
||||
};
|
||||
|
||||
// ---- compute dynstr size ----
|
||||
let dynstrsz: u64 = 1u64; // leading NUL
|
||||
let pi: i32 = 0;
|
||||
for (pi < nsos) {
|
||||
@@ -325,7 +316,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// ---- fill dynstr ----
|
||||
let dynstr: []u8 = alloc([], dynstrsz)!;
|
||||
let dynstrpos: u64 = 1u64; // past leading NUL
|
||||
|
||||
@@ -365,7 +355,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// ---- per-dyn-sym versym index ----
|
||||
let versymfor: []u8 = alloc([], nu * 2u64)!;
|
||||
pi = 0;
|
||||
for (pi < n) {
|
||||
@@ -400,7 +389,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// ---- compute byte sizes ----
|
||||
let ehdrsz: u64 = 64u64;
|
||||
let nphdrs: u64 = 4u64;
|
||||
let phdrsz: u64 = nphdrs * 56u64;
|
||||
@@ -433,7 +421,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
let ndyn: u64 = (nsos: u64) + 11u64 + extra;
|
||||
let dynamicsz: u64 = ndyn * 16u64;
|
||||
|
||||
// ---- compute file offsets ----
|
||||
let off: u64 = ehdrsz + phdrsz;
|
||||
let interpoff: u64 = off; off += interpsz;
|
||||
off = alignup(off, 8u64);
|
||||
@@ -486,7 +473,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
let datafilelen: u64 = l.datalen - bsslen;
|
||||
let filedataend: u64 = dataoff + datafilelen;
|
||||
|
||||
// ---- build .dynsym ----
|
||||
let dynsymbuf: []u8 = alloc([], dynsymsz)!;
|
||||
pi = 0;
|
||||
for (pi < n) {
|
||||
@@ -500,7 +486,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// ---- build .hash (SysV, 1 bucket) ----
|
||||
// .hash is SysV with a single bucket.
|
||||
let hashbuf: []u8 = alloc([], hashsz)!;
|
||||
dwr32(hashbuf.ptr, 0u64, nbuckets);
|
||||
dwr32(hashbuf.ptr, 4u64, nchain);
|
||||
@@ -515,7 +501,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
ci += 1u64;
|
||||
};
|
||||
|
||||
// ---- build .rela.plt ----
|
||||
let relapltbuf: []u8 = alloc([], relapltsz)!;
|
||||
pi = 0;
|
||||
for (pi < n) {
|
||||
@@ -527,7 +512,7 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// ---- build .gnu.version (u16 per dynsym entry) ----
|
||||
// .gnu.version is one u16 per dynsym entry.
|
||||
let versymbuf: []u8 = alloc([], versymsz)!;
|
||||
dwr16(versymbuf.ptr, 0u64, VER_NDX_LOCAL_D);
|
||||
pi = 0;
|
||||
@@ -536,7 +521,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// ---- build .gnu.version_r ----
|
||||
let verneedbuf: []u8 = alloc([], verneedsz)!;
|
||||
if (verneedsz > 0u64) {
|
||||
let vnoff: u64 = 0u64;
|
||||
@@ -575,7 +559,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
};
|
||||
};
|
||||
|
||||
// ---- build .plt ----
|
||||
let pltbuf: []u8 = alloc([], pltsz)!;
|
||||
pi = 0;
|
||||
for (pi < n) {
|
||||
@@ -590,11 +573,9 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// ---- build .got.plt ----
|
||||
let gotpltbuf: []u8 = alloc([], gotpltsz)!;
|
||||
dwr64(gotpltbuf.ptr, 0u64, dynamicva);
|
||||
|
||||
// ---- build .dynamic ----
|
||||
let dynamicbuf: []u8 = alloc([], dynamicsz)!;
|
||||
let dk: u64 = 0u64;
|
||||
pi = 0;
|
||||
@@ -625,7 +606,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
return 1;
|
||||
};
|
||||
|
||||
// ---- patch .text relocs targeting dynamic syms ----
|
||||
let r: *lrel = l.rels;
|
||||
for (r != nil) {
|
||||
if (r.sym != nil) {
|
||||
@@ -646,7 +626,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
r = r.rnext;
|
||||
};
|
||||
|
||||
// ---- assemble file buffer ----
|
||||
let filebuf: []u8 = alloc([], fileend)!;
|
||||
filebuf.len = fileend: i32;
|
||||
|
||||
@@ -721,7 +700,6 @@ export fn emitdynelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
dwr64(filebuf.ptr, p3 + 40u64, dynamicsz);
|
||||
dwr64(filebuf.ptr, p3 + 48u64, 8u64);
|
||||
|
||||
// Sections.
|
||||
dbcopy(filebuf.ptr, interpoff, INTERP.ptr, INTERP.len: u64);
|
||||
dwr8(filebuf.ptr, interpoff + (INTERP.len: u64), 0u8);
|
||||
dbcopy(filebuf.ptr, dynstroff, dynstr.ptr, dynstrsz);
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
// selfhost/cmd/w6l/main.ww — port of cmd/w6l/main.c.
|
||||
//
|
||||
// w6l = amd64 linker. Reads relocatable ELF .o files, SysV `ar`
|
||||
// archives, and shared objects (ET_DYN). Resolves symbols, applies
|
||||
// relocations, writes a static or dynamic-linked ELF executable.
|
||||
// Port of cmd/w6l/main.c.
|
||||
//
|
||||
// w6l_ww -o out [-L<dir>...] [-l<name>...] file1.o file2.o ...
|
||||
|
||||
@@ -25,10 +21,6 @@ fn mklnk() *lnk = {
|
||||
return l;
|
||||
};
|
||||
|
||||
// `cstreq` lives in obj.ww — same bundle, single definition.
|
||||
|
||||
// `cstrlen` lives in obj.ww — same bundle, single definition.
|
||||
|
||||
// Build "<dir>/lib<name>.<ext>" into dst (NUL-terminated). Returns total
|
||||
// length excluding NUL. dst must be large enough.
|
||||
fn buildpath(dst: *u8, dir: *u8, name: *u8, ext: str) u64 = {
|
||||
@@ -274,8 +266,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
k += 1;
|
||||
};
|
||||
|
||||
// Then resolve -l flags and load each. Archives append; shared
|
||||
// objects register their exports.
|
||||
// Archives append; shared objects register their exports.
|
||||
let lf: i32 = 0;
|
||||
for (lf < nlflags) {
|
||||
let p: *u8 = resolvelib(lflags[lf], libdirs.ptr, nlibdirs);
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
// selfhost/cmd/w6l/obj.ww — port of cmd/w6l/obj.c.
|
||||
//
|
||||
// Loads relocatable ELF64 .o files emitted by w6a, appends .text to
|
||||
// the combined image, and pulls in symbols + relocations with
|
||||
// offsets adjusted to the combined section.
|
||||
//
|
||||
// Also handles SysV `ar` archives (libwwrt.a). The two-pass loader
|
||||
// indexes members on the first pass and iteratively pulls members
|
||||
// that define currently-undefined symbols on subsequent passes.
|
||||
// Port of cmd/w6l/obj.c.
|
||||
|
||||
package w6l;
|
||||
|
||||
@@ -22,7 +14,6 @@ def SHT_SYMTAB: i32 = 2;
|
||||
def SHT_STRTAB: i32 = 3;
|
||||
def SHT_RELA: i32 = 4;
|
||||
|
||||
// ---- little-endian byte readers ----------------------------------------
|
||||
// w6a/w6l use straight LE on amd64. Reading via byte offsets keeps us off
|
||||
// the cgen's u16 field-load story for now (MOVZBQ exists; MOVZWQ doesn't).
|
||||
|
||||
@@ -46,7 +37,6 @@ fn rdu64(p: *u8, off: u64) u64 = {
|
||||
return lo | (hi << 32u64);
|
||||
};
|
||||
|
||||
// ---- ELF64 section header offsets (40 bytes total) --------------------
|
||||
def SHDR_SIZE: u64 = 64u64; // sizeof(Shdr) per ELF64 spec
|
||||
def SHDR_NAME: u64 = 0u64;
|
||||
def SHDR_TYPE: u64 = 4u64;
|
||||
@@ -76,8 +66,6 @@ def RELA_OFFSET: u64 = 0u64;
|
||||
def RELA_INFO: u64 = 8u64;
|
||||
def RELA_ADDEND: u64 = 16u64;
|
||||
|
||||
// ---- file slurp --------------------------------------------------------
|
||||
|
||||
fn slurp(path: *u8) (*u8, u64) = {
|
||||
let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { return nil, 0u64; };
|
||||
@@ -100,8 +88,6 @@ fn slurp(path: *u8) (*u8, u64) = {
|
||||
return buf.ptr, n: u64;
|
||||
};
|
||||
|
||||
// ---- text buffer growth ------------------------------------------------
|
||||
|
||||
fn emittext(l: *lnk, src: *u8, n: u64) void = {
|
||||
if (l.textlen + n > l.textcap) {
|
||||
let nc: u64 = l.textcap;
|
||||
@@ -149,17 +135,13 @@ fn emitdata(l: *lnk, src: *u8, n: u64) void = {
|
||||
l.datalen += n;
|
||||
};
|
||||
|
||||
// ---- C-string helpers --------------------------------------------------
|
||||
|
||||
fn cstrlen(p: *u8) u64 = {
|
||||
let n: u64 = 0u64;
|
||||
for (p[n] != 0u8) { n += 1u64; };
|
||||
return n;
|
||||
};
|
||||
|
||||
// pathstr — view a NUL-terminated *u8 as a str. Bridges argv-style
|
||||
// callers to lib/os entrypoints (str post-task-#23). Shared with
|
||||
// main.ww and dyn.ww via the w6l bundle.
|
||||
// Bridges argv-style callers to lib/os entrypoints (str post-task-#23).
|
||||
fn pathstr(p: *u8) str = {
|
||||
let r: str;
|
||||
r.ptr = p;
|
||||
@@ -179,7 +161,6 @@ fn cstreq(p: *u8, lit: str) bool = {
|
||||
return true;
|
||||
};
|
||||
|
||||
// Build a ww str from a NUL-terminated *u8 (for passing to intern).
|
||||
fn cstrtostr(p: *u8) str = {
|
||||
let n: u64 = cstrlen(p);
|
||||
let view: str;
|
||||
@@ -188,8 +169,6 @@ fn cstrtostr(p: *u8) str = {
|
||||
return strings.dup(view);
|
||||
};
|
||||
|
||||
// ---- archive (SysV ar) types and helpers -------------------------------
|
||||
//
|
||||
// Each archive member starts with a 60-byte ar_hdr. The fields we care
|
||||
// about are the first byte (member type) and the size at offset 48 (a
|
||||
// 10-byte, space-padded decimal). Member bodies are 2-byte aligned.
|
||||
@@ -231,9 +210,8 @@ fn arfield(p: *u8, n: u64) u64 = {
|
||||
return v;
|
||||
};
|
||||
|
||||
// elfglobals — return a linked list of names of globally-defined
|
||||
// (STB_GLOBAL) symbols whose section is `.text`. Names are owned
|
||||
// heap copies, so the source ELF buffer can be freed afterward.
|
||||
// Names are owned heap copies, so the source ELF buffer can be freed
|
||||
// afterward.
|
||||
fn elfglobals(buf: *u8, len: u64) *defent = {
|
||||
if (len < EHDR_SIZE) { return nil; };
|
||||
if (buf[0u64] != 127u8) { return nil; };
|
||||
@@ -310,9 +288,8 @@ fn elfglobals(buf: *u8, len: u64) *defent = {
|
||||
return head;
|
||||
};
|
||||
|
||||
// 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).
|
||||
// Names not already interned are uninteresting (the link doesn't need
|
||||
// them yet).
|
||||
fn memberdefinesundef(l: *lnk, m: *armember) bool = {
|
||||
let de: *defent = m.defs;
|
||||
for (de != nil) {
|
||||
@@ -406,8 +383,6 @@ fn loadarchive(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
// ---- main loader -------------------------------------------------------
|
||||
|
||||
export fn load(l: *lnk, path: *u8) i32 = {
|
||||
let bufp: *u8;
|
||||
let buflen: u64;
|
||||
@@ -441,7 +416,6 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
||||
let shstrshoff: u64 = rdu64(buf, shoff + (shstrndx: u64) * SHDR_SIZE + SHDR_OFFSET);
|
||||
let shstr: *u8 = buf + shstrshoff;
|
||||
|
||||
// find .text, .data, .symtab, .rela.text, .rela.data
|
||||
let idxtext: i32 = -1;
|
||||
let idxdata: i32 = -1;
|
||||
let idxsymtab: i32 = -1;
|
||||
@@ -497,7 +471,6 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
||||
datasize = rdu64(buf, datash + SHDR_SIZE_F);
|
||||
};
|
||||
|
||||
// Track this object.
|
||||
let ob: *lobj = alloc(lobj {
|
||||
path = cstrtostr(path),
|
||||
buf = buf,
|
||||
@@ -510,18 +483,16 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
||||
})!;
|
||||
l.objs = ob;
|
||||
|
||||
// Append .text bytes to the combined image.
|
||||
emittext(l, buf + textoff, textsize);
|
||||
// Append .data bytes (if present) to the combined .data buffer.
|
||||
if (idxdata >= 0) {
|
||||
if (datasize > 0u64) {
|
||||
emitdata(l, buf + dataoff, datasize);
|
||||
};
|
||||
};
|
||||
|
||||
// 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
|
||||
// than dancing around the cgen's u64-shift gaps.
|
||||
// We don't keep a per-object map[] of *lsym. Instead the reloc
|
||||
// loop re-walks symtab and re-interns by name. Simpler than
|
||||
// dancing around the cgen's u64-shift gaps.
|
||||
let si: u64 = 1u64; // skip index 0 (always undef sentinel)
|
||||
for (si < nsyms) {
|
||||
let symp: u64 = symoff + si * SYM_SIZE;
|
||||
@@ -569,7 +540,6 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
||||
si += 1u64;
|
||||
};
|
||||
|
||||
// Per-object relocation collection.
|
||||
if (idxrela >= 0) {
|
||||
let relash: u64 = shoff + (idxrela: u64) * SHDR_SIZE;
|
||||
let relaoff: u64 = rdu64(buf, relash + SHDR_OFFSET);
|
||||
@@ -590,7 +560,6 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
||||
addend = raddend: i64,
|
||||
rnext = l.rels,
|
||||
})!;
|
||||
// Look up the referenced sym by name (re-walk symtab).
|
||||
if ((rsymidx: u64) < nsyms) {
|
||||
let sp: u64 = symoff + (rsymidx: u64) * SYM_SIZE;
|
||||
let sname: u32 = rdu32(buf, sp + SYM_NAME);
|
||||
@@ -605,8 +574,8 @@ fn loadimage(l: *lnk, path: *u8, buf: *u8, len: u64) i32 = {
|
||||
};
|
||||
};
|
||||
|
||||
// Data-reloc collection. Offsets land in .data, shifted by
|
||||
// this object's data_off so they index the combined buffer.
|
||||
// Offsets land in .data, shifted by this object's dataoff so
|
||||
// they index the combined buffer.
|
||||
if (idxrelad >= 0) {
|
||||
let relash: u64 = shoff + (idxrelad: u64) * SHDR_SIZE;
|
||||
let relaoff: u64 = rdu64(buf, relash + SHDR_OFFSET);
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
// selfhost/cmd/w6l/out.ww — port of cmd/w6l/out.c.
|
||||
//
|
||||
// Emit a static ELF64 executable. File layout (per the C original):
|
||||
// [0..64) Ehdr
|
||||
// [64..120) Phdr (one PT_LOAD)
|
||||
// [120..0x1000) zero pad
|
||||
// [0x1000..) .text bytes
|
||||
// Single PT_LOAD covers the whole file, R+X. No interpreter, no .bss.
|
||||
// Port of cmd/w6l/out.c.
|
||||
|
||||
package w6l;
|
||||
|
||||
@@ -27,8 +20,6 @@ def PF_R: u32 = 4u32;
|
||||
def TEXT_OFF: u64 = 4096u64; // 0x1000
|
||||
def PAGE_SZ: u64 = 4096u64;
|
||||
|
||||
// ---- little-endian byte writers ----------------------------------------
|
||||
|
||||
fn wru16(buf: *u8, off: u64, v: u16) void = {
|
||||
buf[off] = (v & 255u16): u8;
|
||||
buf[off + 1u64] = ((v >> 8u16) & 255u16): u8;
|
||||
@@ -46,8 +37,6 @@ fn wru64(buf: *u8, off: u64, v: u64) void = {
|
||||
wru32(buf, off + 4u64, ((v >> 32u64) & 4294967295u64): u32);
|
||||
};
|
||||
|
||||
// ---- emit ---------------------------------------------------------------
|
||||
|
||||
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.
|
||||
@@ -92,7 +81,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
let hdr: []u8 = alloc([], TEXT_OFF)!;
|
||||
hdr.len = TEXT_OFF: i32;
|
||||
|
||||
// --- Ehdr (64 bytes) ---
|
||||
// Ehdr (64 bytes).
|
||||
hdr[0u64] = 127u8; // 0x7f
|
||||
hdr[1u64] = 'E';
|
||||
hdr[2u64] = 'L';
|
||||
@@ -115,7 +104,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
wru16(hdr.ptr, 60u64, 0u16); // e_shnum
|
||||
wru16(hdr.ptr, 62u64, 0u16); // e_shstrndx
|
||||
|
||||
// --- Phdr #1 (R+X) at offset 64 ---
|
||||
// Phdr #1 (R+X) at offset 64.
|
||||
wru32(hdr.ptr, 64u64, PT_LOAD);
|
||||
wru32(hdr.ptr, 68u64, PF_R | PF_X);
|
||||
wru64(hdr.ptr, 72u64, 0u64); // p_offset
|
||||
@@ -126,7 +115,7 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
wru64(hdr.ptr, 112u64, TEXT_OFF); // p_align
|
||||
|
||||
if (hasdata) {
|
||||
// --- Phdr #2 (R+W) at offset 64+56=120 ---
|
||||
// Phdr #2 (R+W) at offset 64+56=120.
|
||||
wru32(hdr.ptr, 120u64, PT_LOAD);
|
||||
wru32(hdr.ptr, 124u64, PF_R | PF_W);
|
||||
wru64(hdr.ptr, 128u64, dataoff); // p_offset
|
||||
@@ -137,7 +126,6 @@ export fn emitelf(l: *lnk, fd: i32, base: u64, entry: u64) i32 = {
|
||||
wru64(hdr.ptr, 168u64, PAGE_SZ); // p_align
|
||||
};
|
||||
|
||||
// Write [0..0x1000) then .text.
|
||||
let r1: (i64 | os.oserror) = os.writeall(fd, hdr.ptr, TEXT_OFF);
|
||||
let n1: i64 = 0i64;
|
||||
match (r1) {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
// selfhost/cmd/w6l/pass.ww — port of cmd/w6l/pass.c.
|
||||
//
|
||||
// Resolution + relocation. l_resolve flags every undefined symbol
|
||||
// referenced by a relocation, and promotes those provided by some
|
||||
// loaded .so to "dynamic" with a freshly-assigned PLT slot.
|
||||
// l_relocate walks the rel list and patches the .text bytes in place
|
||||
// once the final virtual base is known. Dynamic refs are deferred:
|
||||
// their site is patched later in dynout, once the PLT vaddr is known.
|
||||
// Port of cmd/w6l/pass.c.
|
||||
//
|
||||
// Supported relocation kinds: PC32 (=2), PLT32 (=4); both are 32-bit
|
||||
// PC-relative displacements (PLT32 == PC32 for static).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// selfhost/cmd/w6l/sym.ww — port of cmd/w6l/sym.c.
|
||||
// Port of cmd/w6l/sym.c.
|
||||
//
|
||||
// Linker symbol table. Singly-linked list, usually a few hundred
|
||||
// entries; hashing isn't worth it yet.
|
||||
// Singly-linked list, usually a few hundred entries; hashing isn't
|
||||
// worth it yet.
|
||||
|
||||
package w6l;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user