#include #include #include #include #include #include #include #include #include "io.h" #include "ir.h" #include "lex.h" #define ELF_HEADER_SIZE 0xb0 size_t compile(void) { var argc, argv, env; init(&argc, &argv, &env); var a = lit(52); var b = lit(10); var exit_code = sub(a, b); var sys_exit = lit(60); var args[2] = { sys_exit, exit_code }; syscall(2, args); return ELF_HEADER_SIZE; } static void write_elf(uint64_t entry_point) { uint64_t file_len = here; // Hardcoded ELF header for statically-linked position-independent executable. // Since we only support Linux amd64 static PIE, there's no need to abstract over this for now. uint8_t elf_header[ELF_HEADER_SIZE] = { // ELF header 0x7F, 'E', 'L', 'F', // ELF magic 2, 1, 1, 3, 0, // 64-bit little-endian Linux, ELF version 1 0, 0, 0, 0, 0, 0, 0, // padding 3, 0, 0x3E, 0, 1, 0, 0, 0, // dynamic executable, amd64, ELF version 1 again 0, 0, 0, 0, 0, 0, 0, 0, // PATCHME: entry point address 0x40, 0, 0, 0, 0, 0, 0, 0, // program header table offset (immediately after ELF) 0, 0, 0, 0, 0, 0, 0, 0, // section eader table offset (none) 0, 0, 0, 0, 0x40, 0, 0x38, 0, // flags (none), header sizes 2, 0, 0, 0, 0, 0, 0, 0, // 2 segments, no sections // program header segment 6, 0, 0, 0, 4, 0, 0, 0, // program header segment, readable 0x40, 0, 0, 0, 0, 0, 0, 0, // immediately after ELF header 0x40, 0, 0, 0, 0, 0, 0, 0, // virtual address 0, 0, 0, 0, 0, 0, 0, 0, // physical address 0x70, 0, 0, 0, 0, 0, 0, 0, // size in file (2 * size of program header) 0x70, 0, 0, 0, 0, 0, 0, 0, // size in memory 8, 0, 0, 0, 0, 0, 0, 0, // alignment // executable segment 1, 0, 0, 0, 5, 0, 0, 0, // loadable segment, readable and executable 0, 0, 0, 0, 0, 0, 0, 0, // whole file 0, 0, 0, 0, 0, 0, 0, 0, // virtual address 0, 0, 0, 0, 0, 0, 0, 0, // physical address 0, 0, 0, 0, 0, 0, 0, 0, // PATCHME: size in file 0, 0, 0, 0, 0, 0, 0, 0, // PATCHME: size in memory 0, 0x10, 0, 0, 0, 0, 0, 0, // alignment (4K) }; uint64_t ep = (uint64_t) entry_point; uint64_t fl = (uint64_t) file_len; memcpy(&elf_header[0x18], &entry_point, sizeof(uint64_t)); memcpy(&elf_header[0x98], &file_len, sizeof(uint64_t)); memcpy(&elf_header[0x98 + sizeof(uint64_t)], &file_len, sizeof(uint64_t)); patch(0, elf_header, ELF_HEADER_SIZE); } int main(int argc, char** argv) { if (argc != 3) { fprintf(stderr, "usage: %s \n", argv[0]); exit(1); } open_files(argv[2], argv[1]); struct token tok; do { tok = lex(); switch (tok.type) { case TOK_NAME: fprintf(stdout, "%s\n", tok.data.name); break; case TOK_LABEL: fprintf(stdout, "'%s\n", tok.data.label); break; case TOK_INTEGER: fprintf(stdout, "%zi\n", tok.data.int_); break; case TOK_STRING: fprintf(stdout, "\"%s\"\n", tok.data.string); break; case TOK_OPEN_GROUP: fprintf(stdout, "(\n"); break; case TOK_CLOSE_GROUP: fprintf(stdout, ")\n"); break; case TOK_OPEN_BLOCK: fprintf(stdout, "{\n"); break; case TOK_CLOSE_BLOCK: fprintf(stdout, "}\n"); break; case TOK_TERMINATOR: fprintf(stdout, ";\n"); break; case TOK_SEPARATOR: fprintf(stdout, ",\n"); break; case TOK_OPERATOR: fprintf(stdout, "OP: %i\n", tok.data.op); break; case TOK_EOF: fprintf(stdout, "EOF\n"); break; } } while (tok.type != TOK_EOF); reserve(ELF_HEADER_SIZE); size_t entry_point = compile(); write_elf((uint64_t) entry_point); close_files(); return 0; }