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