#ifndef SIX_L_H #define SIX_L_H #include #include #include typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef struct Lsym Lsym; typedef struct Lrel Lrel; typedef struct Lobj Lobj; typedef struct Lso Lso; typedef struct Lnk Lnk; struct Lsym { const char *name; u64 val; /* offset within combined .text (or .data when * in_data=1) once linked */ int defined; /* 1 if a Lobj defines this symbol */ int in_data; /* 1 if defined in .data (writable globals); * 0 means .text (the default). Mutually * exclusive with is_dyn. */ Lobj *owner; int idx_in_owner; /* Dynamic-linking fields. Set by l_resolve when an undefined sym * is provided by some loaded Lso. Patched-in PLT slot index lets * the relocator route PC32/PLT32 references through the stub. */ int is_dyn; Lso *dyn_lib; const char *dyn_version; /* matched export's version, NULL if none */ int plt_idx; /* 0..dyn_n-1, -1 if no PLT slot */ int dynsym_idx; /* index in emitted .dynsym, -1 otherwise */ Lsym *next; }; struct Lrel { u64 off; /* offset within the relocation's section */ int section; /* 0 = .text, 1 = .data */ int kind; /* R_X86_64_* */ Lsym *sym; i64 addend; Lrel *next; }; struct Lobj { const char *path; u8 *buf; /* mmapped or read-in object bytes */ u64 len; u64 text_off; /* offset of .text in combined output */ u64 text_size; u64 data_off; /* offset of .data in combined output */ u64 data_size; /* bytes contributed to combined .data (0 if none) */ Lobj *next; }; struct Lso { const char *path; /* full filesystem path used to load */ const char *soname; /* DT_SONAME, or basename if missing */ char **exports; /* NULL-terminated list of GLOBAL/WEAK syms */ char **versions; /* parallel to exports[]; NULL for unversioned, * else strdup'd version name e.g. "GLIBC_2.2.5" */ Lso *next; }; struct Lnk { Lobj *objs; Lso *sos; Lsym *syms; Lrel *rels; u8 *text; /* combined .text */ u64 textcap, textlen; u8 *data; /* combined .data (writable). Empty unless any * input .o has a .data PROGBITS section. */ u64 datacap, datalen; int errs; int dyn_n; /* number of symbols routed through PLT */ }; /* obj.c */ int l_load(Lnk*, const char *path); int l_read_all(const char *path, u8 **out, u64 *len); /* shared helper */ /* dyn.c */ int l_load_so(Lnk*, const char *path); int l_so_provides(Lso*, const char *name); /* l_so_provides_v: same, but also returns the export's version name * (NULL for unversioned globals) via *out_version on a hit. */ int l_so_provides_v(Lso*, const char *name, const char **out_version); /* sym.c */ Lsym *l_intern(Lnk*, const char *name); Lsym *l_lookup(Lnk*, const char *name); /* pass.c */ int l_resolve(Lnk*); /* Patch relocations in l->text. text_va is the VA where .text will be * mapped; data_va is the VA where .data will be mapped (pass 0 if no * data symbols). PC32/PLT32 displacements between text symbols cancel * the absolute VA, but data targets need the real data_va. */ int l_relocate(Lnk*, u64 text_va, u64 data_va); /* out.c */ int l_emit_elf(Lnk*, FILE *out, u64 base, u64 entry); /* dynout.c — emit a dynamic-linked ELF executable. Called by * l_emit_elf when l->sos is non-empty. */ int l_emit_dyn_elf(Lnk*, FILE *out, u64 base, u64 entry); #endif