// Port of cmd/w6l/sym.c. // // Singly-linked list, usually a few hundred entries; hashing isn't // worth it yet. package main; import strings; type lsym = struct { name: str, val: u64, // offset within combined .text (or .data when // indata=1) once linked defined: i32, // 1 if some lobj defines this symbol indata: i32, // 1 if defined in .data (writable globals) owner: *lobj, idxinowner: i32, // Dynamic-linking fields. Set by resolve when an undefined sym // is provided by some loaded lso. pltidx and dynsymidx default // to -1 (set explicitly by resolve; alloc-zeroing gives 0, not -1). isdyn: i32, dynlib: *lso, dynversion: str, // matched export's version; len 0 if none pltidx: i32, dynsymidx: i32, snext: *lsym, }; type lrel = struct { off: u64, // offset within the relocation's section section: i32, // 0 = .text, 1 = .data kind: i32, // R_X86_64_* sym: *lsym, addend: i64, rnext: *lrel, }; type lobj = struct { path: str, buf: *u8, // object bytes len: u64, textoff: u64, // offset of .text in combined output textsize: u64, dataoff: u64, // offset of .data in combined output datasize: u64, // bytes contributed to combined .data (0 if none) onext: *lobj, }; // lexport — one entry per GLOBAL/WEAK symbol exported by a loaded .so. // Stored as a chain in the order the .so's dynsym presents them, so // soprovides_v's first-match semantics agree with the C version. type lexport = struct { name: str, version: str, // len 0 for unversioned globals enext: *lexport, }; type lso = struct { path: str, // full filesystem path used to load soname: str, // DT_SONAME, or basename if missing exports: *lexport, // dynsym-order chain of exported names sonext: *lso, }; type lnk = struct { objs: *lobj, sos: *lso, syms: *lsym, rels: *lrel, text: *u8, // combined .text textcap: u64, textlen: u64, // Combined .data (writable). Empty unless any input .o has a // .data PROGBITS section. data: *u8, datacap: u64, datalen: u64, errs: i32, dynn: i32, // number of syms routed through PLT }; export fn intern(l: *lnk, name: str) *lsym = { let s: *lsym = l.syms; for (s != nil) { if (strings.compare(s.name, name) == 0) { return s; }; s = s.snext; }; let n: *lsym = alloc(lsym { name = name, snext = l.syms })!; l.syms = n; return n; }; export fn lookup(l: *lnk, name: str) *lsym = { let s: *lsym = l.syms; for (s != nil) { if (strings.compare(s.name, name) == 0) { return s; }; s = s.snext; }; return nil; };