diff options
| -rw-r--r-- | README.md | 25 | ||||
| -rw-r--r-- | main.c | 119 | ||||
| -rw-r--r-- | minias.h | 33 |
3 files changed, 177 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..e07bb93 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# minias + +An assembler for elf x86_64, written for fun and learning. + +Goals: + +- Assemble the output of [cproc](https://github.com/michaelforney/cproc)/[qbe](https://c9x.me/compile/). +- x86_64 elf output. +- Static linking. +- A simple, tiny, fast implementation (in that order). + +Stretch goals: + +- Assemble what is needed to compile musl libc. +- Dynamic linking. + +Non Goals: + +- Assemble every assembly instruction. +- Work as a library. + +# Resources + +- [goas](https://github.com/DQNEO/goas) +- [neatas](https://repo.or.cz/neatas.git)
\ No newline at end of file @@ -0,0 +1,119 @@ +#include "minias.h" + +typedef struct { + Elf64_Shdr hdr; + size_t capacity; + uint8_t *data; +} Section; + +#define MAXSECTIONS 32 +static Section sections[MAXSECTIONS]; +static size_t nsections = 0; + +static Section *strtab = NULL; +static Section *symtab = NULL; +static Section *textsec = NULL; + +void secappend(Section *s, uint8_t *bytes, size_t n) { + while (s->capacity < s->hdr.sh_size + n) { + s->capacity = s->capacity * 2; + s->data = xrealloc(s->data, s->capacity); + } + memcpy(s->data + s->hdr.sh_size, bytes, n); + s->hdr.sh_size += n; +} + +Elf64_Word elfstr(const char *s) { + Elf64_Word i; + for (i = 0; i < strtab->hdr.sh_size; i++) { + if (i == 0 || (strtab->data[i - 1] == 0)) + if (strcmp(s, (char *)&strtab->data[i]) == 0) + return i; + } + secappend(strtab, (uint8_t *)s, strlen(s) + 1); + return i; +} + +Section *newsection(const char *name) { + Section *s; + s = §ions[nsections++]; + if (nsections > MAXSECTIONS) + die("too many sections"); + s->hdr.sh_name = elfstr(name); + s->capacity = 16; + s->data = xmalloc(s->capacity); + return s; +} + +void initsections(void) { + /* Manually init string table */ + strtab = §ions[nsections++]; + strtab->hdr.sh_type = SHT_STRTAB; + strtab->capacity = 16; + strtab->data = xmalloc(strtab->capacity); + strtab->hdr.sh_name = elfstr(".strtab"); + strtab->hdr.sh_entsize = 1; + + symtab = newsection(".symtab"); + symtab->hdr.sh_type = SHT_SYMTAB; + symtab->hdr.sh_link = 1; + symtab->hdr.sh_entsize = sizeof(Elf64_Sym); + + textsec = newsection(".text"); + textsec->hdr.sh_type = SHT_PROGBITS; + textsec->hdr.sh_flags = SHF_EXECINSTR | SHF_ALLOC; + textsec->hdr.sh_entsize = 1; +} + +void out(uint8_t *buf, size_t n) { + if (write(STDOUT_FILENO, buf, n) != n) + die("io error"); +} + +void outelf(void) { + size_t i; + uint64_t offset = 0; + Elf64_Ehdr ehdr = {0}; + + ehdr.e_ident[0] = 0x7f; + ehdr.e_ident[1] = 'E'; + ehdr.e_ident[2] = 'L'; + ehdr.e_ident[3] = 'F'; + ehdr.e_ident[4] = ELFCLASS64; + ehdr.e_ident[5] = ELFDATA2LSB; + ehdr.e_ident[6] = 1; + ehdr.e_type = ET_REL; + ehdr.e_machine = EM_X86_64; + ehdr.e_flags = 0; + ehdr.e_version = 1; + ehdr.e_ehsize = sizeof(Elf64_Ehdr); + ehdr.e_shentsize = sizeof(Elf64_Shdr); + ehdr.e_shoff = sizeof(Elf64_Ehdr); + ehdr.e_shnum = nsections; + ehdr.e_shstrndx = 1; + offset = sizeof(Elf64_Shdr) * nsections; + /* + textsec->shdr.sh_offset = offset; + textsec->shdr.sh_size = 0; + offset += textsec->shdr.sh_size * textsec->shdr.sh_entsize; + symstrsec->shdr.sh_size = 0; + symstrsec->shdr.sh_offset = offset; + offset += symstrsec->shdr.sh_size * symstrsec->shdr.sh_entsize; + */ + + out((uint8_t *)&ehdr, sizeof(ehdr)); + for (i = 0; i < nsections; i++) { + sections[i].hdr.sh_offset = offset; + out((uint8_t *)§ions[i].hdr, sizeof(Elf64_Shdr)); + offset += sections[i].hdr.sh_size; + } + for (i = 0; i < nsections; i++) { + out(sections[i].data, sections[i].hdr.sh_size); + } +} + +int main() { + initsections(); + outelf(); + return 0; +}
\ No newline at end of file diff --git a/minias.h b/minias.h new file mode 100644 index 0000000..f694f79 --- /dev/null +++ b/minias.h @@ -0,0 +1,33 @@ +#include <elf.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void die(char *s) { + write(STDERR_FILENO, s, strlen(s)); + exit(1); +} + +static void *xcalloc(size_t nmemb, size_t n) { + void *p; + p = calloc(nmemb, n); + if (!p) + die("out of memory"); + return p; +} + +static void *xmalloc(size_t n) { + void *p; + p = malloc(n); + if (!p) + die("out of memory"); + return p; +} + +static void *xrealloc(void *p, size_t n) { + p = realloc(p, n); + if (!p) + die("out of memory"); + return p; +}
\ No newline at end of file |
