about summary refs log tree commit diff stats
path: root/subx/020elf.cc
blob: 7bc6ded844767024661915a74d5f9554b558feda (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// https://github.com/kragen/stoneknifeforth/blob/702d2ebe1b/386.c

:(before "End Main")
assert(argc > 1);
if (is_equal(argv[1], "run")) {
  assert(argc > 2);
  reset();
  load_elf(argv[2]);
  while (EIP < End_of_program)
    run_one_instruction();
}

:(code)
void load_elf(const string& filename) {
  int fd = open(filename.c_str(), O_RDONLY);
  if (fd < 0) die("%s: open", filename.c_str());
  off_t size = lseek(fd, 0, SEEK_END);
  lseek(fd, 0, SEEK_SET);
  uint8_t* elf_contents = static_cast<uint8_t*>(malloc(size));
  if (elf_contents == NULL) die("malloc(%d)", size);
  ssize_t read_size = read(fd, elf_contents, size);
  if (size != read_size) die("read → %d (!= %d)", size, read_size);
  load_elf_contents(elf_contents, size);
  free(elf_contents);
}

void load_elf_contents(uint8_t* elf_contents, size_t length) {
  uint8_t magic[5] = {0};
  memcpy(magic, elf_contents, 4);
  if (0 != memcmp(magic, "\177ELF", 4))
    die("Invalid ELF file starting with \"%s\"", magic);

  uint32_t e_type = u32_in(&elf_contents[16]);
  if (0x00030002 != e_type)
    die("ELF type/machine 0x%x isn't i386 executable", e_type);

  uint32_t e_entry = u32_in(&elf_contents[24]);
  uint32_t e_phoff = u32_in(&elf_contents[28]);
  uint32_t p_vaddr = u32_in(&elf_contents[e_phoff + 8]);
  uint32_t p_memsz = u32_in(&elf_contents[e_phoff + 20]);

  Mem.resize(p_memsz);  // TODO: not sure if this should be + p_vaddr
  if (length > p_memsz - p_vaddr) length = p_memsz - p_vaddr;
  for (size_t i = 0;  i < length;  ++i)
    Mem.at(p_vaddr + i) = elf_contents[i];
  End_of_program = p_memsz;

  // TODO: need to set up real stack somewhere

  Reg[ESP].u = Reg[EBP].u = End_of_program;
  EIP = e_entry;
}

inline uint32_t u32_in(uint8_t* p) {
  return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
}

void die(const char* format, ...) {
  va_list args;
  va_start(args, format);
  vfprintf(stderr, format, args);
  if (errno)
    perror("‌");
  else
    fprintf(stderr, "\n");
  va_end(args);
  abort();
}

:(before "End Types")
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>