pass-lang/src/main.c

84 lines
3.0 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"
#define ELF_HEADER_SIZE 0xb0
size_t compile(void) {
init();
var code = lit(42);
var call = lit(60);
var args[2] = { call, code };
syscall(2, args);
return ELF_HEADER_SIZE;
}
static void write_elf(uint64_t entry_point) {
uint64_t file_len = ftell(outfile);
fseek(outfile, 0, SEEK_SET);
// 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 header 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));
emit(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]);
fseek(outfile, ELF_HEADER_SIZE, SEEK_SET);
size_t entry_point = compile();
write_elf((uint64_t) entry_point);
close_files();
return 0;
}