mcc
mcc is a machine code compiler.
Log | Files | << Repositories
tree e51c4b1e9ff6e1f200546348f4ddebaa07c693a1 parent fab3a56d9021c1f6a5e45f72a2d5c9bfeff5fbba author esote <esote.net@gmail.com> 1558146334 -0500 committer esote <esote.net@gmail.com> 1558146334 -0500 gpgsig -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQTXAxYDuIzimYoNSPuhTmRAjzzC8gUCXSArHQAKCRChTmRAjzzC 8tsBAQD+//h/1r46DUImzZK12cywQlxIcdidxq6FymDKvdAXkwEA7TrrWA2arxYA w+Nxm+bncyZoZmdK6gPhxmpPB6hCnQ8= =PuRW -----END PGP SIGNATURE----- Produce both 32 and 64-bit executables Properly read memsize. Use options structure to keep track of useful values. Cast to avoid superfluous warnings with debug.
Makefile | 16 ++- README | 15 ++- hello_i386.mcc | 2 +- hello_x86_64.mcc | 19 ++++ mcc.c | 302 ++++++++++++------------------------------------------- mcc.h | 38 +++++++ write.h | 24 +++++ write_32.c | 172 +++++++++++++++++++++++++++++++ write_64.c | 172 +++++++++++++++++++++++++++++++ 9 files changed, 514 insertions(+), 246 deletions(-)
diff --git a/Makefile b/Makefile index 8ef55fe..f97cf54 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,14 @@ -mcc: mcc.c - gcc -O2 -o mcc.out mcc.c +PROG= mcc +SRCS= mcc.c write_32.c write_64.c -debug: mcc.c - gcc -g -Wall -Wextra -Wconversion -o mcc.out mcc.c +CFLAGS= -O2 -fstack-protector -D_FORTIFY_SOURCE=2 -pie -fPIE +LDFLAGS= -Wl,-z,now -Wl,-z,relro + +$(PROG): $(SRCS) + gcc $(CFLAGS) $(LDFLAGS) -o $(PROG).out $(SRCS) + +debug: $(SRCS) + gcc -g -Wall -Wextra -Wconversion -o $(PROG).out $(SRCS) clean: - rm -f mcc.out + rm -f $(PROG).out diff --git a/README b/README index 9c23cea..53feb23 100644 --- a/README +++ b/README @@ -1,10 +1,15 @@ -Reads machine code text and produces i386 ELF executables. +Reads machine code text and produces x86-64 or i386 Linux-compatible ELF +executables. Accepts ASCII text '0' and '1'. All other characters are ignored except the comment token ';'. Comments begin with ';' and continue until EOL. -Only uses the .bss and .text sections, starting at 0x804a000 and 0x8049000 -respectively. Page size is set to 0x1000 (4096). .bss is aligned to a 16-byte -constraint and .text to an 8-byte constraint. +Programmer's manual: + In 64-bit mode .bss and .text start at 0x402000 and 0x401000 + respectively, and in 32-bit mode 0x804a000 and 0x8049000 respectively. -Currently may only work with the Linux kernel. + Program header segment alignment is set to 0x1000 (page size on most + systems). + + .bss is aligned to a 16-byte constraint and .text to an 8-byte + constraint. diff --git a/hello_i386.mcc b/hello_i386.mcc index a52a3cb..3ef0251 100644 --- a/hello_i386.mcc +++ b/hello_i386.mcc @@ -1,6 +1,6 @@ ; MCC -; Compile with ./mcc.out -m 7 hello_i386.mcc +; Compile with ./mcc.out -3 -m 7 hello_i386.mcc 11000111 00000101 00000000 10100000 00000100 00001000 01001000 00000000 00000000 00000000 ; mov DWORD [buffer + 0], 'H' ; buffer is 0x804a000 11000111 00000101 00000001 10100000 00000100 00001000 01100101 00000000 00000000 00000000 ; mov DWORD [buffer + 1], 'e' diff --git a/hello_x86_64.mcc b/hello_x86_64.mcc new file mode 100644 index 0000000..d1ac7f8 --- /dev/null +++ b/hello_x86_64.mcc @@ -0,0 +1,19 @@ +; MCC + +; Compile with ./mcc.out -m 7 hello_x86_64.mcc + +11000111 00000100 00100101 00000000 00100000 01000000 00000000 01001000 00000000 00000000 00000000 ; mov DWORD [buffer + 0], 'H' ; buffer is 0x402000 +11000111 00000100 00100101 00000001 00100000 01000000 00000000 01100101 00000000 00000000 00000000 ; mov DWORD [buffer + 1], 'e' +11000111 00000100 00100101 00000010 00100000 01000000 00000000 01101100 00000000 00000000 00000000 ; mov DWORD [buffer + 2], 'l' +11000111 00000100 00100101 00000011 00100000 01000000 00000000 01101100 00000000 00000000 00000000 ; mov DWORD [buffer + 3], 'l' +11000111 00000100 00100101 00000100 00100000 01000000 00000000 01101111 00000000 00000000 00000000 ; mov DWORD [buffer + 4], 'o' +11000111 00000100 00100101 00000101 00100000 01000000 00000000 00100001 00000000 00000000 00000000 ; mov DWORD [buffer + 5], '!' +11000111 00000100 00100101 00000110 00100000 01000000 00000000 00001010 00000000 00000000 00000000 ; mov DWORD [buffer + 6], 0xA +01001000 10111000 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ; mov rax, 1 ; sys_write +01001000 10111111 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ; mov rdi, 1 ; stdout +01001000 10111110 00000000 00100000 01000000 00000000 00000000 00000000 00000000 00000000 ; mov rsi, buffer +01001000 10111010 00000111 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ; mov rdx, 0x7 ; buffer size +00001111 00000101 ; syscall +01001000 10111000 00111100 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ; mov rax, 60 ; sys_exit +01001000 10111111 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ; mov rdi, 0 ; exit success +00001111 00000101 ; syscall diff --git a/mcc.c b/mcc.c index 3945d59..b1883d8 100644 --- a/mcc.c +++ b/mcc.c @@ -18,86 +18,72 @@ #include <sys/stat.h> -#include <elf.h> #include <err.h> +#include <errno.h> #include <getopt.h> -#include <stddef.h> +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -uint32_t byte_len(FILE *const); +#include "mcc.h" +#include "write.h" -uint32_t write_elf_hdr(FILE *const, uint32_t const); - -void write_text_hdr(FILE *const, uint32_t const, uint32_t const, int const); -void write_bss_hdr(FILE *const, uint32_t const); - -void write_mcode(FILE *const, FILE *const); - -void write_section_names(FILE *const); - -void write_null_section(FILE *const); -void write_text_section(FILE *const, uint32_t const, uint32_t const); -void write_bss_section(FILE *const, uint32_t const); -void write_shstrtab_section(FILE *const, uint32_t const, uint32_t const); - -#define BSS_VADDR 0x804a000 -#define TEXT_VADDR 0x8049000 - -/* length of section header string including null terminator */ -#define NULL_LEN (0 + 1) -#define SHSTRTAB_LEN (9 + 1) -#define TEXT_LEN (5 + 1) -#define BSS_LEN (4 + 1) - -#define SHSTRTAB_ADDRALIGN (1 << 0) -#define BSS_ADDRALIGN (1 << 2) -#define TEXT_ADDRALIGN (1 << 4) - -/* index in section header string table section */ -#define SHSTRTAB_INDEX 1 -#define TEXT_INDEX (SHSTRTAB_LEN + 1) -#define BSS_INDEX (SHSTRTAB_LEN + TEXT_LEN+1) - -#define PAGE_SIZE 4096 +uint64_t byte_len(FILE *const); +void write_mcode(FILE *const, FILE *const); +void write_section_names(FILE *const); #define COMMENT ';' -static unsigned char const zero = 0; - int main(int argc, char *argv[]) { FILE *in; FILE *out; + struct mcc_opts opts; + char *end; char *iname; char const *oname; - uint32_t len; - uint32_t mem; - uint32_t off; + uint64_t mem; + int use_64; int ch; - int self_m; + + opts.self_m = 0; oname = "a.out"; mem = 0; - self_m = 0; - while ((ch = getopt(argc, argv, "m:o:s")) != -1) { + /* default 64-bit */ + use_64 = 1; + opts.bss_vaddr.n64 = 0x402000; + opts.text_vaddr.n64 = 0x401000; + + while ((ch = getopt(argc, argv, "3m:o:s")) != -1) { switch (ch) { + case '3': + use_64 = 0; + opts.bss_vaddr.n32 = 0x804a000; + opts.text_vaddr.n32 = 0x8049000; + break; case 'm': /* TODO remove BSS section if mem == 0 */ - mem = atoi(optarg); + mem = strtoull(optarg, &end, 10); + + if (errno == EINVAL || errno == ERANGE) { + err(1, "memsize invalid"); + } else if (optarg == end) { + errx(1, "no memsize read"); + } + break; case 'o': oname = optarg; break; case 's': - self_m = 1; + opts.self_m = 1; break; default: (void)fprintf(stderr, - "usage: %s [-s] [-m memsize] [-o file] " + "usage: %s [-3s] [-m memsize] [-o file] " "[file]\n", argv[0]); return 1; @@ -105,8 +91,10 @@ main(int argc, char *argv[]) } if (mem == 0) { - warnx("mem is 0, using .bss could segfault or overflow into " - "other sections"); + warnx("memsize is 0, using .bss could segfault or overflow " + "into other sections"); + } else if (!use_64 && mem > UINT32_MAX) { + warnx("memsize may overflow"); } argv += optind; @@ -123,21 +111,34 @@ main(int argc, char *argv[]) err(1, "open out"); } - len = byte_len(in); - - off = write_elf_hdr(out, len); - - write_text_hdr(out, off, len, self_m); - write_bss_hdr(out, mem); + if (use_64) { + opts.mem.n64 = mem; + opts.len.n64 = byte_len(in); + write_ehdr64(out, &opts); + write_phdr64_text(out, &opts); + write_phdr64_bss(out, &opts); + } else { + opts.mem.n32 = (uint32_t)mem; + opts.len.n32 = (uint32_t)byte_len(in); + write_ehdr32(out, &opts); + write_phdr32_text(out, &opts); + write_phdr32_bss(out, &opts); + } write_mcode(in, out); - write_section_names(out); - write_null_section(out); - write_text_section(out, off, len); - write_bss_section(out, mem); - write_shstrtab_section(out, off, len); + if (use_64) { + write_shdr64_null(out); + write_shdr64_text(out, &opts); + write_shdr64_bss(out, &opts); + write_shdr64_shstrtab(out, &opts); + } else { + write_shdr32_null(out); + write_shdr32_text(out, &opts); + write_shdr32_bss(out, &opts); + write_shdr32_shstrtab(out, &opts); + } if (fclose(in) == EOF) { err(1, "close in"); @@ -154,11 +155,11 @@ main(int argc, char *argv[]) return 0; } -uint32_t +uint64_t byte_len(FILE *const in) { unsigned char buf; - uint32_t len; + uint64_t len; len = 0; @@ -193,103 +194,10 @@ out: return len / 8; } -uint32_t -write_elf_hdr(FILE *const out, uint32_t const len) -{ - Elf32_Ehdr e = {0}; - - e.e_ident[EI_MAG0] = ELFMAG0; - e.e_ident[EI_MAG1] = ELFMAG1; - e.e_ident[EI_MAG2] = ELFMAG2; - e.e_ident[EI_MAG3] = ELFMAG3; - /* TODO support 64-bit */ - e.e_ident[EI_CLASS] = ELFCLASS32; - /* TODO support big endian */ - e.e_ident[EI_DATA] = ELFDATA2LSB; - e.e_ident[EI_VERSION] = EV_CURRENT; - /* TODO support other ABIs */ - e.e_ident[EI_OSABI] = ELFOSABI_SYSV; - e.e_ident[EI_ABIVERSION] = 0; - /* TODO support writing other object file types */ - e.e_type = ET_EXEC; - /* TODO support other architectures */ - e.e_machine = EM_386; - e.e_version = EV_CURRENT; - e.e_flags = 0; - - e.e_ehsize = sizeof(Elf32_Ehdr); - e.e_phentsize = sizeof(Elf32_Phdr); - e.e_shentsize = sizeof(Elf32_Shdr); - - e.e_phnum = 2; - e.e_shnum = 4; - e.e_shstrndx = 3; - - /* program hdrs start after elf hdr */ - e.e_phoff = e.e_ehsize; - - e.e_entry = TEXT_VADDR + e.e_ehsize + e.e_phnum * e.e_phentsize; - - /* section hdrs start after elf hdr, program hdrs, text, and shstrtab */ - e.e_shoff = e.e_ehsize + e.e_phnum * e.e_phentsize + len + - NULL_LEN + SHSTRTAB_LEN + TEXT_LEN + BSS_LEN; - - if (fwrite(&e, sizeof(Elf32_Ehdr), 1, out) != 1) { - err(1, "write elf hdr"); - } - - /* return offset to mcode */ - return e.e_ehsize + e.e_phnum * e.e_phentsize; -} - -void -write_text_hdr(FILE *const out, uint32_t const off, uint32_t const len, - int const self_m) -{ - Elf32_Phdr text = {0}; - - text.p_type = PT_LOAD; - text.p_offset = 0; - text.p_vaddr = TEXT_VADDR; - text.p_paddr = text.p_vaddr; - text.p_filesz = len + off; - text.p_memsz = text.p_filesz; - text.p_flags = PF_X | PF_R; - - if (self_m) { - text.p_flags |= PF_W; - } - - text.p_align = PAGE_SIZE; - - if (fwrite(&text, sizeof(Elf32_Phdr), 1, out) != 1) { - err(1, "write text hdr"); - } -} - -void -write_bss_hdr(FILE *const out, uint32_t const mem) -{ - Elf32_Phdr bss = {0}; - - bss.p_type = PT_LOAD; - bss.p_offset = 0; - bss.p_vaddr = BSS_VADDR; - bss.p_paddr = bss.p_vaddr; - bss.p_filesz = 0; - bss.p_memsz = mem; - bss.p_flags = PF_R | PF_W; - bss.p_align = PAGE_SIZE; - - if (fwrite(&bss, sizeof(Elf32_Phdr), 1, out) != 1) { - err(1, "write bss hdr"); - } -} - void write_mcode(FILE *const in, FILE *const out) { - uint32_t i; + uint64_t i; unsigned char buf; unsigned char cur; @@ -309,7 +217,7 @@ write_mcode(FILE *const in, FILE *const out) break; case '0': case '1': - cur |= (buf - '0') << --i; + cur = (unsigned char)(cur | (buf - '0') << --i); if (i == 0) { if (fwrite(&cur, 1, 1, out) != 1) { @@ -330,6 +238,7 @@ write_section_names(FILE *const out) static char const *const shstrtab = ".shstrtab"; static char const *const text = ".text"; static char const *const bss = ".bss"; + static unsigned char const zero = 0; /* null section name */ if (fwrite(&zero, NULL_LEN, 1, out) != 1) { @@ -348,80 +257,3 @@ write_section_names(FILE *const out) err(1, "write bss name"); } } - -void -write_null_section(FILE *const out) -{ - Elf32_Shdr null = {0}; - - null.sh_name = SHT_NULL; - - if (fwrite(&null, sizeof(Elf32_Shdr), 1, out) != 1) { - err(1, "write null section"); - } -} - -void -write_text_section(FILE *const out, uint32_t const off, uint32_t const len) -{ - Elf32_Shdr text = {0}; - - text.sh_name = TEXT_INDEX; - text.sh_type = SHT_PROGBITS; - text.sh_flags = SHF_ALLOC | SHF_EXECINSTR; - text.sh_addr = TEXT_VADDR + off; - text.sh_offset = off; - text.sh_size = len; - text.sh_link = 0; - text.sh_info = 0; - text.sh_addralign = TEXT_ADDRALIGN; - text.sh_entsize = 0; - - if (fwrite(&text, sizeof(Elf32_Shdr), 1, out) != 1) { - err(1, "write text section"); - } -} - -void -write_bss_section(FILE *const out, uint32_t const mem) -{ - Elf32_Shdr bss = {0}; - - bss.sh_name = BSS_INDEX; - bss.sh_type = SHT_NOBITS; - bss.sh_flags = SHF_WRITE | SHF_ALLOC; - bss.sh_addr = BSS_VADDR; - /* TODO magic */ - bss.sh_offset = 0x1000; - bss.sh_size = mem; - bss.sh_link = 0; - bss.sh_info = 0; - bss.sh_addralign = BSS_ADDRALIGN; - bss.sh_entsize = 0; - - if (fwrite(&bss, sizeof(Elf32_Shdr), 1, out) != 1) { - err(1, "write bss section"); - } -} - -void -write_shstrtab_section(FILE *const out, uint32_t const off, uint32_t const len) -{ - Elf32_Shdr shstrtab = {0}; - - shstrtab.sh_name = SHSTRTAB_INDEX; - shstrtab.sh_type = SHT_STRTAB; - shstrtab.sh_flags = 0; - shstrtab.sh_addr = 0; - /* TODO magic */ - shstrtab.sh_offset = off + len; - shstrtab.sh_size = NULL_LEN + SHSTRTAB_LEN + TEXT_LEN + BSS_LEN; - shstrtab.sh_link = 0; - shstrtab.sh_info = 0; - shstrtab.sh_addralign = SHSTRTAB_ADDRALIGN; - shstrtab.sh_entsize = 0; - - if (fwrite(&shstrtab, sizeof(Elf32_Shdr), 1, out) != 1) { - err(1, "write shstrtab section"); - } -} diff --git a/mcc.h b/mcc.h new file mode 100644 index 0000000..ec02db8 --- /dev/null +++ b/mcc.h @@ -0,0 +1,38 @@ +#ifndef MCC_H +#define MCC_H + +union size { + uint32_t n32; + uint64_t n64; +}; + +struct mcc_opts { + union size bss_vaddr; + union size text_vaddr; + + union size len; + union size off; + + union size mem; + + int self_m; +}; + +#define PAGE_SIZE 4096 + +#define SHSTRTAB_ADDRALIGN (1 << 0) +#define BSS_ADDRALIGN (1 << 2) +#define TEXT_ADDRALIGN (1 << 4) + +/* length of section header string including null terminator */ +#define NULL_LEN (0 + 1) +#define SHSTRTAB_LEN (9 + 1) +#define TEXT_LEN (5 + 1) +#define BSS_LEN (4 + 1) + +/* index in section header string table section */ +#define SHSTRTAB_INDEX 1 +#define TEXT_INDEX (SHSTRTAB_LEN + 1) +#define BSS_INDEX (SHSTRTAB_LEN + TEXT_LEN+1) + +#endif /* MCC_H */ diff --git a/write.h b/write.h new file mode 100644 index 0000000..2f8e720 --- /dev/null +++ b/write.h @@ -0,0 +1,24 @@ +#ifndef WRITE_H +#define WRITE_H + +void write_ehdr64(FILE *const, struct mcc_opts *const); + +void write_phdr64_text(FILE *const, struct mcc_opts const *const); +void write_phdr64_bss(FILE *const, struct mcc_opts const *const); + +void write_shdr64_null(FILE *const); +void write_shdr64_text(FILE *const, struct mcc_opts const *const); +void write_shdr64_bss(FILE *const, struct mcc_opts const *const); +void write_shdr64_shstrtab(FILE *const, struct mcc_opts const *const); + +void write_ehdr32(FILE *const, struct mcc_opts *const); + +void write_phdr32_text(FILE *const, struct mcc_opts const *const); +void write_phdr32_bss(FILE *const, struct mcc_opts const *const); + +void write_shdr32_null(FILE *const); +void write_shdr32_text(FILE *const, struct mcc_opts const *const); +void write_shdr32_bss(FILE *const, struct mcc_opts const *const); +void write_shdr32_shstrtab(FILE *const, struct mcc_opts const *const); + +#endif /* WRITE_H */ diff --git a/write_32.c b/write_32.c new file mode 100644 index 0000000..412996e --- /dev/null +++ b/write_32.c @@ -0,0 +1,172 @@ +#include <elf.h> +#include <err.h> +#include <stdint.h> +#include <stdio.h> + +#include "mcc.h" + +void +write_ehdr32(FILE *const out, struct mcc_opts *const opts) +{ + Elf32_Ehdr e = {0}; + + e.e_ident[EI_MAG0] = ELFMAG0; + e.e_ident[EI_MAG1] = ELFMAG1; + e.e_ident[EI_MAG2] = ELFMAG2; + e.e_ident[EI_MAG3] = ELFMAG3; + e.e_ident[EI_CLASS] = ELFCLASS32; + /* TODO support big endian */ + e.e_ident[EI_DATA] = ELFDATA2LSB; + e.e_ident[EI_VERSION] = EV_CURRENT; + /* TODO support other ABIs */ + e.e_ident[EI_OSABI] = ELFOSABI_SYSV; + e.e_ident[EI_ABIVERSION] = 0; + /* TODO support writing other object file types */ + e.e_type = ET_EXEC; + /* TODO support other architectures */ + e.e_machine = EM_386; + e.e_version = EV_CURRENT; + e.e_flags = 0; + + e.e_ehsize = sizeof(Elf32_Ehdr); + e.e_phentsize = sizeof(Elf32_Phdr); + e.e_shentsize = sizeof(Elf32_Shdr); + + e.e_phnum = 2; + e.e_shnum = 4; + e.e_shstrndx = 3; + + /* program hdrs start after elf hdr */ + e.e_phoff = e.e_ehsize; + + opts->off.n32 = (uint32_t)(e.e_ehsize + e.e_phnum * e.e_phentsize); + + e.e_entry = opts->text_vaddr.n32 + opts->off.n32; + + /* section hdrs start after elf hdr, program hdrs, text, and shstrtab */ + e.e_shoff = opts->off.n32 + opts->len.n32 + NULL_LEN + SHSTRTAB_LEN + + TEXT_LEN + BSS_LEN; + + if (fwrite(&e, sizeof(Elf32_Ehdr), 1, out) != 1) { + err(1, "write ehdr32"); + } +} + +void +write_phdr32_text(FILE *const out, struct mcc_opts const *const opts) +{ + Elf32_Phdr text = {0}; + + text.p_type = PT_LOAD; + text.p_offset = 0; + text.p_vaddr = opts->text_vaddr.n32; + text.p_paddr = text.p_vaddr; + text.p_filesz = opts->len.n32 + opts->off.n32; + text.p_memsz = text.p_filesz; + text.p_flags = PF_X | PF_R; + + if (opts->self_m) { + text.p_flags |= PF_W; + } + + text.p_align = PAGE_SIZE; + + if (fwrite(&text, sizeof(Elf32_Phdr), 1, out) != 1) { + err(1, "write phdr32 text"); + } +} + +void +write_phdr32_bss(FILE *const out, struct mcc_opts const *const opts) +{ + Elf32_Phdr bss = {0}; + + bss.p_type = PT_LOAD; + bss.p_offset = 0; + bss.p_vaddr = opts->bss_vaddr.n32; + bss.p_paddr = bss.p_vaddr; + bss.p_filesz = 0; + bss.p_memsz = opts->mem.n32; + bss.p_flags = PF_R | PF_W; + bss.p_align = PAGE_SIZE; + + if (fwrite(&bss, sizeof(Elf32_Phdr), 1, out) != 1) { + err(1, "write phdr32 bss"); + } +} + +void +write_shdr32_null(FILE *const out) +{ + Elf32_Shdr null = {0}; + + null.sh_name = SHT_NULL; + + if (fwrite(&null, sizeof(Elf32_Shdr), 1, out) != 1) { + err(1, "write shdr32 null"); + } +} + +void +write_shdr32_text(FILE *const out, struct mcc_opts const *const opts) +{ + Elf32_Shdr text = {0}; + + text.sh_name = TEXT_INDEX; + text.sh_type = SHT_PROGBITS; + text.sh_flags = SHF_ALLOC | SHF_EXECINSTR; + text.sh_addr = opts->text_vaddr.n32 + opts->off.n32; + text.sh_offset = opts->off.n32; + text.sh_size = opts->len.n32; + text.sh_link = 0; + text.sh_info = 0; + text.sh_addralign = TEXT_ADDRALIGN; + text.sh_entsize = 0; + + if (fwrite(&text, sizeof(Elf32_Shdr), 1, out) != 1) { + err(1, "write shdr32 text"); + } +} + +void +write_shdr32_bss(FILE *const out, struct mcc_opts const *const opts) +{ + Elf32_Shdr bss = {0}; + + bss.sh_name = BSS_INDEX; + bss.sh_type = SHT_NOBITS; + bss.sh_flags = SHF_WRITE | SHF_ALLOC; + bss.sh_addr = opts->bss_vaddr.n32; + /* TODO magic */ + bss.sh_offset = 0x1000; + bss.sh_size = opts->mem.n32; + bss.sh_link = 0; + bss.sh_info = 0; + bss.sh_addralign = BSS_ADDRALIGN; + bss.sh_entsize = 0; + + if (fwrite(&bss, sizeof(Elf32_Shdr), 1, out) != 1) { + err(1, "write shdr32 bss"); + } +} + +void +write_shdr32_shstrtab(FILE *const out, struct mcc_opts const *const opts) +{ + Elf32_Shdr shstrtab = {0}; + + shstrtab.sh_name = SHSTRTAB_INDEX; + shstrtab.sh_type = SHT_STRTAB; + shstrtab.sh_flags = 0; + shstrtab.sh_addr = 0; + shstrtab.sh_offset = opts->off.n32 + opts->len.n32; + shstrtab.sh_size = NULL_LEN + SHSTRTAB_LEN + TEXT_LEN + BSS_LEN; + shstrtab.sh_link = 0; + shstrtab.sh_info = 0; + shstrtab.sh_addralign = SHSTRTAB_ADDRALIGN; + shstrtab.sh_entsize = 0; + + if (fwrite(&shstrtab, sizeof(Elf32_Shdr), 1, out) != 1) { + err(1, "write shdr32 shstrtab"); + } +} diff --git a/write_64.c b/write_64.c new file mode 100644 index 0000000..88a6157 --- /dev/null +++ b/write_64.c @@ -0,0 +1,172 @@ +#include <elf.h> +#include <err.h> +#include <stdint.h> +#include <stdio.h> + +#include "mcc.h" + +void +write_ehdr64(FILE *const out, struct mcc_opts *const opts) +{ + Elf64_Ehdr e = {0}; + + e.e_ident[EI_MAG0] = ELFMAG0; + e.e_ident[EI_MAG1] = ELFMAG1; + e.e_ident[EI_MAG2] = ELFMAG2; + e.e_ident[EI_MAG3] = ELFMAG3; + e.e_ident[EI_CLASS] = ELFCLASS64; + /* TODO support big endian */ + e.e_ident[EI_DATA] = ELFDATA2LSB; + e.e_ident[EI_VERSION] = EV_CURRENT; + /* TODO support other ABIs */ + e.e_ident[EI_OSABI] = ELFOSABI_SYSV; + e.e_ident[EI_ABIVERSION] = 0; + /* TODO support writing other object file types */ + e.e_type = ET_EXEC; + /* TODO support other architectures */ + e.e_machine = EM_X86_64; + e.e_version = EV_CURRENT; + e.e_flags = 0; + + e.e_ehsize = sizeof(Elf64_Ehdr); + e.e_phentsize = sizeof(Elf64_Phdr); + e.e_shentsize = sizeof(Elf64_Shdr); + + e.e_phnum = 2; + e.e_shnum = 4; + e.e_shstrndx = 3; + + /* program hdrs start after elf hdr */ + e.e_phoff = e.e_ehsize; + + opts->off.n64 = (uint64_t)(e.e_ehsize + e.e_phnum * e.e_phentsize); + + e.e_entry = opts->text_vaddr.n64 + opts->off.n64; + + /* section hdrs start after elf hdr, program hdrs, text, and shstrtab */ + e.e_shoff = opts->off.n64 + opts->len.n64 + NULL_LEN + SHSTRTAB_LEN + + TEXT_LEN + BSS_LEN; + + if (fwrite(&e, sizeof(Elf64_Ehdr), 1, out) != 1) { + err(1, "write ehdr64"); + } +} + +void +write_phdr64_text(FILE *const out, struct mcc_opts const *const opts) +{ + Elf64_Phdr text = {0}; + + text.p_type = PT_LOAD; + text.p_offset = 0; + text.p_vaddr = opts->text_vaddr.n64; + text.p_paddr = text.p_vaddr; + text.p_filesz = opts->len.n64 + opts->off.n64; + text.p_memsz = text.p_filesz; + text.p_flags = PF_X | PF_R; + + if (opts->self_m) { + text.p_flags |= PF_W; + } + + text.p_align = PAGE_SIZE; + + if (fwrite(&text, sizeof(Elf64_Phdr), 1, out) != 1) { + err(1, "write phdr64 text"); + } +} + +void +write_phdr64_bss(FILE *const out, struct mcc_opts const *const opts) +{ + Elf64_Phdr bss = {0}; + + bss.p_type = PT_LOAD; + bss.p_offset = 0; + bss.p_vaddr = opts->bss_vaddr.n64; + bss.p_paddr = bss.p_vaddr; + bss.p_filesz = 0; + bss.p_memsz = opts->mem.n64; + bss.p_flags = PF_R | PF_W; + bss.p_align = PAGE_SIZE; + + if (fwrite(&bss, sizeof(Elf64_Phdr), 1, out) != 1) { + err(1, "write phdr64 bss"); + } +} + +void +write_shdr64_null(FILE *const out) +{ + Elf64_Shdr null = {0}; + + null.sh_name = SHT_NULL; + + if (fwrite(&null, sizeof(Elf64_Shdr), 1, out) != 1) { + err(1, "write shdr64 null"); + } +} + +void +write_shdr64_text(FILE *const out, struct mcc_opts const *const opts) +{ + Elf64_Shdr text = {0}; + + text.sh_name = TEXT_INDEX; + text.sh_type = SHT_PROGBITS; + text.sh_flags = SHF_ALLOC | SHF_EXECINSTR; + text.sh_addr = opts->text_vaddr.n64 + opts->off.n64; + text.sh_offset = opts->off.n64; + text.sh_size = opts->len.n64; + text.sh_link = 0; + text.sh_info = 0; + text.sh_addralign = TEXT_ADDRALIGN; + text.sh_entsize = 0; + + if (fwrite(&text, sizeof(Elf64_Shdr), 1, out) != 1) { + err(1, "write shdr64 text"); + } +} + +void +write_shdr64_bss(FILE *const out, struct mcc_opts const *const opts) +{ + Elf64_Shdr bss = {0}; + + bss.sh_name = BSS_INDEX; + bss.sh_type = SHT_NOBITS; + bss.sh_flags = SHF_WRITE | SHF_ALLOC; + bss.sh_addr = opts->bss_vaddr.n64; + /* TODO magic */ + bss.sh_offset = 0x1000; + bss.sh_size = opts->mem.n64; + bss.sh_link = 0; + bss.sh_info = 0; + bss.sh_addralign = BSS_ADDRALIGN; + bss.sh_entsize = 0; + + if (fwrite(&bss, sizeof(Elf64_Shdr), 1, out) != 1) { + err(1, "write shdr64 bss"); + } +} + +void +write_shdr64_shstrtab(FILE *const out, struct mcc_opts const *const opts) +{ + Elf64_Shdr shstrtab = {0}; + + shstrtab.sh_name = SHSTRTAB_INDEX; + shstrtab.sh_type = SHT_STRTAB; + shstrtab.sh_flags = 0; + shstrtab.sh_addr = 0; + shstrtab.sh_offset = opts->off.n64 + opts->len.n64; + shstrtab.sh_size = NULL_LEN + SHSTRTAB_LEN + TEXT_LEN + BSS_LEN; + shstrtab.sh_link = 0; + shstrtab.sh_info = 0; + shstrtab.sh_addralign = SHSTRTAB_ADDRALIGN; + shstrtab.sh_entsize = 0; + + if (fwrite(&shstrtab, sizeof(Elf64_Shdr), 1, out) != 1) { + err(1, "write shdr64 shstrtab"); + } +}