6l: port ET_DYN dynamic linking to the ww side
Ports cmd/6l/{dyn,dynout}.c into selfhost/cmd/6l/{dyn,dynout}.ww:
ET_DYN .so loading + PT_INTERP/PT_DYNAMIC ELF emission with .rela.plt,
.gnu.version_r, BIND_NOW. lsym grows dyn fields; pass.ww promotes
undefs to dyn; out.ww dispatches; main.ww takes -L/-l. The ww driver
forwards -L/-l to 6l_ww so 'ww_ww build snake.ww -L /usr/lib -l ncurses
-l c' runs without cc.
Test 996 pins byte-identical output to C-6l on snake.
'make bootstrap' gains a fourth stage with cmp ww3 == ww4, proving
ww3 is byte-stable when used as a compiler — not just a coincidental
two-stage equilibrium.
Four wwstage 6c cgen quirks surfaced and are documented in dynout.ww's
header (two-level field-write through a pointer field, (scalar, str)
tuple returns, def : str, ≤6 arg calling convention).
This commit is contained in:
@@ -1,31 +1,76 @@
|
||||
// selfhost/cmd/6l/pass.ww — port of cmd/6l/pass.c.
|
||||
//
|
||||
// Resolution + relocation. l_resolve flags every undefined symbol
|
||||
// referenced by a relocation. l_relocate walks the rel list and
|
||||
// patches the .text bytes in place once the final virtual base is
|
||||
// known. Supported relocation kinds: PC32 (=2), PLT32 (=4); both
|
||||
// are 32-bit PC-relative displacements (PLT32 == PC32 for static).
|
||||
// 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.
|
||||
//
|
||||
// Supported relocation kinds: PC32 (=2), PLT32 (=4); both are 32-bit
|
||||
// PC-relative displacements (PLT32 == PC32 for static).
|
||||
|
||||
use os;
|
||||
use sym;
|
||||
use dyn;
|
||||
|
||||
def R_X86_64_PC32: i32 = 2;
|
||||
def R_X86_64_PLT32: i32 = 4;
|
||||
|
||||
export fn l_resolve(l: *lnk) i32 = {
|
||||
// Initialise dynamic-linking sentinels. amalloc zeroes, so
|
||||
// is_dyn/dyn_lib start clean — but plt_idx and dynsym_idx
|
||||
// must be -1, not 0.
|
||||
let si: *lsym = l.syms;
|
||||
for (si != nil) {
|
||||
si.plt_idx = -1;
|
||||
si.dynsym_idx = -1;
|
||||
si = si.snext;
|
||||
};
|
||||
|
||||
// Promote each undefined sym that some lso exports to dynamic
|
||||
// and hand it a PLT slot. Iteration order over the relocation
|
||||
// list determines slot numbering and is stable across runs.
|
||||
let r: *lrel = l.rels;
|
||||
for (r != nil) {
|
||||
if (r.sym != nil) {
|
||||
if (r.sym.defined == 0) {
|
||||
os.write(2, "6l: undefined reference to '".ptr, 28u64);
|
||||
let nm: str = r.sym.name;
|
||||
os.write(2, nm.ptr, nm.len: u64);
|
||||
os.write(2, "'\n".ptr, 2u64);
|
||||
l.errs += 1;
|
||||
let sym: *lsym = r.sym;
|
||||
if (sym.is_dyn == 0) {
|
||||
let so: *lso = l.sos;
|
||||
for (so != nil) {
|
||||
if (l_so_provides(so, sym.name) != 0) {
|
||||
sym.is_dyn = 1;
|
||||
sym.dyn_lib = so;
|
||||
sym.plt_idx = l.dyn_n;
|
||||
l.dyn_n += 1;
|
||||
so = nil; // break
|
||||
} else {
|
||||
so = so.sonext;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
r = r.rnext;
|
||||
};
|
||||
|
||||
// What remains undefined truly is undefined.
|
||||
let r2: *lrel = l.rels;
|
||||
for (r2 != nil) {
|
||||
if (r2.sym != nil) {
|
||||
if (r2.sym.defined == 0) {
|
||||
if (r2.sym.is_dyn == 0) {
|
||||
os.write(2, "6l: undefined reference to '".ptr, 28u64);
|
||||
let nm: str = r2.sym.name;
|
||||
os.write(2, nm.ptr, nm.len: u64);
|
||||
os.write(2, "'\n".ptr, 2u64);
|
||||
l.errs += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
r2 = r2.rnext;
|
||||
};
|
||||
return l.errs;
|
||||
};
|
||||
|
||||
@@ -40,6 +85,12 @@ export fn l_relocate(l: *lnk, base: u64) i32 = {
|
||||
let r: *lrel = l.rels;
|
||||
for (r != nil) {
|
||||
if (r.sym != nil) {
|
||||
// Dynamic refs are patched later in dynout once the
|
||||
// PLT vaddr is known.
|
||||
if (r.sym.is_dyn != 0) {
|
||||
r = r.rnext;
|
||||
continue;
|
||||
};
|
||||
if (r.sym.defined != 0) {
|
||||
let k: i32 = r.kind;
|
||||
if (k == R_X86_64_PC32) {
|
||||
|
||||
Reference in New Issue
Block a user