1
2
3
4 :(before "End Main")
5 assert(argc > 1);
6 if (is_equal(argv[1], "run")) {
7 START_TRACING_UNTIL_END_OF_SCOPE;
8 assert(argc > 2);
9 reset();
10 cerr << std::hex;
11 initialize_mem();
12 Mem_offset = CODE_START;
13 load_elf(argv[2]);
14 while (EIP < End_of_program)
15 run_one_instruction();
16 trace(90, "load") << "executed past end of the world: " << EIP << " vs " << End_of_program << end();
17 return 0;
18 }
19
20 :(code)
21 void load_elf(const string& filename) {
22 int fd = open(filename.c_str(), O_RDONLY);
23 if (fd < 0) raise << filename.c_str() << ": open" << perr() << '\n' << die();
24 off_t size = lseek(fd, 0, SEEK_END);
25 lseek(fd, 0, SEEK_SET);
26 uint8_t* elf_contents = static_cast<uint8_t*>(malloc(size));
27 if (elf_contents == NULL) raise << "malloc(" << size << ')' << perr() << '\n' << die();
28 ssize_t read_size = read(fd, elf_contents, size);
29 if (size != read_size) raise << "read → " << size << " (!= " << read_size << ')' << perr() << '\n' << die();
30 load_elf_contents(elf_contents, size);
31 free(elf_contents);
32 }
33
34 void load_elf_contents(uint8_t* elf_contents, size_t size) {
35 uint8_t magic[5] = {0};
36 memcpy(magic, elf_contents, 4);
37 if (memcmp(magic, "\177ELF", 4) != 0)
38 raise << "Invalid ELF file; starts with \"" << magic << '"' << die();
39 if (elf_contents[4] != 1)
40 raise << "Only 32-bit ELF files (4-byte words; virtual addresses up to 4GB) supported.\n" << die();
41 if (elf_contents[5] != 1)
42 raise << "Only little-endian ELF files supported.\n" << die();
43
44 uint32_t e_machine_type = u32_in(&elf_contents[16]);
45 if (e_machine_type != 0x00030002)
46 raise << "ELF type/machine 0x" << HEXWORD << e_machine_type << " isn't i386 executable\n" << die();
47
48 uint32_t e_entry = u32_in(&elf_contents[24]);
49 uint32_t e_phoff = u32_in(&elf_contents[28]);
50
51
52 uint32_t e_ehsize = u16_in(&elf_contents[40]);
53 if (e_ehsize < 52) raise << "Invalid binary; ELF header too small\n" << die();
54 uint32_t e_phentsize = u16_in(&elf_contents[42]);
55 uint32_t e_phnum = u16_in(&elf_contents[44]);
56 trace(90, "load") << e_phnum << " entries in the program header, each " << e_phentsize << " bytes long" << end();
57
58
59
60
61 for (size_t i = 0; i < e_phnum; ++i)
62 load_segment_from_program_header(elf_contents, size, e_phoff + i*e_phentsize, e_ehsize);
63
64
65 Reg[ESP].u = AFTER_STACK;
66 Reg[EBP].u = 0;
67 EIP = e_entry;
68 }
69
70 void load_segment_from_program_header(uint8_t* elf_contents, size_t size, uint32_t offset, uint32_t e_ehsize) {
71 uint32_t p_type = u32_in(&elf_contents[offset]);
72 trace(90, "load") << "program header at offset " << offset << ": type " << p_type << end();
73 if (p_type != 1) {
74 trace(90, "load") << "ignoring segment at offset " << offset << " of non PT_LOAD type " << p_type << " (see http://refspecs.linuxbase.org/elf/elf.pdf)" << end();
75 return;
76 }
77 uint32_t p_offset = u32_in(&elf_contents[offset + 4]);
78 uint32_t p_vaddr = u32_in(&elf_contents[offset + 8]);
79 if (e_ehsize > p_vaddr) raise << "Invalid binary; program header overlaps ELF header\n" << die();
80
81 uint32_t p_filesz = u32_in(&elf_contents[offset + 16]);
82 uint32_t p_memsz = u32_in(&elf_contents[offset + 20]);
83 if (p_filesz != p_memsz)
84 raise << "Can't handle segments where p_filesz != p_memsz (see http://refspecs.linuxbase.org/elf/elf.pdf)\n" << die();
85
86 if (p_offset + p_filesz > size)
87 raise << "Invalid binary; segment at offset " << offset << " is too large: wants to end at " << p_offset+p_filesz << " but the file ends at " << size << '\n' << die();
88 if (Mem.size() < p_vaddr + p_memsz)
89 Mem.resize(p_vaddr + p_memsz);
90 if (size > p_memsz) size = p_memsz;
91 trace(90, "load") << "blitting file offsets (" << p_offset << ", " << (p_offset+p_filesz) << ") to addresses (" << p_vaddr << ", " << (p_vaddr+p_memsz) << ')' << end();
92 for (size_t i = 0; i < p_filesz; ++i)
93 write_mem_u8(p_vaddr+i, elf_contents[p_offset+i]);
94 if (End_of_program < p_vaddr+p_memsz)
95 End_of_program = p_vaddr+p_memsz;
96 }
97
98 :(before "End Includes")
99
100
101
102
103
104 const int CODE_START = 0x08048000;
105 const int SEGMENT_SIZE = 0x1000;
106 const int AFTER_STACK = 0x0804c000;
107 :(code)
108 void initialize_mem() {
109 Mem.resize(AFTER_STACK - CODE_START);
110 }
111
112 inline uint32_t u32_in(uint8_t* p) {
113 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
114 }
115
116 inline uint16_t u16_in(uint8_t* p) {
117 return p[0] | p[1] << 8;
118 }
119
120 :(before "End Types")
121 struct perr {};
122 :(code)
123 ostream& operator<<(ostream& os, perr ) {
124 if (errno)
125 os << ": " << strerror(errno);
126 return os;
127 }
128
129 :(before "End Types")
130 struct die {};
131 :(code)
132 ostream& operator<<(ostream& , die ) {
133 if (Trace_stream) Trace_stream->newline();
134 exit(1);
135 }
136
137 :(before "End Includes")
138
139
140
141
142
143