pass-lang/src/main.c

129 lines
4.3 KiB
C

#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#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 <output file> <source file>\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;
}