diff options
| author | 2025-10-19 08:09:09 +0200 | |
|---|---|---|
| committer | 2025-10-19 08:09:09 +0200 | |
| commit | dea8fd171acb54b6d9685422d5e391fb55074008 (patch) | |
| tree | 2c149892f35c5183c9b2a1da4ab437228dc432ef /obj | |
| parent | 3437945692f2b87883a4f066473c9deed50f25f5 (diff) | |
Organize source files into directories
Diffstat (limited to 'obj')
| -rw-r--r-- | obj/elf.c | 525 | ||||
| -rw-r--r-- | obj/elf.h | 206 | ||||
| -rw-r--r-- | obj/obj.c | 105 | ||||
| -rw-r--r-- | obj/obj.h | 30 |
4 files changed, 866 insertions, 0 deletions
diff --git a/obj/elf.c b/obj/elf.c new file mode 100644 index 0000000..d889fdd --- /dev/null +++ b/obj/elf.c @@ -0,0 +1,525 @@ +#include "elf.h" +#include "obj.h" +#include "../ir/ir.h" /* mctarg */ +#include "../endian.h" +#include <unistd.h> +#include <stdlib.h> /* qsort */ + +static union { + ELF_HDRIDENT; + struct elf32hdr h32; + struct elf64hdr h64; +} hdr; +static vec_of(uchar) strs; +struct sym { + uint name; + uchar bind : 4, + type : 4; + ushort shndx; + uvlong value, + size; +}; +static vec_of(struct sym) symtab; +static uint ntextrel, nrodatarel, ndatarel; +struct reloc { + uchar section; + ushort kind; + uint sym; + uint off; + vlong addend; +}; +static vec_of(struct reloc) relocs; + +#define O objout + +void +elfinit(void) +{ + memcpy(hdr.i_mag, ELFMAG, 4); + hdr.i_class = ELFCLASS32 + targ_64bit; + hdr.i_data = ELFDATA2LSB + targ_bigendian; + hdr.i_version = ELFVERSION; + hdr.i_osabi = ELFOSABI_SYSV; + hdr.i_abiversion = 0; + hdr.h32.type = ET_REL; + switch (mctarg->isa) { + case ISamd64: hdr.h32.machine = EM_X86_64; break; + } + hdr.h32.version = ELFVERSION; + if (targ_64bit) { + hdr.h64.ehsize = sizeof(struct elf64hdr); + hdr.h64.shentsize = sizeof(struct elf64shdr); + } else { + hdr.h32.ehsize = sizeof(struct elf32hdr); + hdr.h32.shentsize = sizeof(struct elf32shdr); + } + vpush(&symtab, ((struct sym) { 0 })); + vpush(&symtab, ((struct sym) { .type = STT_FILE, .shndx = SHN_ABS })); +} + +uint +str2idx(const char *s) +{ + static pmap_of(uint) ht; + uint *p, i; + + if ((p = pmap_get(&ht, s))) return *p; + if (!strs.n) vpush(&strs, 0); + i = strs.n; + vpushn(&strs, s, strlen(s)+1); + pmap_set(&ht, s, i); + return i; +} + +static struct sym * +findsym(uint name) +{ + for (int i = 0; i < symtab.n; ++i) + if (symtab.p[i].name == name) + return &symtab.p[i]; + return NULL; +} + +enum { + TEXT_SHNDX = 1, + RODATA_SHNDX = 2, + DATA_SHNDX = 3, + BSS_SHNDX = 4, +}; + +void +elfaddsym(const char *nam, int info, enum section sect, uvlong value, uvlong size) +{ + uint str = str2idx(nam); + struct sym *sym = findsym(str), sym0 = {0}; + + if (!sym) { + sym = &sym0; + sym->name = str; + } + sym->bind = info >> 4; + sym->type = info & 0xF; + switch (sect) { + case Snone: sym->shndx = SHN_UND; break; + case Stext: sym->shndx = TEXT_SHNDX; break; + case Srodata: sym->shndx = RODATA_SHNDX; break; + case Sdata: sym->shndx = DATA_SHNDX; break; + case Sbss: sym->shndx = BSS_SHNDX; break; + } + sym->value = value; + sym->size = size; + if (sym == &sym0) vpush(&symtab, sym0); +} + +static const ushort relktab[][NRELOCKIND] = { + [ISamd64] = { + [REL_ABS64] = 1, /* R_X86_64_64 */ + [REL_ABS32] = 10, /* R_X86_64_32 */ + [REL_ABS32S] = 11, /* R_X86_64_32S */ + [REL_PCREL32] = 2, /* R_X86_64_PC32 */ + [REL_PLT32] = 4, /* R_X86_64_PLT32 */ + [REL_GOTPCRELX] = 41, /* R_X86_64_GOTPCRELX */ + [REL_GOTPCRELX_REX] = 42, /* R_X86_64_REX_GOTPCRELX */ + } +}; + +void +elfreloc(const char *sym, enum relockind kind, enum section section, uint off, vlong addend) +{ + uint snam = str2idx(sym); + switch (section) { + default: assert(0); + case Stext: ++ntextrel; break; + case Srodata: ++nrodatarel; break; + case Sdata: ++ndatarel; break; + } + assert(kind < NRELOCKIND); + vpush(&relocs, ((struct reloc) { section, relktab[mctarg->isa][kind], snam, off, addend })); +} + +static void +elf64puthdr(struct wbuf *out, struct elf64hdr *hdr) +{ + if (!hostntarg_sameendian()) { + hdr->type = bswap16(hdr->type); + hdr->machine = bswap16(hdr->machine); + hdr->version = bswap32(hdr->version); + hdr->entry = bswap64(hdr->entry); + hdr->phoff = bswap64(hdr->phoff); + hdr->shoff = bswap64(hdr->shoff); + hdr->flags = bswap32(hdr->flags); + hdr->ehsize = bswap16(hdr->ehsize); + hdr->phentsize = bswap16(hdr->phentsize); + hdr->phnum = bswap16(hdr->phnum); + hdr->shentsize = bswap16(hdr->shentsize); + hdr->shnum = bswap16(hdr->shnum); + hdr->shstrndx = bswap16(hdr->shstrndx); + } + iowrite(out, hdr, sizeof *hdr); +} + +static void +elf32puthdr(struct wbuf *out, struct elf32hdr *hdr) +{ + if (!hostntarg_sameendian()) { + hdr->type = bswap16(hdr->type); + hdr->machine = bswap16(hdr->machine); + hdr->version = bswap32(hdr->version); + hdr->entry = bswap32(hdr->entry); + hdr->phoff = bswap32(hdr->phoff); + hdr->shoff = bswap32(hdr->shoff); + hdr->flags = bswap32(hdr->flags); + hdr->ehsize = bswap16(hdr->ehsize); + hdr->phentsize = bswap16(hdr->phentsize); + hdr->phnum = bswap16(hdr->phnum); + hdr->shentsize = bswap16(hdr->shentsize); + hdr->shnum = bswap16(hdr->shnum); + hdr->shstrndx = bswap16(hdr->shstrndx); + } + iowrite(out, hdr, sizeof *hdr); +} + +static void +elf64putshdr(struct wbuf *out, struct elf64shdr *shdr) +{ + if (!hostntarg_sameendian()) { + shdr->name = bswap32(shdr->name); + shdr->type = bswap32(shdr->type); + shdr->flags = bswap64(shdr->flags); + shdr->addr = bswap64(shdr->addr); + shdr->offset = bswap64(shdr->offset); + shdr->size = bswap64(shdr->size); + shdr->link = bswap32(shdr->link); + shdr->info = bswap32(shdr->info); + shdr->addralign = bswap64(shdr->addralign); + shdr->entsize = bswap64(shdr->entsize); + } + iowrite(out, shdr, sizeof *shdr); +} + +static void +elf32putshdr(struct wbuf *out, struct elf32shdr *shdr) +{ + if (!hostntarg_sameendian()) { + shdr->name = bswap32(shdr->name); + shdr->type = bswap32(shdr->type); + shdr->flags = bswap32(shdr->flags); + shdr->addr = bswap32(shdr->addr); + shdr->offset = bswap32(shdr->offset); + shdr->size = bswap32(shdr->size); + shdr->link = bswap32(shdr->link); + shdr->info = bswap32(shdr->info); + shdr->addralign = bswap32(shdr->addralign); + shdr->entsize = bswap32(shdr->entsize); + } + iowrite(out, shdr, sizeof *shdr); +} + +static void +elf64putsym(struct wbuf *out, struct elf64sym *sym) +{ + if (!hostntarg_sameendian()) { + sym->name = bswap32(sym->name); + sym->shndx = bswap16(sym->shndx); + sym->value = bswap64(sym->value); + sym->size = bswap64(sym->size); + } + iowrite(out, sym, sizeof *sym); +} + +static void +elf32putsym(struct wbuf *out, struct elf32sym *sym) +{ + if (!hostntarg_sameendian()) { + sym->name = bswap32(sym->name); + sym->value = bswap32(sym->value); + sym->size = bswap32(sym->size); + sym->shndx = bswap16(sym->shndx); + } + iowrite(out, sym, sizeof *sym); +} + +static void +putsym(struct wbuf *out, const struct sym *sym) +{ + if (targ_64bit) { + elf64putsym(out, &(struct elf64sym) { + sym->name, .info = ELF_S_INFO(sym->bind, sym->type), + .shndx = sym->shndx, .value = sym->value, .size = sym->size }); + } else { + elf32putsym(out, &(struct elf32sym) { + sym->name, .info = ELF_S_INFO(sym->bind, sym->type), + .shndx = sym->shndx, .value = sym->value, .size = sym->size }); + } +} + +static void +elf64putrel(struct wbuf *out, struct elf64rel *rel) +{ + if (!hostntarg_sameendian()) { + rel->offset = bswap64(rel->offset); + rel->info = bswap64(rel->info); + } + iowrite(out, rel, sizeof *rel); +} + +static void +elf32putrel(struct wbuf *out, struct elf32rel *rel) +{ + if (!hostntarg_sameendian()) { + rel->offset = bswap32(rel->offset); + rel->info = bswap32(rel->info); + } + iowrite(out, rel, sizeof *rel); +} + +static void +elf64putrela(struct wbuf *out, struct elf64rela *rel) +{ + if (!hostntarg_sameendian()) { + rel->offset = bswap64(rel->offset); + rel->info = bswap64(rel->info); + rel->addend = bswap64(rel->addend); + } + iowrite(out, rel, sizeof *rel); +} + +static void +elf32putrela(struct wbuf *out, struct elf32rela *rel) +{ + if (!hostntarg_sameendian()) { + rel->offset = bswap32(rel->offset); + rel->info = bswap32(rel->info); + rel->addend = bswap32(rel->addend); + } + iowrite(out, rel, sizeof *rel); +} + +static void +putreloc(struct wbuf *out, const struct reloc *rel, bool userela) +{ + if (userela) { + if (targ_64bit) { + elf64putrela(out, &(struct elf64rela) { + rel->off, ELF64_R_INFO(rel->sym, rel->kind), rel->addend }); + } else { + elf32putrela(out, &(struct elf32rela) { + rel->off, ELF32_R_INFO(rel->sym, rel->kind), rel->addend }); + } + } else { + if (targ_64bit) { + elf64putrel(out, &(struct elf64rel) { + rel->off, ELF64_R_INFO(rel->sym, rel->kind) }); + } else { + elf32putrel(out, &(struct elf32rel) { + rel->off, ELF32_R_INFO(rel->sym, rel->kind) }); + } + } +} + +/* ensure .symtab entries are ordered like this: + * (0. zero entry: NOTYPE LOCAL UND) + * (1. file: FILE LOCAL ABS "...") + * 2. locals + * 3. defined globals + * 4. undefined globals + */ +static int +symcmp(const void *L, const void *R) +{ + const struct sym *l = L, *r = R; + int tmp; + if ((tmp = l->bind - r->bind)) return tmp; /* locals prio */ + if ((tmp = r->shndx - l->shndx)) return tmp; /* section prio (real sections > SHN_UND) */ + return l->name - r->name; +} + +static void +wordalign(struct wbuf *out, int align) +{ + size_t off = out->len + lseek(out->fd, 0, SEEK_CUR); + while (off++ & (align - 1)) ioputc(out, 0); +} + +static const bool userelatab[] = { [ISamd64] = 1 }; + +void +elffini(struct wbuf *out) +{ + enum { + shnam_text = 1, shnam_rodata = 7, shnam_data = 15, shnam_bss = 21, shnam_shstrtab = 26, + shnam_strtab = 36, shnam_symtab = 44, shnam_reltext = 52, shnam_relrodata = 63, shnam_reldata = 76 + }; + int align = targ_64bit ? 8 : 4; + bool userela = userelatab[mctarg->isa]; + char shstrs[] = "\0.text\0.rodata\0.data\0.bss\0.shstrtab\0.strtab\0.symtab\0" + ".rela.text\0.rela.rodata\0.rela.data"; + if (!userela) { + /* .rela -> .rel */ + memcpy(shstrs + shnam_reltext + 4, ".text\0", 6); + memcpy(shstrs + shnam_relrodata + 4, ".rodata\0", 8); + memcpy(shstrs + shnam_reldata + 4, ".data\0", 6); + } + + symtab.p[1].name = str2idx(objout.infile); + qsort(symtab.p+2, symtab.n-2, sizeof *symtab.p, symcmp); + /* fixup relocs */ + for (int i = 0; i < relocs.n; ++i) { + struct reloc *rel = &relocs.p[i]; + struct sym *sym; + sym = findsym(rel->sym); + if (sym) rel->sym = sym - symtab.p; + else { + sym = &(struct sym) { rel->sym, .bind = STB_GLOBAL, .type = STT_NOTYPE, .shndx = SHN_UND }; + rel->sym = symtab.n; + vpush(&symtab, *sym); + } + if (!userela) { + uchar *p; + switch (rel->section) { + default: assert(0); + case Sdata: p = O.data.p + rel->off; break; + case Srodata: p = O.rodata.p + rel->off; break; + case Stext: p = O.textbegin + rel->off; break; + } + if (targ_64bit) + wr64targ(p, rel->addend); + else + wr32targ(p, rel->addend); + } + } + size_t codesize = alignup(O.code - O.textbegin, align), + rodataoff = (targ_64bit ? sizeof hdr.h64 : sizeof hdr.h32) + codesize, + rodatasize = O.rodata.n, + dataoff = rodataoff + rodatasize, + datasize = O.data.n, + bsssize = O.nbss, + shstrsoff = dataoff + datasize, + shstrssize = sizeof(shstrs), + strsoff = shstrsoff + shstrssize, + strssize = strs.n, + symtaboff = alignup(strsoff + strssize, align), + symtabsize = symtab.n * (targ_64bit ? 24 : 16), + reltextoff = symtaboff + symtabsize, + relxsiz = userela ? (targ_64bit ? 24 : 12) : (targ_64bit ? 16 : 8), + reltextsize = ntextrel * relxsiz, + relrodataoff = reltextoff + reltextsize, + relrodatasize = nrodatarel * relxsiz, + reldataoff = relrodataoff + relrodatasize, + reldatasize = ndatarel * relxsiz; + int nlocal = 0; + +#define CHECKOFF(s, x) \ + efmt(s " expect OFF: %u ; ACTUAL %u\n", (uint)(x),(uint)(lseek(out->fd, 0, SEEK_CUR) + out->len)) + + if (targ_64bit) { + hdr.h64.shoff = alignup(reldataoff + reldatasize, align); + hdr.h64.shnum = 11; + hdr.h64.shstrndx = 5; + } else { + hdr.h32.shoff = alignup(reldataoff + reldatasize, align); + hdr.h32.shnum = 11; + hdr.h32.shstrndx = 5; + } + + /* elf header */ + if (targ_64bit) + elf64puthdr(out, &hdr.h64); + else + elf32puthdr(out, &hdr.h32); + + /* .text progbits */ + iowrite(out, O.textbegin, codesize); + + /* .rodata progbits */ + iowrite(out, O.rodata.p, O.rodata.n); + + /* .data progbits */ + iowrite(out, O.data.p, O.data.n); + + /* section names */ + iowrite(out, shstrs, sizeof shstrs); + + /* strings */ + iowrite(out, strs.p, strs.n); + + /* symtab */ + wordalign(out, align); + for (int i = 0; i < symtab.n; ++i) { + struct sym *sym = &symtab.p[i]; + if (sym->bind == STB_LOCAL) ++nlocal; + putsym(out, sym); + } + + /* rel.* */ + assert(relocs.n == ntextrel + nrodatarel + ndatarel); + for (enum section s = Stext; s <= Sbss; ++s) { + for (int i = 0; i < relocs.n; ++i) { + struct reloc *rel = &relocs.p[i]; + if (rel->section != s) continue; + putreloc(out, rel, userela); + } + } + + /** Section Headers **/ + wordalign(out, align); +#define putshdr(...) if (targ_64bit) elf64putshdr(out, &(struct elf64shdr) { __VA_ARGS__ }); \ + else elf32putshdr(out, &(struct elf32shdr) { __VA_ARGS__ }); + /* §0 null section */ + putshdr(0); + /* §1 .text */ + putshdr(.name = shnam_text, .type = SHT_PROGBITS, + .flags = SHF_ALLOC | SHF_EXECINSTR, + .offset = targ_64bit ? hdr.h64.ehsize : hdr.h32.ehsize, .size = codesize, + .addralign = align); + /* §2 .rodata */ + putshdr(.name = shnam_rodata, .type = SHT_PROGBITS, + .flags = SHF_ALLOC, + .offset = rodataoff, .size = rodatasize, + .addralign = O.rodataalign,); + /* §3 .data */ + putshdr(.name = shnam_data, .type = SHT_PROGBITS, + .flags = SHF_ALLOC | SHF_WRITE, + .offset = dataoff, .size = datasize, + .addralign = O.dataalign,); + /* §4 .bss */ + putshdr(.name = shnam_bss, .type = SHT_NOBITS, + .size = bsssize, + .flags = SHF_ALLOC | SHF_WRITE, + .addralign = O.bssalign,); + /* §5 .shstrtab */ + putshdr(.name = shnam_shstrtab, .type = SHT_STRTAB, + .offset = shstrsoff, .size = shstrssize, + .flags = SHF_STRINGS ); + /* §6 .strtab */ + putshdr(.name = shnam_strtab, .type = SHT_STRTAB, + .offset = strsoff, .size = strssize, + .flags = SHF_STRINGS ); + /* §7 .symtab */ + putshdr(.name = shnam_symtab, .type = SHT_SYMTAB, + .offset = symtaboff, .size = symtabsize, + .flags = SHF_STRINGS, + .link = 6, /* .strtab */ + .info = nlocal, + .entsize = targ_64bit ? 24 : 16 ); + /* §8 .rel.text */ + putshdr(.name = shnam_reltext, .type = SHT_RELA, + .offset = reltextoff, .size = reltextsize, + .link = 7, /* .symtab */ + .entsize = relxsiz, + .info = TEXT_SHNDX ); + /* §9 .rel.rodata */ + putshdr(.name = shnam_relrodata, .type = SHT_RELA, + .offset = relrodataoff, .size = relrodatasize, + .link = 7, /* .symtab */ + .entsize = relxsiz, + .info = RODATA_SHNDX ); + /* §10 .rel.data */ + putshdr(.name = shnam_reldata, .type = SHT_RELA, + .offset = reldataoff, .size = reldatasize, + .link = 7, /* .symtab */ + .entsize = relxsiz, + .info = DATA_SHNDX ); +} + +/* vim:set ts=3 sw=3 expandtab: */ diff --git a/obj/elf.h b/obj/elf.h new file mode 100644 index 0000000..c96ae8b --- /dev/null +++ b/obj/elf.h @@ -0,0 +1,206 @@ +#include "../common.h" + +#define ELFMAG "\177ELF" +enum { + ELFCLASS32 = 1, + ELFCLASS64 = 2, + + ELFDATA2LSB = 1, + ELFDATA2MSB = 2, + + ELFVERSION = 1, + + ELFOSABI_SYSV = 0, + ELFOSABI_ARM = 97, + ELFOSABI_STANDALONE = 255, + + ET_NONE = 0, + ET_REL, ET_EXEC, ET_DYN, ET_CORE, + + EM_NONE = 0, + EM_386 = 3, + EM_486 = 6, + EM_MIPS = 8, + EM_MIPS_RS4_BE = 0xA, + EM_ARM = 0x28, + EM_X86_64 = 0x3E, + EM_ARM64 = 0xB7, +}; + +#define ELF_HDRIDENT \ + union { \ + uchar ident[16]; \ + struct { \ + uchar i_mag[4], \ + i_class, \ + i_data, \ + i_version, \ + i_osabi, \ + i_abiversion, \ + i_pad[7]; \ + }; \ + } + +struct elf64hdr { + ELF_HDRIDENT; + ushort type, + machine; + uint version; + uvlong entry, + phoff, + shoff; + uint flags; + ushort ehsize, + phentsize, + phnum, + shentsize, + shnum, + shstrndx; +}; +static_assert(sizeof(struct elf64hdr) == 64); + +struct elf32hdr { + ELF_HDRIDENT; + ushort type, + machine; + uint version; + uint entry, + phoff, + shoff; + uint flags; + ushort ehsize, + phentsize, + phnum, + shentsize, + shnum, + shstrndx; +}; +static_assert(sizeof(struct elf32hdr) == 52); + +enum { + SHT_NULL = 0x0, + SHT_PROGBITS = 0x1, + SHT_SYMTAB = 0x2, + SHT_STRTAB = 0x3, + SHT_RELA = 0x4, + SHT_HASH = 0x5, + SHT_DYNAMIC = 0x6, + SHT_NOTE = 0x7, + SHT_NOBITS = 0x8, + SHT_REL = 0x9, + SHT_SHLIB = 0xA, + SHT_DYNSYM = 0xB, + SHT_INIT_ARRAY = 0xE, + SHT_FINI_ARRAY = 0xF, + SHT_PREINIT_ARRAY = 0x10, + SHT_GROUP = 0x12, + SHT_SYMTAB_SHNDX = 0x13, +}; + +enum { + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_MERGE = 0x10, + SHF_STRINGS = 0x20, + SHF_INFO_LINK = 0x40, + SHF_LINK_ORDER = 0x80, + SHF_OS_NONCONFORMING = 0x100, + SHF_GROUP = 0x200, + SHF_TLS = 0x400, +}; + +struct elf64shdr { + uint name, + type; + uvlong flags, + addr, + offset, + size; + uint link, + info; + uvlong addralign, + entsize; +}; +static_assert(sizeof(struct elf64shdr) == 64); + +struct elf32shdr { + uint name, + type, + flags, + addr, + offset, + size, + link, + info, + addralign, + entsize; +}; +static_assert(sizeof(struct elf32shdr) == 40); + +enum { + STB_LOCAL, + STB_GLOBAL, + STB_WEAK +}; + +enum { + STT_NOTYPE, + STT_OBJECT, + STT_FUNC, + STT_SECTION, + STT_FILE, +}; + +enum { + SHN_UND = 0, + SHN_ABS = 0xFFF1, +}; + +#define ELF_S_INFO(b,t) ((b) << 4 | (t)) + +struct elf64sym { + uint name; + uchar info, + other; + ushort shndx; + uvlong value, + size; +}; +static_assert(sizeof(struct elf64sym) == 24); + +struct elf32sym { + uint name, + value, + size; + uchar info, + other; + ushort shndx; +}; +static_assert(sizeof(struct elf32sym) == 16); + +#define ELF64_R_INFO(s,t) ((uvlong) (s) << 32 | (uint)(t)) +struct elf64rel { + uvlong offset, info; +}; +static_assert(sizeof(struct elf64rel) == 16); + +#define ELF32_R_INFO(s,t) ((s) << 8 | (uchar)(t)) +struct elf32rel { + uint offset, info; +}; +static_assert(sizeof(struct elf32rel) == 8); + +struct elf64rela { + uvlong offset, info; + vlong addend; +}; +static_assert(sizeof(struct elf64rela) == 24); + +struct elf32rela { + uint offset, info; + int addend; +}; +static_assert(sizeof(struct elf32rela) == 12); + +/* vim:set ts=3 sw=3 expandtab: */ diff --git a/obj/obj.c b/obj/obj.c new file mode 100644 index 0000000..b9e2c79 --- /dev/null +++ b/obj/obj.c @@ -0,0 +1,105 @@ +#include "obj.h" +#include "../ir/ir.h" +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + + +void elfinit(void); +void elfaddsym(const char *, int info, enum section, uvlong value, uvlong size); +void elfreloc(const char *sym, enum relockind, enum section, uint off, vlong addend); +void elffini(struct wbuf *); + +struct objfile objout; + +enum { NTEXT = 4<<20 /* 4MiB */ }; + +void +objini(const char *infile, const char *outfile) +{ + assert(!objout.outfile); + objout.infile = infile; + objout.outfile = outfile; + objout.code = objout.textbegin = mapzeros(NTEXT); + objout.textend = objout.textbegin + NTEXT; + + switch (mctarg->objkind) { + case OBJELF: elfinit(); break; + } +} + +void +objdeffunc(const char *nam, bool globl, uint off, uint siz) +{ + switch (mctarg->objkind) { + case OBJELF: + elfaddsym(nam, /*STT_LOCAL/GLOBAL*/globl << 4 | /*STT_FUNC*/2, Stext, off, siz); + break; + } +} + +uint +objnewdat(const char *name, enum section sec, bool globl, uint siz, uint align) +{ + uint off; + + assert(siz && align && ispo2(align)); + + switch (sec) { + default: assert(0); + case Srodata: + if (align > objout.rodataalign) objout.rodataalign = align; + while (objout.rodata.n & (align - 1)) vpush(&objout.rodata, 0); + off = objout.rodata.n; + vresize(&objout.rodata, objout.rodata.n + siz); + memset(objout.rodata.p+off, 0, siz); + break; + case Sdata: + if (align > objout.dataalign) objout.dataalign = align; + while (objout.data.n & (align - 1)) vpush(&objout.data, 0); + off = objout.data.n; + vresize(&objout.data, objout.data.n + siz); + memset(objout.data.p+off, 0, siz); + break; + case Sbss: + if (align > objout.bssalign) objout.bssalign = align; + off = alignup(objout.nbss, align); + objout.nbss = off + siz; + break; + } + + switch (mctarg->objkind) { + case OBJELF: + elfaddsym(name, /*STT_LOCAL/GLOBAL*/globl<<4 | /*STT_OBJECT*/1, sec, off, siz); + break; + } + return off; +} + +void +objreloc(const char *sym, enum relockind reloc, enum section section, uint off, vlong addend) +{ + switch (mctarg->objkind) { + case OBJELF: + elfreloc(sym, reloc, section, off, addend); + break; + } +} + +void +objfini(void) +{ + static char buf[1<<12]; + struct wbuf out = FDBUF(buf, sizeof buf, open(objout.outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666)); + if (out.fd < 0) fatal(NULL, "could not open %'s for writing: %s", objout.outfile, strerror(errno)); + + switch (mctarg->objkind) { + case OBJELF: elffini(&out); break; + } + + munmap(objout.textbegin, NTEXT); + ioflush(&out); + close(out.fd); +} + +/* vim:set ts=3 sw=3 expandtab: */ diff --git a/obj/obj.h b/obj/obj.h new file mode 100644 index 0000000..235ab4d --- /dev/null +++ b/obj/obj.h @@ -0,0 +1,30 @@ +#include "../common.h" + +extern struct objfile { + const char *infile, *outfile; + uchar *textbegin, *textend; + uchar *code; + uchar dataalign, rodataalign, bssalign; + uint nbss; + vec_of(uchar) data, rodata; +} objout; + +enum relockind { + REL_ABS64, + REL_ABS32, + REL_ABS32S, + REL_PCREL32, + REL_PLT32, + REL_GOTPCRELX, + REL_GOTPCRELX_REX, + NRELOCKIND, +}; +enum section { Snone, Stext, Srodata, Sdata, Sbss }; + +void objini(const char *infile, const char *outfile); +void objdeffunc(const char *nam, bool globl, uint off, uint siz); +uint objnewdat(const char *name, enum section, bool globl, uint siz, uint align); +void objreloc(const char *sym, enum relockind, enum section, uint off, vlong addend); +void objfini(void); + +/* vim:set ts=3 sw=3 expandtab: */ |