diff --git a/html/010---vm.cc.html b/html/010---vm.cc.html
index 232da129..227acfd4 100644
--- a/html/010---vm.cc.html
+++ b/html/010---vm.cc.html
@@ -14,7 +14,7 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
-.PreProc { color: #c000c0; }
+.cSpecial { color: #008000; }
.LineNr { }
.Constant { color: #008787; }
.Comment { color: #005faf; }
@@ -22,7 +22,7 @@ a { color:inherit; }
.Special { color: #d70000; }
.Identifier { color: #af5f00; }
.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.cSpecial { color: #008000; }
+.PreProc { color: #c000c0; }
.SalientComment { color: #0000af; }
-->
@@ -428,7 +428,7 @@ if ('onhashchange' in window) {
367 cerr << " f3 0f " << p->first << ": " << p->second << '\n';
368 cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n"
369 "For complete details on these instructions, consult the IA-32 manual (volume 2).\n"
-370 "There's various versions of it online, such as https://c9x.me/x86.\n"
+370 "There's various versions of it online, such as https://c9x.me/x86.\n"
371 "The mnemonics in brackets will help you locate each instruction.\n";
372 return 0;
373 }
diff --git a/html/011run.cc.html b/html/011run.cc.html
index 3be170bf..4f30046d 100644
--- a/html/011run.cc.html
+++ b/html/011run.cc.html
@@ -14,9 +14,9 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
+.cSpecial { color: #008000; }
.LineNr { }
.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.cSpecial { color: #008000; }
.Comment { color: #005faf; }
.Delimiter { color: #c000c0; }
.Special { color: #d70000; }
diff --git a/html/012elf.cc.html b/html/012elf.cc.html
index 055fd5c0..a1195d1b 100644
--- a/html/012elf.cc.html
+++ b/html/012elf.cc.html
@@ -66,189 +66,190 @@ if ('onhashchange' in window) {
5 :(before "End Main")
6 assert(argc > 1);
7 if (is_equal(argv[1], "run")) {
- 8 START_TRACING_UNTIL_END_OF_SCOPE;
- 9 trace(2, "run") << "=== Starting to run" << end();
- 10 assert(argc > 2);
- 11 reset();
- 12 cerr << std::hex;
- 13 load_elf(argv[2], argc, argv);
- 14 while (EIP < End_of_program)
- 15 run_one_instruction();
- 16 raise << "executed past end of the world: " << EIP << " vs " << End_of_program << '\n' << end();
- 17 return 1;
- 18 }
- 19
- 20 :(code)
- 21 void load_elf(const string& filename, int argc, char* argv[]) {
- 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, argc, argv);
- 31 free(elf_contents);
- 32 }
- 33
- 34 void load_elf_contents(uint8_t* elf_contents, size_t size, int argc, char* argv[]) {
- 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 set<uint32_t> overlap;
- 62 for (size_t i = 0; i < e_phnum; ++i)
- 63 load_segment_from_program_header(elf_contents, i, size, e_phoff + i*e_phentsize, e_ehsize, overlap);
- 64
- 65
- 66 assert(overlap.find(STACK_SEGMENT) == overlap.end());
- 67 Mem.push_back(vma(STACK_SEGMENT));
- 68 assert(overlap.find(AFTER_STACK) == overlap.end());
- 69
- 70 Reg[ESP].u = AFTER_STACK;
- 71 Reg[EBP].u = 0;
- 72 EIP = e_entry;
- 73
- 74
- 75
- 76
- 77 Mem.push_back(vma(ARGV_DATA_SEGMENT));
- 78 uint32_t argv_data = ARGV_DATA_SEGMENT;
- 79 for (int i = argc-1; i >= 2; --i) {
- 80 push(argv_data);
- 81 for (size_t j = 0; j <= strlen(argv[i]); ++j) {
- 82 assert(overlap.find(argv_data) == overlap.end());
- 83 write_mem_u8(argv_data, argv[i][j]);
- 84 argv_data += sizeof(char);
- 85 assert(argv_data < ARGV_DATA_SEGMENT + SEGMENT_ALIGNMENT);
- 86 }
- 87 }
- 88 push(argc-2);
- 89 }
- 90
- 91 void push(uint32_t val) {
- 92 Reg[ESP].u -= 4;
- 93 if (Reg[ESP].u < STACK_SEGMENT) {
- 94 raise << "The stack overflowed its segment. "
- 95 << "Maybe SPACE_FOR_SEGMENT should be larger? "
- 96 << "Or you need to carve out an exception for the stack segment "
- 97 << "to be larger.\n" << die();
- 98 }
- 99 trace(Callstack_depth+1, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
-100 trace(Callstack_depth+1, "run") << "pushing value 0x" << HEXWORD << val << end();
-101 write_mem_u32(Reg[ESP].u, val);
-102 }
-103
-104 void load_segment_from_program_header(uint8_t* elf_contents, int segment_index, size_t size, uint32_t offset, uint32_t e_ehsize, set<uint32_t>& overlap) {
-105 uint32_t p_type = u32_in(&elf_contents[offset]);
-106 trace(90, "load") << "program header at offset " << offset << ": type " << p_type << end();
-107 if (p_type != 1) {
-108 trace(90, "load") << "ignoring segment at offset " << offset << " of non PT_LOAD type " << p_type << " (see http://refspecs.linuxbase.org/elf/elf.pdf)" << end();
-109 return;
-110 }
-111 uint32_t p_offset = u32_in(&elf_contents[offset + 4]);
-112 uint32_t p_vaddr = u32_in(&elf_contents[offset + 8]);
-113 if (e_ehsize > p_vaddr) raise << "Invalid binary; program header overlaps ELF header\n" << die();
-114
-115 uint32_t p_filesz = u32_in(&elf_contents[offset + 16]);
-116 uint32_t p_memsz = u32_in(&elf_contents[offset + 20]);
-117 if (p_filesz != p_memsz)
-118 raise << "Can't yet handle segments where p_filesz != p_memsz (see http://refspecs.linuxbase.org/elf/elf.pdf)\n" << die();
-119
-120 if (p_offset + p_filesz > size)
-121 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();
-122 if (p_memsz >= SEGMENT_ALIGNMENT) {
-123 raise << "Code segment too small for SubX; for now please manually increase SEGMENT_ALIGNMENT.\n" << end();
-124 return;
-125 }
-126 trace(90, "load") << "blitting file offsets (" << p_offset << ", " << (p_offset+p_filesz) << ") to addresses (" << p_vaddr << ", " << (p_vaddr+p_memsz) << ')' << end();
-127 if (size > p_memsz) size = p_memsz;
-128 Mem.push_back(vma(p_vaddr));
-129 for (size_t i = 0; i < p_filesz; ++i) {
-130 assert(overlap.find(p_vaddr+i) == overlap.end());
-131 write_mem_u8(p_vaddr+i, elf_contents[p_offset+i]);
-132 overlap.insert(p_vaddr+i);
-133 }
-134 if (segment_index == 0 && End_of_program < p_vaddr+p_memsz)
-135 End_of_program = p_vaddr+p_memsz;
-136 }
-137
-138 :(before "End Includes")
-139
-140
-141
-142
-143
-144
-145
-146
-147 const uint32_t START_HEAP = 0x0b000000;
-148 const uint32_t END_HEAP = 0xbd000000;
-149 const uint32_t STACK_SEGMENT = 0xbd000000;
-150 const uint32_t AFTER_STACK = 0xbe000000;
-151 const uint32_t ARGV_DATA_SEGMENT = 0xbf000000;
-152
-153
-154 :(before "End Dump Info for Instruction")
-155
-156 :(code)
-157 void dump_stack() {
-158 ostringstream out;
-159 trace(Callstack_depth+1, "run") << "stack:" << end();
-160 for (uint32_t a = AFTER_STACK-4; a > Reg[ESP].u; a -= 4)
-161 trace(Callstack_depth+2, "run") << " 0x" << HEXWORD << a << " => 0x" << HEXWORD << read_mem_u32(a) << end();
-162 trace(Callstack_depth+2, "run") << " 0x" << HEXWORD << Reg[ESP].u << " => 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << " <=== ESP" << end();
-163 for (uint32_t a = Reg[ESP].u-4; a > Reg[ESP].u-40; a -= 4)
-164 trace(Callstack_depth+2, "run") << " 0x" << HEXWORD << a << " => 0x" << HEXWORD << read_mem_u32(a) << end();
-165 }
-166
-167 inline uint32_t u32_in(uint8_t* p) {
-168 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
-169 }
-170
-171 inline uint16_t u16_in(uint8_t* p) {
-172 return p[0] | p[1] << 8;
-173 }
-174
-175 :(before "End Types")
-176 struct perr {};
-177 :(code)
-178 ostream& operator<<(ostream& os, perr ) {
-179 if (errno)
-180 os << ": " << strerror(errno);
-181 return os;
-182 }
-183
-184 :(before "End Includes")
-185 #include <sys/types.h>
-186 #include <sys/stat.h>
-187 #include <fcntl.h>
-188 #include <stdarg.h>
-189 #include <errno.h>
-190 #include <unistd.h>
+ 8
+ 9 if (Trace_file.is_open()) Trace_stream = new trace_stream;
+ 10 trace(2, "run") << "=== Starting to run" << end();
+ 11 assert(argc > 2);
+ 12 reset();
+ 13 cerr << std::hex;
+ 14 load_elf(argv[2], argc, argv);
+ 15 while (EIP < End_of_program)
+ 16 run_one_instruction();
+ 17 raise << "executed past end of the world: " << EIP << " vs " << End_of_program << '\n' << end();
+ 18 return 1;
+ 19 }
+ 20
+ 21 :(code)
+ 22 void load_elf(const string& filename, int argc, char* argv[]) {
+ 23 int fd = open(filename.c_str(), O_RDONLY);
+ 24 if (fd < 0) raise << filename.c_str() << ": open" << perr() << '\n' << die();
+ 25 off_t size = lseek(fd, 0, SEEK_END);
+ 26 lseek(fd, 0, SEEK_SET);
+ 27 uint8_t* elf_contents = static_cast<uint8_t*>(malloc(size));
+ 28 if (elf_contents == NULL) raise << "malloc(" << size << ')' << perr() << '\n' << die();
+ 29 ssize_t read_size = read(fd, elf_contents, size);
+ 30 if (size != read_size) raise << "read → " << size << " (!= " << read_size << ')' << perr() << '\n' << die();
+ 31 load_elf_contents(elf_contents, size, argc, argv);
+ 32 free(elf_contents);
+ 33 }
+ 34
+ 35 void load_elf_contents(uint8_t* elf_contents, size_t size, int argc, char* argv[]) {
+ 36 uint8_t magic[5] = {0};
+ 37 memcpy(magic, elf_contents, 4);
+ 38 if (memcmp(magic, "\177ELF", 4) != 0)
+ 39 raise << "Invalid ELF file; starts with \"" << magic << '"' << die();
+ 40 if (elf_contents[4] != 1)
+ 41 raise << "Only 32-bit ELF files (4-byte words; virtual addresses up to 4GB) supported.\n" << die();
+ 42 if (elf_contents[5] != 1)
+ 43 raise << "Only little-endian ELF files supported.\n" << die();
+ 44
+ 45 uint32_t e_machine_type = u32_in(&elf_contents[16]);
+ 46 if (e_machine_type != 0x00030002)
+ 47 raise << "ELF type/machine 0x" << HEXWORD << e_machine_type << " isn't i386 executable\n" << die();
+ 48
+ 49 uint32_t e_entry = u32_in(&elf_contents[24]);
+ 50 uint32_t e_phoff = u32_in(&elf_contents[28]);
+ 51
+ 52
+ 53 uint32_t e_ehsize = u16_in(&elf_contents[40]);
+ 54 if (e_ehsize < 52) raise << "Invalid binary; ELF header too small\n" << die();
+ 55 uint32_t e_phentsize = u16_in(&elf_contents[42]);
+ 56 uint32_t e_phnum = u16_in(&elf_contents[44]);
+ 57 trace(90, "load") << e_phnum << " entries in the program header, each " << e_phentsize << " bytes long" << end();
+ 58
+ 59
+ 60
+ 61
+ 62 set<uint32_t> overlap;
+ 63 for (size_t i = 0; i < e_phnum; ++i)
+ 64 load_segment_from_program_header(elf_contents, i, size, e_phoff + i*e_phentsize, e_ehsize, overlap);
+ 65
+ 66
+ 67 assert(overlap.find(STACK_SEGMENT) == overlap.end());
+ 68 Mem.push_back(vma(STACK_SEGMENT));
+ 69 assert(overlap.find(AFTER_STACK) == overlap.end());
+ 70
+ 71 Reg[ESP].u = AFTER_STACK;
+ 72 Reg[EBP].u = 0;
+ 73 EIP = e_entry;
+ 74
+ 75
+ 76
+ 77
+ 78 Mem.push_back(vma(ARGV_DATA_SEGMENT));
+ 79 uint32_t argv_data = ARGV_DATA_SEGMENT;
+ 80 for (int i = argc-1; i >= 2; --i) {
+ 81 push(argv_data);
+ 82 for (size_t j = 0; j <= strlen(argv[i]); ++j) {
+ 83 assert(overlap.find(argv_data) == overlap.end());
+ 84 write_mem_u8(argv_data, argv[i][j]);
+ 85 argv_data += sizeof(char);
+ 86 assert(argv_data < ARGV_DATA_SEGMENT + SEGMENT_ALIGNMENT);
+ 87 }
+ 88 }
+ 89 push(argc-2);
+ 90 }
+ 91
+ 92 void push(uint32_t val) {
+ 93 Reg[ESP].u -= 4;
+ 94 if (Reg[ESP].u < STACK_SEGMENT) {
+ 95 raise << "The stack overflowed its segment. "
+ 96 << "Maybe SPACE_FOR_SEGMENT should be larger? "
+ 97 << "Or you need to carve out an exception for the stack segment "
+ 98 << "to be larger.\n" << die();
+ 99 }
+100 trace(Callstack_depth+1, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
+101 trace(Callstack_depth+1, "run") << "pushing value 0x" << HEXWORD << val << end();
+102 write_mem_u32(Reg[ESP].u, val);
+103 }
+104
+105 void load_segment_from_program_header(uint8_t* elf_contents, int segment_index, size_t size, uint32_t offset, uint32_t e_ehsize, set<uint32_t>& overlap) {
+106 uint32_t p_type = u32_in(&elf_contents[offset]);
+107 trace(90, "load") << "program header at offset " << offset << ": type " << p_type << end();
+108 if (p_type != 1) {
+109 trace(90, "load") << "ignoring segment at offset " << offset << " of non PT_LOAD type " << p_type << " (see http://refspecs.linuxbase.org/elf/elf.pdf)" << end();
+110 return;
+111 }
+112 uint32_t p_offset = u32_in(&elf_contents[offset + 4]);
+113 uint32_t p_vaddr = u32_in(&elf_contents[offset + 8]);
+114 if (e_ehsize > p_vaddr) raise << "Invalid binary; program header overlaps ELF header\n" << die();
+115
+116 uint32_t p_filesz = u32_in(&elf_contents[offset + 16]);
+117 uint32_t p_memsz = u32_in(&elf_contents[offset + 20]);
+118 if (p_filesz != p_memsz)
+119 raise << "Can't yet handle segments where p_filesz != p_memsz (see http://refspecs.linuxbase.org/elf/elf.pdf)\n" << die();
+120
+121 if (p_offset + p_filesz > size)
+122 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();
+123 if (p_memsz >= SEGMENT_ALIGNMENT) {
+124 raise << "Code segment too small for SubX; for now please manually increase SEGMENT_ALIGNMENT.\n" << end();
+125 return;
+126 }
+127 trace(90, "load") << "blitting file offsets (" << p_offset << ", " << (p_offset+p_filesz) << ") to addresses (" << p_vaddr << ", " << (p_vaddr+p_memsz) << ')' << end();
+128 if (size > p_memsz) size = p_memsz;
+129 Mem.push_back(vma(p_vaddr));
+130 for (size_t i = 0; i < p_filesz; ++i) {
+131 assert(overlap.find(p_vaddr+i) == overlap.end());
+132 write_mem_u8(p_vaddr+i, elf_contents[p_offset+i]);
+133 overlap.insert(p_vaddr+i);
+134 }
+135 if (segment_index == 0 && End_of_program < p_vaddr+p_memsz)
+136 End_of_program = p_vaddr+p_memsz;
+137 }
+138
+139 :(before "End Includes")
+140
+141
+142
+143
+144
+145
+146
+147
+148 const uint32_t START_HEAP = 0x0b000000;
+149 const uint32_t END_HEAP = 0xbd000000;
+150 const uint32_t STACK_SEGMENT = 0xbd000000;
+151 const uint32_t AFTER_STACK = 0xbe000000;
+152 const uint32_t ARGV_DATA_SEGMENT = 0xbf000000;
+153
+154
+155 :(before "End Dump Info for Instruction")
+156
+157 :(code)
+158 void dump_stack() {
+159 ostringstream out;
+160 trace(Callstack_depth+1, "run") << "stack:" << end();
+161 for (uint32_t a = AFTER_STACK-4; a > Reg[ESP].u; a -= 4)
+162 trace(Callstack_depth+2, "run") << " 0x" << HEXWORD << a << " => 0x" << HEXWORD << read_mem_u32(a) << end();
+163 trace(Callstack_depth+2, "run") << " 0x" << HEXWORD << Reg[ESP].u << " => 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << " <=== ESP" << end();
+164 for (uint32_t a = Reg[ESP].u-4; a > Reg[ESP].u-40; a -= 4)
+165 trace(Callstack_depth+2, "run") << " 0x" << HEXWORD << a << " => 0x" << HEXWORD << read_mem_u32(a) << end();
+166 }
+167
+168 inline uint32_t u32_in(uint8_t* p) {
+169 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+170 }
+171
+172 inline uint16_t u16_in(uint8_t* p) {
+173 return p[0] | p[1] << 8;
+174 }
+175
+176 :(before "End Types")
+177 struct perr {};
+178 :(code)
+179 ostream& operator<<(ostream& os, perr ) {
+180 if (errno)
+181 os << ": " << strerror(errno);
+182 return os;
+183 }
+184
+185 :(before "End Includes")
+186 #include <sys/types.h>
+187 #include <sys/stat.h>
+188 #include <fcntl.h>
+189 #include <stdarg.h>
+190 #include <errno.h>
+191 #include <unistd.h>