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) // weak final-gasp termination check - 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 // unused: remaining 10 bytes of e_ident - 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 // unused: e_version. We only support version 1, and later versions will be backwards compatible. - 48 uint32_t e_entry = u32_in(&elf_contents[24]); - 49 uint32_t e_phoff = u32_in(&elf_contents[28]); - 50 // unused: e_shoff - 51 // unused: e_flags - 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 // unused: e_shentsize - 58 // unused: e_shnum - 59 // unused: e_shstrndx - 60 - 61 set<uint32_t> overlap; // to detect overlapping segments - 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 // initialize code and stack - 66 assert(overlap.find(STACK_SEGMENT) == overlap.end()); - 67 Mem.push_back(vma(STACK_SEGMENT)); - 68 assert(overlap.find(AFTER_STACK) == overlap.end()); - 69 // The stack grows downward. - 70 Reg[ESP].u = AFTER_STACK; - 71 Reg[EBP].u = 0; - 72 EIP = e_entry; - 73 - 74 // initialize args on stack - 75 // no envp for now - 76 // we wastefully use a separate page of memory for argv - 77 Mem.push_back(vma(ARGV_DATA_SEGMENT)); - 78 uint32_t argv_data = ARGV_DATA_SEGMENT; - 79 for (int i = argc-1; i >= /*skip 'subx_bin' and 'run'*/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()); // don't bother comparing ARGV and STACK - 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-/*skip 'subx_bin' and 'run'*/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 // unused: p_paddr -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 // Very primitive/fixed/insecure ELF segments for now. -140 // --- inaccessible: 0x00000000 -> 0x08047fff -141 // code: 0x09000000 -> 0x09ffffff (specified in ELF binary) -142 // data: 0x0a000000 -> 0x0affffff (specified in ELF binary) -143 // --- heap gets mmap'd somewhere here --- -144 // stack: 0xbdffffff -> 0xbd000000 (downward; not in ELF binary) -145 // argv hack: 0xbf000000 -> 0xbfffffff (not in ELF binary) -146 // --- reserved for kernel: 0xc0000000 -> ... -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 // When updating the above memory map, don't forget to update `mmap`'s -153 // implementation in the 'syscalls' layer. -154 :(before "End Dump Info for Instruction") -155 //? dump_stack(); // slow -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 /*unused*/) { -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 // Outside of tests, traces must be explicitly requested. + 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) // weak final-gasp termination check + 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 // unused: remaining 10 bytes of e_ident + 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 // unused: e_version. We only support version 1, and later versions will be backwards compatible. + 49 uint32_t e_entry = u32_in(&elf_contents[24]); + 50 uint32_t e_phoff = u32_in(&elf_contents[28]); + 51 // unused: e_shoff + 52 // unused: e_flags + 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 // unused: e_shentsize + 59 // unused: e_shnum + 60 // unused: e_shstrndx + 61 + 62 set<uint32_t> overlap; // to detect overlapping segments + 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 // initialize code and stack + 67 assert(overlap.find(STACK_SEGMENT) == overlap.end()); + 68 Mem.push_back(vma(STACK_SEGMENT)); + 69 assert(overlap.find(AFTER_STACK) == overlap.end()); + 70 // The stack grows downward. + 71 Reg[ESP].u = AFTER_STACK; + 72 Reg[EBP].u = 0; + 73 EIP = e_entry; + 74 + 75 // initialize args on stack + 76 // no envp for now + 77 // we wastefully use a separate page of memory for argv + 78 Mem.push_back(vma(ARGV_DATA_SEGMENT)); + 79 uint32_t argv_data = ARGV_DATA_SEGMENT; + 80 for (int i = argc-1; i >= /*skip 'subx_bin' and 'run'*/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()); // don't bother comparing ARGV and STACK + 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-/*skip 'subx_bin' and 'run'*/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 // unused: p_paddr +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 // Very primitive/fixed/insecure ELF segments for now. +141 // --- inaccessible: 0x00000000 -> 0x08047fff +142 // code: 0x09000000 -> 0x09ffffff (specified in ELF binary) +143 // data: 0x0a000000 -> 0x0affffff (specified in ELF binary) +144 // --- heap gets mmap'd somewhere here --- +145 // stack: 0xbdffffff -> 0xbd000000 (downward; not in ELF binary) +146 // argv hack: 0xbf000000 -> 0xbfffffff (not in ELF binary) +147 // --- reserved for kernel: 0xc0000000 -> ... +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 // When updating the above memory map, don't forget to update `mmap`'s +154 // implementation in the 'syscalls' layer. +155 :(before "End Dump Info for Instruction") +156 //? dump_stack(); // slow +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 /*unused*/) { +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> diff --git a/html/013direct_addressing.cc.html b/html/013direct_addressing.cc.html index 8944da91..f96cb2f1 100644 --- a/html/013direct_addressing.cc.html +++ b/html/013direct_addressing.cc.html @@ -1260,7 +1260,7 @@ if ('onhashchange' in window) { 1199 " 53 \n" // push EBX to stack 1200 ); 1201 CHECK_TRACE_CONTENTS( -1202 "run: push EBX\n" +1202 "run: push EBX\n" 1203 "run: decrementing ESP to 0xbd000004\n" 1204 "run: pushing value 0x0000000a\n" 1205 ); @@ -1278,7 +1278,7 @@ if ('onhashchange' in window) { 1217 uint8_t reg = op & 0x7; 1218 trace(Callstack_depth+1, "run") << "push " << rname(reg) << end(); 1219 //? cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n'; -1220 push(Reg[reg].u); +1220 push(Reg[reg].u); 1221 break; 1222 } 1223 @@ -1335,7 +1335,7 @@ if ('onhashchange' in window) { 1274 trace(Callstack_depth+1, "run") << "popping value 0x" << HEXWORD << result << end(); 1275 Reg[ESP].u += 4; 1276 trace(Callstack_depth+1, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end(); -1277 assert(Reg[ESP].u < AFTER_STACK); +1277 assert(Reg[ESP].u < AFTER_STACK); 1278 return result; 1279 } diff --git a/html/014indirect_addressing.cc.html b/html/014indirect_addressing.cc.html index dcebc975..02e6241e 100644 --- a/html/014indirect_addressing.cc.html +++ b/html/014indirect_addressing.cc.html @@ -829,7 +829,7 @@ if ('onhashchange' in window) { 770 "af 00 00 00\n" // 0x000000af 771 ); 772 CHECK_TRACE_CONTENTS( - 773 "run: push r/m32\n" + 773 "run: push r/m32\n" 774 "run: effective address is 0x00002000 (EAX)\n" 775 "run: decrementing ESP to 0xbd000010\n" 776 "run: pushing value 0x000000af\n" @@ -840,7 +840,7 @@ if ('onhashchange' in window) { 781 case 6: { // push r/m32 to stack 782 trace(Callstack_depth+1, "run") << "push r/m32" << end(); 783 const int32_t* val = effective_address(modrm); - 784 push(*val); + 784 push(*val); 785 break; 786 } 787 diff --git a/html/015immediate_addressing.cc.html b/html/015immediate_addressing.cc.html index 09fa552d..9a45a6e1 100644 --- a/html/015immediate_addressing.cc.html +++ b/html/015immediate_addressing.cc.html @@ -1315,7 +1315,7 @@ if ('onhashchange' in window) { 1254 " 68 af 00 00 00 \n" // push *EAX to stack 1255 ); 1256 CHECK_TRACE_CONTENTS( -1257 "run: push imm32 0x000000af\n" +1257 "run: push imm32 0x000000af\n" 1258 "run: ESP is now 0xbd000010\n" 1259 "run: contents at ESP: 0x000000af\n" 1260 ); @@ -1326,7 +1326,7 @@ if ('onhashchange' in window) { 1265 const uint32_t val = static_cast<uint32_t>(next32()); 1266 trace(Callstack_depth+1, "run") << "push imm32 0x" << HEXWORD << val << end(); 1267 //? cerr << "push: " << val << " => " << Reg[ESP].u << '\n'; -1268 push(val); +1268 push(val); 1269 trace(Callstack_depth+1, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end(); 1270 trace(Callstack_depth+1, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end(); 1271 break; diff --git a/html/019functions.cc.html b/html/019functions.cc.html index a8931e70..f6c9d579 100644 --- a/html/019functions.cc.html +++ b/html/019functions.cc.html @@ -87,7 +87,7 @@ if ('onhashchange' in window) { 27 ++Callstack_depth; 28 trace(Callstack_depth+1, "run") << "call imm32 0x" << HEXWORD << offset << end(); 29 //? cerr << "push: EIP: " << EIP << " => " << Reg[ESP].u << '\n'; - 30 push(EIP); + 30 push(EIP); 31 EIP += offset; 32 trace(Callstack_depth+1, "run") << "jumping to 0x" << HEXWORD << EIP << end(); 33 break; @@ -119,7 +119,7 @@ if ('onhashchange' in window) { 59 case 2: { // call function pointer at r/m32 60 trace(Callstack_depth+1, "run") << "call to r/m32" << end(); 61 const int32_t* offset = effective_address(modrm); - 62 push(EIP); + 62 push(EIP); 63 EIP += *offset; 64 trace(Callstack_depth+1, "run") << "jumping to 0x" << HEXWORD << EIP << end(); 65 ++Callstack_depth; diff --git a/html/020syscalls.cc.html b/html/020syscalls.cc.html index a6924627..70c529af 100644 --- a/html/020syscalls.cc.html +++ b/html/020syscalls.cc.html @@ -167,13 +167,13 @@ if ('onhashchange' in window) { 107 108 :(before "End Globals") 109 // Very primitive/fixed/insecure mmap segments for now. -110 uint32_t Segments_allocated_above = END_HEAP; +110 uint32_t Segments_allocated_above = END_HEAP; 111 :(code) 112 // always allocate multiples of the segment size 113 uint32_t new_segment(uint32_t length) { 114 assert(length > 0); 115 uint32_t result = (Segments_allocated_above - length) & 0xff000000; // same number of zeroes as SEGMENT_ALIGNMENT -116 if (result <= START_HEAP) { +116 if (result <= START_HEAP) { 117 raise << "Allocated too many segments; the VM ran out of memory. " 118 << "Maybe SEGMENT_ALIGNMENT can be smaller?\n" << die(); 119 } diff --git a/html/028translate.cc.html b/html/028translate.cc.html index ad822f33..fe277b0a 100644 --- a/html/028translate.cc.html +++ b/html/028translate.cc.html @@ -79,198 +79,199 @@ if ('onhashchange' in window) { 18 19 :(before "End Main") 20 if (is_equal(argv[1], "translate")) { - 21 START_TRACING_UNTIL_END_OF_SCOPE; - 22 reset(); - 23 // Begin subx translate - 24 program p; - 25 string output_filename; - 26 for (int i = /*skip 'subx translate'*/2; i < argc; ++i) { - 27 if (is_equal(argv[i], "-o")) { - 28 ++i; - 29 if (i >= argc) { - 30 print_translate_usage(); - 31 cerr << "'-o' must be followed by a filename to write results to\n"; - 32 exit(1); - 33 } - 34 output_filename = argv[i]; - 35 } - 36 else { - 37 trace(2, "parse") << argv[i] << end(); - 38 ifstream fin(argv[i]); - 39 if (!fin) { - 40 cerr << "could not open " << argv[i] << '\n'; - 41 return 1; - 42 } - 43 parse(fin, p); - 44 if (trace_contains_errors()) return 1; - 45 } - 46 } - 47 if (p.segments.empty()) { - 48 print_translate_usage(); - 49 cerr << "nothing to do; must provide at least one file to read\n"; - 50 exit(1); - 51 } - 52 if (output_filename.empty()) { - 53 print_translate_usage(); - 54 cerr << "must provide a filename to write to using '-o'\n"; - 55 exit(1); - 56 } - 57 trace(2, "transform") << "begin" << end(); - 58 transform(p); - 59 if (trace_contains_errors()) return 1; - 60 trace(2, "translate") << "begin" << end(); - 61 save_elf(p, output_filename); - 62 if (trace_contains_errors()) { - 63 unlink(output_filename.c_str()); - 64 return 1; - 65 } - 66 // End subx translate - 67 return 0; - 68 } - 69 - 70 :(code) - 71 void print_translate_usage() { - 72 cerr << "Usage: subx translate file1 file2 ... -o output\n"; - 73 } - 74 - 75 // write out a program to a bare-bones ELF file - 76 void save_elf(const program& p, const string& filename) { - 77 ofstream out(filename.c_str(), ios::binary); - 78 save_elf(p, out); - 79 out.close(); - 80 } - 81 - 82 void save_elf(const program& p, ostream& out) { - 83 // validation: stay consistent with the self-hosted translator - 84 if (p.entry == 0) { - 85 raise << "no 'Entry' label found\n" << end(); - 86 return; - 87 } - 88 if (find(p, "data") == NULL) { - 89 raise << "must include a 'data' segment\n" << end(); - 90 return; - 91 } - 92 // processing - 93 write_elf_header(out, p); - 94 for (size_t i = 0; i < p.segments.size(); ++i) - 95 write_segment(p.segments.at(i), out); - 96 } - 97 - 98 void write_elf_header(ostream& out, const program& p) { - 99 char c = '\0'; -100 #define O(X) c = (X); out.write(&c, sizeof(c)) -101 // host is required to be little-endian -102 #define emit(X) out.write(reinterpret_cast<const char*>(&X), sizeof(X)) -103 //// ehdr -104 // e_ident -105 O(0x7f); O(/*E*/0x45); O(/*L*/0x4c); O(/*F*/0x46); -106 O(0x1); // 32-bit format -107 O(0x1); // little-endian -108 O(0x1); O(0x0); -109 for (size_t i = 0; i < 8; ++i) { O(0x0); } -110 // e_type -111 O(0x02); O(0x00); -112 // e_machine -113 O(0x03); O(0x00); -114 // e_version -115 O(0x01); O(0x00); O(0x00); O(0x00); -116 // e_entry -117 uint32_t e_entry = p.entry; -118 // Override e_entry -119 emit(e_entry); -120 // e_phoff -- immediately after ELF header -121 uint32_t e_phoff = 0x34; -122 emit(e_phoff); -123 // e_shoff; unused -124 uint32_t dummy32 = 0; -125 emit(dummy32); -126 // e_flags; unused -127 emit(dummy32); -128 // e_ehsize -129 uint16_t e_ehsize = 0x34; -130 emit(e_ehsize); -131 // e_phentsize -132 uint16_t e_phentsize = 0x20; -133 emit(e_phentsize); -134 // e_phnum -135 uint16_t e_phnum = SIZE(p.segments); -136 emit(e_phnum); -137 // e_shentsize -138 uint16_t dummy16 = 0x0; -139 emit(dummy16); -140 // e_shnum -141 emit(dummy16); -142 // e_shstrndx -143 emit(dummy16); -144 -145 uint32_t p_offset = /*size of ehdr*/0x34 + SIZE(p.segments)*0x20/*size of each phdr*/; -146 for (int i = 0; i < SIZE(p.segments); ++i) { -147 const segment& curr = p.segments.at(i); -148 //// phdr -149 // p_type -150 uint32_t p_type = 0x1; -151 emit(p_type); -152 // p_offset -153 emit(p_offset); -154 // p_vaddr -155 uint32_t p_start = curr.start; -156 emit(p_start); -157 // p_paddr -158 emit(p_start); -159 // p_filesz -160 uint32_t size = num_words(curr); -161 assert(p_offset + size < SEGMENT_ALIGNMENT); -162 emit(size); -163 // p_memsz -164 emit(size); -165 // p_flags -166 uint32_t p_flags = (curr.name == "code") ? /*r-x*/0x5 : /*rw-*/0x6; -167 emit(p_flags); -168 -169 // p_align -170 // "As the system creates or augments a process image, it logically copies -171 // a file's segment to a virtual memory segment. When—and if— the system -172 // physically reads the file depends on the program's execution behavior, -173 // system load, and so on. A process does not require a physical page -174 // unless it references the logical page during execution, and processes -175 // commonly leave many pages unreferenced. Therefore delaying physical -176 // reads frequently obviates them, improving system performance. To obtain -177 // this efficiency in practice, executable and shared object files must -178 // have segment images whose file offsets and virtual addresses are -179 // congruent, modulo the page size." -- http://refspecs.linuxbase.org/elf/elf.pdf (page 95) -180 uint32_t p_align = 0x1000; // default page size on linux -181 emit(p_align); -182 if (p_offset % p_align != p_start % p_align) { -183 raise << "segment starting at 0x" << HEXWORD << p_start << " is improperly aligned; alignment for p_offset " << p_offset << " should be " << (p_offset % p_align) << " but is " << (p_start % p_align) << '\n' << end(); -184 return; -185 } -186 -187 // prepare for next segment -188 p_offset += size; -189 } -190 #undef O -191 #undef emit -192 } -193 -194 void write_segment(const segment& s, ostream& out) { -195 for (int i = 0; i < SIZE(s.lines); ++i) { -196 const vector<word>& w = s.lines.at(i).words; -197 for (int j = 0; j < SIZE(w); ++j) { -198 uint8_t x = hex_byte(w.at(j).data); // we're done with metadata by this point -199 out.write(reinterpret_cast<const char*>(&x), /*sizeof(byte)*/1); -200 } -201 } -202 } -203 -204 uint32_t num_words(const segment& s) { -205 uint32_t sum = 0; -206 for (int i = 0; i < SIZE(s.lines); ++i) -207 sum += SIZE(s.lines.at(i).words); -208 return sum; -209 } -210 -211 :(before "End Includes") -212 using std::ios; + 21 // Outside of tests, traces must be explicitly requested. + 22 if (Trace_file.is_open()) Trace_stream = new trace_stream; + 23 reset(); + 24 // Begin subx translate + 25 program p; + 26 string output_filename; + 27 for (int i = /*skip 'subx translate'*/2; i < argc; ++i) { + 28 if (is_equal(argv[i], "-o")) { + 29 ++i; + 30 if (i >= argc) { + 31 print_translate_usage(); + 32 cerr << "'-o' must be followed by a filename to write results to\n"; + 33 exit(1); + 34 } + 35 output_filename = argv[i]; + 36 } + 37 else { + 38 trace(2, "parse") << argv[i] << end(); + 39 ifstream fin(argv[i]); + 40 if (!fin) { + 41 cerr << "could not open " << argv[i] << '\n'; + 42 return 1; + 43 } + 44 parse(fin, p); + 45 if (trace_contains_errors()) return 1; + 46 } + 47 } + 48 if (p.segments.empty()) { + 49 print_translate_usage(); + 50 cerr << "nothing to do; must provide at least one file to read\n"; + 51 exit(1); + 52 } + 53 if (output_filename.empty()) { + 54 print_translate_usage(); + 55 cerr << "must provide a filename to write to using '-o'\n"; + 56 exit(1); + 57 } + 58 trace(2, "transform") << "begin" << end(); + 59 transform(p); + 60 if (trace_contains_errors()) return 1; + 61 trace(2, "translate") << "begin" << end(); + 62 save_elf(p, output_filename); + 63 if (trace_contains_errors()) { + 64 unlink(output_filename.c_str()); + 65 return 1; + 66 } + 67 // End subx translate + 68 return 0; + 69 } + 70 + 71 :(code) + 72 void print_translate_usage() { + 73 cerr << "Usage: subx translate file1 file2 ... -o output\n"; + 74 } + 75 + 76 // write out a program to a bare-bones ELF file + 77 void save_elf(const program& p, const string& filename) { + 78 ofstream out(filename.c_str(), ios::binary); + 79 save_elf(p, out); + 80 out.close(); + 81 } + 82 + 83 void save_elf(const program& p, ostream& out) { + 84 // validation: stay consistent with the self-hosted translator + 85 if (p.entry == 0) { + 86 raise << "no 'Entry' label found\n" << end(); + 87 return; + 88 } + 89 if (find(p, "data") == NULL) { + 90 raise << "must include a 'data' segment\n" << end(); + 91 return; + 92 } + 93 // processing + 94 write_elf_header(out, p); + 95 for (size_t i = 0; i < p.segments.size(); ++i) + 96 write_segment(p.segments.at(i), out); + 97 } + 98 + 99 void write_elf_header(ostream& out, const program& p) { +100 char c = '\0'; +101 #define O(X) c = (X); out.write(&c, sizeof(c)) +102 // host is required to be little-endian +103 #define emit(X) out.write(reinterpret_cast<const char*>(&X), sizeof(X)) +104 //// ehdr +105 // e_ident +106 O(0x7f); O(/*E*/0x45); O(/*L*/0x4c); O(/*F*/0x46); +107 O(0x1); // 32-bit format +108 O(0x1); // little-endian +109 O(0x1); O(0x0); +110 for (size_t i = 0; i < 8; ++i) { O(0x0); } +111 // e_type +112 O(0x02); O(0x00); +113 // e_machine +114 O(0x03); O(0x00); +115 // e_version +116 O(0x01); O(0x00); O(0x00); O(0x00); +117 // e_entry +118 uint32_t e_entry = p.entry; +119 // Override e_entry +120 emit(e_entry); +121 // e_phoff -- immediately after ELF header +122 uint32_t e_phoff = 0x34; +123 emit(e_phoff); +124 // e_shoff; unused +125 uint32_t dummy32 = 0; +126 emit(dummy32); +127 // e_flags; unused +128 emit(dummy32); +129 // e_ehsize +130 uint16_t e_ehsize = 0x34; +131 emit(e_ehsize); +132 // e_phentsize +133 uint16_t e_phentsize = 0x20; +134 emit(e_phentsize); +135 // e_phnum +136 uint16_t e_phnum = SIZE(p.segments); +137 emit(e_phnum); +138 // e_shentsize +139 uint16_t dummy16 = 0x0; +140 emit(dummy16); +141 // e_shnum +142 emit(dummy16); +143 // e_shstrndx +144 emit(dummy16); +145 +146 uint32_t p_offset = /*size of ehdr*/0x34 + SIZE(p.segments)*0x20/*size of each phdr*/; +147 for (int i = 0; i < SIZE(p.segments); ++i) { +148 const segment& curr = p.segments.at(i); +149 //// phdr +150 // p_type +151 uint32_t p_type = 0x1; +152 emit(p_type); +153 // p_offset +154 emit(p_offset); +155 // p_vaddr +156 uint32_t p_start = curr.start; +157 emit(p_start); +158 // p_paddr +159 emit(p_start); +160 // p_filesz +161 uint32_t size = num_words(curr); +162 assert(p_offset + size < SEGMENT_ALIGNMENT); +163 emit(size); +164 // p_memsz +165 emit(size); +166 // p_flags +167 uint32_t p_flags = (curr.name == "code") ? /*r-x*/0x5 : /*rw-*/0x6; +168 emit(p_flags); +169 +170 // p_align +171 // "As the system creates or augments a process image, it logically copies +172 // a file's segment to a virtual memory segment. When—and if— the system +173 // physically reads the file depends on the program's execution behavior, +174 // system load, and so on. A process does not require a physical page +175 // unless it references the logical page during execution, and processes +176 // commonly leave many pages unreferenced. Therefore delaying physical +177 // reads frequently obviates them, improving system performance. To obtain +178 // this efficiency in practice, executable and shared object files must +179 // have segment images whose file offsets and virtual addresses are +180 // congruent, modulo the page size." -- http://refspecs.linuxbase.org/elf/elf.pdf (page 95) +181 uint32_t p_align = 0x1000; // default page size on linux +182 emit(p_align); +183 if (p_offset % p_align != p_start % p_align) { +184 raise << "segment starting at 0x" << HEXWORD << p_start << " is improperly aligned; alignment for p_offset " << p_offset << " should be " << (p_offset % p_align) << " but is " << (p_start % p_align) << '\n' << end(); +185 return; +186 } +187 +188 // prepare for next segment +189 p_offset += size; +190 } +191 #undef O +192 #undef emit +193 } +194 +195 void write_segment(const segment& s, ostream& out) { +196 for (int i = 0; i < SIZE(s.lines); ++i) { +197 const vector<word>& w = s.lines.at(i).words; +198 for (int j = 0; j < SIZE(w); ++j) { +199 uint8_t x = hex_byte(w.at(j).data); // we're done with metadata by this point +200 out.write(reinterpret_cast<const char*>(&x), /*sizeof(byte)*/1); +201 } +202 } +203 } +204 +205 uint32_t num_words(const segment& s) { +206 uint32_t sum = 0; +207 for (int i = 0; i < SIZE(s.lines); ++i) +208 sum += SIZE(s.lines.at(i).words); +209 return sum; +210 } +211 +212 :(before "End Includes") +213 using std::ios; diff --git a/html/030---operands.cc.html b/html/030---operands.cc.html index faf0a21a..46498b39 100644 --- a/html/030---operands.cc.html +++ b/html/030---operands.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/032check_operand_bounds.cc.html b/html/032check_operand_bounds.cc.html index a6cae0de..ae3bd972 100644 --- a/html/032check_operand_bounds.cc.html +++ b/html/032check_operand_bounds.cc.html @@ -14,6 +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; } +.cSpecial { color: #008000; } .LineNr { } .Constant { color: #008787; } .Comment { color: #005faf; } @@ -21,7 +22,6 @@ a { color:inherit; } .Special { color: #d70000; } .Identifier { color: #af5f00; } .Delimiter { color: #c000c0; } -.cSpecial { color: #008000; } .SalientComment { color: #0000af; } --> diff --git a/html/038---literal_strings.cc.html b/html/038---literal_strings.cc.html index 3c7d3842..07e85f14 100644 --- a/html/038---literal_strings.cc.html +++ b/html/038---literal_strings.cc.html @@ -14,6 +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; } +.CommentedCode { color: #8a8a8a; } .LineNr { } .Constant { color: #008787; } .Comment { color: #005faf; } @@ -71,7 +72,7 @@ if ('onhashchange' in window) { 12 CHECK_TRACE_CONTENTS( 13 "transform: -- move literal strings to data segment\n" 14 "transform: adding global variable '__subx_global_1' containing \"test\"\n" - 15 "transform: instruction after transform: 'b8 __subx_global_1'\n" + 15 "transform: line after transform: 'b8 __subx_global_1'\n" 16 ); 17 } 18 @@ -80,307 +81,332 @@ if ('onhashchange' in window) { 21 //: layers to transform. 22 :(after "Begin Transforms") 23 // Begin Level-3 Transforms - 24 Transform.push_back(transform_literal_strings); + 24 Transform.push_back(transform_literal_strings); 25 // End Level-3 Transforms 26 27 :(before "End Globals") - 28 int Next_auto_global = 1; - 29 :(code) - 30 void transform_literal_strings(program& p) { - 31 trace(3, "transform") << "-- move literal strings to data segment" << end(); - 32 if (p.segments.empty()) return; - 33 segment& code = *find(p, "code"); - 34 segment& data = *find(p, "data"); - 35 for (int i = 0; i < SIZE(code.lines); ++i) { - 36 line& inst = code.lines.at(i); - 37 for (int j = 0; j < SIZE(inst.words); ++j) { - 38 word& curr = inst.words.at(j); - 39 if (curr.data.at(0) != '"') continue; - 40 ostringstream global_name; - 41 global_name << "__subx_global_" << Next_auto_global; - 42 ++Next_auto_global; - 43 add_global_to_data_segment(global_name.str(), curr, data); - 44 curr.data = global_name.str(); - 45 } - 46 trace(99, "transform") << "instruction after transform: '" << data_to_string(inst) << "'" << end(); - 47 } - 48 } - 49 - 50 void add_global_to_data_segment(const string& name, const word& value, segment& data) { - 51 trace(99, "transform") << "adding global variable '" << name << "' containing " << value.data << end(); - 52 // emit label - 53 data.lines.push_back(label(name)); - 54 // emit size for size-prefixed array - 55 data.lines.push_back(line()); - 56 emit_hex_bytes(data.lines.back(), SIZE(value.data)-/*skip quotes*/2, 4/*bytes*/); - 57 // emit data byte by byte - 58 data.lines.push_back(line()); - 59 line& curr = data.lines.back(); - 60 for (int i = /*skip start quote*/1; i < SIZE(value.data)-/*skip end quote*/1; ++i) { - 61 char c = value.data.at(i); - 62 curr.words.push_back(word()); - 63 curr.words.back().data = hex_byte_to_string(c); - 64 curr.words.back().metadata.push_back(string(1, c)); - 65 } - 66 } - 67 - 68 //: Within strings, whitespace is significant. So we need to redo our instruction - 69 //: parsing. - 70 - 71 void test_instruction_with_string_literal() { - 72 parse_instruction_character_by_character( - 73 "a \"abc def\" z\n" // two spaces inside string - 74 ); - 75 CHECK_TRACE_CONTENTS( - 76 "parse2: word: a\n" - 77 "parse2: word: \"abc def\"\n" - 78 "parse2: word: z\n" - 79 ); - 80 // no other words - 81 CHECK_TRACE_COUNT("parse2", 3); - 82 } - 83 - 84 :(before "End Line Parsing Special-cases(line_data -> l)") - 85 if (line_data.find('"') != string::npos) { // can cause false-positives, but we can handle them - 86 parse_instruction_character_by_character(line_data, l); - 87 continue; - 88 } - 89 - 90 :(code) - 91 void parse_instruction_character_by_character(const string& line_data, vector<line>& out) { - 92 if (line_data.find('\n') != string::npos && line_data.find('\n') != line_data.size()-1) { - 93 raise << "parse_instruction_character_by_character: should receive only a single line\n" << end(); - 94 return; - 95 } - 96 // parse literals - 97 istringstream in(line_data); - 98 in >> std::noskipws; - 99 line result; -100 result.original = line_data; -101 // add tokens (words or strings) one by one -102 while (has_data(in)) { -103 skip_whitespace(in); -104 if (!has_data(in)) break; -105 char c = in.get(); -106 if (c == '#') break; // comment; drop rest of line -107 if (c == ':') break; // line metadata; skip for now -108 if (c == '.') { -109 if (!has_data(in)) break; // comment token at end of line -110 if (isspace(in.peek())) -111 continue; // '.' followed by space is comment token; skip -112 } -113 result.words.push_back(word()); -114 if (c == '"') { -115 // string literal; slurp everything between quotes into data -116 ostringstream d; -117 d << c; -118 while (has_data(in)) { -119 in >> c; -120 if (c == '\\') { -121 in >> c; -122 if (c == 'n') d << '\n'; -123 else if (c == '"') d << '"'; -124 else if (c == '\\') d << '\\'; -125 else { -126 raise << "parse_instruction_character_by_character: unknown escape sequence '\\" << c << "'\n" << end(); -127 return; -128 } -129 continue; -130 } else { -131 d << c; -132 } -133 if (c == '"') break; -134 } -135 result.words.back().data = d.str(); -136 // slurp metadata -137 ostringstream m; -138 while (!isspace(in.peek()) && has_data(in)) { // peek can sometimes trigger eof(), so do it first -139 in >> c; -140 if (c == '/') { -141 if (!m.str().empty()) result.words.back().metadata.push_back(m.str()); -142 m.str(""); -143 } -144 else { -145 m << c; -146 } -147 } -148 if (!m.str().empty()) result.words.back().metadata.push_back(m.str()); -149 } -150 else { -151 // not a string literal; slurp all characters until whitespace -152 ostringstream w; -153 w << c; -154 while (!isspace(in.peek()) && has_data(in)) { // peek can sometimes trigger eof(), so do it first -155 in >> c; -156 w << c; -157 } -158 parse_word(w.str(), result.words.back()); -159 } -160 trace(99, "parse2") << "word: " << to_string(result.words.back()) << end(); -161 } -162 if (!result.words.empty()) -163 out.push_back(result); -164 } -165 -166 void skip_whitespace(istream& in) { -167 while (true) { -168 if (has_data(in) && isspace(in.peek())) in.get(); -169 else break; -170 } -171 } -172 -173 void skip_comment(istream& in) { -174 if (has_data(in) && in.peek() == '#') { -175 in.get(); -176 while (has_data(in) && in.peek() != '\n') in.get(); -177 } -178 } -179 -180 line label(string s) { -181 line result; -182 result.words.push_back(word()); -183 result.words.back().data = (s+":"); -184 return result; -185 } -186 -187 // helper for tests -188 void parse_instruction_character_by_character(const string& line_data) { -189 vector<line> out; -190 parse_instruction_character_by_character(line_data, out); -191 } -192 -193 void test_parse2_comment_token_in_middle() { -194 parse_instruction_character_by_character( -195 "a . z\n" -196 ); -197 CHECK_TRACE_CONTENTS( -198 "parse2: word: a\n" -199 "parse2: word: z\n" -200 ); -201 CHECK_TRACE_DOESNT_CONTAIN("parse2: word: ."); -202 // no other words -203 CHECK_TRACE_COUNT("parse2", 2); -204 } -205 -206 void test_parse2_word_starting_with_dot() { -207 parse_instruction_character_by_character( -208 "a .b c\n" -209 ); -210 CHECK_TRACE_CONTENTS( -211 "parse2: word: a\n" -212 "parse2: word: .b\n" -213 "parse2: word: c\n" -214 ); -215 } -216 -217 void test_parse2_comment_token_at_start() { -218 parse_instruction_character_by_character( -219 ". a b\n" -220 ); -221 CHECK_TRACE_CONTENTS( -222 "parse2: word: a\n" -223 "parse2: word: b\n" -224 ); -225 CHECK_TRACE_DOESNT_CONTAIN("parse2: word: ."); -226 } -227 -228 void test_parse2_comment_token_at_end() { -229 parse_instruction_character_by_character( -230 "a b .\n" -231 ); -232 CHECK_TRACE_CONTENTS( -233 "parse2: word: a\n" -234 "parse2: word: b\n" -235 ); -236 CHECK_TRACE_DOESNT_CONTAIN("parse2: word: ."); -237 } -238 -239 void test_parse2_word_starting_with_dot_at_start() { -240 parse_instruction_character_by_character( -241 ".a b c\n" -242 ); -243 CHECK_TRACE_CONTENTS( -244 "parse2: word: .a\n" -245 "parse2: word: b\n" -246 "parse2: word: c\n" -247 ); -248 } -249 -250 void test_parse2_metadata() { -251 parse_instruction_character_by_character( -252 ".a b/c d\n" -253 ); -254 CHECK_TRACE_CONTENTS( -255 "parse2: word: .a\n" -256 "parse2: word: b /c\n" -257 "parse2: word: d\n" -258 ); -259 } -260 -261 void test_parse2_string_with_metadata() { -262 parse_instruction_character_by_character( -263 "a \"bc def\"/disp32 g\n" -264 ); -265 CHECK_TRACE_CONTENTS( -266 "parse2: word: a\n" -267 "parse2: word: \"bc def\" /disp32\n" -268 "parse2: word: g\n" -269 ); -270 } -271 -272 void test_parse2_string_with_metadata_at_end() { -273 parse_instruction_character_by_character( -274 "a \"bc def\"/disp32\n" -275 ); -276 CHECK_TRACE_CONTENTS( -277 "parse2: word: a\n" -278 "parse2: word: \"bc def\" /disp32\n" -279 ); -280 } -281 -282 void test_parse2_string_with_metadata_at_end_of_line_without_newline() { -283 parse_instruction_character_by_character( -284 "68/push \"test\"/f" // no newline, which is how calls from parse() will look -285 ); -286 CHECK_TRACE_CONTENTS( -287 "parse2: word: 68 /push\n" -288 "parse2: word: \"test\" /f\n" + 28 int Next_auto_global = 1; + 29 :(before "End Reset") + 30 Next_auto_global = 1; + 31 :(code) + 32 void transform_literal_strings(program& p) { + 33 trace(3, "transform") << "-- move literal strings to data segment" << end(); + 34 if (p.segments.empty()) return; + 35 vector<line> new_lines; + 36 for (int s = 0; s < SIZE(p.segments); ++s) { + 37 segment& seg = p.segments.at(s); + 38 trace(99, "transform") << "segment '" << seg.name << "'" << end(); + 39 for (int i = 0; i < SIZE(seg.lines); ++i) { + 40 //? cerr << seg.name << '/' << i << '\n'; + 41 line& line = seg.lines.at(i); + 42 for (int j = 0; j < SIZE(line.words); ++j) { + 43 word& curr = line.words.at(j); + 44 if (curr.data.at(0) != '"') continue; + 45 ostringstream global_name; + 46 global_name << "__subx_global_" << Next_auto_global; + 47 ++Next_auto_global; + 48 add_global_to_data_segment(global_name.str(), curr, new_lines); + 49 curr.data = global_name.str(); + 50 } + 51 trace(99, "transform") << "line after transform: '" << data_to_string(line) << "'" << end(); + 52 } + 53 } + 54 segment* data = find(p, "data"); + 55 if (data) + 56 data->lines.insert(data->lines.end(), new_lines.begin(), new_lines.end()); + 57 } + 58 + 59 void add_global_to_data_segment(const string& name, const word& value, vector<line>& out) { + 60 trace(99, "transform") << "adding global variable '" << name << "' containing " << value.data << end(); + 61 // emit label + 62 out.push_back(label(name)); + 63 // emit size for size-prefixed array + 64 out.push_back(line()); + 65 emit_hex_bytes(out.back(), SIZE(value.data)-/*skip quotes*/2, 4/*bytes*/); + 66 // emit data byte by byte + 67 out.push_back(line()); + 68 line& curr = out.back(); + 69 for (int i = /*skip start quote*/1; i < SIZE(value.data)-/*skip end quote*/1; ++i) { + 70 char c = value.data.at(i); + 71 curr.words.push_back(word()); + 72 curr.words.back().data = hex_byte_to_string(c); + 73 curr.words.back().metadata.push_back(string(1, c)); + 74 } + 75 } + 76 + 77 //: Within strings, whitespace is significant. So we need to redo our instruction + 78 //: parsing. + 79 + 80 void test_instruction_with_string_literal() { + 81 parse_instruction_character_by_character( + 82 "a \"abc def\" z\n" // two spaces inside string + 83 ); + 84 CHECK_TRACE_CONTENTS( + 85 "parse2: word: a\n" + 86 "parse2: word: \"abc def\"\n" + 87 "parse2: word: z\n" + 88 ); + 89 // no other words + 90 CHECK_TRACE_COUNT("parse2", 3); + 91 } + 92 + 93 void test_string_literal_in_data_segment() { + 94 run( + 95 "== code 0x1\n" + 96 "b8/copy X/imm32\n" + 97 "== data 0x2000\n" + 98 "X:\n" + 99 "\"test\"/imm32\n" +100 ); +101 CHECK_TRACE_CONTENTS( +102 "transform: -- move literal strings to data segment\n" +103 "transform: adding global variable '__subx_global_1' containing \"test\"\n" +104 "transform: line after transform: '__subx_global_1'\n" +105 ); +106 } +107 +108 :(before "End Line Parsing Special-cases(line_data -> l)") +109 if (line_data.find('"') != string::npos) { // can cause false-positives, but we can handle them +110 parse_instruction_character_by_character(line_data, l); +111 continue; +112 } +113 +114 :(code) +115 void parse_instruction_character_by_character(const string& line_data, vector<line>& out) { +116 if (line_data.find('\n') != string::npos && line_data.find('\n') != line_data.size()-1) { +117 raise << "parse_instruction_character_by_character: should receive only a single line\n" << end(); +118 return; +119 } +120 // parse literals +121 istringstream in(line_data); +122 in >> std::noskipws; +123 line result; +124 result.original = line_data; +125 // add tokens (words or strings) one by one +126 while (has_data(in)) { +127 skip_whitespace(in); +128 if (!has_data(in)) break; +129 char c = in.get(); +130 if (c == '#') break; // comment; drop rest of line +131 if (c == ':') break; // line metadata; skip for now +132 if (c == '.') { +133 if (!has_data(in)) break; // comment token at end of line +134 if (isspace(in.peek())) +135 continue; // '.' followed by space is comment token; skip +136 } +137 result.words.push_back(word()); +138 if (c == '"') { +139 // string literal; slurp everything between quotes into data +140 ostringstream d; +141 d << c; +142 while (has_data(in)) { +143 in >> c; +144 if (c == '\\') { +145 in >> c; +146 if (c == 'n') d << '\n'; +147 else if (c == '"') d << '"'; +148 else if (c == '\\') d << '\\'; +149 else { +150 raise << "parse_instruction_character_by_character: unknown escape sequence '\\" << c << "'\n" << end(); +151 return; +152 } +153 continue; +154 } else { +155 d << c; +156 } +157 if (c == '"') break; +158 } +159 result.words.back().data = d.str(); +160 result.words.back().original = d.str(); +161 // slurp metadata +162 ostringstream m; +163 while (!isspace(in.peek()) && has_data(in)) { // peek can sometimes trigger eof(), so do it first +164 in >> c; +165 if (c == '/') { +166 if (!m.str().empty()) result.words.back().metadata.push_back(m.str()); +167 m.str(""); +168 } +169 else { +170 m << c; +171 } +172 } +173 if (!m.str().empty()) result.words.back().metadata.push_back(m.str()); +174 } +175 else { +176 // not a string literal; slurp all characters until whitespace +177 ostringstream w; +178 w << c; +179 while (!isspace(in.peek()) && has_data(in)) { // peek can sometimes trigger eof(), so do it first +180 in >> c; +181 w << c; +182 } +183 parse_word(w.str(), result.words.back()); +184 } +185 trace(99, "parse2") << "word: " << to_string(result.words.back()) << end(); +186 } +187 if (!result.words.empty()) +188 out.push_back(result); +189 } +190 +191 void skip_whitespace(istream& in) { +192 while (true) { +193 if (has_data(in) && isspace(in.peek())) in.get(); +194 else break; +195 } +196 } +197 +198 void skip_comment(istream& in) { +199 if (has_data(in) && in.peek() == '#') { +200 in.get(); +201 while (has_data(in) && in.peek() != '\n') in.get(); +202 } +203 } +204 +205 line label(string s) { +206 line result; +207 result.words.push_back(word()); +208 result.words.back().data = (s+":"); +209 return result; +210 } +211 +212 // helper for tests +213 void parse_instruction_character_by_character(const string& line_data) { +214 vector<line> out; +215 parse_instruction_character_by_character(line_data, out); +216 } +217 +218 void test_parse2_comment_token_in_middle() { +219 parse_instruction_character_by_character( +220 "a . z\n" +221 ); +222 CHECK_TRACE_CONTENTS( +223 "parse2: word: a\n" +224 "parse2: word: z\n" +225 ); +226 CHECK_TRACE_DOESNT_CONTAIN("parse2: word: ."); +227 // no other words +228 CHECK_TRACE_COUNT("parse2", 2); +229 } +230 +231 void test_parse2_word_starting_with_dot() { +232 parse_instruction_character_by_character( +233 "a .b c\n" +234 ); +235 CHECK_TRACE_CONTENTS( +236 "parse2: word: a\n" +237 "parse2: word: .b\n" +238 "parse2: word: c\n" +239 ); +240 } +241 +242 void test_parse2_comment_token_at_start() { +243 parse_instruction_character_by_character( +244 ". a b\n" +245 ); +246 CHECK_TRACE_CONTENTS( +247 "parse2: word: a\n" +248 "parse2: word: b\n" +249 ); +250 CHECK_TRACE_DOESNT_CONTAIN("parse2: word: ."); +251 } +252 +253 void test_parse2_comment_token_at_end() { +254 parse_instruction_character_by_character( +255 "a b .\n" +256 ); +257 CHECK_TRACE_CONTENTS( +258 "parse2: word: a\n" +259 "parse2: word: b\n" +260 ); +261 CHECK_TRACE_DOESNT_CONTAIN("parse2: word: ."); +262 } +263 +264 void test_parse2_word_starting_with_dot_at_start() { +265 parse_instruction_character_by_character( +266 ".a b c\n" +267 ); +268 CHECK_TRACE_CONTENTS( +269 "parse2: word: .a\n" +270 "parse2: word: b\n" +271 "parse2: word: c\n" +272 ); +273 } +274 +275 void test_parse2_metadata() { +276 parse_instruction_character_by_character( +277 ".a b/c d\n" +278 ); +279 CHECK_TRACE_CONTENTS( +280 "parse2: word: .a\n" +281 "parse2: word: b /c\n" +282 "parse2: word: d\n" +283 ); +284 } +285 +286 void test_parse2_string_with_metadata() { +287 parse_instruction_character_by_character( +288 "a \"bc def\"/disp32 g\n" 289 ); -290 } -291 -292 //: Make sure slashes inside strings don't trigger adding stuff from inside the -293 //: string to metadata. -294 -295 void test_parse2_string_containing_slashes() { -296 parse_instruction_character_by_character( -297 "a \"bc/def\"/disp32\n" -298 ); -299 CHECK_TRACE_CONTENTS( -300 "parse2: word: \"bc/def\" /disp32\n" -301 ); -302 } -303 -304 void test_instruction_with_string_literal_with_escaped_quote() { -305 parse_instruction_character_by_character( -306 "\"a\\\"b\"\n" // escaped quote inside string -307 ); -308 CHECK_TRACE_CONTENTS( -309 "parse2: word: \"a\"b\"\n" +290 CHECK_TRACE_CONTENTS( +291 "parse2: word: a\n" +292 "parse2: word: \"bc def\" /disp32\n" +293 "parse2: word: g\n" +294 ); +295 } +296 +297 void test_parse2_string_with_metadata_at_end() { +298 parse_instruction_character_by_character( +299 "a \"bc def\"/disp32\n" +300 ); +301 CHECK_TRACE_CONTENTS( +302 "parse2: word: a\n" +303 "parse2: word: \"bc def\" /disp32\n" +304 ); +305 } +306 +307 void test_parse2_string_with_metadata_at_end_of_line_without_newline() { +308 parse_instruction_character_by_character( +309 "68/push \"test\"/f" // no newline, which is how calls from parse() will look 310 ); -311 // no other words -312 CHECK_TRACE_COUNT("parse2", 1); -313 } -314 -315 void test_instruction_with_string_literal_with_escaped_backslash() { -316 parse_instruction_character_by_character( -317 "\"a\\\\b\"\n" // escaped backslash inside string -318 ); -319 CHECK_TRACE_CONTENTS( -320 "parse2: word: \"a\\b\"\n" -321 ); -322 // no other words -323 CHECK_TRACE_COUNT("parse2", 1); -324 } +311 CHECK_TRACE_CONTENTS( +312 "parse2: word: 68 /push\n" +313 "parse2: word: \"test\" /f\n" +314 ); +315 } +316 +317 //: Make sure slashes inside strings don't trigger adding stuff from inside the +318 //: string to metadata. +319 +320 void test_parse2_string_containing_slashes() { +321 parse_instruction_character_by_character( +322 "a \"bc/def\"/disp32\n" +323 ); +324 CHECK_TRACE_CONTENTS( +325 "parse2: word: \"bc/def\" /disp32\n" +326 ); +327 } +328 +329 void test_instruction_with_string_literal_with_escaped_quote() { +330 parse_instruction_character_by_character( +331 "\"a\\\"b\"\n" // escaped quote inside string +332 ); +333 CHECK_TRACE_CONTENTS( +334 "parse2: word: \"a\"b\"\n" +335 ); +336 // no other words +337 CHECK_TRACE_COUNT("parse2", 1); +338 } +339 +340 void test_instruction_with_string_literal_with_escaped_backslash() { +341 parse_instruction_character_by_character( +342 "\"a\\\\b\"\n" // escaped backslash inside string +343 ); +344 CHECK_TRACE_CONTENTS( +345 "parse2: word: \"a\\b\"\n" +346 ); +347 // no other words +348 CHECK_TRACE_COUNT("parse2", 1); +349 } diff --git a/html/050_write.subx.html b/html/050_write.subx.html index da3cd835..0870917b 100644 --- a/html/050_write.subx.html +++ b/html/050_write.subx.html @@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } +.subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.Constant { color: #008787; } .subxMinorFunction { color: #875f5f; } -.subxS2Comment { color: #8a8a8a; } +.Constant { color: #008787; } --> diff --git a/html/051test.subx.html b/html/051test.subx.html index 235c5788..4247ae36 100644 --- a/html/051test.subx.html +++ b/html/051test.subx.html @@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Constant { color: #008787; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxS2Comment { color: #8a8a8a; } --> diff --git a/html/052kernel-string-equal.subx.html b/html/052kernel-string-equal.subx.html index ba70c9a7..d1257e5e 100644 --- a/html/052kernel-string-equal.subx.html +++ b/html/052kernel-string-equal.subx.html @@ -14,17 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxS2Comment { color: #8a8a8a; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxMinorFunction { color: #875f5f; } -.subxTest { color: #5f8700; } +.Constant { color: #008787; } +.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> diff --git a/html/053new-segment.subx.html b/html/053new-segment.subx.html index 19b7cfde..aca8a347 100644 --- a/html/053new-segment.subx.html +++ b/html/053new-segment.subx.html @@ -15,14 +15,14 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxMinorFunction { color: #875f5f; } -.subxS2Comment { color: #8a8a8a; } +.Constant { color: #008787; } --> diff --git a/html/054string-equal.subx.html b/html/054string-equal.subx.html index 2bf6831c..39942aa3 100644 --- a/html/054string-equal.subx.html +++ b/html/054string-equal.subx.html @@ -14,17 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } +.subxS1Comment { color: #0000af; } +.CommentedCode { color: #8a8a8a; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxS2Comment { color: #8a8a8a; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } .subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> diff --git a/html/055stream.subx.html b/html/055stream.subx.html index 9eec2d00..75c81244 100644 --- a/html/055stream.subx.html +++ b/html/055stream.subx.html @@ -15,12 +15,12 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.Constant { color: #008787; } --> diff --git a/html/056trace.subx.html b/html/056trace.subx.html index 2a3cd2e5..d6033fd0 100644 --- a/html/056trace.subx.html +++ b/html/056trace.subx.html @@ -14,18 +14,18 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } -.subxTest { color: #5f8700; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } +.subxFunction { color: #af5f00; text-decoration: underline; } .subxH1Comment { color: #005faf; text-decoration: underline; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.CommentedCode { color: #8a8a8a; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxMinorFunction { color: #875f5f; } .subxS2Comment { color: #8a8a8a; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/057write.subx.html b/html/057write.subx.html index 2d0c2193..06b88a4d 100644 --- a/html/057write.subx.html +++ b/html/057write.subx.html @@ -15,14 +15,14 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxMinorFunction { color: #875f5f; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/058stream-equal.subx.html b/html/058stream-equal.subx.html index 305a50a3..9c4cdede 100644 --- a/html/058stream-equal.subx.html +++ b/html/058stream-equal.subx.html @@ -14,12 +14,12 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxS2Comment { color: #8a8a8a; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxS1Comment { color: #0000af; } .subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } .subxTest { color: #5f8700; } --> diff --git a/html/059stop.subx.html b/html/059stop.subx.html index ddd44270..a18d9068 100644 --- a/html/059stop.subx.html +++ b/html/059stop.subx.html @@ -14,15 +14,15 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.CommentedCode { color: #8a8a8a; } .subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .subxMinorFunction { color: #875f5f; } +.Constant { color: #008787; } .subxTest { color: #5f8700; } --> @@ -100,171 +100,173 @@ if ('onhashchange' in window) { 39 40 # Configure an exit-descriptor for a call pushing 'nbytes' bytes of args to 41 # the stack. - 42 # Ugly that we need to know the size of args, but so it goes. - 43 tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void> - 44 # . prolog - 45 55/push-EBP - 46 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 47 # . save registers - 48 50/push-EAX - 49 51/push-ECX - 50 # EAX = nbytes - 51 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX - 52 # Let X be the value of ESP in the caller, before the call to tailor-exit-descriptor. - 53 # The return address for a call in the caller's body will be at: - 54 # X-8 if the caller takes 4 bytes of args for the exit-descriptor (add 4 bytes for the return address) - 55 # X-12 if the caller takes 8 bytes of args - 56 # ..and so on - 57 # That's the value we need to return: X-nbytes-4 - 58 # - 59 # However, we also need to account for the perturbance to ESP caused by the - 60 # call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4 - 61 # bytes for the return address and 4 bytes to push EBP above. - 62 # So EBP at this point is X-16. - 63 # - 64 # So the return address for the next call in the caller is: - 65 # EBP+8 if the caller takes 4 bytes of args - 66 # EBP+4 if the caller takes 8 bytes of args - 67 # EBP if the caller takes 12 bytes of args - 68 # EBP-4 if the caller takes 16 bytes of args - 69 # ..and so on - 70 # That's EBP+12-nbytes. - 71 # option 1: 6 + 3 bytes - 72 #? 2d/subtract 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # subtract from EAX - 73 #? 8d/copy-address 0/mod/indirect 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX . . # copy EBP+EAX to EAX - 74 # option 2: 2 + 4 bytes - 75 f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX - 76 8d/copy-address 1/mod/*+disp8 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EBP+EAX+12 to EAX - 77 # copy EAX to ed->target - 78 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - 79 89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX - 80 # initialize ed->value - 81 c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4) - 82 $tailor-exit-descriptor:end: - 83 # . restore registers - 84 59/pop-to-ECX - 85 58/pop-to-EAX - 86 # . epilog - 87 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 88 5d/pop-to-EBP - 89 c3/return - 90 - 91 stop: # ed : (address exit-descriptor), value : int - 92 # no prolog; one way or another, we're going to clobber registers - 93 # EAX = ed - 94 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # copy *(ESP+4) to EAX - 95 # if (ed->target == 0) really exit - 96 81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX - 97 75/jump-if-not-equal $stop:fake/disp8 - 98 # . syscall(exit, value) - 99 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(ESP+8) to EBX -100 b8/copy-to-EAX 1/imm32/exit -101 cd/syscall 0x80/imm8 -102 $stop:fake: -103 # otherwise: -104 # ed->value = value+1 -105 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(ESP+8) to ECX -106 41/increment-ECX -107 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4) -108 # perform a non-local jump to ed->target -109 8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP -110 $stop:end: -111 c3/return # doesn't return to caller -112 -113 test-stop-skips-returns-on-exit: -114 # This looks like the standard prolog, but is here for different reasons. -115 # A function calling 'stop' can't rely on EBP persisting past the call. -116 # -117 # Use EBP here as a stable base to refer to locals and arguments from in the -118 # presence of push/pop/call instructions. -119 # *Don't* use EBP as a way to restore ESP. -120 55/push-EBP -121 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -122 # Make room for an exit descriptor on the stack. That's almost always the -123 # right place for it, available only as long as it's legal to use. Once this -124 # containing function returns we'll need a new exit descriptor. -125 # var ed/EAX : (address exit-descriptor) -126 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP -127 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX -128 # Size the exit-descriptor precisely for the next call below, to _test-stop-1. -129 # tailor-exit-descriptor(ed, 4) -130 # . . push args -131 68/push 4/imm32/nbytes-of-args-for-_test-stop-1 -132 50/push-EAX -133 # . . call -134 e8/call tailor-exit-descriptor/disp32 -135 # . . discard args -136 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -137 # . _test-stop-1(ed) -138 # . . push args -139 50/push-EAX -140 # . . call -141 e8/call _test-stop-1/disp32 -142 # registers except ESP may be clobbered at this point -143 # restore args -144 58/pop-to-EAX -145 # check that _test-stop-1 tried to call exit(1) -146 # check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 -147 # . . push args -148 68/push "F - test-stop-skips-returns-on-exit"/imm32 -149 68/push 2/imm32 -150 # . . push ed->value -151 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -152 # . . call -153 e8/call check-ints-equal/disp32 -154 # . . discard args -155 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -156 # . epilog -157 # don't restore ESP from EBP; manually reclaim locals -158 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -159 5d/pop-to-EBP -160 c3/return -161 -162 _test-stop-1: # ed : (address exit-descriptor) -163 # . prolog -164 55/push-EBP -165 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -166 # _test-stop-2(ed) -167 # . . push args -168 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -169 # . . call -170 e8/call _test-stop-2/disp32 -171 # should never get past this point -172 $_test-stop-1:dead-end: -173 # . . discard args -174 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -175 # signal test failed: check-ints-equal(1, 0, msg) -176 # . . push args -177 68/push "F - test-stop-skips-returns-on-exit"/imm32 -178 68/push 0/imm32 -179 68/push 1/imm32 -180 # . . call -181 e8/call check-ints-equal/disp32 -182 # . . discard args -183 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -184 # . epilog -185 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -186 5d/pop-to-EBP -187 c3/return -188 -189 _test-stop-2: # ed : (address exit-descriptor) -190 # . prolog -191 55/push-EBP -192 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -193 # . stop(ed, 1) -194 # . . push args -195 68/push 1/imm32 -196 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -197 # . . call -198 e8/call stop/disp32 -199 # should never get past this point -200 $_test-stop-2:dead-end: -201 # . epilog -202 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -203 5d/pop-to-EBP -204 c3/return -205 -206 # . . vim:nowrap:textwidth=0 + 42 # Ugly that we need to know the size of args. Don't allocate variables between + 43 # tailor-exit-descriptor and the call it's for. + 44 tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void> + 45 # . prolog + 46 55/push-EBP + 47 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 48 # . save registers + 49 50/push-EAX + 50 51/push-ECX + 51 # EAX = nbytes + 52 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX + 53 # Let X be the value of ESP in the caller, before the call to tailor-exit-descriptor. + 54 # The return address for a call in the caller's body will be at: + 55 # X-8 if the caller takes 4 bytes of args for the exit-descriptor (add 4 bytes for the return address) + 56 # X-12 if the caller takes 8 bytes of args + 57 # ..and so on + 58 # That's the value we need to return: X-nbytes-4 + 59 # + 60 # However, we also need to account for the perturbance to ESP caused by the + 61 # call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4 + 62 # bytes for the return address and 4 bytes to push EBP above. + 63 # So EBP at this point is X-16. + 64 # + 65 # So the return address for the next call in the caller is: + 66 # EBP+8 if the caller takes 4 bytes of args + 67 # EBP+4 if the caller takes 8 bytes of args + 68 # EBP if the caller takes 12 bytes of args + 69 # EBP-4 if the caller takes 16 bytes of args + 70 # ..and so on + 71 # That's EBP+12-nbytes. + 72 # option 1: 6 + 3 bytes + 73 #? 2d/subtract 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # subtract from EAX + 74 #? 8d/copy-address 0/mod/indirect 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX . . # copy EBP+EAX to EAX + 75 # option 2: 2 + 4 bytes + 76 f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX + 77 8d/copy-address 1/mod/*+disp8 4/rm32/sib 5/base/EBP 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EBP+EAX+12 to EAX + 78 # copy EAX to ed->target + 79 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX + 80 89/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to *ECX + 81 # initialize ed->value + 82 c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # copy to *(ECX+4) + 83 $tailor-exit-descriptor:end: + 84 # . restore registers + 85 59/pop-to-ECX + 86 58/pop-to-EAX + 87 # . epilog + 88 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 89 5d/pop-to-EBP + 90 c3/return + 91 + 92 stop: # ed : (address exit-descriptor), value : int + 93 # no prolog; one way or another, we're going to clobber registers + 94 # EAX = ed + 95 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # copy *(ESP+4) to EAX + 96 # if (ed->target == 0) really exit + 97 81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX + 98 75/jump-if-not-equal $stop:fake/disp8 + 99 # . syscall(exit, value) +100 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(ESP+8) to EBX +101 b8/copy-to-EAX 1/imm32/exit +102 cd/syscall 0x80/imm8 +103 $stop:fake: +104 # otherwise: +105 # ed->value = value+1 +106 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(ESP+8) to ECX +107 41/increment-ECX +108 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4) +109 # perform a non-local jump to ed->target +110 8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP +111 $stop:end: +112 c3/return # doesn't return to caller +113 +114 test-stop-skips-returns-on-exit: +115 # This looks like the standard prolog, but is here for different reasons. +116 # A function calling 'stop' can't rely on EBP persisting past the call. +117 # +118 # Use EBP here as a stable base to refer to locals and arguments from in the +119 # presence of push/pop/call instructions. +120 # *Don't* use EBP as a way to restore ESP. +121 55/push-EBP +122 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +123 # Make room for an exit descriptor on the stack. That's almost always the +124 # right place for it, available only as long as it's legal to use. Once this +125 # containing function returns we'll need a new exit descriptor. +126 # var ed/EAX : (address exit-descriptor) +127 68/push 0/imm32 +128 68/push 0/imm32 +129 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX +130 # Size the exit-descriptor precisely for the next call below, to _test-stop-1. +131 # tailor-exit-descriptor(ed, 4) +132 # . . push args +133 68/push 4/imm32/nbytes-of-args-for-_test-stop-1 +134 50/push-EAX +135 # . . call +136 e8/call tailor-exit-descriptor/disp32 +137 # . . discard args +138 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +139 # . _test-stop-1(ed) +140 # . . push args +141 50/push-EAX +142 # . . call +143 e8/call _test-stop-1/disp32 +144 # registers except ESP may be clobbered at this point +145 # restore args +146 58/pop-to-EAX +147 # check that _test-stop-1 tried to call exit(1) +148 # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 +149 # . . push args +150 68/push "F - test-stop-skips-returns-on-exit"/imm32 +151 68/push 2/imm32 +152 # . . push ed->value +153 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +154 # . . call +155 e8/call check-ints-equal/disp32 +156 # . . discard args +157 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +158 # . epilog +159 # don't restore ESP from EBP; manually reclaim locals +160 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +161 5d/pop-to-EBP +162 c3/return +163 +164 _test-stop-1: # ed : (address exit-descriptor) +165 # . prolog +166 55/push-EBP +167 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +168 # _test-stop-2(ed) +169 # . . push args +170 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +171 # . . call +172 e8/call _test-stop-2/disp32 +173 # should never get past this point +174 $_test-stop-1:dead-end: +175 # . . discard args +176 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +177 # signal test failed: check-ints-equal(1, 0, msg) +178 # . . push args +179 68/push "F - test-stop-skips-returns-on-exit"/imm32 +180 68/push 0/imm32 +181 68/push 1/imm32 +182 # . . call +183 e8/call check-ints-equal/disp32 +184 # . . discard args +185 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +186 # . epilog +187 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +188 5d/pop-to-EBP +189 c3/return +190 +191 _test-stop-2: # ed : (address exit-descriptor) +192 # . prolog +193 55/push-EBP +194 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +195 # . stop(ed, 1) +196 # . . push args +197 68/push 1/imm32 +198 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +199 # . . call +200 e8/call stop/disp32 +201 # should never get past this point +202 $_test-stop-2:dead-end: +203 # . epilog +204 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +205 5d/pop-to-EBP +206 c3/return +207 +208 # . . vim:nowrap:textwidth=0 diff --git a/html/060read.subx.html b/html/060read.subx.html index 1e396c38..3253272a 100644 --- a/html/060read.subx.html +++ b/html/060read.subx.html @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxMinorFunction { color: #875f5f; } +.Constant { color: #008787; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> diff --git a/html/061read-byte.subx.html b/html/061read-byte.subx.html index 82284b63..b42a49a4 100644 --- a/html/061read-byte.subx.html +++ b/html/061read-byte.subx.html @@ -14,17 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } +.Constant { color: #008787; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxMinorFunction { color: #875f5f; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -352,7 +352,45 @@ if ('onhashchange' in window) { 290 # data 291 00 00 00 00 00 00 # 6 bytes 292 -293 # . . vim:nowrap:textwidth=0 +293 _test-input-stream: +294 # current write index +295 0/imm32 +296 # current read index +297 0/imm32 +298 # length +299 0x100/imm32 # 256 bytes +300 # data (16 lines x 16 bytes/line) +301 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +302 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +303 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +304 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +305 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +306 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +307 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +308 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +309 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +311 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +312 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +313 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +314 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +315 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +316 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +317 +318 # a test buffered file for _test-input-stream +319 _test-input-buffered-file: +320 # file descriptor or (address stream) +321 _test-input-stream/imm32 +322 # current write index +323 0/imm32 +324 # current read index +325 0/imm32 +326 # length +327 6/imm32 +328 # data +329 00 00 00 00 00 00 # 6 bytes +330 +331 # . . vim:nowrap:textwidth=0 diff --git a/html/062write-stream.subx.html b/html/062write-stream.subx.html index afc7df0d..10f9150e 100644 --- a/html/062write-stream.subx.html +++ b/html/062write-stream.subx.html @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.CommentedCode { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxMinorFunction { color: #875f5f; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/063error.subx.html b/html/063error.subx.html index b0ffd00f..59ebe1cc 100644 --- a/html/063error.subx.html +++ b/html/063error.subx.html @@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } .SpecialChar { color: #d70000; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxS1Comment { color: #0000af; } .subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } --> @@ -98,7 +98,7 @@ if ('onhashchange' in window) { 39 68/push 1/imm32 40 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) 41 # . . call -42 e8/call stop/disp32 +42 e8/call stop/disp32 43 # should never get past this point 44 $error:dead-end: 45 # . epilog diff --git a/html/064write-byte.subx.html b/html/064write-byte.subx.html index 4ac80171..698cac56 100644 --- a/html/064write-byte.subx.html +++ b/html/064write-byte.subx.html @@ -14,16 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxTest { color: #5f8700; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.subxMinorFunction { color: #875f5f; } .LineNr { } -.subxH1Comment { color: #005faf; text-decoration: underline; } +.subxS1Comment { color: #0000af; } +.Constant { color: #008787; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } +.subxH1Comment { color: #005faf; text-decoration: underline; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } --> @@ -346,7 +347,93 @@ if ('onhashchange' in window) { 285 # . end 286 c3/return 287 -288 # . . vim:nowrap:textwidth=0 +288 == data +289 +290 _test-output-stream: +291 # current write index +292 0/imm32 +293 # current read index +294 0/imm32 +295 # length +296 0x200/imm32 # 512 bytes +297 # data (32 lines x 16 bytes/line) +298 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +299 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +301 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +302 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +303 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +304 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +305 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +306 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +307 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +308 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +309 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +311 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +312 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +313 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +314 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +315 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +316 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +317 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +318 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +319 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +321 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +322 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +323 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +324 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +325 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +326 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +327 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +328 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +329 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +330 +331 # a test buffered file for _test-output-stream +332 _test-output-buffered-file: +333 # file descriptor or (address stream) +334 _test-output-stream/imm32 +335 # current write index +336 0/imm32 +337 # current read index +338 0/imm32 +339 # length +340 6/imm32 +341 # data +342 00 00 00 00 00 00 # 6 bytes +343 +344 _test-error-stream: +345 # current write index +346 0/imm32 +347 # current read index +348 0/imm32 +349 # line +350 0x80/imm32 # 128 bytes +351 # data (8 lines x 16 bytes/line) +352 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +353 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +354 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +355 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +356 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +357 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +358 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +359 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +360 +361 # a test buffered file for _test-error-stream +362 _test-error-buffered-file: +363 # file descriptor or (address stream) +364 _test-error-stream/imm32 +365 # current write index +366 0/imm32 +367 # current read index +368 0/imm32 +369 # length +370 6/imm32 +371 # data +372 00 00 00 00 00 00 # 6 bytes +373 +374 # . . vim:nowrap:textwidth=0 diff --git a/html/065write-buffered.subx.html b/html/065write-buffered.subx.html index 8e9dbd67..6838c5c9 100644 --- a/html/065write-buffered.subx.html +++ b/html/065write-buffered.subx.html @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } .SpecialChar { color: #d70000; } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxS1Comment { color: #0000af; } .subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxH1Comment { color: #005faf; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } --> diff --git a/html/066print-int.subx.html b/html/066print-int.subx.html index ba1d58ae..40071775 100644 --- a/html/066print-int.subx.html +++ b/html/066print-int.subx.html @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Constant { color: #008787; } -.Folded { color: #080808; background-color: #949494; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .subxS2Comment { color: #8a8a8a; } +.Folded { color: #080808; background-color: #949494; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Constant { color: #008787; } +.subxH1Comment { color: #005faf; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxTest { color: #5f8700; } --> diff --git a/html/067parse-hex.subx.html b/html/067parse-hex.subx.html index a4c3bedc..aac02910 100644 --- a/html/067parse-hex.subx.html +++ b/html/067parse-hex.subx.html @@ -15,14 +15,14 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } .SpecialChar { color: #d70000; } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxS1Comment { color: #0000af; } .subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } --> @@ -681,10 +681,10 @@ if ('onhashchange' in window) { 621 e8/call parse-hex-int/disp32 622 # . . discard args 623 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -624 # check-ints-equal(EAX, 0xfffffffd, msg) +624 # check-ints-equal(EAX, -3, msg) 625 # . . push args 626 68/push "F - test-parse-hex-int-negative"/imm32 -627 68/push 0xfffffffd/imm32 +627 68/push -3/imm32 628 50/push-EAX 629 # . . call 630 e8/call check-ints-equal/disp32 diff --git a/html/068error-byte.subx.html b/html/068error-byte.subx.html index 511b8035..adb4db3b 100644 --- a/html/068error-byte.subx.html +++ b/html/068error-byte.subx.html @@ -14,15 +14,15 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } .SpecialChar { color: #d70000; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxS1Comment { color: #0000af; } +.CommentedCode { color: #8a8a8a; } .subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } --> @@ -140,7 +140,7 @@ if ('onhashchange' in window) { 80 68/push 1/imm32 81 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) 82 # . . call -83 e8/call stop/disp32 +83 e8/call stop/disp32 84 # should never get past this point 85 $error-byte:dead-end: 86 # . epilog diff --git a/html/069allocate.subx.html b/html/069allocate.subx.html index 25897bc6..a3a315eb 100644 --- a/html/069allocate.subx.html +++ b/html/069allocate.subx.html @@ -15,14 +15,14 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxMinorFunction { color: #875f5f; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/070new-stream.subx.html b/html/070new-stream.subx.html index 078d5e90..cc194994 100644 --- a/html/070new-stream.subx.html +++ b/html/070new-stream.subx.html @@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/071read-line.subx.html b/html/071read-line.subx.html index c74238c8..b4efa7c0 100644 --- a/html/071read-line.subx.html +++ b/html/071read-line.subx.html @@ -14,15 +14,15 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxH1Comment { color: #005faf; text-decoration: underline; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/072slice.subx.html b/html/072slice.subx.html index 196bf921..8d872082 100644 --- a/html/072slice.subx.html +++ b/html/072slice.subx.html @@ -14,14 +14,14 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxS2Comment { color: #8a8a8a; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxS2Comment { color: #8a8a8a; } .Folded { color: #080808; background-color: #949494; } +.LineNr { } +.subxS1Comment { color: #0000af; } .subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxH1Comment { color: #005faf; text-decoration: underline; } .Constant { color: #008787; } .subxTest { color: #5f8700; } --> diff --git a/html/073next-token.subx.html b/html/073next-token.subx.html index 4c53130e..bc0a7487 100644 --- a/html/073next-token.subx.html +++ b/html/073next-token.subx.html @@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.Constant { color: #008787; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.subxTest { color: #5f8700; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.Constant { color: #008787; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxTest { color: #5f8700; } --> @@ -57,903 +57,1173 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/master/073next-token.subx
-  1 # Some tokenization primitives.
-  2 
-  3 == code
-  4 #   instruction                     effective address                                                   register    displacement    immediate
-  5 # . op          subop               mod             rm32          base        index         scale       r32
-  6 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
-  7 
-  8 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
-  9 # on reaching end of file, return an empty interval
- 10 next-token:  # in : (address stream), delimiter : byte, out : (address slice)
- 11     # . prolog
- 12     55/push-EBP
- 13     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
- 14     # . save registers
- 15     50/push-EAX
- 16     51/push-ECX
- 17     56/push-ESI
- 18     57/push-EDI
- 19     # ESI = in
- 20     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
- 21     # EDI = out
- 22     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0x10/disp8      .                 # copy *(EBP+16) to EDI
- 23     # skip-chars-matching(in, delimiter)
- 24     # . . push args
- 25     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
- 26     56/push-ESI
- 27     # . . call
- 28     e8/call  skip-chars-matching/disp32
- 29     # . . discard args
- 30     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
- 31     # out->start = &in->data[in->read]
- 32     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
- 33     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
- 34     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
- 35     # skip-chars-not-matching(in, delimiter)
- 36     # . . push args
- 37     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
- 38     56/push-ESI
- 39     # . . call
- 40     e8/call  skip-chars-not-matching/disp32
- 41     # . . discard args
- 42     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
- 43     # out->end = &in->data[in->read]
- 44     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
- 45     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
- 46     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
- 47     # . restore registers
- 48     5f/pop-to-EDI
- 49     5e/pop-to-ESI
- 50     59/pop-to-ECX
- 51     58/pop-to-EAX
- 52     # . epilog
- 53     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
- 54     5d/pop-to-EBP
- 55     c3/return
- 56 
- 57 test-next-token:
- 58     # . prolog
- 59     55/push-EBP
- 60     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
- 61     # setup
- 62     # . clear-stream(_test-stream)
- 63     # . . push args
- 64     68/push  _test-stream/imm32
- 65     # . . call
- 66     e8/call  clear-stream/disp32
- 67     # . . discard args
- 68     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
- 69     # var slice/ECX = {0, 0}
- 70     68/push  0/imm32/end
- 71     68/push  0/imm32/start
- 72     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
- 73     # write(_test-stream, "  ab")
- 74     # . . push args
- 75     68/push  "  ab"/imm32
- 76     68/push  _test-stream/imm32
- 77     # . . call
- 78     e8/call  write/disp32
- 79     # . . discard args
- 80     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
- 81     # next-token(_test-stream, 0x20/space, slice)
- 82     # . . push args
- 83     51/push-ECX
- 84     68/push  0x20/imm32
- 85     68/push  _test-stream/imm32
- 86     # . . call
- 87     e8/call  next-token/disp32
- 88     # . . discard args
- 89     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
- 90     # check-ints-equal(slice->start - _test-stream->data, 2, msg)
- 91     # . check-ints-equal(slice->start - _test-stream, 14, msg)
- 92     # . . push args
- 93     68/push  "F - test-next-token: start"/imm32
- 94     68/push  0xe/imm32
- 95     # . . push slice->start - _test-stream
- 96     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
- 97     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-stream/imm32 # subtract from EAX
- 98     50/push-EAX
- 99     # . . call
-100     e8/call  check-ints-equal/disp32
-101     # . . discard args
-102     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-103     # check-ints-equal(slice->end - _test-stream->data, 4, msg)
-104     # . check-ints-equal(slice->end - _test-stream, 16, msg)
-105     # . . push args
-106     68/push  "F - test-next-token: end"/imm32
-107     68/push  0x10/imm32
-108     # . . push slice->end - _test-stream
-109     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
-110     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-stream/imm32 # subtract from EAX
-111     50/push-EAX
-112     # . . call
-113     e8/call  check-ints-equal/disp32
-114     # . . discard args
-115     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-116     # . epilog
-117     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-118     5d/pop-to-EBP
-119     c3/return
-120 
-121 test-next-token-Eof:
-122     # . prolog
-123     55/push-EBP
-124     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-125     # setup
-126     # . clear-stream(_test-stream)
-127     # . . push args
-128     68/push  _test-stream/imm32
-129     # . . call
-130     e8/call  clear-stream/disp32
-131     # . . discard args
-132     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-133     # var slice/ECX = {0, 0}
-134     68/push  0/imm32/end
-135     68/push  0/imm32/start
-136     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
-137     # write nothing to _test-stream
-138     # next-token(_test-stream, 0x20/space, slice)
-139     # . . push args
-140     51/push-ECX
-141     68/push  0x20/imm32
-142     68/push  _test-stream/imm32
-143     # . . call
-144     e8/call  next-token/disp32
-145     # . . discard args
-146     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-147     # check-ints-equal(slice->end, slice->start, msg)
-148     # . . push args
-149     68/push  "F - test-next-token-Eof"/imm32
-150     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           4/disp8         .                 # push *(ECX+4)
-151     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
-152     # . . call
-153     e8/call  check-ints-equal/disp32
-154     # . . discard args
-155     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-156     # . epilog
-157     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-158     5d/pop-to-EBP
-159     c3/return
-160 
-161 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
-162 # on reaching end of file, return an empty interval
-163 next-token-from-slice:  # start : (address byte), end : (address byte), delimiter : byte, out : (address slice) -> <void>
-164     # . prolog
-165     55/push-EBP
-166     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-167     # . save registers
-168     50/push-EAX
-169     51/push-ECX
-170     52/push-EDX
-171     57/push-EDI
-172     # ECX = end
-173     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
-174     # EDX = delimiter
-175     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8      .                 # copy *(EBP+16) to EDX
-176     # EDI = out
-177     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0x14/disp8      .                 # copy *(EBP+20) to EDI
-178     # EAX = skip-chars-matching-in-slice(start, end, delimiter)
-179     # . . push args
-180     52/push-EDX
-181     51/push-ECX
-182     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
-183     # . . call
-184     e8/call  skip-chars-matching-in-slice/disp32
-185     # . . discard args
-186     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-187     # out->start = EAX
-188     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
-189     # EAX = skip-chars-not-matching-in-slice(EAX, end, delimiter)
-190     # . . push args
-191     52/push-EDX
-192     51/push-ECX
-193     50/push-EAX
-194     # . . call
-195     e8/call  skip-chars-not-matching-in-slice/disp32
-196     # . . discard args
-197     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-198     # out->end = EAX
-199     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
-200     # . restore registers
-201     5f/pop-to-EDI
-202     5a/pop-to-EDX
-203     59/pop-to-ECX
-204     58/pop-to-EAX
-205     # . epilog
-206     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-207     5d/pop-to-EBP
-208     c3/return
-209 
-210 test-next-token-from-slice:
-211     # . prolog
-212     55/push-EBP
-213     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-214     # (EAX..ECX) = "  ab"
-215     b8/copy-to-EAX  "  ab"/imm32
-216     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
-217     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
-218     05/add-to-EAX  4/imm32
-219     # var out/EDI : (address slice) = {0, 0}
-220     68/push  0/imm32/end
-221     68/push  0/imm32/start
-222     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
-223     # next-token-from-slice(EAX, ECX, 0x20/space, out)
-224     # . . push args
-225     57/push-EDI
-226     68/push  0x20/imm32
-227     51/push-ECX
-228     50/push-EAX
-229     # . . call
-230     e8/call  next-token-from-slice/disp32
-231     # . . discard args
-232     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
-233     # out->start should be at the 'a'
-234     # . check-ints-equal(out->start - in->start, 2, msg)
-235     # . . push args
-236     68/push  "F - test-next-token-from-slice: start"/imm32
-237     68/push  2/imm32
-238     # . . push out->start - in->start
-239     8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy *EDI to ECX
-240     2b/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract EAX from ECX
-241     51/push-ECX
-242     # . . call
-243     e8/call  check-ints-equal/disp32
-244     # . . discard args
-245     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-246     # out->end should be after the 'b'
-247     # check-ints-equal(out->end - in->start, 4, msg)
-248     # . . push args
-249     68/push  "F - test-next-token-from-slice: end"/imm32
-250     68/push  4/imm32
-251     # . . push out->end - in->start
-252     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
-253     2b/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract EAX from ECX
-254     51/push-ECX
-255     # . . call
-256     e8/call  check-ints-equal/disp32
-257     # . . discard args
-258     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-259     # . epilog
-260     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-261     5d/pop-to-EBP
-262     c3/return
-263 
-264 test-next-token-from-slice-Eof:
-265     # . prolog
-266     55/push-EBP
-267     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-268     # var out/EDI : (address slice) = {0, 0}
-269     68/push  0/imm32/end
-270     68/push  0/imm32/start
-271     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
-272     # next-token-from-slice(0, 0, 0x20/space, out)
-273     # . . push args
-274     57/push-EDI
-275     68/push  0x20/imm32
-276     68/push  0/imm32
-277     68/push  0/imm32
-278     # . . call
-279     e8/call  next-token-from-slice/disp32
-280     # . . discard args
-281     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
-282     # out should be empty
-283     # . check-ints-equal(out->end - out->start, 0, msg)
-284     # . . push args
-285     68/push  "F - test-next-token-from-slice-Eof"/imm32
-286     68/push  0/imm32
-287     # . . push out->start - in->start
-288     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
-289     2b/subtract                     0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # subtract *EDI from ECX
-290     51/push-ECX
-291     # . . call
-292     e8/call  check-ints-equal/disp32
-293     # . . discard args
-294     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-295     # . epilog
-296     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-297     5d/pop-to-EBP
-298     c3/return
-299 
-300 test-next-token-from-slice-nothing:
-301     # . prolog
-302     55/push-EBP
-303     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-304     # (EAX..ECX) = "    "
-305     b8/copy-to-EAX  "    "/imm32
-306     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
-307     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
-308     05/add-to-EAX  4/imm32
-309     # var out/EDI : (address slice) = {0, 0}
-310     68/push  0/imm32/end
-311     68/push  0/imm32/start
-312     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
-313     # next-token-from-slice(in, 0x20/space, out)
-314     # . . push args
-315     57/push-EDI
-316     68/push  0x20/imm32
-317     51/push-ECX
-318     50/push-EAX
-319     # . . call
-320     e8/call  next-token-from-slice/disp32
-321     # . . discard args
-322     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
-323     # out should be empty
-324     # . check-ints-equal(out->end - out->start, 0, msg)
-325     # . . push args
-326     68/push  "F - test-next-token-from-slice-Eof"/imm32
-327     68/push  0/imm32
-328     # . . push out->start - in->start
-329     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
-330     2b/subtract                     0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # subtract *EDI from ECX
-331     51/push-ECX
-332     # . . call
-333     e8/call  check-ints-equal/disp32
-334     # . . discard args
-335     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-336     # . epilog
-337     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-338     5d/pop-to-EBP
-339     c3/return
-340 
-341 skip-chars-matching:  # in : (address stream), delimiter : byte
-342     # . prolog
-343     55/push-EBP
-344     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-345     # . save registers
-346     50/push-EAX
-347     51/push-ECX
-348     52/push-EDX
-349     53/push-EBX
-350     56/push-ESI
-351     # ESI = in
-352     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
-353     # ECX = in->read
-354     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
-355     # EBX = in->write
-356     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
-357     # EDX = delimiter
-358     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
-359 $skip-chars-matching:loop:
-360     # if (in->read >= in->write) break
-361     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
-362     7d/jump-if-greater-or-equal  $skip-chars-matching:end/disp8
-363     # EAX = in->data[in->read]
-364     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
-365     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
-366     # if (EAX != delimiter) break
-367     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # compare EAX and EDX
-368     75/jump-if-not-equal  $skip-chars-matching:end/disp8
-369     # ++in->read
-370     41/increment-ECX
-371     eb/jump  $skip-chars-matching:loop/disp8
-372 $skip-chars-matching:end:
-373     # persist in->read
-374     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
-375     # . restore registers
-376     5e/pop-to-ESI
-377     5b/pop-to-EBX
-378     5a/pop-to-EDX
-379     59/pop-to-ECX
-380     58/pop-to-EAX
-381     # . epilog
-382     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-383     5d/pop-to-EBP
-384     c3/return
-385 
-386 test-skip-chars-matching:
-387     # setup
-388     # . clear-stream(_test-stream)
-389     # . . push args
-390     68/push  _test-stream/imm32
-391     # . . call
-392     e8/call  clear-stream/disp32
-393     # . . discard args
-394     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-395     # write(_test-stream, "  ab")
-396     # . . push args
-397     68/push  "  ab"/imm32
-398     68/push  _test-stream/imm32
-399     # . . call
-400     e8/call  write/disp32
-401     # . . discard args
-402     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-403     # skip-chars-matching(_test-stream, 0x20/space)
-404     # . . push args
-405     68/push  0x20/imm32
-406     68/push  _test-stream/imm32
-407     # . . call
-408     e8/call  skip-chars-matching/disp32
-409     # . . discard args
-410     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-411     # check-ints-equal(_test-stream->read, 2, msg)
-412     # . . push args
-413     68/push  "F - test-skip-chars-matching"/imm32
-414     68/push  2/imm32
-415     # . . push *_test-stream->read
-416     b8/copy-to-EAX  _test-stream/imm32
-417     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
-418     # . . call
-419     e8/call  check-ints-equal/disp32
-420     # . . discard args
-421     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-422     # end
-423     c3/return
-424 
-425 test-skip-chars-matching-none:
-426     # setup
-427     # . clear-stream(_test-stream)
-428     # . . push args
-429     68/push  _test-stream/imm32
-430     # . . call
-431     e8/call  clear-stream/disp32
-432     # . . discard args
-433     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-434     # write(_test-stream, "ab")
-435     # . . push args
-436     68/push  "ab"/imm32
-437     68/push  _test-stream/imm32
-438     # . . call
-439     e8/call  write/disp32
-440     # . . discard args
-441     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-442     # skip-chars-matching(_test-stream, 0x20/space)
-443     # . . push args
-444     68/push  0x20/imm32
-445     68/push  _test-stream/imm32
-446     # . . call
-447     e8/call  skip-chars-matching/disp32
-448     # . . discard args
-449     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-450     # check-ints-equal(_test-stream->read, 0, msg)
-451     # . . push args
-452     68/push  "F - test-skip-chars-matching-none"/imm32
-453     68/push  0/imm32
-454     # . . push *_test-stream->read
-455     b8/copy-to-EAX  _test-stream/imm32
-456     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
-457     # . . call
-458     e8/call  check-ints-equal/disp32
-459     # . . discard args
-460     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-461     # end
-462     c3/return
-463 
-464 # minor fork of 'skip-chars-matching'
-465 skip-chars-not-matching:  # in : (address stream), delimiter : byte
-466     # . prolog
-467     55/push-EBP
-468     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-469     # . save registers
-470     50/push-EAX
-471     51/push-ECX
-472     52/push-EDX
-473     53/push-EBX
-474     56/push-ESI
-475     # ESI = in
-476     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
-477     # ECX = in->read
-478     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
-479     # EBX = in->write
-480     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
-481     # EDX = delimiter
-482     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
-483 $skip-chars-not-matching:loop:
-484     # if (in->read >= in->write) break
-485     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
-486     7d/jump-if-greater-or-equal  $skip-chars-not-matching:end/disp8
-487     # EAX = in->data[in->read]
-488     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
-489     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
-490     # if (EAX == delimiter) break
-491     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # compare EAX and EDX
-492     74/jump-if-equal  $skip-chars-not-matching:end/disp8
-493     # ++in->read
-494     41/increment-ECX
-495     eb/jump  $skip-chars-not-matching:loop/disp8
-496 $skip-chars-not-matching:end:
-497     # persist in->read
-498     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
-499     # . restore registers
-500     5e/pop-to-ESI
-501     5b/pop-to-EBX
-502     5a/pop-to-EDX
-503     59/pop-to-ECX
-504     58/pop-to-EAX
-505     # . epilog
-506     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-507     5d/pop-to-EBP
-508     c3/return
-509 
-510 test-skip-chars-not-matching:
-511     # setup
-512     # . clear-stream(_test-stream)
-513     # . . push args
-514     68/push  _test-stream/imm32
-515     # . . call
-516     e8/call  clear-stream/disp32
-517     # . . discard args
-518     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-519     # write(_test-stream, "ab ")
-520     # . . push args
-521     68/push  "ab "/imm32
-522     68/push  _test-stream/imm32
-523     # . . call
-524     e8/call  write/disp32
-525     # . . discard args
-526     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-527     # skip-chars-not-matching(_test-stream, 0x20/space)
-528     # . . push args
-529     68/push  0x20/imm32
-530     68/push  _test-stream/imm32
-531     # . . call
-532     e8/call  skip-chars-not-matching/disp32
-533     # . . discard args
-534     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-535     # check-ints-equal(_test-stream->read, 2, msg)
-536     # . . push args
-537     68/push  "F - test-skip-chars-not-matching"/imm32
-538     68/push  2/imm32
-539     # . . push *_test-stream->read
-540     b8/copy-to-EAX  _test-stream/imm32
-541     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
-542     # . . call
-543     e8/call  check-ints-equal/disp32
-544     # . . discard args
-545     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-546     # end
-547     c3/return
-548 
-549 test-skip-chars-not-matching-none:
-550     # setup
-551     # . clear-stream(_test-stream)
-552     # . . push args
-553     68/push  _test-stream/imm32
-554     # . . call
-555     e8/call  clear-stream/disp32
-556     # . . discard args
-557     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-558     # write(_test-stream, " ab")
-559     # . . push args
-560     68/push  " ab"/imm32
-561     68/push  _test-stream/imm32
-562     # . . call
-563     e8/call  write/disp32
-564     # . . discard args
-565     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-566     # skip-chars-not-matching(_test-stream, 0x20/space)
-567     # . . push args
-568     68/push  0x20/imm32
-569     68/push  _test-stream/imm32
-570     # . . call
-571     e8/call  skip-chars-not-matching/disp32
-572     # . . discard args
-573     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-574     # check-ints-equal(_test-stream->read, 0, msg)
-575     # . . push args
-576     68/push  "F - test-skip-chars-not-matching-none"/imm32
-577     68/push  0/imm32
-578     # . . push *_test-stream->read
-579     b8/copy-to-EAX  _test-stream/imm32
-580     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
-581     # . . call
-582     e8/call  check-ints-equal/disp32
-583     # . . discard args
-584     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-585     # end
-586     c3/return
-587 
-588 test-skip-chars-not-matching-all:
-589     # setup
-590     # . clear-stream(_test-stream)
-591     # . . push args
-592     68/push  _test-stream/imm32
-593     # . . call
-594     e8/call  clear-stream/disp32
-595     # . . discard args
-596     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-597     # write(_test-stream, "ab")
-598     # . . push args
-599     68/push  "ab"/imm32
-600     68/push  _test-stream/imm32
-601     # . . call
-602     e8/call  write/disp32
-603     # . . discard args
-604     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-605     # skip-chars-not-matching(_test-stream, 0x20/space)
-606     # . . push args
-607     68/push  0x20/imm32
-608     68/push  _test-stream/imm32
-609     # . . call
-610     e8/call  skip-chars-not-matching/disp32
-611     # . . discard args
-612     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-613     # check-ints-equal(_test-stream->read, 2, msg)
-614     # . . push args
-615     68/push  "F - test-skip-chars-not-matching-all"/imm32
-616     68/push  2/imm32
-617     # . . push *_test-stream->read
-618     b8/copy-to-EAX  _test-stream/imm32
-619     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
-620     # . . call
-621     e8/call  check-ints-equal/disp32
-622     # . . discard args
-623     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-624     # end
-625     c3/return
-626 
-627 skip-chars-not-matching-whitespace:  # in : (address stream)
-628     # . prolog
-629     55/push-EBP
-630     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-631     # . save registers
-632     50/push-EAX
-633     51/push-ECX
-634     53/push-EBX
-635     56/push-ESI
-636     # ESI = in
-637     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
-638     # ECX = in->read
-639     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
-640     # EBX = in->write
-641     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
-642 $skip-chars-not-matching-whitespace:loop:
-643     # if (in->read >= in->write) break
-644     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
-645     7d/jump-if-greater-or-equal  $skip-chars-not-matching-whitespace:end/disp8
-646     # EAX = in->data[in->read]
-647     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
-648     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
-649     # if (EAX == ' ') break
-650     3d/compare-EAX-and  0x20/imm32/space
-651     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
-652     # if (EAX == '\n') break
-653     3d/compare-EAX-and  0x0a/imm32/newline
-654     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
-655     # if (EAX == '\t') break
-656     3d/compare-EAX-and  0x09/imm32/tab
-657     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
-658     # if (EAX == '\r') break
-659     3d/compare-EAX-and  0x0d/imm32/cr
-660     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
-661     # ++in->read
-662     41/increment-ECX
-663     eb/jump  $skip-chars-not-matching-whitespace:loop/disp8
-664 $skip-chars-not-matching-whitespace:end:
-665     # persist in->read
-666     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
-667     # . restore registers
-668     5e/pop-to-ESI
-669     5b/pop-to-EBX
-670     59/pop-to-ECX
-671     58/pop-to-EAX
-672     # . epilog
-673     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-674     5d/pop-to-EBP
-675     c3/return
-676 
-677 skip-chars-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
-678     # . prolog
-679     55/push-EBP
-680     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-681     # . save registers
-682     51/push-ECX
-683     52/push-EDX
-684     53/push-EBX
-685     # EAX = curr
-686     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
-687     # ECX = end
-688     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
-689     # EDX = delimiter
-690     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
-691     # EBX = 0
-692     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
-693 $skip-chars-matching-in-slice:loop:
-694     # if (curr >= end) break
-695     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
-696     73/jump-if-greater-or-equal-unsigned  $skip-chars-matching-in-slice:end/disp8
-697     # if (*curr != delimiter) break
-698     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
-699     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
-700     75/jump-if-not-equal  $skip-chars-matching-in-slice:end/disp8
-701     # ++curr
-702     40/increment-EAX
-703     eb/jump  $skip-chars-matching-in-slice:loop/disp8
-704 $skip-chars-matching-in-slice:end:
-705     # . restore registers
-706     5b/pop-to-EBX
-707     5a/pop-to-EDX
-708     59/pop-to-ECX
-709     # . epilog
-710     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-711     5d/pop-to-EBP
-712     c3/return
-713 
-714 test-skip-chars-matching-in-slice:
-715     # (EAX..ECX) = "  ab"
-716     b8/copy-to-EAX  "  ab"/imm32
-717     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
-718     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
-719     05/add-to-EAX  4/imm32
-720     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
-721     # . . push args
-722     68/push  0x20/imm32/space
-723     51/push-ECX
-724     50/push-EAX
-725     # . . call
-726     e8/call  skip-chars-matching-in-slice/disp32
-727     # . . discard args
-728     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-729     # check-ints-equal(ECX-EAX, 2, msg)
-730     # . . push args
-731     68/push  "F - test-skip-chars-matching-in-slice"/imm32
-732     68/push  2/imm32
-733     # . . push ECX-EAX
-734     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
-735     51/push-ECX
-736     # . . call
-737     e8/call  check-ints-equal/disp32
-738     # . . discard args
-739     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-740     # end
-741     c3/return
-742 
-743 test-skip-chars-matching-in-slice-none:
-744     # (EAX..ECX) = "ab"
-745     b8/copy-to-EAX  "ab"/imm32
-746     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
-747     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
-748     05/add-to-EAX  4/imm32
-749     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
-750     # . . push args
-751     68/push  0x20/imm32/space
-752     51/push-ECX
-753     50/push-EAX
-754     # . . call
-755     e8/call  skip-chars-matching-in-slice/disp32
-756     # . . discard args
-757     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-758     # check-ints-equal(ECX-EAX, 2, msg)
-759     # . . push args
-760     68/push  "F - test-skip-chars-matching-in-slice-none"/imm32
-761     68/push  2/imm32
-762     # . . push ECX-EAX
-763     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
-764     51/push-ECX
-765     # . . call
-766     e8/call  check-ints-equal/disp32
-767     # . . discard args
-768     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-769     # end
-770     c3/return
-771 
-772 # minor fork of 'skip-chars-matching-in-slice'
-773 skip-chars-not-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
-774     # . prolog
-775     55/push-EBP
-776     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-777     # . save registers
-778     51/push-ECX
-779     52/push-EDX
-780     53/push-EBX
-781     # EAX = curr
-782     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
-783     # ECX = end
-784     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
-785     # EDX = delimiter
-786     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
-787     # EBX = 0
-788     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
-789 $skip-chars-not-matching-in-slice:loop:
-790     # if (curr >= end) break
-791     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
-792     73/jump-if-greater-or-equal-unsigned  $skip-chars-not-matching-in-slice:end/disp8
-793     # if (*curr == delimiter) break
-794     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
-795     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
-796     74/jump-if-equal  $skip-chars-not-matching-in-slice:end/disp8
-797     # ++curr
-798     40/increment-EAX
-799     eb/jump  $skip-chars-not-matching-in-slice:loop/disp8
-800 $skip-chars-not-matching-in-slice:end:
-801     # . restore registers
-802     5b/pop-to-EBX
-803     5a/pop-to-EDX
-804     59/pop-to-ECX
-805     # . epilog
-806     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
-807     5d/pop-to-EBP
-808     c3/return
-809 
-810 test-skip-chars-not-matching-in-slice:
-811     # (EAX..ECX) = "ab "
-812     b8/copy-to-EAX  "ab "/imm32
-813     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
-814     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
-815     05/add-to-EAX  4/imm32
-816     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
-817     # . . push args
-818     68/push  0x20/imm32/space
-819     51/push-ECX
-820     50/push-EAX
-821     # . . call
-822     e8/call  skip-chars-not-matching-in-slice/disp32
-823     # . . discard args
-824     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-825     # check-ints-equal(ECX-EAX, 1, msg)
-826     # . . push args
-827     68/push  "F - test-skip-chars-not-matching-in-slice"/imm32
-828     68/push  1/imm32
-829     # . . push ECX-EAX
-830     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
-831     51/push-ECX
-832     # . . call
-833     e8/call  check-ints-equal/disp32
-834     # . . discard args
-835     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-836     # end
-837     c3/return
-838 
-839 test-skip-chars-not-matching-in-slice-none:
-840     # (EAX..ECX) = " ab"
-841     b8/copy-to-EAX  " ab"/imm32
-842     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
-843     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
-844     05/add-to-EAX  4/imm32
-845     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
-846     # . . push args
-847     68/push  0x20/imm32/space
-848     51/push-ECX
-849     50/push-EAX
-850     # . . call
-851     e8/call  skip-chars-not-matching-in-slice/disp32
-852     # . . discard args
-853     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-854     # check-ints-equal(ECX-EAX, 3, msg)
-855     # . . push args
-856     68/push  "F - test-skip-chars-not-matching-in-slice-none"/imm32
-857     68/push  3/imm32
-858     # . . push ECX-EAX
-859     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
-860     51/push-ECX
-861     # . . call
-862     e8/call  check-ints-equal/disp32
-863     # . . discard args
-864     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-865     # end
-866     c3/return
-867 
-868 test-skip-chars-not-matching-in-slice-all:
-869     # (EAX..ECX) = "ab"
-870     b8/copy-to-EAX  "ab"/imm32
-871     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
-872     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
-873     05/add-to-EAX  4/imm32
-874     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
-875     # . . push args
-876     68/push  0x20/imm32/space
-877     51/push-ECX
-878     50/push-EAX
-879     # . . call
-880     e8/call  skip-chars-not-matching-in-slice/disp32
-881     # . . discard args
-882     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-883     # check-ints-equal(ECX-EAX, 0, msg)
-884     # . . push args
-885     68/push  "F - test-skip-chars-not-matching-in-slice-all"/imm32
-886     68/push  0/imm32
-887     # . . push ECX-EAX
-888     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
-889     51/push-ECX
-890     # . . call
-891     e8/call  check-ints-equal/disp32
-892     # . . discard args
-893     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-894     # end
-895     c3/return
-896 
-897 # . . vim:nowrap:textwidth=0
+   1 # Some tokenization primitives.
+   2 
+   3 == code
+   4 #   instruction                     effective address                                                   register    displacement    immediate
+   5 # . op          subop               mod             rm32          base        index         scale       r32
+   6 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+   7 
+   8 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
+   9 # on reaching end of file, return an empty interval
+  10 next-token:  # in : (address stream), delimiter : byte, out : (address slice)
+  11     # . prolog
+  12     55/push-EBP
+  13     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  14     # . save registers
+  15     50/push-EAX
+  16     51/push-ECX
+  17     56/push-ESI
+  18     57/push-EDI
+  19     # ESI = in
+  20     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+  21     # EDI = out
+  22     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0x10/disp8      .                 # copy *(EBP+16) to EDI
+  23     # skip-chars-matching(in, delimiter)
+  24     # . . push args
+  25     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+  26     56/push-ESI
+  27     # . . call
+  28     e8/call  skip-chars-matching/disp32
+  29     # . . discard args
+  30     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  31     # out->start = &in->data[in->read]
+  32     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+  33     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
+  34     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
+  35     # skip-chars-not-matching(in, delimiter)
+  36     # . . push args
+  37     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+  38     56/push-ESI
+  39     # . . call
+  40     e8/call  skip-chars-not-matching/disp32
+  41     # . . discard args
+  42     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  43     # out->end = &in->data[in->read]
+  44     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+  45     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
+  46     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
+  47     # . restore registers
+  48     5f/pop-to-EDI
+  49     5e/pop-to-ESI
+  50     59/pop-to-ECX
+  51     58/pop-to-EAX
+  52     # . epilog
+  53     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+  54     5d/pop-to-EBP
+  55     c3/return
+  56 
+  57 test-next-token:
+  58     # . prolog
+  59     55/push-EBP
+  60     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  61     # setup
+  62     # . clear-stream(_test-stream)
+  63     # . . push args
+  64     68/push  _test-stream/imm32
+  65     # . . call
+  66     e8/call  clear-stream/disp32
+  67     # . . discard args
+  68     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+  69     # var slice/ECX = {0, 0}
+  70     68/push  0/imm32/end
+  71     68/push  0/imm32/start
+  72     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+  73     # write(_test-stream, "  ab")
+  74     # . . push args
+  75     68/push  "  ab"/imm32
+  76     68/push  _test-stream/imm32
+  77     # . . call
+  78     e8/call  write/disp32
+  79     # . . discard args
+  80     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  81     # next-token(_test-stream, 0x20/space, slice)
+  82     # . . push args
+  83     51/push-ECX
+  84     68/push  0x20/imm32
+  85     68/push  _test-stream/imm32
+  86     # . . call
+  87     e8/call  next-token/disp32
+  88     # . . discard args
+  89     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+  90     # check-ints-equal(slice->start - _test-stream->data, 2, msg)
+  91     # . check-ints-equal(slice->start - _test-stream, 14, msg)
+  92     # . . push args
+  93     68/push  "F - test-next-token: start"/imm32
+  94     68/push  0xe/imm32
+  95     # . . push slice->start - _test-stream
+  96     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+  97     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-stream/imm32 # subtract from EAX
+  98     50/push-EAX
+  99     # . . call
+ 100     e8/call  check-ints-equal/disp32
+ 101     # . . discard args
+ 102     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 103     # check-ints-equal(slice->end - _test-stream->data, 4, msg)
+ 104     # . check-ints-equal(slice->end - _test-stream, 16, msg)
+ 105     # . . push args
+ 106     68/push  "F - test-next-token: end"/imm32
+ 107     68/push  0x10/imm32
+ 108     # . . push slice->end - _test-stream
+ 109     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+ 110     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-stream/imm32 # subtract from EAX
+ 111     50/push-EAX
+ 112     # . . call
+ 113     e8/call  check-ints-equal/disp32
+ 114     # . . discard args
+ 115     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 116     # . epilog
+ 117     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 118     5d/pop-to-EBP
+ 119     c3/return
+ 120 
+ 121 test-next-token-Eof:
+ 122     # . prolog
+ 123     55/push-EBP
+ 124     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 125     # setup
+ 126     # . clear-stream(_test-stream)
+ 127     # . . push args
+ 128     68/push  _test-stream/imm32
+ 129     # . . call
+ 130     e8/call  clear-stream/disp32
+ 131     # . . discard args
+ 132     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 133     # var slice/ECX = {0, 0}
+ 134     68/push  0/imm32/end
+ 135     68/push  0/imm32/start
+ 136     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+ 137     # write nothing to _test-stream
+ 138     # next-token(_test-stream, 0x20/space, slice)
+ 139     # . . push args
+ 140     51/push-ECX
+ 141     68/push  0x20/imm32
+ 142     68/push  _test-stream/imm32
+ 143     # . . call
+ 144     e8/call  next-token/disp32
+ 145     # . . discard args
+ 146     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 147     # check-ints-equal(slice->end, slice->start, msg)
+ 148     # . . push args
+ 149     68/push  "F - test-next-token-Eof"/imm32
+ 150     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           4/disp8         .                 # push *(ECX+4)
+ 151     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 152     # . . call
+ 153     e8/call  check-ints-equal/disp32
+ 154     # . . discard args
+ 155     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 156     # . epilog
+ 157     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 158     5d/pop-to-EBP
+ 159     c3/return
+ 160 
+ 161 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
+ 162 # on reaching end of file, return an empty interval
+ 163 next-token-from-slice:  # start : (address byte), end : (address byte), delimiter : byte, out : (address slice) -> <void>
+ 164     # . prolog
+ 165     55/push-EBP
+ 166     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 167     # . save registers
+ 168     50/push-EAX
+ 169     51/push-ECX
+ 170     52/push-EDX
+ 171     57/push-EDI
+ 172     # ECX = end
+ 173     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
+ 174     # EDX = delimiter
+ 175     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8      .                 # copy *(EBP+16) to EDX
+ 176     # EDI = out
+ 177     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0x14/disp8      .                 # copy *(EBP+20) to EDI
+ 178     # EAX = skip-chars-matching-in-slice(start, end, delimiter)
+ 179     # . . push args
+ 180     52/push-EDX
+ 181     51/push-ECX
+ 182     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+ 183     # . . call
+ 184     e8/call  skip-chars-matching-in-slice/disp32
+ 185     # . . discard args
+ 186     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 187     # out->start = EAX
+ 188     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
+ 189     # EAX = skip-chars-not-matching-in-slice(EAX, end, delimiter)
+ 190     # . . push args
+ 191     52/push-EDX
+ 192     51/push-ECX
+ 193     50/push-EAX
+ 194     # . . call
+ 195     e8/call  skip-chars-not-matching-in-slice/disp32
+ 196     # . . discard args
+ 197     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 198     # out->end = EAX
+ 199     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
+ 200     # . restore registers
+ 201     5f/pop-to-EDI
+ 202     5a/pop-to-EDX
+ 203     59/pop-to-ECX
+ 204     58/pop-to-EAX
+ 205     # . epilog
+ 206     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 207     5d/pop-to-EBP
+ 208     c3/return
+ 209 
+ 210 test-next-token-from-slice:
+ 211     # . prolog
+ 212     55/push-EBP
+ 213     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 214     # (EAX..ECX) = "  ab"
+ 215     b8/copy-to-EAX  "  ab"/imm32
+ 216     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+ 217     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+ 218     05/add-to-EAX  4/imm32
+ 219     # var out/EDI : (address slice) = {0, 0}
+ 220     68/push  0/imm32/end
+ 221     68/push  0/imm32/start
+ 222     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
+ 223     # next-token-from-slice(EAX, ECX, 0x20/space, out)
+ 224     # . . push args
+ 225     57/push-EDI
+ 226     68/push  0x20/imm32
+ 227     51/push-ECX
+ 228     50/push-EAX
+ 229     # . . call
+ 230     e8/call  next-token-from-slice/disp32
+ 231     # . . discard args
+ 232     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+ 233     # out->start should be at the 'a'
+ 234     # . check-ints-equal(out->start - in->start, 2, msg)
+ 235     # . . push args
+ 236     68/push  "F - test-next-token-from-slice: start"/imm32
+ 237     68/push  2/imm32
+ 238     # . . push out->start - in->start
+ 239     8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy *EDI to ECX
+ 240     2b/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract EAX from ECX
+ 241     51/push-ECX
+ 242     # . . call
+ 243     e8/call  check-ints-equal/disp32
+ 244     # . . discard args
+ 245     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 246     # out->end should be after the 'b'
+ 247     # check-ints-equal(out->end - in->start, 4, msg)
+ 248     # . . push args
+ 249     68/push  "F - test-next-token-from-slice: end"/imm32
+ 250     68/push  4/imm32
+ 251     # . . push out->end - in->start
+ 252     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
+ 253     2b/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract EAX from ECX
+ 254     51/push-ECX
+ 255     # . . call
+ 256     e8/call  check-ints-equal/disp32
+ 257     # . . discard args
+ 258     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 259     # . epilog
+ 260     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 261     5d/pop-to-EBP
+ 262     c3/return
+ 263 
+ 264 test-next-token-from-slice-Eof:
+ 265     # . prolog
+ 266     55/push-EBP
+ 267     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 268     # var out/EDI : (address slice) = {0, 0}
+ 269     68/push  0/imm32/end
+ 270     68/push  0/imm32/start
+ 271     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
+ 272     # next-token-from-slice(0, 0, 0x20/space, out)
+ 273     # . . push args
+ 274     57/push-EDI
+ 275     68/push  0x20/imm32
+ 276     68/push  0/imm32
+ 277     68/push  0/imm32
+ 278     # . . call
+ 279     e8/call  next-token-from-slice/disp32
+ 280     # . . discard args
+ 281     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+ 282     # out should be empty
+ 283     # . check-ints-equal(out->end - out->start, 0, msg)
+ 284     # . . push args
+ 285     68/push  "F - test-next-token-from-slice-Eof"/imm32
+ 286     68/push  0/imm32
+ 287     # . . push out->start - in->start
+ 288     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
+ 289     2b/subtract                     0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # subtract *EDI from ECX
+ 290     51/push-ECX
+ 291     # . . call
+ 292     e8/call  check-ints-equal/disp32
+ 293     # . . discard args
+ 294     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 295     # . epilog
+ 296     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 297     5d/pop-to-EBP
+ 298     c3/return
+ 299 
+ 300 test-next-token-from-slice-nothing:
+ 301     # . prolog
+ 302     55/push-EBP
+ 303     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 304     # (EAX..ECX) = "    "
+ 305     b8/copy-to-EAX  "    "/imm32
+ 306     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+ 307     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+ 308     05/add-to-EAX  4/imm32
+ 309     # var out/EDI : (address slice) = {0, 0}
+ 310     68/push  0/imm32/end
+ 311     68/push  0/imm32/start
+ 312     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
+ 313     # next-token-from-slice(in, 0x20/space, out)
+ 314     # . . push args
+ 315     57/push-EDI
+ 316     68/push  0x20/imm32
+ 317     51/push-ECX
+ 318     50/push-EAX
+ 319     # . . call
+ 320     e8/call  next-token-from-slice/disp32
+ 321     # . . discard args
+ 322     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+ 323     # out should be empty
+ 324     # . check-ints-equal(out->end - out->start, 0, msg)
+ 325     # . . push args
+ 326     68/push  "F - test-next-token-from-slice-Eof"/imm32
+ 327     68/push  0/imm32
+ 328     # . . push out->start - in->start
+ 329     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
+ 330     2b/subtract                     0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # subtract *EDI from ECX
+ 331     51/push-ECX
+ 332     # . . call
+ 333     e8/call  check-ints-equal/disp32
+ 334     # . . discard args
+ 335     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 336     # . epilog
+ 337     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 338     5d/pop-to-EBP
+ 339     c3/return
+ 340 
+ 341 skip-chars-matching:  # in : (address stream), delimiter : byte
+ 342     # . prolog
+ 343     55/push-EBP
+ 344     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 345     # . save registers
+ 346     50/push-EAX
+ 347     51/push-ECX
+ 348     52/push-EDX
+ 349     53/push-EBX
+ 350     56/push-ESI
+ 351     # ESI = in
+ 352     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 353     # ECX = in->read
+ 354     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+ 355     # EBX = in->write
+ 356     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
+ 357     # EDX = delimiter
+ 358     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
+ 359 $skip-chars-matching:loop:
+ 360     # if (in->read >= in->write) break
+ 361     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
+ 362     7d/jump-if-greater-or-equal  $skip-chars-matching:end/disp8
+ 363     # EAX = in->data[in->read]
+ 364     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 365     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+ 366     # if (EAX != delimiter) break
+ 367     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # compare EAX and EDX
+ 368     75/jump-if-not-equal  $skip-chars-matching:end/disp8
+ 369     # ++in->read
+ 370     41/increment-ECX
+ 371     eb/jump  $skip-chars-matching:loop/disp8
+ 372 $skip-chars-matching:end:
+ 373     # persist in->read
+ 374     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
+ 375     # . restore registers
+ 376     5e/pop-to-ESI
+ 377     5b/pop-to-EBX
+ 378     5a/pop-to-EDX
+ 379     59/pop-to-ECX
+ 380     58/pop-to-EAX
+ 381     # . epilog
+ 382     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 383     5d/pop-to-EBP
+ 384     c3/return
+ 385 
+ 386 test-skip-chars-matching:
+ 387     # setup
+ 388     # . clear-stream(_test-stream)
+ 389     # . . push args
+ 390     68/push  _test-stream/imm32
+ 391     # . . call
+ 392     e8/call  clear-stream/disp32
+ 393     # . . discard args
+ 394     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 395     # write(_test-stream, "  ab")
+ 396     # . . push args
+ 397     68/push  "  ab"/imm32
+ 398     68/push  _test-stream/imm32
+ 399     # . . call
+ 400     e8/call  write/disp32
+ 401     # . . discard args
+ 402     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 403     # skip-chars-matching(_test-stream, 0x20/space)
+ 404     # . . push args
+ 405     68/push  0x20/imm32
+ 406     68/push  _test-stream/imm32
+ 407     # . . call
+ 408     e8/call  skip-chars-matching/disp32
+ 409     # . . discard args
+ 410     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 411     # check-ints-equal(_test-stream->read, 2, msg)
+ 412     # . . push args
+ 413     68/push  "F - test-skip-chars-matching"/imm32
+ 414     68/push  2/imm32
+ 415     # . . push *_test-stream->read
+ 416     b8/copy-to-EAX  _test-stream/imm32
+ 417     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+ 418     # . . call
+ 419     e8/call  check-ints-equal/disp32
+ 420     # . . discard args
+ 421     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 422     # end
+ 423     c3/return
+ 424 
+ 425 test-skip-chars-matching-none:
+ 426     # setup
+ 427     # . clear-stream(_test-stream)
+ 428     # . . push args
+ 429     68/push  _test-stream/imm32
+ 430     # . . call
+ 431     e8/call  clear-stream/disp32
+ 432     # . . discard args
+ 433     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 434     # write(_test-stream, "ab")
+ 435     # . . push args
+ 436     68/push  "ab"/imm32
+ 437     68/push  _test-stream/imm32
+ 438     # . . call
+ 439     e8/call  write/disp32
+ 440     # . . discard args
+ 441     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 442     # skip-chars-matching(_test-stream, 0x20/space)
+ 443     # . . push args
+ 444     68/push  0x20/imm32
+ 445     68/push  _test-stream/imm32
+ 446     # . . call
+ 447     e8/call  skip-chars-matching/disp32
+ 448     # . . discard args
+ 449     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 450     # check-ints-equal(_test-stream->read, 0, msg)
+ 451     # . . push args
+ 452     68/push  "F - test-skip-chars-matching-none"/imm32
+ 453     68/push  0/imm32
+ 454     # . . push *_test-stream->read
+ 455     b8/copy-to-EAX  _test-stream/imm32
+ 456     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+ 457     # . . call
+ 458     e8/call  check-ints-equal/disp32
+ 459     # . . discard args
+ 460     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 461     # end
+ 462     c3/return
+ 463 
+ 464 skip-chars-matching-whitespace:  # in : (address stream)
+ 465     # . prolog
+ 466     55/push-EBP
+ 467     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 468     # . save registers
+ 469     50/push-EAX
+ 470     51/push-ECX
+ 471     53/push-EBX
+ 472     56/push-ESI
+ 473     # ESI = in
+ 474     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 475     # ECX = in->read
+ 476     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+ 477     # EBX = in->write
+ 478     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
+ 479 $skip-chars-matching-whitespace:loop:
+ 480     # if (in->read >= in->write) break
+ 481     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
+ 482     7d/jump-if-greater-or-equal  $skip-chars-matching-whitespace:end/disp8
+ 483     # EAX = in->data[in->read]
+ 484     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 485     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+ 486     # if (EAX == ' ') goto body
+ 487     3d/compare-EAX-and  0x20/imm32/space
+ 488     74/jump-if-equal  $skip-chars-matching-whitespace:body/disp8
+ 489     # if (EAX == '\n') goto body
+ 490     3d/compare-EAX-and  0x0a/imm32/newline
+ 491     74/jump-if-equal  $skip-chars-matching-whitespace:body/disp8
+ 492     # if (EAX == '\t') goto body
+ 493     3d/compare-EAX-and  0x09/imm32/tab
+ 494     74/jump-if-equal  $skip-chars-matching-whitespace:body/disp8
+ 495     # if (EAX != '\r') break
+ 496     3d/compare-EAX-and  0x0d/imm32/cr
+ 497     75/jump-if-not-equal  $skip-chars-matching-whitespace:end/disp8
+ 498 $skip-chars-matching-whitespace:body:
+ 499     # ++in->read
+ 500     41/increment-ECX
+ 501     eb/jump  $skip-chars-matching-whitespace:loop/disp8
+ 502 $skip-chars-matching-whitespace:end:
+ 503     # persist in->read
+ 504     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
+ 505     # . restore registers
+ 506     5e/pop-to-ESI
+ 507     5b/pop-to-EBX
+ 508     59/pop-to-ECX
+ 509     58/pop-to-EAX
+ 510     # . epilog
+ 511     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 512     5d/pop-to-EBP
+ 513     c3/return
+ 514 
+ 515 test-skip-chars-matching-whitespace:
+ 516     # setup
+ 517     # . clear-stream(_test-stream)
+ 518     # . . push args
+ 519     68/push  _test-stream/imm32
+ 520     # . . call
+ 521     e8/call  clear-stream/disp32
+ 522     # . . discard args
+ 523     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 524     # write(_test-stream, " \nab")
+ 525     # . . push args
+ 526     68/push  " \nab"/imm32
+ 527     68/push  _test-stream/imm32
+ 528     # . . call
+ 529     e8/call  write/disp32
+ 530     # . . discard args
+ 531     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 532     # skip-chars-matching-whitespace(_test-stream)
+ 533     # . . push args
+ 534     68/push  _test-stream/imm32
+ 535     # . . call
+ 536     e8/call  skip-chars-matching-whitespace/disp32
+ 537     # . . discard args
+ 538     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 539     # check-ints-equal(_test-stream->read, 2, msg)
+ 540     # . . push args
+ 541     68/push  "F - test-skip-chars-matching-whitespace"/imm32
+ 542     68/push  2/imm32
+ 543     # . . push *_test-stream->read
+ 544     b8/copy-to-EAX  _test-stream/imm32
+ 545     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+ 546     # . . call
+ 547     e8/call  check-ints-equal/disp32
+ 548     # . . discard args
+ 549     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 550     # end
+ 551     c3/return
+ 552 
+ 553 # minor fork of 'skip-chars-matching'
+ 554 skip-chars-not-matching:  # in : (address stream), delimiter : byte
+ 555     # . prolog
+ 556     55/push-EBP
+ 557     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 558     # . save registers
+ 559     50/push-EAX
+ 560     51/push-ECX
+ 561     52/push-EDX
+ 562     53/push-EBX
+ 563     56/push-ESI
+ 564     # ESI = in
+ 565     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 566     # ECX = in->read
+ 567     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+ 568     # EBX = in->write
+ 569     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
+ 570     # EDX = delimiter
+ 571     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
+ 572 $skip-chars-not-matching:loop:
+ 573     # if (in->read >= in->write) break
+ 574     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
+ 575     7d/jump-if-greater-or-equal  $skip-chars-not-matching:end/disp8
+ 576     # EAX = in->data[in->read]
+ 577     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 578     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+ 579     # if (EAX == delimiter) break
+ 580     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # compare EAX and EDX
+ 581     74/jump-if-equal  $skip-chars-not-matching:end/disp8
+ 582     # ++in->read
+ 583     41/increment-ECX
+ 584     eb/jump  $skip-chars-not-matching:loop/disp8
+ 585 $skip-chars-not-matching:end:
+ 586     # persist in->read
+ 587     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
+ 588     # . restore registers
+ 589     5e/pop-to-ESI
+ 590     5b/pop-to-EBX
+ 591     5a/pop-to-EDX
+ 592     59/pop-to-ECX
+ 593     58/pop-to-EAX
+ 594     # . epilog
+ 595     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 596     5d/pop-to-EBP
+ 597     c3/return
+ 598 
+ 599 test-skip-chars-not-matching:
+ 600     # setup
+ 601     # . clear-stream(_test-stream)
+ 602     # . . push args
+ 603     68/push  _test-stream/imm32
+ 604     # . . call
+ 605     e8/call  clear-stream/disp32
+ 606     # . . discard args
+ 607     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 608     # write(_test-stream, "ab ")
+ 609     # . . push args
+ 610     68/push  "ab "/imm32
+ 611     68/push  _test-stream/imm32
+ 612     # . . call
+ 613     e8/call  write/disp32
+ 614     # . . discard args
+ 615     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 616     # skip-chars-not-matching(_test-stream, 0x20/space)
+ 617     # . . push args
+ 618     68/push  0x20/imm32
+ 619     68/push  _test-stream/imm32
+ 620     # . . call
+ 621     e8/call  skip-chars-not-matching/disp32
+ 622     # . . discard args
+ 623     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 624     # check-ints-equal(_test-stream->read, 2, msg)
+ 625     # . . push args
+ 626     68/push  "F - test-skip-chars-not-matching"/imm32
+ 627     68/push  2/imm32
+ 628     # . . push *_test-stream->read
+ 629     b8/copy-to-EAX  _test-stream/imm32
+ 630     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+ 631     # . . call
+ 632     e8/call  check-ints-equal/disp32
+ 633     # . . discard args
+ 634     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 635     # end
+ 636     c3/return
+ 637 
+ 638 test-skip-chars-not-matching-none:
+ 639     # setup
+ 640     # . clear-stream(_test-stream)
+ 641     # . . push args
+ 642     68/push  _test-stream/imm32
+ 643     # . . call
+ 644     e8/call  clear-stream/disp32
+ 645     # . . discard args
+ 646     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 647     # write(_test-stream, " ab")
+ 648     # . . push args
+ 649     68/push  " ab"/imm32
+ 650     68/push  _test-stream/imm32
+ 651     # . . call
+ 652     e8/call  write/disp32
+ 653     # . . discard args
+ 654     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 655     # skip-chars-not-matching(_test-stream, 0x20/space)
+ 656     # . . push args
+ 657     68/push  0x20/imm32
+ 658     68/push  _test-stream/imm32
+ 659     # . . call
+ 660     e8/call  skip-chars-not-matching/disp32
+ 661     # . . discard args
+ 662     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 663     # check-ints-equal(_test-stream->read, 0, msg)
+ 664     # . . push args
+ 665     68/push  "F - test-skip-chars-not-matching-none"/imm32
+ 666     68/push  0/imm32
+ 667     # . . push *_test-stream->read
+ 668     b8/copy-to-EAX  _test-stream/imm32
+ 669     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+ 670     # . . call
+ 671     e8/call  check-ints-equal/disp32
+ 672     # . . discard args
+ 673     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 674     # end
+ 675     c3/return
+ 676 
+ 677 test-skip-chars-not-matching-all:
+ 678     # setup
+ 679     # . clear-stream(_test-stream)
+ 680     # . . push args
+ 681     68/push  _test-stream/imm32
+ 682     # . . call
+ 683     e8/call  clear-stream/disp32
+ 684     # . . discard args
+ 685     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 686     # write(_test-stream, "ab")
+ 687     # . . push args
+ 688     68/push  "ab"/imm32
+ 689     68/push  _test-stream/imm32
+ 690     # . . call
+ 691     e8/call  write/disp32
+ 692     # . . discard args
+ 693     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 694     # skip-chars-not-matching(_test-stream, 0x20/space)
+ 695     # . . push args
+ 696     68/push  0x20/imm32
+ 697     68/push  _test-stream/imm32
+ 698     # . . call
+ 699     e8/call  skip-chars-not-matching/disp32
+ 700     # . . discard args
+ 701     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 702     # check-ints-equal(_test-stream->read, 2, msg)
+ 703     # . . push args
+ 704     68/push  "F - test-skip-chars-not-matching-all"/imm32
+ 705     68/push  2/imm32
+ 706     # . . push *_test-stream->read
+ 707     b8/copy-to-EAX  _test-stream/imm32
+ 708     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+ 709     # . . call
+ 710     e8/call  check-ints-equal/disp32
+ 711     # . . discard args
+ 712     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 713     # end
+ 714     c3/return
+ 715 
+ 716 skip-chars-not-matching-whitespace:  # in : (address stream)
+ 717     # . prolog
+ 718     55/push-EBP
+ 719     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 720     # . save registers
+ 721     50/push-EAX
+ 722     51/push-ECX
+ 723     53/push-EBX
+ 724     56/push-ESI
+ 725     # ESI = in
+ 726     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 727     # ECX = in->read
+ 728     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+ 729     # EBX = in->write
+ 730     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
+ 731 $skip-chars-not-matching-whitespace:loop:
+ 732     # if (in->read >= in->write) break
+ 733     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
+ 734     7d/jump-if-greater-or-equal  $skip-chars-not-matching-whitespace:end/disp8
+ 735     # EAX = in->data[in->read]
+ 736     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 737     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+ 738     # if (EAX == ' ') break
+ 739     3d/compare-EAX-and  0x20/imm32/space
+ 740     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
+ 741     # if (EAX == '\n') break
+ 742     3d/compare-EAX-and  0x0a/imm32/newline
+ 743     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
+ 744     # if (EAX == '\t') break
+ 745     3d/compare-EAX-and  0x09/imm32/tab
+ 746     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
+ 747     # if (EAX == '\r') break
+ 748     3d/compare-EAX-and  0x0d/imm32/cr
+ 749     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
+ 750     # ++in->read
+ 751     41/increment-ECX
+ 752     eb/jump  $skip-chars-not-matching-whitespace:loop/disp8
+ 753 $skip-chars-not-matching-whitespace:end:
+ 754     # persist in->read
+ 755     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
+ 756     # . restore registers
+ 757     5e/pop-to-ESI
+ 758     5b/pop-to-EBX
+ 759     59/pop-to-ECX
+ 760     58/pop-to-EAX
+ 761     # . epilog
+ 762     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 763     5d/pop-to-EBP
+ 764     c3/return
+ 765 
+ 766 test-skip-chars-not-matching-whitespace:
+ 767     # setup
+ 768     # . clear-stream(_test-stream)
+ 769     # . . push args
+ 770     68/push  _test-stream/imm32
+ 771     # . . call
+ 772     e8/call  clear-stream/disp32
+ 773     # . . discard args
+ 774     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 775     # write(_test-stream, "ab\n")
+ 776     # . . push args
+ 777     68/push  "ab\n"/imm32
+ 778     68/push  _test-stream/imm32
+ 779     # . . call
+ 780     e8/call  write/disp32
+ 781     # . . discard args
+ 782     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 783     # skip-chars-not-matching-whitespace(_test-stream)
+ 784     # . . push args
+ 785     68/push  _test-stream/imm32
+ 786     # . . call
+ 787     e8/call  skip-chars-not-matching-whitespace/disp32
+ 788     # . . discard args
+ 789     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 790     # check-ints-equal(_test-stream->read, 2, msg)
+ 791     # . . push args
+ 792     68/push  "F - test-skip-chars-not-matching-whitespace"/imm32
+ 793     68/push  2/imm32
+ 794     # . . push *_test-stream->read
+ 795     b8/copy-to-EAX  _test-stream/imm32
+ 796     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+ 797     # . . call
+ 798     e8/call  check-ints-equal/disp32
+ 799     # . . discard args
+ 800     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 801     # end
+ 802     c3/return
+ 803 
+ 804 skip-chars-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
+ 805     # . prolog
+ 806     55/push-EBP
+ 807     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 808     # . save registers
+ 809     51/push-ECX
+ 810     52/push-EDX
+ 811     53/push-EBX
+ 812     # EAX = curr
+ 813     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
+ 814     # ECX = end
+ 815     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
+ 816     # EDX = delimiter
+ 817     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
+ 818     # EBX = 0
+ 819     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+ 820 $skip-chars-matching-in-slice:loop:
+ 821     # if (curr >= end) break
+ 822     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
+ 823     73/jump-if-greater-or-equal-unsigned  $skip-chars-matching-in-slice:end/disp8
+ 824     # if (*curr != delimiter) break
+ 825     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
+ 826     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
+ 827     75/jump-if-not-equal  $skip-chars-matching-in-slice:end/disp8
+ 828     # ++curr
+ 829     40/increment-EAX
+ 830     eb/jump  $skip-chars-matching-in-slice:loop/disp8
+ 831 $skip-chars-matching-in-slice:end:
+ 832     # . restore registers
+ 833     5b/pop-to-EBX
+ 834     5a/pop-to-EDX
+ 835     59/pop-to-ECX
+ 836     # . epilog
+ 837     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 838     5d/pop-to-EBP
+ 839     c3/return
+ 840 
+ 841 test-skip-chars-matching-in-slice:
+ 842     # (EAX..ECX) = "  ab"
+ 843     b8/copy-to-EAX  "  ab"/imm32
+ 844     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+ 845     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+ 846     05/add-to-EAX  4/imm32
+ 847     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
+ 848     # . . push args
+ 849     68/push  0x20/imm32/space
+ 850     51/push-ECX
+ 851     50/push-EAX
+ 852     # . . call
+ 853     e8/call  skip-chars-matching-in-slice/disp32
+ 854     # . . discard args
+ 855     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 856     # check-ints-equal(ECX-EAX, 2, msg)
+ 857     # . . push args
+ 858     68/push  "F - test-skip-chars-matching-in-slice"/imm32
+ 859     68/push  2/imm32
+ 860     # . . push ECX-EAX
+ 861     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+ 862     51/push-ECX
+ 863     # . . call
+ 864     e8/call  check-ints-equal/disp32
+ 865     # . . discard args
+ 866     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 867     # end
+ 868     c3/return
+ 869 
+ 870 test-skip-chars-matching-in-slice-none:
+ 871     # (EAX..ECX) = "ab"
+ 872     b8/copy-to-EAX  "ab"/imm32
+ 873     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+ 874     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+ 875     05/add-to-EAX  4/imm32
+ 876     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
+ 877     # . . push args
+ 878     68/push  0x20/imm32/space
+ 879     51/push-ECX
+ 880     50/push-EAX
+ 881     # . . call
+ 882     e8/call  skip-chars-matching-in-slice/disp32
+ 883     # . . discard args
+ 884     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 885     # check-ints-equal(ECX-EAX, 2, msg)
+ 886     # . . push args
+ 887     68/push  "F - test-skip-chars-matching-in-slice-none"/imm32
+ 888     68/push  2/imm32
+ 889     # . . push ECX-EAX
+ 890     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+ 891     51/push-ECX
+ 892     # . . call
+ 893     e8/call  check-ints-equal/disp32
+ 894     # . . discard args
+ 895     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 896     # end
+ 897     c3/return
+ 898 
+ 899 skip-chars-matching-whitespace-in-slice:  # in : (address stream)
+ 900     # . prolog
+ 901     55/push-EBP
+ 902     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 903     # . save registers
+ 904     51/push-ECX
+ 905     53/push-EBX
+ 906     # EAX = curr
+ 907     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
+ 908     # ECX = end
+ 909     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
+ 910     # EBX = 0
+ 911     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+ 912 $skip-chars-matching-whitespace-in-slice:loop:
+ 913     # if (curr >= end) break
+ 914     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
+ 915     0f 83/jump-if-greater-or-equal-unsigned  $skip-chars-matching-in-slice:end/disp32
+ 916     # EBX = *curr
+ 917     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
+ 918     # if (*curr == ' ') goto body
+ 919     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x20/imm32/space  # compare EBX
+ 920     74/jump-if-equal  $skip-chars-matching-whitespace-in-slice:body/disp8
+ 921     # if (*curr == '\n') goto body
+ 922     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x0a/imm32/newline  # compare EBX
+ 923     74/jump-if-equal  $skip-chars-matching-whitespace-in-slice:body/disp8
+ 924     # if (*curr == '\t') goto body
+ 925     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x09/imm32/tab    # compare EBX
+ 926     74/jump-if-equal  $skip-chars-matching-whitespace-in-slice:body/disp8
+ 927     # if (*curr != '\r') break
+ 928     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x0d/imm32/cr     # compare EBX
+ 929     75/jump-if-not-equal  $skip-chars-matching-whitespace-in-slice:end/disp8
+ 930 $skip-chars-matching-whitespace-in-slice:body:
+ 931     # ++curr
+ 932     40/increment-EAX
+ 933     eb/jump  $skip-chars-matching-whitespace-in-slice:loop/disp8
+ 934 $skip-chars-matching-whitespace-in-slice:end:
+ 935     # . restore registers
+ 936     5b/pop-to-EBX
+ 937     59/pop-to-ECX
+ 938     # . epilog
+ 939     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 940     5d/pop-to-EBP
+ 941     c3/return
+ 942 
+ 943 test-skip-chars-matching-whitespace-in-slice:
+ 944     # (EAX..ECX) = " \nab"
+ 945     b8/copy-to-EAX  " \nab"/imm32
+ 946     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+ 947     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+ 948     05/add-to-EAX  4/imm32
+ 949     # EAX = skip-chars-matching-whitespace-in-slice(EAX, ECX)
+ 950     # . . push args
+ 951     51/push-ECX
+ 952     50/push-EAX
+ 953     # . . call
+ 954     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+ 955     # . . discard args
+ 956     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 957     # check-ints-equal(ECX-EAX, 2, msg)
+ 958     # . . push args
+ 959     68/push  "F - test-skip-chars-matching-whitespace-in-slice"/imm32
+ 960     68/push  2/imm32
+ 961     # . . push ECX-EAX
+ 962     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+ 963     51/push-ECX
+ 964     # . . call
+ 965     e8/call  check-ints-equal/disp32
+ 966     # . . discard args
+ 967     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 968     # end
+ 969     c3/return
+ 970 
+ 971 # minor fork of 'skip-chars-matching-in-slice'
+ 972 skip-chars-not-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
+ 973     # . prolog
+ 974     55/push-EBP
+ 975     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 976     # . save registers
+ 977     51/push-ECX
+ 978     52/push-EDX
+ 979     53/push-EBX
+ 980     # EAX = curr
+ 981     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
+ 982     # ECX = end
+ 983     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
+ 984     # EDX = delimiter
+ 985     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
+ 986     # EBX = 0
+ 987     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+ 988 $skip-chars-not-matching-in-slice:loop:
+ 989     # if (curr >= end) break
+ 990     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
+ 991     73/jump-if-greater-or-equal-unsigned  $skip-chars-not-matching-in-slice:end/disp8
+ 992     # if (*curr == delimiter) break
+ 993     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
+ 994     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
+ 995     74/jump-if-equal  $skip-chars-not-matching-in-slice:end/disp8
+ 996     # ++curr
+ 997     40/increment-EAX
+ 998     eb/jump  $skip-chars-not-matching-in-slice:loop/disp8
+ 999 $skip-chars-not-matching-in-slice:end:
+1000     # . restore registers
+1001     5b/pop-to-EBX
+1002     5a/pop-to-EDX
+1003     59/pop-to-ECX
+1004     # . epilog
+1005     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1006     5d/pop-to-EBP
+1007     c3/return
+1008 
+1009 test-skip-chars-not-matching-in-slice:
+1010     # (EAX..ECX) = "ab "
+1011     b8/copy-to-EAX  "ab "/imm32
+1012     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1013     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1014     05/add-to-EAX  4/imm32
+1015     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
+1016     # . . push args
+1017     68/push  0x20/imm32/space
+1018     51/push-ECX
+1019     50/push-EAX
+1020     # . . call
+1021     e8/call  skip-chars-not-matching-in-slice/disp32
+1022     # . . discard args
+1023     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1024     # check-ints-equal(ECX-EAX, 1, msg)
+1025     # . . push args
+1026     68/push  "F - test-skip-chars-not-matching-in-slice"/imm32
+1027     68/push  1/imm32
+1028     # . . push ECX-EAX
+1029     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+1030     51/push-ECX
+1031     # . . call
+1032     e8/call  check-ints-equal/disp32
+1033     # . . discard args
+1034     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1035     # end
+1036     c3/return
+1037 
+1038 test-skip-chars-not-matching-in-slice-none:
+1039     # (EAX..ECX) = " ab"
+1040     b8/copy-to-EAX  " ab"/imm32
+1041     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1042     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1043     05/add-to-EAX  4/imm32
+1044     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
+1045     # . . push args
+1046     68/push  0x20/imm32/space
+1047     51/push-ECX
+1048     50/push-EAX
+1049     # . . call
+1050     e8/call  skip-chars-not-matching-in-slice/disp32
+1051     # . . discard args
+1052     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1053     # check-ints-equal(ECX-EAX, 3, msg)
+1054     # . . push args
+1055     68/push  "F - test-skip-chars-not-matching-in-slice-none"/imm32
+1056     68/push  3/imm32
+1057     # . . push ECX-EAX
+1058     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+1059     51/push-ECX
+1060     # . . call
+1061     e8/call  check-ints-equal/disp32
+1062     # . . discard args
+1063     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1064     # end
+1065     c3/return
+1066 
+1067 test-skip-chars-not-matching-in-slice-all:
+1068     # (EAX..ECX) = "ab"
+1069     b8/copy-to-EAX  "ab"/imm32
+1070     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1071     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1072     05/add-to-EAX  4/imm32
+1073     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
+1074     # . . push args
+1075     68/push  0x20/imm32/space
+1076     51/push-ECX
+1077     50/push-EAX
+1078     # . . call
+1079     e8/call  skip-chars-not-matching-in-slice/disp32
+1080     # . . discard args
+1081     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1082     # check-ints-equal(ECX-EAX, 0, msg)
+1083     # . . push args
+1084     68/push  "F - test-skip-chars-not-matching-in-slice-all"/imm32
+1085     68/push  0/imm32
+1086     # . . push ECX-EAX
+1087     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+1088     51/push-ECX
+1089     # . . call
+1090     e8/call  check-ints-equal/disp32
+1091     # . . discard args
+1092     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1093     # end
+1094     c3/return
+1095 
+1096 skip-chars-not-matching-whitespace-in-slice:  # in : (address stream)
+1097     # . prolog
+1098     55/push-EBP
+1099     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1100     # . save registers
+1101     51/push-ECX
+1102     53/push-EBX
+1103     # EAX = curr
+1104     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
+1105     # ECX = end
+1106     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
+1107     # EBX = 0
+1108     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+1109 $skip-chars-not-matching-whitespace-in-slice:loop:
+1110     # if (curr >= end) break
+1111     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
+1112     0f 83/jump-if-greater-or-equal-unsigned  $skip-chars-not-matching-in-slice:end/disp32
+1113     # EBX = *curr
+1114     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
+1115     # if (*curr == ' ') break
+1116     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x20/imm32/space  # compare EBX
+1117     74/jump-if-equal  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1118     # if (*curr == '\n') break
+1119     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x0a/imm32/newline  # compare EBX
+1120     74/jump-if-equal  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1121     # if (*curr == '\t') break
+1122     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x09/imm32/tab    # compare EBX
+1123     74/jump-if-equal  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1124     # if (*curr == '\r') break
+1125     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0x0d/imm32/cr     # compare EBX
+1126     74/jump-if-equal  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1127     # ++curr
+1128     40/increment-EAX
+1129     eb/jump  $skip-chars-not-matching-whitespace-in-slice:loop/disp8
+1130 $skip-chars-not-matching-whitespace-in-slice:end:
+1131     # . restore registers
+1132     5b/pop-to-EBX
+1133     59/pop-to-ECX
+1134     # . epilog
+1135     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1136     5d/pop-to-EBP
+1137     c3/return
+1138 
+1139 test-skip-chars-not-matching-whitespace-in-slice:
+1140     # (EAX..ECX) = "ab\n"
+1141     b8/copy-to-EAX  "ab\n"/imm32
+1142     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1143     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1144     05/add-to-EAX  4/imm32
+1145     # EAX = skip-chars-not-matching-whitespace-in-slice(EAX, ECX)
+1146     # . . push args
+1147     51/push-ECX
+1148     50/push-EAX
+1149     # . . call
+1150     e8/call  skip-chars-not-matching-whitespace-in-slice/disp32
+1151     # . . discard args
+1152     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1153     # check-ints-equal(ECX-EAX, 1, msg)
+1154     # . . push args
+1155     68/push  "F - test-skip-chars-not-matching-whitespace-in-slice"/imm32
+1156     68/push  1/imm32
+1157     # . . push ECX-EAX
+1158     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+1159     51/push-ECX
+1160     # . . call
+1161     e8/call  check-ints-equal/disp32
+1162     # . . discard args
+1163     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1164     # end
+1165     c3/return
+1166 
+1167 # . . vim:nowrap:textwidth=0
 
diff --git a/html/074print-int-decimal.subx.html b/html/074print-int-decimal.subx.html index 851e879c..df3446ee 100644 --- a/html/074print-int-decimal.subx.html +++ b/html/074print-int-decimal.subx.html @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.Folded { color: #080808; background-color: #949494; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxS2Comment { color: #8a8a8a; } +.Folded { color: #080808; background-color: #949494; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxH1Comment { color: #005faf; text-decoration: underline; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/075array-equal.subx.html b/html/075array-equal.subx.html index b2f9183d..788c3c03 100644 --- a/html/075array-equal.subx.html +++ b/html/075array-equal.subx.html @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxTest { color: #5f8700; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } -.subxH1Comment { color: #005faf; text-decoration: underline; } +.subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } +.subxH1Comment { color: #005faf; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } --> @@ -363,7 +363,7 @@ if ('onhashchange' in window) { 302 52/push-EDX 303 51/push-ECX 304 # . . call -305 e8/call skip-chars-matching-in-slice/disp32 +305 e8/call skip-chars-matching-in-slice/disp32 306 # . . discard args 307 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 308 # . ECX = EAX @@ -378,7 +378,7 @@ if ('onhashchange' in window) { 317 52/push-EDX 318 51/push-ECX 319 # . . call -320 e8/call skip-chars-not-matching-in-slice/disp32 +320 e8/call skip-chars-not-matching-in-slice/disp32 321 # . . discard args 322 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 323 # . ECX = EAX @@ -424,7 +424,7 @@ if ('onhashchange' in window) { 363 52/push-EDX 364 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX 365 # . . call -366 e8/call skip-chars-matching-in-slice/disp32 +366 e8/call skip-chars-matching-in-slice/disp32 367 # . . discard args 368 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 369 # . slice->start = EAX @@ -439,7 +439,7 @@ if ('onhashchange' in window) { 378 52/push-EDX 379 50/push-EAX 380 # . . call -381 e8/call skip-chars-not-matching-in-slice/disp32 +381 e8/call skip-chars-not-matching-in-slice/disp32 382 # . . discard args 383 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 384 # . slice->end = EAX diff --git a/html/076zero-out.subx.html b/html/076zero-out.subx.html index eb92cabd..2bb15365 100644 --- a/html/076zero-out.subx.html +++ b/html/076zero-out.subx.html @@ -14,12 +14,12 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxS2Comment { color: #8a8a8a; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxS1Comment { color: #0000af; } .subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } .subxTest { color: #5f8700; } --> diff --git a/html/077slurp.subx.html b/html/077slurp.subx.html index 3c49b01c..f68c3515 100644 --- a/html/077slurp.subx.html +++ b/html/077slurp.subx.html @@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxTest { color: #5f8700; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .subxS2Comment { color: #8a8a8a; } +.LineNr { } +.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/078table.subx.html b/html/078table.subx.html new file mode 100644 index 00000000..e3d29f43 --- /dev/null +++ b/html/078table.subx.html @@ -0,0 +1,1761 @@ + + + + +Mu - 078table.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/078table.subx +
+   1 # A table is a stream of (key, value) rows.
+   2 #
+   3 # Each row consists of a 4-byte key (address to a string) and a variable-size
+   4 # value.
+   5 #
+   6 # Accessing the table performs a linear scan for a key string, and always
+   7 # requires passing in the row size.
+   8 #
+   9 # Table primitives have the form <variant>(stream, <arg>, row-size, ...) -> address/EAX
+  10 #
+  11 # The following table shows available options for <variant>:
+  12 #   if not found:           | arg=string              arg=slice
+  13 #   ------------------------+---------------------------------------------------
+  14 #   abort                   | get                     get-slice
+  15 #   insert key              | get-or-insert           leaky-get-or-insert-slice
+  16 #   stop                    | get-or-stop             get-slice-or-stop
+  17 #   return null             | maybe-get               maybe-get-slice
+  18 # Some variants may take extra args.
+  19 
+  20 == code
+  21 #   instruction                     effective address                                                   register    displacement    immediate
+  22 # . op          subop               mod             rm32          base        index         scale       r32
+  23 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+  24 
+  25 # if no row is found, abort
+  26 get:  # table : (address stream {string, _}), key : (address string), row-size : int, abort-message-prefix : (address string) -> EAX : (address _)
+  27     # pseudocode:
+  28     #   curr = table->data
+  29     #   max = &table->data[table->write]
+  30     #   while curr < max
+  31     #     if string-equal?(key, *curr)
+  32     #       return curr+4
+  33     #     curr += row-size
+  34     #   abort
+  35     #
+  36     # . prolog
+  37     55/push-EBP
+  38     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  39     # . save registers
+  40     51/push-ECX
+  41     52/push-EDX
+  42     56/push-ESI
+  43     # ESI = table
+  44     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+  45     # curr/ECX = table->data
+  46     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+  47     # max/EDX = table->data + table->write
+  48     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+  49     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+  50 $get:search-loop:
+  51     # if (curr >= max) abort
+  52     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+  53     73/jump-if-greater-or-equal-unsigned  $get:abort/disp8
+  54     # if (string-equal?(key, *curr)) return curr+4
+  55     # . EAX = string-equal?(key, *curr)
+  56     # . . push args
+  57     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+  58     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+  59     # . . call
+  60     e8/call  string-equal?/disp32
+  61     # . . discard args
+  62     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  63     # . if (EAX != 0) return EAX = curr+4
+  64     3d/compare-EAX-and  0/imm32
+  65     74/jump-if-equal  $get:mismatch/disp8
+  66     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+  67     eb/jump  $get:end/disp8
+  68 $get:mismatch:
+  69     # curr += row-size
+  70     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+  71     # loop
+  72     eb/jump  $get:search-loop/disp8
+  73 $get:end:
+  74     # . restore registers
+  75     5e/pop-to-ESI
+  76     5a/pop-to-EDX
+  77     59/pop-to-ECX
+  78     # . epilog
+  79     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+  80     5d/pop-to-EBP
+  81     c3/return
+  82 
+  83 $get:abort:
+  84     # . _write(2/stderr, abort-message-prefix)
+  85     # . . push args
+  86     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
+  87     68/push  2/imm32/stderr
+  88     # . . call
+  89     e8/call  _write/disp32
+  90     # . . discard args
+  91     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  92     # . _write(2/stderr, error)
+  93     # . . push args
+  94     68/push  ": get: key not found: "/imm32
+  95     68/push  2/imm32/stderr
+  96     # . . call
+  97     e8/call  _write/disp32
+  98     # . . discard args
+  99     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 100     # . _write(2/stderr, key)
+ 101     # . . push args
+ 102     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 103     68/push  2/imm32/stderr
+ 104     # . . call
+ 105     e8/call  _write/disp32
+ 106     # . . discard args
+ 107     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 108     # . _write(2/stderr, "\n")
+ 109     # . . push args
+ 110     68/push  "\n"/imm32
+ 111     68/push  2/imm32/stderr
+ 112     # . . call
+ 113     e8/call  _write/disp32
+ 114     # . . discard args
+ 115     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 116     # . syscall(exit, 1)
+ 117     bb/copy-to-EBX  1/imm32
+ 118     b8/copy-to-EAX  1/imm32/exit
+ 119     cd/syscall  0x80/imm8
+ 120     # never gets here
+ 121 
+ 122 test-get:
+ 123     # . prolog
+ 124     55/push-EBP
+ 125     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 126     # - setup: create a table with a couple of keys
+ 127     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+ 128     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+ 129     68/push  0x10/imm32/length
+ 130     68/push  0/imm32/read
+ 131     68/push  0/imm32/write
+ 132     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+ 133     # insert(table, "code", 8 bytes per row)
+ 134     # . . push args
+ 135     68/push  8/imm32/row-size
+ 136     68/push  "code"/imm32
+ 137     51/push-ECX
+ 138     # . . call
+ 139     e8/call  get-or-insert/disp32
+ 140     # . . discard args
+ 141     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 142     # insert(table, "data", 8 bytes per row)
+ 143     # . . push args
+ 144     68/push  8/imm32/row-size
+ 145     68/push  "data"/imm32
+ 146     51/push-ECX
+ 147     # . . call
+ 148     e8/call  get-or-insert/disp32
+ 149     # . . discard args
+ 150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 151 $test-get:check1:
+ 152     # EAX = get(table, "code", 8 bytes per row)
+ 153     # . . push args
+ 154     68/push  8/imm32/row-size
+ 155     68/push  "code"/imm32
+ 156     51/push-ECX
+ 157     # . . call
+ 158     e8/call  get/disp32
+ 159     # . . discard args
+ 160     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 161     # check-ints-equal(EAX - table->data, 4, msg)
+ 162     # . check-ints-equal(EAX - table, 16, msg)
+ 163     # . . push args
+ 164     68/push  "F - test-get/0"/imm32
+ 165     68/push  0x10/imm32
+ 166     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 167     50/push-EAX
+ 168     # . . call
+ 169     e8/call  check-ints-equal/disp32
+ 170     # . . discard args
+ 171     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 172 $test-get:check2:
+ 173     # EAX = get(table, "data", 8 bytes per row)
+ 174     # . . push args
+ 175     68/push  8/imm32/row-size
+ 176     68/push  "data"/imm32
+ 177     51/push-ECX
+ 178     # . . call
+ 179     e8/call  get/disp32
+ 180     # . . discard args
+ 181     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 182     # check-ints-equal(EAX - table->data, 12, msg)
+ 183     # . check-ints-equal(EAX - table, 24, msg)
+ 184     # . . push args
+ 185     68/push  "F - test-get/1"/imm32
+ 186     68/push  0x18/imm32
+ 187     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 188     50/push-EAX
+ 189     # . . call
+ 190     e8/call  check-ints-equal/disp32
+ 191     # . . discard args
+ 192     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 193 $test-get:end:
+ 194     # . epilog
+ 195     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 196     5d/pop-to-EBP
+ 197     c3/return
+ 198 
+ 199 # if no row is found, abort
+ 200 get-slice:  # table : (address stream {string, _}), key : (address slice), row-size : int, abort-message-prefix : (address string) -> EAX : (address _)
+ 201     # pseudocode:
+ 202     #   curr = table->data
+ 203     #   max = &table->data[table->write]
+ 204     #   while curr < max
+ 205     #     if slice-equal?(key, *curr)
+ 206     #       return curr+4
+ 207     #     curr += row-size
+ 208     #   abort
+ 209     #
+ 210     # . prolog
+ 211     55/push-EBP
+ 212     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 213     # . save registers
+ 214     51/push-ECX
+ 215     52/push-EDX
+ 216     56/push-ESI
+ 217     # ESI = table
+ 218     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 219     # curr/ECX = table->data
+ 220     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+ 221     # max/EDX = table->data + table->write
+ 222     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+ 223     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+ 224 $get-slice:search-loop:
+ 225     # if (curr >= max) abort
+ 226     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+ 227     73/jump-if-greater-or-equal-unsigned  $get-slice:abort/disp8
+ 228     # if (slice-equal?(key, *curr)) return curr+4
+ 229     # . EAX = slice-equal?(key, *curr)
+ 230     # . . push args
+ 231     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 232     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 233     # . . call
+ 234     e8/call  slice-equal?/disp32
+ 235     # . . discard args
+ 236     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 237     # . if (EAX != 0) return EAX = curr+4
+ 238     3d/compare-EAX-and  0/imm32
+ 239     74/jump-if-equal  $get-slice:mismatch/disp8
+ 240     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+ 241     eb/jump  $get-slice:end/disp8
+ 242 $get-slice:mismatch:
+ 243     # curr += row-size
+ 244     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+ 245     # loop
+ 246     eb/jump  $get-slice:search-loop/disp8
+ 247 $get-slice:end:
+ 248     # . restore registers
+ 249     5e/pop-to-ESI
+ 250     5a/pop-to-EDX
+ 251     59/pop-to-ECX
+ 252     # . epilog
+ 253     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 254     5d/pop-to-EBP
+ 255     c3/return
+ 256 
+ 257 $get-slice:abort:
+ 258     # . _write(2/stderr, abort-message-prefix)
+ 259     # . . push args
+ 260     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
+ 261     68/push  2/imm32/stderr
+ 262     # . . call
+ 263     e8/call  _write/disp32
+ 264     # . . discard args
+ 265     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 266     # . _write(2/stderr, error)
+ 267     # . . push args
+ 268     68/push  ": get-slice: key not found: "/imm32
+ 269     68/push  2/imm32/stderr
+ 270     # . . call
+ 271     e8/call  _write/disp32
+ 272     # . . discard args
+ 273     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 274     # . write-slice-buffered(Stderr, key)
+ 275     # . . push args
+ 276     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 277     68/push  Stderr/imm32
+ 278     # . . call
+ 279     e8/call  write-slice-buffered/disp32
+ 280     # . . discard args
+ 281     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 282     # . flush(Stderr)
+ 283     # . . push args
+ 284     68/push  Stderr/imm32
+ 285     # . . call
+ 286     e8/call  flush/disp32
+ 287     # . . discard args
+ 288     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 289     # . _write(2/stderr, "\n")
+ 290     # . . push args
+ 291     68/push  "\n"/imm32
+ 292     68/push  2/imm32/stderr
+ 293     # . . call
+ 294     e8/call  _write/disp32
+ 295     # . . discard args
+ 296     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 297     # . syscall(exit, 1)
+ 298     bb/copy-to-EBX  1/imm32
+ 299     b8/copy-to-EAX  1/imm32/exit
+ 300     cd/syscall  0x80/imm8
+ 301     # never gets here
+ 302 
+ 303 test-get-slice:
+ 304     # . prolog
+ 305     55/push-EBP
+ 306     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 307     # - setup: create a table with a couple of keys
+ 308     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+ 309     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+ 310     68/push  0x10/imm32/length
+ 311     68/push  0/imm32/read
+ 312     68/push  0/imm32/write
+ 313     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+ 314     # insert(table, "code", 8 bytes per row)
+ 315     # . . push args
+ 316     68/push  8/imm32/row-size
+ 317     68/push  "code"/imm32
+ 318     51/push-ECX
+ 319     # . . call
+ 320     e8/call  get-or-insert/disp32
+ 321     # . . discard args
+ 322     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 323     # insert(table, "data", 8 bytes per row)
+ 324     # . . push args
+ 325     68/push  8/imm32/row-size
+ 326     68/push  "data"/imm32
+ 327     51/push-ECX
+ 328     # . . call
+ 329     e8/call  get-or-insert/disp32
+ 330     # . . discard args
+ 331     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 332 $test-get-slice:check1:
+ 333     # (EAX..EDX) = "code"
+ 334     b8/copy-to-EAX  "code"/imm32
+ 335     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy *EAX to EDX
+ 336     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  2/index/EDX   .           2/r32/EDX   4/disp8         .                 # copy EAX+EDX+4 to EDX
+ 337     05/add-to-EAX  4/imm32
+ 338     # var slice/EDX = {EAX, EDX}
+ 339     52/push-EDX
+ 340     50/push-EAX
+ 341     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+ 342     # EAX = get-slice(table, "code", 8 bytes per row)
+ 343     # . . push args
+ 344     68/push  8/imm32/row-size
+ 345     52/push-EDX
+ 346     51/push-ECX
+ 347     # . . call
+ 348     e8/call  get-slice/disp32
+ 349     # . . discard args
+ 350     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 351     # check-ints-equal(EAX - table->data, 4, msg)  # first row's value slot returned
+ 352     # . check-ints-equal(EAX - table, 16, msg)
+ 353     # . . push args
+ 354     68/push  "F - test-get-slice/0"/imm32
+ 355     68/push  0x10/imm32
+ 356     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 357     50/push-EAX
+ 358     # . . call
+ 359     e8/call  check-ints-equal/disp32
+ 360     # . . discard args
+ 361     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 362 $test-get-slice:check2:
+ 363     # (EAX..EDX) = "data"
+ 364     b8/copy-to-EAX  "data"/imm32
+ 365     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy *EAX to EDX
+ 366     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  2/index/EDX   .           2/r32/EDX   4/disp8         .                 # copy EAX+EDX+4 to EDX
+ 367     05/add-to-EAX  4/imm32
+ 368     # var slice/EDX = {EAX, EDX}
+ 369     52/push-EDX
+ 370     50/push-EAX
+ 371     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+ 372     # EAX = get-slice(table, "data" slice, 8 bytes per row)
+ 373     # . . push args
+ 374     68/push  8/imm32/row-size
+ 375     52/push-EDX
+ 376     51/push-ECX
+ 377     # . . call
+ 378     e8/call  get-slice/disp32
+ 379     # . . discard args
+ 380     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 381     # check-ints-equal(EAX - table->data, 12, msg)
+ 382     # . check-ints-equal(EAX - table, 24, msg)
+ 383     # . . push args
+ 384     68/push  "F - test-get-slice/1"/imm32
+ 385     68/push  0x18/imm32
+ 386     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 387     50/push-EAX
+ 388     # . . call
+ 389     e8/call  check-ints-equal/disp32
+ 390     # . . discard args
+ 391     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 392 $test-get-slice:end:
+ 393     # . epilog
+ 394     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 395     5d/pop-to-EBP
+ 396     c3/return
+ 397 
+ 398 # if no row is found, save 'key' to the next available row
+ 399 # if there are no rows free, abort
+ 400 # return the address of the value
+ 401 # Beware: assume keys are immutable; they're inserted by reference
+ 402 # TODO: pass in an allocation descriptor
+ 403 get-or-insert:  # table : (address stream {string, _}), key : (address string), row-size : int -> EAX : (address _)
+ 404     # pseudocode:
+ 405     #   curr = table->data
+ 406     #   max = &table->data[table->write]
+ 407     #   while curr < max
+ 408     #     if string-equal?(key, *curr)
+ 409     #       return curr+4
+ 410     #     curr += row-size
+ 411     #   if table->write >= table->length
+ 412     #     abort
+ 413     #   zero-out(max, row-size)
+ 414     #   *max = key
+ 415     #   table->write += row-size
+ 416     #   return max+4
+ 417     #
+ 418     # . prolog
+ 419     55/push-EBP
+ 420     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 421     # . save registers
+ 422     51/push-ECX
+ 423     52/push-EDX
+ 424     56/push-ESI
+ 425     # ESI = table
+ 426     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 427     # curr/ECX = table->data
+ 428     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+ 429     # max/EDX = table->data + table->write
+ 430     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+ 431     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+ 432 $get-or-insert:search-loop:
+ 433     # if (curr >= max) break
+ 434     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+ 435     73/jump-if-greater-or-equal-unsigned  $get-or-insert:not-found/disp8
+ 436     # if (string-equal?(key, *curr)) return curr+4
+ 437     # . EAX = string-equal?(key, *curr)
+ 438     # . . push args
+ 439     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 440     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 441     # . . call
+ 442     e8/call  string-equal?/disp32
+ 443     # . . discard args
+ 444     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 445     # . if (EAX != 0) return EAX = curr+4
+ 446     3d/compare-EAX-and  0/imm32
+ 447     74/jump-if-equal  $get-or-insert:mismatch/disp8
+ 448     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+ 449     eb/jump  $get-or-insert:end/disp8
+ 450 $get-or-insert:mismatch:
+ 451     # curr += row-size
+ 452     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+ 453     # loop
+ 454     eb/jump  $get-or-insert:search-loop/disp8
+ 455 $get-or-insert:not-found:
+ 456     # result/EAX = 0
+ 457     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 458     # if (table->write >= table->length) abort
+ 459     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
+ 460     3b/compare                      1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   8/disp8         .                 # compare ECX with *(ESI+8)
+ 461     73/jump-if-greater-or-equal-unsigned  $get-or-insert:abort/disp8
+ 462     # zero-out(max, row-size)
+ 463     # . . push args
+ 464     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
+ 465     52/push-EDX
+ 466     # . . call
+ 467     e8/call  zero-out/disp32
+ 468     # . . discard args
+ 469     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 470     # *max = key
+ 471     # . EAX = key
+ 472     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy *(EBP+12) to EAX
+ 473     # . *max = EAX
+ 474     89/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDX
+ 475     # table->write += row-size
+ 476     # . EAX = row-size
+ 477     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0x10/disp8      .                 # copy *(EBP+16) to EAX
+ 478     # . table->write += EAX
+ 479     01/add                          0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # add EAX to *ESI
+ 480     # return max+4
+ 481     # . EAX = max
+ 482     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy EDX to EAX
+ 483     # . EAX += 4
+ 484     05/add-to-EAX  4/imm32
+ 485 $get-or-insert:end:
+ 486     # . restore registers
+ 487     5e/pop-to-ESI
+ 488     5a/pop-to-EDX
+ 489     59/pop-to-ECX
+ 490     # . epilog
+ 491     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 492     5d/pop-to-EBP
+ 493     c3/return
+ 494 
+ 495 $get-or-insert:abort:
+ 496     # . _write(2/stderr, error)
+ 497     # . . push args
+ 498     68/push  "get-or-insert: table is full\n"/imm32
+ 499     68/push  2/imm32/stderr
+ 500     # . . call
+ 501     e8/call  _write/disp32
+ 502     # . . discard args
+ 503     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 504     # . syscall(exit, 1)
+ 505     bb/copy-to-EBX  1/imm32
+ 506     b8/copy-to-EAX  1/imm32/exit
+ 507     cd/syscall  0x80/imm8
+ 508     # never gets here
+ 509 
+ 510 test-get-or-insert:
+ 511     # . prolog
+ 512     55/push-EBP
+ 513     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 514     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+ 515     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+ 516     68/push  0x10/imm32/length
+ 517     68/push  0/imm32/read
+ 518     68/push  0/imm32/write
+ 519     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+ 520 $test-get-or-insert:first-call:
+ 521     # - start with an empty table, insert one key, verify that it was inserted
+ 522     # EAX = get-or-insert(table, "code", 8 bytes per row)
+ 523     # . . push args
+ 524     68/push  8/imm32/row-size
+ 525     68/push  "code"/imm32
+ 526     51/push-ECX
+ 527     # . . call
+ 528     e8/call  get-or-insert/disp32
+ 529     # . . discard args
+ 530     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 531     # check-ints-equal(EAX - table->data, 4, msg)  # first row's value slot returned
+ 532     # . check-ints-equal(EAX - table, 16, msg)
+ 533     # . . push args
+ 534     68/push  "F - test-get-or-insert/0"/imm32
+ 535     68/push  0x10/imm32
+ 536     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 537     50/push-EAX
+ 538     # . . call
+ 539     e8/call  check-ints-equal/disp32
+ 540     # . . discard args
+ 541     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 542 $test-get-or-insert:check2:
+ 543     # check-ints-equal(table->write, row-size = 8, msg)
+ 544     # . . push args
+ 545     68/push  "F - test-get-or-insert/1"/imm32
+ 546     68/push  8/imm32/row-size
+ 547     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 548     # . . call
+ 549     e8/call  check-ints-equal/disp32
+ 550     # . . discard args
+ 551     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 552     # check-string-equal(*table->data, "code", msg)
+ 553     # . . push args
+ 554     68/push  "F - test-get-or-insert/2"/imm32
+ 555     68/push  "code"/imm32
+ 556     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0xc/disp8       .                 # push *(ECX+12)
+ 557     # . . call
+ 558     e8/call  check-string-equal/disp32
+ 559     # . . discard args
+ 560     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 561 $test-get-or-insert:second-call:
+ 562     # - insert the same key again, verify that it was reused
+ 563     # EAX = get-or-insert(table, "code", 8 bytes per row)
+ 564     # . . push args
+ 565     68/push  8/imm32/row-size
+ 566     68/push  "code"/imm32
+ 567     51/push-ECX
+ 568     # . . call
+ 569     e8/call  get-or-insert/disp32
+ 570     # . . discard args
+ 571     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 572     # check-ints-equal(EAX - table->data, 4, msg)
+ 573     # . check-ints-equal(EAX - table, 16, msg)
+ 574     # . . push args
+ 575     68/push  "F - test-get-or-insert/3"/imm32
+ 576     68/push  0x10/imm32
+ 577     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 578     50/push-EAX
+ 579     # . . call
+ 580     e8/call  check-ints-equal/disp32
+ 581     # . . discard args
+ 582     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 583     # no new row inserted
+ 584     # . check-ints-equal(table->write, row-size = 8, msg)
+ 585     # . . push args
+ 586     68/push  "F - test-get-or-insert/4"/imm32
+ 587     68/push  8/imm32/row-size
+ 588     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 589     # . . call
+ 590     e8/call  check-ints-equal/disp32
+ 591     # . . discard args
+ 592     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 593     # check-string-equal(*table->data, "code", msg)
+ 594     # . . push args
+ 595     68/push  "F - test-get-or-insert/5"/imm32
+ 596     68/push  "code"/imm32
+ 597     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0xc/disp8       .                 # push *(ECX+12)
+ 598     # . . call
+ 599     e8/call  check-string-equal/disp32
+ 600     # . . discard args
+ 601     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 602 $test-get-or-insert:third-call:
+ 603     # - insert a new key, verify that it was inserted
+ 604     # EAX = get-or-insert(table, "data", 8 bytes per row)
+ 605     # . . push args
+ 606     68/push  8/imm32/row-size
+ 607     68/push  "data"/imm32
+ 608     51/push-ECX
+ 609     # . . call
+ 610     e8/call  get-or-insert/disp32
+ 611     # . . discard args
+ 612     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 613     # table gets a new row
+ 614     # check-ints-equal(EAX - table->data, 12, msg)  # second row's value slot returned
+ 615     # . check-ints-equal(EAX - table, 24, msg)
+ 616     # . . push args
+ 617     68/push  "F - test-get-or-insert/6"/imm32
+ 618     68/push  0x18/imm32
+ 619     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 620     50/push-EAX
+ 621     # . . call
+ 622     e8/call  check-ints-equal/disp32
+ 623     # . . discard args
+ 624     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 625     # check-ints-equal(table->write, 2 rows = 16, msg)
+ 626     # . . push args
+ 627     68/push  "F - test-get-or-insert/7"/imm32
+ 628     68/push  0x10/imm32/two-rows
+ 629     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 630     # . . call
+ 631     e8/call  check-ints-equal/disp32
+ 632     # . . discard args
+ 633     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 634     # check-string-equal(*table->data+8, "data", msg)
+ 635     # check-string-equal(*(table+20), "data", msg)
+ 636     # . . push args
+ 637     68/push  "F - test-get-or-insert/8"/imm32
+ 638     68/push  "data"/imm32
+ 639     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0x14/disp8      .                 # push *(ECX+20)
+ 640     # . . call
+ 641     e8/call  check-string-equal/disp32
+ 642     # . . discard args
+ 643     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 644 $test-get-or-insert:end:
+ 645     # . epilog
+ 646     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 647     5d/pop-to-EBP
+ 648     c3/return
+ 649 
+ 650 # if no row is found, save 'key' in the next available row
+ 651 # if there are no rows free, abort
+ 652 # WARNING: leaks memory
+ 653 # TODO: pass in an allocation descriptor
+ 654 leaky-get-or-insert-slice:  # table : (address stream {string, _}), key : (address slice), row-size : int -> EAX : (address _)
+ 655     # pseudocode:
+ 656     #   curr = table->data
+ 657     #   max = &table->data[table->write]
+ 658     #   while curr < max
+ 659     #     if slice-equal?(key, *curr)
+ 660     #       return curr+4
+ 661     #     curr += row-size
+ 662     #   if table->write >= table->length
+ 663     #     abort
+ 664     #   zero-out(max, row-size)
+ 665     #   *max = slice-to-string(Heap, key)
+ 666     #   table->write += row-size
+ 667     #   return max+4
+ 668     #
+ 669     # . prolog
+ 670     55/push-EBP
+ 671     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 672     # . save registers
+ 673     51/push-ECX
+ 674     52/push-EDX
+ 675     56/push-ESI
+ 676     # ESI = table
+ 677     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 678     # curr/ECX = table->data
+ 679     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+ 680     # max/EDX = table->data + table->write
+ 681     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+ 682     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+ 683 $leaky-get-or-insert-slice:search-loop:
+ 684     # if (curr >= max) break
+ 685     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+ 686     73/jump-if-greater-or-equal-unsigned  $leaky-get-or-insert-slice:not-found/disp8
+ 687     # if (slice-equal?(key, *curr)) return curr+4
+ 688     # . EAX = slice-equal?(key, *curr)
+ 689     # . . push args
+ 690     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 691     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 692     # . . call
+ 693     e8/call  slice-equal?/disp32
+ 694     # . . discard args
+ 695     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 696     # . if (EAX != 0) return EAX = curr+4
+ 697     3d/compare-EAX-and  0/imm32
+ 698     74/jump-if-equal  $leaky-get-or-insert-slice:mismatch/disp8
+ 699     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+ 700     eb/jump  $leaky-get-or-insert-slice:end/disp8
+ 701 $leaky-get-or-insert-slice:mismatch:
+ 702     # curr += row-size
+ 703     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+ 704     # loop
+ 705     eb/jump  $leaky-get-or-insert-slice:search-loop/disp8
+ 706 $leaky-get-or-insert-slice:not-found:
+ 707     # result/EAX = 0
+ 708     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 709     # if (table->write >= table->length) abort
+ 710     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
+ 711     3b/compare                      1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   8/disp8         .                 # compare ECX with *(ESI+8)
+ 712     7d/jump-if-greater-or-equal  $leaky-get-or-insert-slice:abort/disp8
+ 713     # zero-out(max, row-size)
+ 714     # . . push args
+ 715     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
+ 716     52/push-EDX
+ 717     # . . call
+ 718     e8/call  zero-out/disp32
+ 719     # . . discard args
+ 720     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 721     # *max = slice-to-string(Heap, key)
+ 722     # . EAX = slice-to-string(Heap, key)
+ 723     # . . push args
+ 724     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 725     68/push  Heap/imm32
+ 726     # . . call
+ 727     e8/call  slice-to-string/disp32
+ 728     # . . discard args
+ 729     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 730     # . *max = EAX
+ 731     89/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDX
+ 732     # table->write += row-size
+ 733     # . EAX = row-size
+ 734     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0x10/disp8      .                 # copy *(EBP+16) to EAX
+ 735     # . table->write += EAX
+ 736     01/add                          0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # add EAX to *ESI
+ 737     # return max+4
+ 738     # . EAX = max
+ 739     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy EDX to EAX
+ 740     # . EAX += 4
+ 741     05/add-to-EAX  4/imm32
+ 742 $leaky-get-or-insert-slice:end:
+ 743     # . restore registers
+ 744     5e/pop-to-ESI
+ 745     5a/pop-to-EDX
+ 746     59/pop-to-ECX
+ 747     # . epilog
+ 748     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 749     5d/pop-to-EBP
+ 750     c3/return
+ 751 
+ 752 $leaky-get-or-insert-slice:abort:
+ 753     # . _write(2/stderr, error)
+ 754     # . . push args
+ 755     68/push  "leaky-get-or-insert-slice: table is full\n"/imm32
+ 756     68/push  2/imm32/stderr
+ 757     # . . call
+ 758     e8/call  _write/disp32
+ 759     # . . discard args
+ 760     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 761     # . syscall(exit, 1)
+ 762     bb/copy-to-EBX  1/imm32
+ 763     b8/copy-to-EAX  1/imm32/exit
+ 764     cd/syscall  0x80/imm8
+ 765     # never gets here
+ 766 
+ 767 test-leaky-get-or-insert-slice:
+ 768     # . prolog
+ 769     55/push-EBP
+ 770     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 771     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+ 772     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+ 773     68/push  0x10/imm32/length
+ 774     68/push  0/imm32/read
+ 775     68/push  0/imm32/write
+ 776     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+ 777     # (EAX..EDX) = "code"
+ 778     b8/copy-to-EAX  "code"/imm32
+ 779     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy *EAX to EDX
+ 780     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  2/index/EDX   .           2/r32/EDX   4/disp8         .                 # copy EAX+EDX+4 to EDX
+ 781     05/add-to-EAX  4/imm32
+ 782     # var slice/EDX = {EAX, EDX}
+ 783     52/push-EDX
+ 784     50/push-EAX
+ 785     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+ 786 $test-leaky-get-or-insert-slice:first-call:
+ 787     # - start with an empty table, insert one key, verify that it was inserted
+ 788     # EAX = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row)
+ 789     # . . push args
+ 790     68/push  8/imm32/row-size
+ 791     52/push-EDX
+ 792     51/push-ECX
+ 793     # . . call
+ 794     e8/call  leaky-get-or-insert-slice/disp32
+ 795     # . . discard args
+ 796     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 797     # check-ints-equal(EAX - table->data, 4, msg)  # first row's value slot returned
+ 798     # . check-ints-equal(EAX - table, 16, msg)
+ 799     # . . push args
+ 800     68/push  "F - test-leaky-get-or-insert-slice/0"/imm32
+ 801     68/push  0x10/imm32
+ 802     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 803     50/push-EAX
+ 804     # . . call
+ 805     e8/call  check-ints-equal/disp32
+ 806     # . . discard args
+ 807     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 808 $test-leaky-get-or-insert-slice:check2:
+ 809     # check-ints-equal(table->write, row-size = 8, msg)
+ 810     # . . push args
+ 811     68/push  "F - test-leaky-get-or-insert-slice/1"/imm32
+ 812     68/push  8/imm32/row-size
+ 813     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 814     # . . call
+ 815     e8/call  check-ints-equal/disp32
+ 816     # . . discard args
+ 817     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 818     # check-string-equal(*table->data, "code", msg)
+ 819     # . . push args
+ 820     68/push  "F - test-leaky-get-or-insert-slice/2"/imm32
+ 821     68/push  "code"/imm32
+ 822     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0xc/disp8       .                 # push *(ECX+12)
+ 823     # . . call
+ 824     e8/call  check-string-equal/disp32
+ 825     # . . discard args
+ 826     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 827 $test-leaky-get-or-insert-slice:second-call:
+ 828     # - insert the same key again, verify that it was reused
+ 829     # EAX = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row)
+ 830     # . . push args
+ 831     68/push  8/imm32/row-size
+ 832     52/push-EDX
+ 833     51/push-ECX
+ 834     # . . call
+ 835     e8/call  leaky-get-or-insert-slice/disp32
+ 836     # . . discard args
+ 837     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 838     # check-ints-equal(EAX - table->data, 4, msg)
+ 839     # . check-ints-equal(EAX - table, 16, msg)
+ 840     # . . push args
+ 841     68/push  "F - test-leaky-get-or-insert-slice/3"/imm32
+ 842     68/push  0x10/imm32
+ 843     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 844     50/push-EAX
+ 845     # . . call
+ 846     e8/call  check-ints-equal/disp32
+ 847     # . . discard args
+ 848     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 849     # no new row inserted
+ 850     # . check-ints-equal(table->write, row-size = 8, msg)
+ 851     # . . push args
+ 852     68/push  "F - test-leaky-get-or-insert-slice/4"/imm32
+ 853     68/push  8/imm32/row-size
+ 854     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 855     # . . call
+ 856     e8/call  check-ints-equal/disp32
+ 857     # . . discard args
+ 858     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 859     # check-string-equal(*table->data, "code", msg)
+ 860     # . . push args
+ 861     68/push  "F - test-leaky-get-or-insert-slice/5"/imm32
+ 862     68/push  "code"/imm32
+ 863     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0xc/disp8       .                 # push *(ECX+12)
+ 864     # . . call
+ 865     e8/call  check-string-equal/disp32
+ 866     # . . discard args
+ 867     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 868 $test-leaky-get-or-insert-slice:third-call:
+ 869     # - insert a new key, verify that it was inserted
+ 870     # (EAX..EDX) = "data"
+ 871     b8/copy-to-EAX  "data"/imm32
+ 872     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy *EAX to EDX
+ 873     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  2/index/EDX   .           2/r32/EDX   4/disp8         .                 # copy EAX+EDX+4 to EDX
+ 874     05/add-to-EAX  4/imm32
+ 875     # var slice/EDX = {EAX, EDX}
+ 876     52/push-EDX
+ 877     50/push-EAX
+ 878     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+ 879     # EAX = leaky-get-or-insert-slice(table, "data" slice, 8 bytes per row)
+ 880     # . . push args
+ 881     68/push  8/imm32/row-size
+ 882     52/push-EDX
+ 883     51/push-ECX
+ 884     # . . call
+ 885     e8/call  leaky-get-or-insert-slice/disp32
+ 886     # . . discard args
+ 887     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 888     # table gets a new row
+ 889     # check-ints-equal(EAX - table->data, 12, msg)  # second row's value slot returned
+ 890     # . check-ints-equal(EAX - table, 24, msg)
+ 891     # . . push args
+ 892     68/push  "F - test-leaky-get-or-insert-slice/6"/imm32
+ 893     68/push  0x18/imm32
+ 894     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+ 895     50/push-EAX
+ 896     # . . call
+ 897     e8/call  check-ints-equal/disp32
+ 898     # . . discard args
+ 899     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 900     # check-ints-equal(table->write, 2 rows = 16, msg)
+ 901     # . . push args
+ 902     68/push  "F - test-leaky-get-or-insert-slice/7"/imm32
+ 903     68/push  0x10/imm32/two-rows
+ 904     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 905     # . . call
+ 906     e8/call  check-ints-equal/disp32
+ 907     # . . discard args
+ 908     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 909     # check-string-equal(*table->data+8, "data", msg)
+ 910     # check-string-equal(*(table+20), "data", msg)
+ 911     # . . push args
+ 912     68/push  "F - test-leaky-get-or-insert-slice/8"/imm32
+ 913     68/push  "data"/imm32
+ 914     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0x14/disp8      .                 # push *(ECX+20)
+ 915     # . . call
+ 916     e8/call  check-string-equal/disp32
+ 917     # . . discard args
+ 918     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 919 $test-leaky-get-or-insert-slice:end:
+ 920     # . epilog
+ 921     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 922     5d/pop-to-EBP
+ 923     c3/return
+ 924 
+ 925 # if no row is found, stop(ed)
+ 926 get-or-stop:  # table : (address stream {string, _}), key : (address string), row-size : int,
+ 927               # abort-message-prefix : (address string), err : (address buffered-file), ed : (address exit-descriptor)
+ 928               # -> EAX : (address _)
+ 929     # pseudocode:
+ 930     #   curr = table->data
+ 931     #   max = &table->data[table->write]
+ 932     #   while curr < max
+ 933     #     if string-equal?(key, *curr)
+ 934     #       return curr+4
+ 935     #     curr += row-size
+ 936     #   write-buffered(err, msg)
+ 937     #   stop(ed)
+ 938     #
+ 939     # . prolog
+ 940     55/push-EBP
+ 941     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 942     # . save registers
+ 943     51/push-ECX
+ 944     52/push-EDX
+ 945     56/push-ESI
+ 946     # ESI = table
+ 947     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 948     # curr/ECX = table->data
+ 949     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+ 950     # max/EDX = table->data + table->write
+ 951     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+ 952     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+ 953 $get-or-stop:search-loop:
+ 954     # if (curr >= max) stop(ed)
+ 955     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+ 956     73/jump-if-greater-or-equal-unsigned  $get-or-stop:stop/disp8
+ 957     # if (string-equal?(key, *curr)) return curr+4
+ 958     # . EAX = string-equal?(key, *curr)
+ 959     # . . push args
+ 960     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+ 961     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 962     # . . call
+ 963     e8/call  string-equal?/disp32
+ 964     # . . discard args
+ 965     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 966     # . if (EAX != 0) return EAX = curr+4
+ 967     3d/compare-EAX-and  0/imm32
+ 968     74/jump-if-equal  $get-or-stop:mismatch/disp8
+ 969     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+ 970     eb/jump  $get-or-stop:end/disp8
+ 971 $get-or-stop:mismatch:
+ 972     # curr += row-size
+ 973     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+ 974     # loop
+ 975     eb/jump  $get-or-stop:search-loop/disp8
+ 976 $get-or-stop:end:
+ 977     # . restore registers
+ 978     5e/pop-to-ESI
+ 979     5a/pop-to-EDX
+ 980     59/pop-to-ECX
+ 981     # . epilog
+ 982     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 983     5d/pop-to-EBP
+ 984     c3/return
+ 985 
+ 986 $get-or-stop:stop:
+ 987     # . write-buffered(err, abort-message-prefix)
+ 988     # . . push args
+ 989     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
+ 990     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+ 991     # . . call
+ 992     e8/call  write-buffered/disp32
+ 993     # . . discard args
+ 994     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 995     # . write-buffered(err, error)
+ 996     # . . push args
+ 997     68/push  ": get-or-stop: key not found: "/imm32
+ 998     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+ 999     # . . call
+1000     e8/call  write-buffered/disp32
+1001     # . . discard args
+1002     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1003     # . write-buffered(err, key)
+1004     # . . push args
+1005     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1006     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+1007     # . . call
+1008     e8/call  write-buffered/disp32
+1009     # . . discard args
+1010     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1011     # . write-buffered(err, "\n")
+1012     # . . push args
+1013     68/push  "\n"/imm32
+1014     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+1015     # . . call
+1016     e8/call  write-buffered/disp32
+1017     # . . discard args
+1018     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1019     # . stop(ed, 1)
+1020     # . . push args
+1021     68/push  1/imm32
+1022     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x1c/disp8      .                 # push *(EBP+28)
+1023     # . . call
+1024     e8/call  stop/disp32
+1025     # never gets here
+1026 $get-or-stop:terminus:
+1027     # . . discard args
+1028     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1029     # syscall(exit, 1)
+1030     b8/copy-to-EAX  1/imm32/exit
+1031     cd/syscall  0x80/imm8
+1032 
+1033 test-get-or-stop:
+1034     # This test uses exit-descriptors. Use EBP for setting up local variables.
+1035     # . prolog
+1036     55/push-EBP
+1037     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1038     # setup
+1039     # . clear-stream(_test-error-stream)
+1040     # . . push args
+1041     68/push  _test-error-stream/imm32
+1042     # . . call
+1043     e8/call  clear-stream/disp32
+1044     # . . discard args
+1045     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1046     # . clear-stream(_test-error-buffered-file+4)
+1047     # . . push args
+1048     b8/copy-to-EAX  _test-error-buffered-file/imm32
+1049     05/add-to-EAX  4/imm32
+1050     50/push-EAX
+1051     # . . call
+1052     e8/call  clear-stream/disp32
+1053     # . . discard args
+1054     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1055     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+1056     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+1057     68/push  0x10/imm32/length
+1058     68/push  0/imm32/read
+1059     68/push  0/imm32/write
+1060     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1061     # var ed/EDX : (address exit-descriptor)
+1062     68/push  0/imm32
+1063     68/push  0/imm32
+1064     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+1065     # size 'ed' for the calls to 'get-or-stop'
+1066     # . tailor-exit-descriptor(ed, 24)
+1067     # . . push args
+1068     68/push  0x18/imm32/nbytes-of-args-for-get-or-stop
+1069     52/push-EDX
+1070     # . . call
+1071     e8/call  tailor-exit-descriptor/disp32
+1072     # . . discard args
+1073     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1074     # insert(table, "code", 8 bytes per row)
+1075     # . . push args
+1076     68/push  8/imm32/row-size
+1077     68/push  "code"/imm32
+1078     51/push-ECX
+1079     # . . call
+1080     e8/call  get-or-insert/disp32
+1081     # . . discard args
+1082     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1083 $test-get-or-stop:success:
+1084     # EAX = get-or-stop(table, "code", row-size=8, msg, _test-error-buffered-file, ed)
+1085     # . . push args
+1086     52/push-EDX/ed
+1087     68/push  _test-error-buffered-file/imm32
+1088     68/push  "foo"/imm32/abort-prefix
+1089     68/push  8/imm32/row-size
+1090     68/push  "code"/imm32
+1091     51/push-ECX
+1092     # . . call
+1093     e8/call  get-or-stop/disp32
+1094     # . . discard args
+1095     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x18/imm32        # add to ESP
+1096 $test-get-or-stop:success-assertion:
+1097     # check-ints-equal(EAX - table->data, 4, msg)
+1098     # . check-ints-equal(EAX - table, 16, msg)
+1099     # . . push args
+1100     68/push  "F - test-get-or-stop/0"/imm32
+1101     68/push  0x10/imm32
+1102     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+1103     50/push-EAX
+1104     # . . call
+1105     e8/call  check-ints-equal/disp32
+1106     # . . discard args
+1107     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1108 $test-get-or-stop:failure:
+1109     # EAX = get-or-stop(table, "data", row-size=8, msg, _test-error-buffered-file, ed)
+1110     # . . push args
+1111     52/push-EDX/ed
+1112     68/push  _test-error-buffered-file/imm32
+1113     68/push  "foo"/imm32/abort-prefix
+1114     68/push  8/imm32/row-size
+1115     68/push  "data"/imm32
+1116     51/push-ECX
+1117     # . . call
+1118     e8/call  get-or-stop/disp32
+1119     # registers except ESP may be clobbered at this point
+1120     # restore register args, discard others
+1121     59/pop-to-ECX
+1122     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+1123     5a/pop-to-EDX
+1124 $test-get-or-stop:failure-assertion:
+1125     # check that get-or-stop tried to call stop(1)
+1126     # . check-ints-equal(ed->value, 2, msg)
+1127     # . . push args
+1128     68/push  "F - test-get-or-stop/1"/imm32
+1129     68/push  2/imm32
+1130     # . . push ed->value
+1131     ff          6/subop/push        1/mod/*+disp8   2/rm32/EDX    .           .             .           .           4/disp8         .                 # push *(EDX+4)
+1132     # . . call
+1133     e8/call  check-ints-equal/disp32
+1134     # . . discard args
+1135     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1136 $test-get-or-stop:end:
+1137     # . epilog
+1138     # don't restore ESP from EBP; manually reclaim locals
+1139     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x24/imm32        # add to ESP
+1140     5d/pop-to-EBP
+1141     c3/return
+1142 
+1143 # if no row is found, stop(ed)
+1144 get-slice-or-stop:  # table : (address stream {string, _}), key : (address slice), row-size : int,
+1145                     # abort-message-prefix : (address string), err : (address buffered-file), ed : (address exit-descriptor)
+1146                     # -> EAX : (address _)
+1147     # pseudocode:
+1148     #   curr = table->data
+1149     #   max = &table->data[table->write]
+1150     #   while curr < max
+1151     #     if slice-equal?(key, *curr)
+1152     #       return curr+4
+1153     #     curr += row-size
+1154     #   write-buffered(err, msg)
+1155     #   stop(ed)
+1156     #
+1157     # . prolog
+1158     55/push-EBP
+1159     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1160     # . save registers
+1161     51/push-ECX
+1162     52/push-EDX
+1163     56/push-ESI
+1164     # ESI = table
+1165     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+1166     # curr/ECX = table->data
+1167     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+1168     # max/EDX = table->data + table->write
+1169     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+1170     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+1171 $get-slice-or-stop:search-loop:
+1172     # if (curr >= max) stop(ed)
+1173     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+1174     73/jump-if-greater-or-equal-unsigned  $get-slice-or-stop:stop/disp8
+1175     # if (slice-equal?(key, *curr)) return curr+4
+1176     # . EAX = slice-equal?(key, *curr)
+1177     # . . push args
+1178     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+1179     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1180     # . . call
+1181     e8/call  slice-equal?/disp32
+1182     # . . discard args
+1183     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1184     # . if (EAX != 0) return EAX = curr+4
+1185     3d/compare-EAX-and  0/imm32
+1186     74/jump-if-equal  $get-slice-or-stop:mismatch/disp8
+1187     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+1188     eb/jump  $get-slice-or-stop:end/disp8
+1189 $get-slice-or-stop:mismatch:
+1190     # curr += row-size
+1191     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+1192     # loop
+1193     eb/jump  $get-slice-or-stop:search-loop/disp8
+1194 $get-slice-or-stop:end:
+1195     # . restore registers
+1196     5e/pop-to-ESI
+1197     5a/pop-to-EDX
+1198     59/pop-to-ECX
+1199     # . epilog
+1200     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1201     5d/pop-to-EBP
+1202     c3/return
+1203 
+1204 $get-slice-or-stop:stop:
+1205     # . write-buffered(err, abort-message-prefix)
+1206     # . . push args
+1207     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
+1208     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+1209     # . . call
+1210     e8/call  write-buffered/disp32
+1211     # . . discard args
+1212     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1213     # . write-buffered(err, error)
+1214     # . . push args
+1215     68/push  ": get-slice-or-stop: key not found: "/imm32
+1216     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+1217     # . . call
+1218     e8/call  write-buffered/disp32
+1219     # . . discard args
+1220     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1221     # . write-slice-buffered(err, key)
+1222     # . . push args
+1223     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1224     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+1225     # . . call
+1226     e8/call  write-slice-buffered/disp32
+1227     # . . discard args
+1228     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1229     # . write-buffered(err, "\n")
+1230     # . . push args
+1231     68/push  "\n"/imm32
+1232     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+1233     # . . call
+1234     e8/call  write-buffered/disp32
+1235     # . . discard args
+1236     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1237     # . stop(ed, 1)
+1238     # . . push args
+1239     68/push  1/imm32
+1240     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x1c/disp8      .                 # push *(EBP+28)
+1241     # . . call
+1242     e8/call  stop/disp32
+1243     # never gets here
+1244 $get-slice-or-stop:terminus:
+1245     # . . discard args
+1246     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1247     # syscall(exit, 1)
+1248     b8/copy-to-EAX  1/imm32/exit
+1249     cd/syscall  0x80/imm8
+1250 
+1251 test-get-slice-or-stop:
+1252     # This test uses exit-descriptors. Use EBP for setting up local variables.
+1253     # . prolog
+1254     55/push-EBP
+1255     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1256     # setup
+1257     # . clear-stream(_test-error-stream)
+1258     # . . push args
+1259     68/push  _test-error-stream/imm32
+1260     # . . call
+1261     e8/call  clear-stream/disp32
+1262     # . . discard args
+1263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1264     # . clear-stream(_test-error-buffered-file+4)
+1265     # . . push args
+1266     b8/copy-to-EAX  _test-error-buffered-file/imm32
+1267     05/add-to-EAX  4/imm32
+1268     50/push-EAX
+1269     # . . call
+1270     e8/call  clear-stream/disp32
+1271     # . . discard args
+1272     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1273     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+1274     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+1275     68/push  0x10/imm32/length
+1276     68/push  0/imm32/read
+1277     68/push  0/imm32/write
+1278     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1279     # var ed/EDX : (address exit-descriptor)
+1280     68/push  0/imm32
+1281     68/push  0/imm32
+1282     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+1283     # var slice/EBX = "code"
+1284     # . (EAX..EBX) = "code"
+1285     b8/copy-to-EAX  "code"/imm32
+1286     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # copy *EAX to EBX
+1287     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  3/index/EBX   .           3/r32/EBX   4/disp8         .                 # copy EAX+EBX+4 to EBX
+1288     05/add-to-EAX  4/imm32
+1289     # . EBX = {EAX, EBX}
+1290     53/push-EBX
+1291     50/push-EAX
+1292     89/copy                         3/mod/direct    3/rm32/EBX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBX
+1293     # size 'ed' for the calls to 'get-or-stop' (define no locals past this point)
+1294     # . tailor-exit-descriptor(ed, 24)
+1295     # . . push args
+1296     68/push  0x18/imm32/nbytes-of-args-for-get-or-stop
+1297     52/push-EDX
+1298     # . . call
+1299     e8/call  tailor-exit-descriptor/disp32
+1300     # . . discard args
+1301     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1302     # insert(table, "code", 8 bytes per row)
+1303     # . . push args
+1304     68/push  8/imm32/row-size
+1305     68/push  "code"/imm32
+1306     51/push-ECX
+1307     # . . call
+1308     e8/call  get-or-insert/disp32
+1309     # . . discard args
+1310     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1311 $test-get-slice-or-stop:success:
+1312     # EAX = get-slice-or-stop(table, slice, row-size=8, msg, _test-error-buffered-file, ed)
+1313     # . . push args
+1314     52/push-EDX/ed
+1315     68/push  _test-error-buffered-file/imm32
+1316     68/push  "foo"/imm32/abort-prefix
+1317     68/push  8/imm32/row-size
+1318     53/push-EBX/slice
+1319     51/push-ECX
+1320     # . . call
+1321     e8/call  get-slice-or-stop/disp32
+1322     # registers except ESP may be clobbered at this point
+1323     # restore register args, discard others
+1324     59/pop-to-ECX
+1325     5b/pop-to-EBX
+1326     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1327     5a/pop-to-EDX
+1328 $test-get-slice-or-stop:success-assertion:
+1329     # check-ints-equal(EAX - table->data, 4, msg)  # first row's value slot returned
+1330     # . check-ints-equal(EAX - table, 16, msg)
+1331     # . . push args
+1332     68/push  "F - test-get-slice-or-stop/0"/imm32
+1333     68/push  0x10/imm32
+1334     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+1335     50/push-EAX
+1336     # . . call
+1337     e8/call  check-ints-equal/disp32
+1338     # . . discard args
+1339     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1340 $test-get-slice-or-stop:failure:
+1341     # slice = "segment2"
+1342     # . *EBX = "segment2"->data
+1343     b8/copy-to-EAX  "segment2"/imm32
+1344     05/add-to-EAX  4/imm32
+1345     89/copy                         0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EBX
+1346     # . *(EBX+4) = "segment2"->data + len("segment2")
+1347     05/add-to-EAX  8/imm32/strlen
+1348     89/copy                         1/mod/*+disp8   3/rm32/EBX    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EBX+4)
+1349     # EAX = get-slice-or-stop(table, slice, row-size=8, msg, _test-error-buffered-file, ed)
+1350     # . . push args
+1351     52/push-EDX/ed
+1352     68/push  _test-error-buffered-file/imm32
+1353     68/push  "foo"/imm32/abort-prefix
+1354     68/push  8/imm32/row-size
+1355     53/push-EBX/slice
+1356     51/push-ECX
+1357     # . . call
+1358     e8/call  get-slice-or-stop/disp32
+1359     # registers except ESP may be clobbered at this point
+1360     # restore register args, discard others
+1361     59/pop-to-ECX
+1362     5b/pop-to-EBX
+1363     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1364     5a/pop-to-EDX
+1365 $test-get-slice-or-stop:failure-assertion:
+1366     # check that get-or-stop tried to call stop(1)
+1367     # . check-ints-equal(ed->value, 2, msg)
+1368     # . . push args
+1369     68/push  "F - test-get-or-stop/1"/imm32
+1370     68/push  2/imm32
+1371     # . . push ed->value
+1372     ff          6/subop/push        1/mod/*+disp8   2/rm32/EDX    .           .             .           .           4/disp8         .                 # push *(EDX+4)
+1373     # . . call
+1374     e8/call  check-ints-equal/disp32
+1375     # . . discard args
+1376     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1377 $test-get-slice-or-stop:end:
+1378     # . epilog
+1379     # don't restore ESP from EBP; manually reclaim locals
+1380     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x2c/imm32        # add to ESP
+1381     5d/pop-to-EBP
+1382     c3/return
+1383 
+1384 # if no row is found, return null (0)
+1385 maybe-get:  # table : (address stream {string, _}), key : (address string), row-size : int -> EAX : (address _)
+1386     # pseudocode:
+1387     #   curr = table->data
+1388     #   max = &table->data[table->write]
+1389     #   while curr < max
+1390     #     if string-equal?(key, *curr)
+1391     #       return curr+4
+1392     #     curr += row-size
+1393     #   return 0
+1394     #
+1395     # . prolog
+1396     55/push-EBP
+1397     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1398     # . save registers
+1399     51/push-ECX
+1400     52/push-EDX
+1401     56/push-ESI
+1402     # ESI = table
+1403     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+1404     # curr/ECX = table->data
+1405     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+1406     # max/EDX = table->data + table->write
+1407     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+1408     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+1409 $maybe-get:search-loop:
+1410     # if (curr >= max) return null
+1411     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+1412     73/jump-if-greater-or-equal-unsigned  $maybe-get:null/disp8
+1413     # if (string-equal?(key, *curr)) return curr+4
+1414     # . EAX = string-equal?(key, *curr)
+1415     # . . push args
+1416     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+1417     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1418     # . . call
+1419     e8/call  string-equal?/disp32
+1420     # . . discard args
+1421     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1422     # . if (EAX != 0) return EAX = curr+4
+1423     3d/compare-EAX-and  0/imm32
+1424     74/jump-if-equal  $maybe-get:mismatch/disp8
+1425     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+1426     eb/jump  $maybe-get:end/disp8
+1427 $maybe-get:mismatch:
+1428     # curr += row-size
+1429     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+1430     # loop
+1431     eb/jump  $maybe-get:search-loop/disp8
+1432 $maybe-get:null:
+1433     b8/copy-to-EAX  0/imm32
+1434 $maybe-get:end:
+1435     # . restore registers
+1436     5e/pop-to-ESI
+1437     5a/pop-to-EDX
+1438     59/pop-to-ECX
+1439     # . epilog
+1440     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1441     5d/pop-to-EBP
+1442     c3/return
+1443 
+1444 test-maybe-get:
+1445     # . prolog
+1446     55/push-EBP
+1447     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1448     # - setup: create a table with one row
+1449     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+1450     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+1451     68/push  0x10/imm32/length
+1452     68/push  0/imm32/read
+1453     68/push  0/imm32/write
+1454     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1455     # EAX = get-or-insert(table, "code", 8 bytes per row)
+1456     # . . push args
+1457     68/push  8/imm32/row-size
+1458     68/push  "code"/imm32
+1459     51/push-ECX
+1460     # . . call
+1461     e8/call  get-or-insert/disp32
+1462     # . . discard args
+1463     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1464 $test-maybe-get:success:
+1465     # - check for the same key, verify that it was reused
+1466     # EAX = maybe-get(table, "code", 8 bytes per row)
+1467     # . . push args
+1468     68/push  8/imm32/row-size
+1469     68/push  "code"/imm32
+1470     51/push-ECX
+1471     # . . call
+1472     e8/call  maybe-get/disp32
+1473     # . . discard args
+1474     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1475     # check-ints-equal(EAX - table->data, 4, msg)
+1476     # . check-ints-equal(EAX - table, 16, msg)
+1477     # . . push args
+1478     68/push  "F - test-maybe-get/0"/imm32
+1479     68/push  0x10/imm32
+1480     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+1481     50/push-EAX
+1482     # . . call
+1483     e8/call  check-ints-equal/disp32
+1484     # . . discard args
+1485     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1486     # no new row inserted
+1487     # . check-ints-equal(table->write, row-size = 8, msg)
+1488     # . . push args
+1489     68/push  "F - test-maybe-get/1"/imm32
+1490     68/push  8/imm32/row-size
+1491     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+1492     # . . call
+1493     e8/call  check-ints-equal/disp32
+1494     # . . discard args
+1495     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1496     # check-string-equal(*table->data, "code", msg)
+1497     # . . push args
+1498     68/push  "F - test-maybe-get/2"/imm32
+1499     68/push  "code"/imm32
+1500     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0xc/disp8       .                 # push *(ECX+12)
+1501     # . . call
+1502     e8/call  check-string-equal/disp32
+1503     # . . discard args
+1504     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1505 $test-maybe-get:failure:
+1506     # - search for a new key
+1507     # EAX = maybe-get(table, "data", 8 bytes per row)
+1508     # . . push args
+1509     68/push  8/imm32/row-size
+1510     68/push  "data"/imm32
+1511     51/push-ECX
+1512     # . . call
+1513     e8/call  maybe-get/disp32
+1514     # . . discard args
+1515     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1516     # check-ints-equal(EAX, 0, msg)
+1517     # . . push args
+1518     68/push  "F - test-maybe-get/3"/imm32
+1519     68/push  0/imm32
+1520     50/push-EAX
+1521     # . . call
+1522     e8/call  check-ints-equal/disp32
+1523     # . . discard args
+1524     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1525 $test-maybe-get:end:
+1526     # . epilog
+1527     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1528     5d/pop-to-EBP
+1529     c3/return
+1530 
+1531 # if no row is found, return null (0)
+1532 maybe-get-slice:  # table : (address stream {string, _}), key : (address slice), row-size : int -> EAX : (address _)
+1533     # pseudocode:
+1534     #   curr = table->data
+1535     #   max = &table->data[table->write]
+1536     #   while curr < max
+1537     #     if slice-equal?(key, *curr)
+1538     #       return curr+4
+1539     #     curr += row-size
+1540     #   return 0
+1541     #
+1542     # . prolog
+1543     55/push-EBP
+1544     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1545     # . save registers
+1546     51/push-ECX
+1547     52/push-EDX
+1548     56/push-ESI
+1549     # ESI = table
+1550     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+1551     # curr/ECX = table->data
+1552     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy ESI+12 to ECX
+1553     # max/EDX = table->data + table->write
+1554     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+1555     8d/copy-address                 0/mod/indirect  4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   .               .                 # copy ECX+EDX to EDX
+1556 $maybe-get-slice:search-loop:
+1557     # if (curr >= max) return null
+1558     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+1559     73/jump-if-greater-or-equal-unsigned  $maybe-get-slice:null/disp8
+1560     # if (slice-equal?(key, *curr)) return curr+4
+1561     # . EAX = slice-equal?(key, *curr)
+1562     # . . push args
+1563     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+1564     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1565     # . . call
+1566     e8/call  slice-equal?/disp32
+1567     # . . discard args
+1568     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1569     # . if (EAX != 0) return EAX = curr+4
+1570     3d/compare-EAX-and  0/imm32
+1571     74/jump-if-equal  $maybe-get-slice:mismatch/disp8
+1572     8d/copy-address                 1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy ECX+4 to EAX
+1573     eb/jump  $maybe-get-slice:end/disp8
+1574 $maybe-get-slice:mismatch:
+1575     # curr += row-size
+1576     03/add                          1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x10/disp8      .                 # add *(EBP+16) to ECX
+1577     # loop
+1578     eb/jump  $maybe-get-slice:search-loop/disp8
+1579 $maybe-get-slice:null:
+1580     b8/copy-to-EAX  0/imm32
+1581 $maybe-get-slice:end:
+1582     # . restore registers
+1583     5e/pop-to-ESI
+1584     5a/pop-to-EDX
+1585     59/pop-to-ECX
+1586     # . epilog
+1587     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1588     5d/pop-to-EBP
+1589     c3/return
+1590 
+1591 test-maybe-get-slice:
+1592     # . prolog
+1593     55/push-EBP
+1594     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1595     # - setup: create a table with one row
+1596     # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes)
+1597     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # subtract from ESP
+1598     68/push  0x10/imm32/length
+1599     68/push  0/imm32/read
+1600     68/push  0/imm32/write
+1601     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1602     # insert(table, "code", 8 bytes per row)
+1603     # . . push args
+1604     68/push  8/imm32/row-size
+1605     68/push  "code"/imm32
+1606     51/push-ECX
+1607     # . . call
+1608     e8/call  get-or-insert/disp32
+1609     # . . discard args
+1610     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1611 $test-maybe-get-slice:success:
+1612     # - check for the same key, verify that it was reused
+1613     # (EAX..EDX) = "code"
+1614     b8/copy-to-EAX  "code"/imm32
+1615     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy *EAX to EDX
+1616     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  2/index/EDX   .           2/r32/EDX   4/disp8         .                 # copy EAX+EDX+4 to EDX
+1617     05/add-to-EAX  4/imm32
+1618     # var slice/EDX = {EAX, EDX}
+1619     52/push-EDX
+1620     50/push-EAX
+1621     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+1622     # EAX = maybe-get-slice(table, "code" slice, 8 bytes per row)
+1623     # . . push args
+1624     68/push  8/imm32/row-size
+1625     52/push-EDX
+1626     51/push-ECX
+1627     # . . call
+1628     e8/call  maybe-get-slice/disp32
+1629     # . . discard args
+1630     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1631     # check-ints-equal(EAX - table->data, 4, msg)
+1632     # . check-ints-equal(EAX - table, 16, msg)
+1633     # . . push args
+1634     68/push  "F - test-maybe-get-slice/0"/imm32
+1635     68/push  0x10/imm32
+1636     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+1637     50/push-EAX
+1638     # . . call
+1639     e8/call  check-ints-equal/disp32
+1640     # . . discard args
+1641     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1642     # no new row inserted
+1643     # . check-ints-equal(table->write, row-size = 8, msg)
+1644     # . . push args
+1645     68/push  "F - test-maybe-get-slice/1"/imm32
+1646     68/push  8/imm32/row-size
+1647     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
+1648     # . . call
+1649     e8/call  check-ints-equal/disp32
+1650     # . . discard args
+1651     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1652     # check-string-equal(*table->data, "code", msg)
+1653     # . . push args
+1654     68/push  "F - test-maybe-get-slice/2"/imm32
+1655     68/push  "code"/imm32
+1656     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           0xc/disp8       .                 # push *(ECX+12)
+1657     # . . call
+1658     e8/call  check-string-equal/disp32
+1659     # . . discard args
+1660     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1661 $test-maybe-get-slice:failure:
+1662     # - search for a new key
+1663     # (EAX..EDX) = "data"
+1664     b8/copy-to-EAX  "data"/imm32
+1665     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy *EAX to EDX
+1666     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  2/index/EDX   .           2/r32/EDX   4/disp8         .                 # copy EAX+EDX+4 to EDX
+1667     05/add-to-EAX  4/imm32
+1668     # var slice/EDX = {EAX, EDX}
+1669     52/push-EDX
+1670     50/push-EAX
+1671     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+1672     # EAX = maybe-get-slice(table, "data" slice, 8 bytes per row)
+1673     # . . push args
+1674     68/push  8/imm32/row-size
+1675     52/push-EDX
+1676     51/push-ECX
+1677     # . . call
+1678     e8/call  maybe-get-slice/disp32
+1679     # . . discard args
+1680     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1681     # check-ints-equal(EAX, 0, msg)
+1682     # . . push args
+1683     68/push  "F - test-maybe-get-slice/3"/imm32
+1684     68/push  0/imm32
+1685     50/push-EAX
+1686     # . . call
+1687     e8/call  check-ints-equal/disp32
+1688     # . . discard args
+1689     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1690 $test-maybe-get-slice:end:
+1691     # . epilog
+1692     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1693     5d/pop-to-EBP
+1694     c3/return
+1695 
+1696 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/assort.subx.html b/html/apps/assort.subx.html index b5bbd6ed..466f6591 100644 --- a/html/apps/assort.subx.html +++ b/html/apps/assort.subx.html @@ -14,17 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } .subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Folded { color: #080808; background-color: #949494; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -207,14 +207,14 @@ if ('onhashchange' in window) { 161 # setup 162 # . clear-stream(_test-input-stream) 163 # . . push args -164 68/push _test-input-stream/imm32 +164 68/push _test-input-stream/imm32 165 # . . call 166 e8/call clear-stream/disp32 167 # . . discard args 168 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 169 # . clear-stream(_test-input-buffered-file+4) 170 # . . push args -171 b8/copy-to-EAX _test-input-buffered-file/imm32 +171 b8/copy-to-EAX _test-input-buffered-file/imm32 172 05/add-to-EAX 4/imm32 173 50/push-EAX 174 # . . call @@ -223,14 +223,14 @@ if ('onhashchange' in window) { 177 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 178 # . clear-stream(_test-output-stream) 179 # . . push args -180 68/push _test-output-stream/imm32 +180 68/push _test-output-stream/imm32 181 # . . call 182 e8/call clear-stream/disp32 183 # . . discard args 184 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 185 # . clear-stream(_test-output-buffered-file+4) 186 # . . push args -187 b8/copy-to-EAX _test-output-buffered-file/imm32 +187 b8/copy-to-EAX _test-output-buffered-file/imm32 188 05/add-to-EAX 4/imm32 189 50/push-EAX 190 # . . call @@ -255,7 +255,7 @@ if ('onhashchange' in window) { 209 # . write(_test-input-stream, "# comment 1\n") 210 # . . push args 211 68/push "# comment 1\n"/imm32 -212 68/push _test-input-stream/imm32 +212 68/push _test-input-stream/imm32 213 # . . call 214 e8/call write/disp32 215 # . . discard args @@ -263,7 +263,7 @@ if ('onhashchange' in window) { 217 # . write(_test-input-stream, " # comment 2 indented\n") 218 # . . push args 219 68/push " # comment 2 indented\n"/imm32 -220 68/push _test-input-stream/imm32 +220 68/push _test-input-stream/imm32 221 # . . call 222 e8/call write/disp32 223 # . . discard args @@ -271,7 +271,7 @@ if ('onhashchange' in window) { 225 # . write(_test-input-stream, "== code 0x09000000\n") 226 # . . push args 227 68/push "== code 0x09000000\n"/imm32 -228 68/push _test-input-stream/imm32 +228 68/push _test-input-stream/imm32 229 # . . call 230 e8/call write/disp32 231 # . . discard args @@ -279,7 +279,7 @@ if ('onhashchange' in window) { 233 # . write(_test-input-stream, "# comment 3 inside a segment\n") 234 # . . push args 235 68/push "# comment 3 inside a segment\n"/imm32 -236 68/push _test-input-stream/imm32 +236 68/push _test-input-stream/imm32 237 # . . call 238 e8/call write/disp32 239 # . . discard args @@ -287,7 +287,7 @@ if ('onhashchange' in window) { 241 # . write(_test-input-stream, "1\n") 242 # . . push args 243 68/push "1\n"/imm32 -244 68/push _test-input-stream/imm32 +244 68/push _test-input-stream/imm32 245 # . . call 246 e8/call write/disp32 247 # . . discard args @@ -295,7 +295,7 @@ if ('onhashchange' in window) { 249 # . write(_test-input-stream, "\n") # empty line 250 # . . push args 251 68/push "\n"/imm32 -252 68/push _test-input-stream/imm32 +252 68/push _test-input-stream/imm32 253 # . . call 254 e8/call write/disp32 255 # . . discard args @@ -303,7 +303,7 @@ if ('onhashchange' in window) { 257 # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") 258 # . . push args 259 68/push "2 3 # comment 4 inline with other contents\n"/imm32 -260 68/push _test-input-stream/imm32 +260 68/push _test-input-stream/imm32 261 # . . call 262 e8/call write/disp32 263 # . . discard args @@ -311,7 +311,7 @@ if ('onhashchange' in window) { 265 # . write(_test-input-stream, "== data 0x0a000000\n") 266 # . . push args 267 68/push "== data 0x0a000000\n"/imm32 -268 68/push _test-input-stream/imm32 +268 68/push _test-input-stream/imm32 269 # . . call 270 e8/call write/disp32 271 # . . discard args @@ -319,7 +319,7 @@ if ('onhashchange' in window) { 273 # . write(_test-input-stream, "4 5/imm32\n") 274 # . . push args 275 68/push "4 5/imm32\n"/imm32 -276 68/push _test-input-stream/imm32 +276 68/push _test-input-stream/imm32 277 # . . call 278 e8/call write/disp32 279 # . . discard args @@ -327,7 +327,7 @@ if ('onhashchange' in window) { 281 # . write(_test-input-stream, "== code\n") 282 # . . push args 283 68/push "== code\n"/imm32 -284 68/push _test-input-stream/imm32 +284 68/push _test-input-stream/imm32 285 # . . call 286 e8/call write/disp32 287 # . . discard args @@ -335,7 +335,7 @@ if ('onhashchange' in window) { 289 # . write(_test-input-stream, "6 7\n") 290 # . . push args 291 68/push "6 7\n"/imm32 -292 68/push _test-input-stream/imm32 +292 68/push _test-input-stream/imm32 293 # . . call 294 e8/call write/disp32 295 # . . discard args @@ -343,7 +343,7 @@ if ('onhashchange' in window) { 297 # . write(_test-input-stream, "8 9\n") 298 # . . push args 299 68/push "8 9\n"/imm32 -300 68/push _test-input-stream/imm32 +300 68/push _test-input-stream/imm32 301 # . . call 302 e8/call write/disp32 303 # . . discard args @@ -351,7 +351,7 @@ if ('onhashchange' in window) { 305 # . write(_test-input-stream, "== code\n") 306 # . . push args 307 68/push "== code\n"/imm32 -308 68/push _test-input-stream/imm32 +308 68/push _test-input-stream/imm32 309 # . . call 310 e8/call write/disp32 311 # . . discard args @@ -359,22 +359,22 @@ if ('onhashchange' in window) { 313 # . write(_test-input-stream, "10 11\n") 314 # . . push args 315 68/push "10 11\n"/imm32 -316 68/push _test-input-stream/imm32 +316 68/push _test-input-stream/imm32 317 # . . call 318 e8/call write/disp32 319 # . . discard args 320 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 321 # convert(_test-input-buffered-file, _test-output-buffered-file) 322 # . . push args -323 68/push _test-output-buffered-file/imm32 -324 68/push _test-input-buffered-file/imm32 +323 68/push _test-output-buffered-file/imm32 +324 68/push _test-input-buffered-file/imm32 325 # . . call 326 e8/call convert/disp32 327 # . . discard args 328 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 329 # . flush(_test-output-buffered-file) 330 # . . push args -331 68/push _test-output-buffered-file/imm32 +331 68/push _test-output-buffered-file/imm32 332 # . . call 333 e8/call flush/disp32 334 # . . discard args @@ -393,7 +393,7 @@ if ('onhashchange' in window) { 379 # . . push args 380 68/push "F - test-convert/0"/imm32 381 68/push "== code 0x09000000"/imm32 -382 68/push _test-output-stream/imm32 +382 68/push _test-output-stream/imm32 383 # . . call 384 e8/call check-next-stream-line-equal/disp32 385 # . . discard args @@ -402,7 +402,7 @@ if ('onhashchange' in window) { 388 # . . push args 389 68/push "F - test-convert/1"/imm32 390 68/push "1"/imm32 -391 68/push _test-output-stream/imm32 +391 68/push _test-output-stream/imm32 392 # . . call 393 e8/call check-next-stream-line-equal/disp32 394 # . . discard args @@ -411,7 +411,7 @@ if ('onhashchange' in window) { 397 # . . push args 398 68/push "F - test-convert/2"/imm32 399 68/push "2 3 # comment 4 inline with other contents"/imm32 -400 68/push _test-output-stream/imm32 +400 68/push _test-output-stream/imm32 401 # . . call 402 e8/call check-next-stream-line-equal/disp32 403 # . . discard args @@ -420,7 +420,7 @@ if ('onhashchange' in window) { 406 # . . push args 407 68/push "F - test-convert/3"/imm32 408 68/push "6 7"/imm32 -409 68/push _test-output-stream/imm32 +409 68/push _test-output-stream/imm32 410 # . . call 411 e8/call check-next-stream-line-equal/disp32 412 # . . discard args @@ -429,7 +429,7 @@ if ('onhashchange' in window) { 415 # . . push args 416 68/push "F - test-convert/4"/imm32 417 68/push "8 9"/imm32 -418 68/push _test-output-stream/imm32 +418 68/push _test-output-stream/imm32 419 # . . call 420 e8/call check-next-stream-line-equal/disp32 421 # . . discard args @@ -438,7 +438,7 @@ if ('onhashchange' in window) { 424 # . . push args 425 68/push "F - test-convert/5"/imm32 426 68/push "10 11"/imm32 -427 68/push _test-output-stream/imm32 +427 68/push _test-output-stream/imm32 428 # . . call 429 e8/call check-next-stream-line-equal/disp32 430 # . . discard args @@ -447,7 +447,7 @@ if ('onhashchange' in window) { 433 # . . push args 434 68/push "F - test-convert/6"/imm32 435 68/push "== data 0x0a000000"/imm32 -436 68/push _test-output-stream/imm32 +436 68/push _test-output-stream/imm32 437 # . . call 438 e8/call check-next-stream-line-equal/disp32 439 # . . discard args @@ -456,7 +456,7 @@ if ('onhashchange' in window) { 442 # . . push args 443 68/push "F - test-convert/7"/imm32 444 68/push "4 5/imm32"/imm32 -445 68/push _test-output-stream/imm32 +445 68/push _test-output-stream/imm32 446 # . . call 447 e8/call check-next-stream-line-equal/disp32 448 # . . discard args @@ -603,7 +603,7 @@ if ('onhashchange' in window) { 727 52/push-EDX 728 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) 729 # . . call -730 e8/call leaky-get-or-insert-slice/disp32 +730 e8/call leaky-get-or-insert-slice/disp32 731 # . . discard args 732 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 733 # curr-segment = *segment-slot diff --git a/html/apps/crenshaw2-1.subx.html b/html/apps/crenshaw2-1.subx.html index 3e930538..bc5eb083 100644 --- a/html/apps/crenshaw2-1.subx.html +++ b/html/apps/crenshaw2-1.subx.html @@ -14,17 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -376,14 +375,14 @@ if ('onhashchange' in window) { 314 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 315 # . clear-stream(_test-output-stream) 316 # . . push args -317 68/push _test-output-stream/imm32 +317 68/push _test-output-stream/imm32 318 # . . call 319 e8/call clear-stream/disp32 320 # . . discard args 321 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 322 # . clear-stream(_test-error-stream) 323 # . . push args -324 68/push _test-error-stream/imm32 +324 68/push _test-error-stream/imm32 325 # . . call 326 e8/call clear-stream/disp32 327 # . . discard args @@ -406,7 +405,7 @@ if ('onhashchange' in window) { 344 68/push 0x10/imm32/nbytes-of-args-for-get-num 345 50/push-EAX/ed 346 # . . call -347 e8/call tailor-exit-descriptor/disp32 +347 e8/call tailor-exit-descriptor/disp32 348 # . . discard args 349 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 350 # prime the pump @@ -420,8 +419,8 @@ if ('onhashchange' in window) { 358 # get-num(in, out, err, ed) 359 # . . push args 360 50/push-EAX/ed -361 68/push _test-error-stream/imm32 -362 68/push _test-output-stream/imm32 +361 68/push _test-error-stream/imm32 +362 68/push _test-output-stream/imm32 363 68/push _test-buffered-file/imm32 364 # . . call 365 e8/call get-num/disp32 @@ -432,7 +431,7 @@ if ('onhashchange' in window) { 370 # . . push args 371 68/push "F - test-get-num-reads-single-digit"/imm32 372 68/push 0x33/imm32 -373 b8/copy-to-EAX _test-output-stream/imm32 +373 b8/copy-to-EAX _test-output-stream/imm32 374 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) 375 # . . call 376 e8/call check-ints-equal/disp32 @@ -467,14 +466,14 @@ if ('onhashchange' in window) { 405 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 406 # . clear-stream(_test-output-stream) 407 # . . push args -408 68/push _test-output-stream/imm32 +408 68/push _test-output-stream/imm32 409 # . . call 410 e8/call clear-stream/disp32 411 # . . discard args 412 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 413 # . clear-stream(_test-error-stream) 414 # . . push args -415 68/push _test-error-stream/imm32 +415 68/push _test-error-stream/imm32 416 # . . call 417 e8/call clear-stream/disp32 418 # . . discard args @@ -497,15 +496,15 @@ if ('onhashchange' in window) { 435 68/push 0x10/imm32/nbytes-of-args-for-get-num 436 50/push-EAX/ed 437 # . . call -438 e8/call tailor-exit-descriptor/disp32 +438 e8/call tailor-exit-descriptor/disp32 439 # . . discard args 440 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 441 # *don't* prime the pump 442 # get-num(in, out, err, ed) 443 # . . push args 444 50/push-EAX/ed -445 68/push _test-error-stream/imm32 -446 68/push _test-output-stream/imm32 +445 68/push _test-error-stream/imm32 +446 68/push _test-output-stream/imm32 447 68/push _test-buffered-file/imm32 448 # . . call 449 e8/call get-num/disp32 @@ -564,7 +563,7 @@ if ('onhashchange' in window) { 502 68/push 1/imm32 503 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) 504 # . . call -505 e8/call stop/disp32 +505 e8/call stop/disp32 506 # should never get past this point 507 $expected:dead-end: 508 # . epilog @@ -621,30 +620,7 @@ if ('onhashchange' in window) { 559 Look: # (char with some extra padding) 560 0/imm32 561 -562 _test-output-stream: -563 # current write index -564 0/imm32 -565 # current read index -566 0/imm32 -567 # length -568 8/imm32 -569 # data -570 00 00 00 00 00 00 00 00 # 8 bytes -571 -572 _test-error-stream: -573 # current write index -574 0/imm32 -575 # current read index -576 0/imm32 -577 # length -578 0x40/imm32 -579 # data (4 lines x 16 bytes/line) -580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -581 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -582 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -583 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -584 -585 # . . vim:nowrap:textwidth=0 +562 # . . vim:nowrap:textwidth=0 diff --git a/html/apps/crenshaw2-1b.subx.html b/html/apps/crenshaw2-1b.subx.html index 7bfd6cac..5db393ba 100644 --- a/html/apps/crenshaw2-1b.subx.html +++ b/html/apps/crenshaw2-1b.subx.html @@ -14,17 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -394,14 +393,14 @@ if ('onhashchange' in window) { 332 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 333 # . clear-stream(_test-output-stream) 334 # . . push args -335 68/push _test-output-stream/imm32 +335 68/push _test-output-stream/imm32 336 # . . call 337 e8/call clear-stream/disp32 338 # . . discard args 339 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 340 # . clear-stream(_test-error-stream) 341 # . . push args -342 68/push _test-error-stream/imm32 +342 68/push _test-error-stream/imm32 343 # . . call 344 e8/call clear-stream/disp32 345 # . . discard args @@ -424,7 +423,7 @@ if ('onhashchange' in window) { 362 68/push 0x10/imm32/nbytes-of-args-for-get-num 363 50/push-EAX/ed 364 # . . call -365 e8/call tailor-exit-descriptor/disp32 +365 e8/call tailor-exit-descriptor/disp32 366 # . . discard args 367 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 368 # prime the pump @@ -438,8 +437,8 @@ if ('onhashchange' in window) { 376 # get-num(in, out, err, ed) 377 # . . push args 378 50/push-EAX/ed -379 68/push _test-error-stream/imm32 -380 68/push _test-output-stream/imm32 +379 68/push _test-error-stream/imm32 +380 68/push _test-output-stream/imm32 381 68/push _test-buffered-file/imm32 382 # . . call 383 e8/call get-num/disp32 @@ -450,7 +449,7 @@ if ('onhashchange' in window) { 388 # . . push args 389 68/push "F - test-get-num-reads-single-digit"/imm32 390 68/push 0x33/imm32 -391 b8/copy-to-EAX _test-output-stream/imm32 +391 b8/copy-to-EAX _test-output-stream/imm32 392 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) 393 # . . call 394 e8/call check-ints-equal/disp32 @@ -485,14 +484,14 @@ if ('onhashchange' in window) { 423 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 424 # . clear-stream(_test-output-stream) 425 # . . push args -426 68/push _test-output-stream/imm32 +426 68/push _test-output-stream/imm32 427 # . . call 428 e8/call clear-stream/disp32 429 # . . discard args 430 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 431 # . clear-stream(_test-error-stream) 432 # . . push args -433 68/push _test-error-stream/imm32 +433 68/push _test-error-stream/imm32 434 # . . call 435 e8/call clear-stream/disp32 436 # . . discard args @@ -515,15 +514,15 @@ if ('onhashchange' in window) { 453 68/push 0x10/imm32/nbytes-of-args-for-get-num 454 50/push-EAX/ed 455 # . . call -456 e8/call tailor-exit-descriptor/disp32 +456 e8/call tailor-exit-descriptor/disp32 457 # . . discard args 458 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 459 # *don't* prime the pump 460 # get-num(in, out, err, ed) 461 # . . push args 462 50/push-EAX/ed -463 68/push _test-error-stream/imm32 -464 68/push _test-output-stream/imm32 +463 68/push _test-error-stream/imm32 +464 68/push _test-output-stream/imm32 465 68/push _test-buffered-file/imm32 466 # . . call 467 e8/call get-num/disp32 @@ -570,14 +569,14 @@ if ('onhashchange' in window) { 508 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 509 # . clear-stream(_test-output-stream) 510 # . . push args -511 68/push _test-output-stream/imm32 +511 68/push _test-output-stream/imm32 512 # . . call 513 e8/call clear-stream/disp32 514 # . . discard args 515 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 516 # . clear-stream(_test-error-stream) 517 # . . push args -518 68/push _test-error-stream/imm32 +518 68/push _test-error-stream/imm32 519 # . . call 520 e8/call clear-stream/disp32 521 # . . discard args @@ -600,7 +599,7 @@ if ('onhashchange' in window) { 538 68/push 0x10/imm32/nbytes-of-args-for-get-num 539 50/push-EAX/ed 540 # . . call -541 e8/call tailor-exit-descriptor/disp32 +541 e8/call tailor-exit-descriptor/disp32 542 # . . discard args 543 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 544 # prime the pump @@ -614,8 +613,8 @@ if ('onhashchange' in window) { 552 # get-num(in, out, err, ed) 553 # . . push args 554 50/push-EAX/ed -555 68/push _test-error-stream/imm32 -556 68/push _test-output-stream/imm32 +555 68/push _test-error-stream/imm32 +556 68/push _test-output-stream/imm32 557 68/push _test-buffered-file/imm32 558 # . . call 559 e8/call get-num/disp32 @@ -626,7 +625,7 @@ if ('onhashchange' in window) { 564 # . . push args 565 68/push "F - test-get-num-reads-multiple-digits"/imm32 566 68/push 0x36353433/imm32 -567 b8/copy-to-EAX _test-output-stream/imm32 +567 b8/copy-to-EAX _test-output-stream/imm32 568 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) 569 # . . call 570 e8/call check-ints-equal/disp32 @@ -661,14 +660,14 @@ if ('onhashchange' in window) { 599 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 600 # . clear-stream(_test-output-stream) 601 # . . push args -602 68/push _test-output-stream/imm32 +602 68/push _test-output-stream/imm32 603 # . . call 604 e8/call clear-stream/disp32 605 # . . discard args 606 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 607 # . clear-stream(_test-error-stream) 608 # . . push args -609 68/push _test-error-stream/imm32 +609 68/push _test-error-stream/imm32 610 # . . call 611 e8/call clear-stream/disp32 612 # . . discard args @@ -691,7 +690,7 @@ if ('onhashchange' in window) { 629 68/push 0x10/imm32/nbytes-of-args-for-get-num 630 50/push-EAX/ed 631 # . . call -632 e8/call tailor-exit-descriptor/disp32 +632 e8/call tailor-exit-descriptor/disp32 633 # . . discard args 634 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 635 # prime the pump @@ -705,8 +704,8 @@ if ('onhashchange' in window) { 643 # get-num(in, out, err, ed) 644 # . . push args 645 50/push-EAX/ed -646 68/push _test-error-stream/imm32 -647 68/push _test-output-stream/imm32 +646 68/push _test-error-stream/imm32 +647 68/push _test-output-stream/imm32 648 68/push _test-buffered-file/imm32 649 # . . call 650 e8/call get-num/disp32 @@ -717,7 +716,7 @@ if ('onhashchange' in window) { 655 # . . push args 656 68/push "F - test-get-num-reads-multiple-digits-followed-by-nondigit"/imm32 657 68/push 0x36353433/imm32 -658 b8/copy-to-EAX _test-output-stream/imm32 +658 b8/copy-to-EAX _test-output-stream/imm32 659 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) 660 # . . call 661 e8/call check-ints-equal/disp32 @@ -764,7 +763,7 @@ if ('onhashchange' in window) { 702 68/push 1/imm32 703 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) 704 # . . call -705 e8/call stop/disp32 +705 e8/call stop/disp32 706 # should never get past this point 707 $expected:dead-end: 708 # . epilog @@ -821,30 +820,7 @@ if ('onhashchange' in window) { 759 Look: # (char with some extra padding) 760 0/imm32 761 -762 _test-output-stream: -763 # current write index -764 0/imm32 -765 # current read index -766 0/imm32 -767 # length -768 8/imm32 -769 # data -770 00 00 00 00 00 00 00 00 # 8 bytes -771 -772 _test-error-stream: -773 # current write index -774 0/imm32 -775 # current read index -776 0/imm32 -777 # length -778 0x40/imm32 -779 # data (4 lines x 16 bytes/line) -780 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -781 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -782 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -783 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -784 -785 # . . vim:nowrap:textwidth=0 +762 # . . vim:nowrap:textwidth=0 diff --git a/html/apps/desugar.subx.html b/html/apps/desugar.subx.html new file mode 100644 index 00000000..7fea0d16 --- /dev/null +++ b/html/apps/desugar.subx.html @@ -0,0 +1,3790 @@ + + + + +Mu - apps/desugar.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/apps/desugar.subx +
+   1 # Experimental syntax sugar for SubX programs.
+   2 #
+   3 # We're experimenting with the following expressions:
+   4 #
+   5 # 1.
+   6 #   $ echo "ab %eax"  |  ./subx run apps/desugar
+   7 #   ab 3/mod 0/rm32
+   8 #
+   9 # 2.
+  10 #   $ echo "ab *eax"  |  ./subx run apps/desugar
+  11 #   ab 0/mod 0/rm32
+  12 #
+  13 # 3.
+  14 #   $ echo "ab *(eax+4)"  |  ./subx run apps/desugar
+  15 #   ab 2/mod 0/rm32 4/disp32
+  16 #
+  17 # 4.
+  18 #   $ echo "ab *(eax+ecx)"  |  ./subx run apps/desugar
+  19 #   ab 0/mod 4/rm32 0/base 1/index 0/scale
+  20 #
+  21 # 5.
+  22 #   $ echo "ab *(eax+ecx+4)"  |  ./subx run apps/desugar
+  23 #   ab 2/mod 4/rm32 0/base 1/index 0/scale 4/disp32
+  24 #
+  25 # 6.
+  26 #   $ echo "ab *(eax+ecx<<2+4)"  |  ./subx run apps/desugar
+  27 #   ab 2/mod 4/rm32 0/base 1/index 2/scale 4/disp32
+  28 #
+  29 # Addition isn't commutative here. Template must always be (base+index<<scale+disp),
+  30 # though some components are optional as described above.
+  31 #
+  32 # No metadata allowed inside '*(...)'.
+  33 # Whitespace inside '*(...)' is ok. But not immediately after the '*' or '%'.
+  34 
+  35 == code
+  36 #   instruction                     effective address                                                   register    displacement    immediate
+  37 # . op          subop               mod             rm32          base        index         scale       r32
+  38 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+  39 
+  40 Entry:  # run tests if necessary, convert stdin if not
+  41     # initialize heap
+  42     # . Heap = new-segment(Heap-size)
+  43     # . . push args
+  44     68/push  Heap/imm32
+  45     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+  46     # . . call
+  47     e8/call  new-segment/disp32
+  48     # . . discard args
+  49     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  50 
+  51     # run tests if necessary, convert stdin if not
+  52     # . prolog
+  53     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  54     # - if argc > 1 and argv[1] == "test", then return run_tests()
+  55     # . argc > 1
+  56     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
+  57     7e/jump-if-lesser-or-equal  $run-main/disp8
+  58     # . argv[1] == "test"
+  59     # . . push args
+  60     68/push  "test"/imm32
+  61     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+  62     # . . call
+  63     e8/call  kernel-string-equal?/disp32
+  64     # . . discard args
+  65     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  66     # . check result
+  67     3d/compare-EAX-and  1/imm32
+  68     75/jump-if-not-equal  $run-main/disp8
+  69     # . run-tests()
+  70     e8/call  run-tests/disp32
+  71     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
+  72     eb/jump  $main:end/disp8
+  73 $run-main:
+  74     # - otherwise convert stdin
+  75     # convert(Stdin, Stdout)
+  76     # . . push args
+  77     68/push  Stdout/imm32
+  78     68/push  Stdin/imm32
+  79     # . . call
+  80     e8/call  convert/disp32
+  81     # . . discard args
+  82     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x8/imm32         # add to ESP
+  83     # . syscall(exit, 0)
+  84     bb/copy-to-EBX  0/imm32
+  85 $main:end:
+  86     b8/copy-to-EAX  1/imm32/exit
+  87     cd/syscall  0x80/imm8
+  88 
+  89 # error messages considered:
+  90 #   *x + 34                 -> error: base+disp addressing must be within '()'
+  91 convert:  # in : (address buffered-file), out : (address buffered-file) -> <void>
+  92     # pseudocode:
+  93     #   var line = new-stream(512, 1)
+  94     #   while true
+  95     #     clear-stream(line)
+  96     #     read-line-buffered(in, line)
+  97     #     if (line->write == 0) break                     # end of file
+  98     #     while true
+  99     #       var word-slice = next-word-or-expression(line)
+ 100     #       if slice-empty?(word-slice)                   # end of line
+ 101     #         break
+ 102     #       if slice-starts-with?(word-slice, "#")        # comment
+ 103     #         continue
+ 104     #       if slice-starts-with?(word-slice, '%')        # direct mode
+ 105     #         emit-direct-mode(word-slice, out)
+ 106     #       else if slice-starts-with?(word-slice, '*')   # indirect mode
+ 107     #         base, index, scale, disp = parse-effective-address(word-slice)
+ 108     #         emit-indirect-mode(out, base, index, scale, disp)
+ 109     #       else if slice-starts-with?(word-slice, '+')
+ 110     #         abort("'+' only permitted within '*(...)'")
+ 111     #       else
+ 112     #         write-slice-buffered(out, word-slice)
+ 113     #       write(out, " ")
+ 114     #     write(out, "\n")
+ 115     #   flush(out)
+ 116     #
+ 117     # . prolog
+ 118     55/push-EBP
+ 119     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 120     # . save registers
+ 121     50/push-EAX
+ 122     51/push-ECX
+ 123     52/push-EDX
+ 124     53/push-EBX
+ 125     # var line/ECX : (address stream byte) = stream(512)
+ 126     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x200/imm32       # subtract from ESP
+ 127     68/push  0x200/imm32/length
+ 128     68/push  0/imm32/read
+ 129     68/push  0/imm32/write
+ 130     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+ 131     # var word-slice/EDX = {0, 0}
+ 132     68/push  0/imm32/end
+ 133     68/push  0/imm32/start
+ 134     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+ 135 $convert:line-loop:
+ 136     # clear-stream(line)
+ 137     # . . push args
+ 138     51/push-ECX
+ 139     # . . call
+ 140     e8/call  clear-stream/disp32
+ 141     # . . discard args
+ 142     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 143     # read-line-buffered(in, line)
+ 144     # . . push args
+ 145     51/push-ECX
+ 146     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+ 147     # . . call
+ 148     e8/call  read-line-buffered/disp32
+ 149     # . . discard args
+ 150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 151 $convert:check0:
+ 152     # if (line->write == 0) break
+ 153     81          7/subop/compare     0/mod/indirect  1/rm32/ECX    .           .             .           .           .               0/imm32           # compare *ECX
+ 154     0f 84/jump-if-equal  $convert:break/disp32
+ 155 $convert:word-loop:
+ 156     # next-word-or-expression(line, word-slice)
+ 157     # . . push args
+ 158     52/push-EDX
+ 159     51/push-ECX
+ 160     # . . call
+ 161     e8/call  next-word-or-expression/disp32
+ 162     # . . discard args
+ 163     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 164 $convert:check1:
+ 165     # if (slice-empty?(word-slice)) break
+ 166     # . EAX = slice-empty?(word-slice)
+ 167     # . . push args
+ 168     52/push-EDX
+ 169     # . . call
+ 170     e8/call  slice-empty?/disp32
+ 171     # . . discard args
+ 172     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 173     # . if (EAX != 0) break
+ 174     3d/compare-EAX-and  0/imm32
+ 175     0f 85/jump-if-not-equal  $convert:next-line/disp32
+ 176 $convert:check-for-comment:
+ 177     # if (slice-starts-with?(word-slice, "#")) continue
+ 178     # . start/EBX = word-slice->start
+ 179     8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           3/r32/EBX   .               .                 # copy *EDX to EBX
+ 180     # . c/EAX = *start
+ 181     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 182     8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
+ 183     # . if (EAX == '#') continue
+ 184     3d/compare-EAX-and  0x23/imm32/hash
+ 185     74/jump-if-equal  $convert:word-loop/disp8
+ 186 $convert:check-for-direct-mode:
+ 187     # if (!slice-starts-with?(word-slice, "%")) goto next check
+ 188     3d/compare-EAX-and  0x25/imm32/percent
+ 189     75/jump-if-not-equal  $convert:check-for-indirect-mode/disp8
+ 190 $convert:direct-mode:
+ 191 +-- 46 lines: #?     # dump word-slice -----------------------------------------------------------------------------------------------------------------------
+ 237     # emit-direct-mode(word-slice, out)
+ 238     # . . push args
+ 239     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 240     52/push-EDX
+ 241     # . . call
+ 242     e8/call  emit-direct-mode/disp32
+ 243     # . . discard args
+ 244     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 245     # continue
+ 246     e9/jump  $convert:next-word/disp32
+ 247 $convert:check-for-indirect-mode:
+ 248     # if (!slice-starts-with?(word-slice, "*")) goto next check
+ 249     3d/compare-EAX-and  0x2a/imm32/asterisk
+ 250     75/jump-if-not-equal  $convert:check-for-invalid-addition/disp8
+ 251 $convert:indirect-mode:
+ 252     # spill registers
+ 253     50/push-EAX
+ 254     51/push-ECX
+ 255     52/push-EDX
+ 256     53/push-EBX
+ 257     # base/EAX, index/ECX, scale/EDX, disp/EBX = parse-effective-address(word-slice)
+ 258     # . . push args
+ 259     52/push-EDX
+ 260     # . . call
+ 261     e8/call  parse-effective-address/disp32
+ 262     # . . discard args
+ 263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 264     # emit-indirect-mode(out, base, index, scale, disp)
+ 265     # . . push args
+ 266     53/push-EBX
+ 267     52/push-EDX
+ 268     51/push-ECX
+ 269     50/push-EAX
+ 270     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 271     # . . call
+ 272     e8/call  emit-indirect-mode/disp32
+ 273     # . . discard args
+ 274     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+ 275     # restore registers
+ 276     5b/pop-to-EBX
+ 277     5a/pop-to-EDX
+ 278     59/pop-to-ECX
+ 279     58/pop-to-EAX
+ 280     # continue
+ 281     e9/jump  $convert:next-word/disp32
+ 282 $convert:check-for-invalid-addition:
+ 283     # if (slice-starts-with?(word-slice, "+")) goto error1
+ 284     3d/compare-EAX-and  0x2b/imm32/plus
+ 285     74/jump-if-equal  $convert:error1/disp8
+ 286 $convert:check-for-invalid-left-shift:
+ 287     # if (slice-starts-with?(word-slice, "<")) goto error1
+ 288     3d/compare-EAX-and  0x3c/imm32/less-than
+ 289     74/jump-if-equal  $convert:error1/disp8
+ 290 $convert:regular-word:
+ 291     # write-slice-buffered(out, word-slice)
+ 292     # . . push args
+ 293     52/push-EDX
+ 294     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 295     # . . call
+ 296     e8/call  write-slice-buffered/disp32
+ 297     # . . discard args
+ 298     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 299     # fall through
+ 300 $convert:next-word:
+ 301     # write-buffered(out, " ")
+ 302     # . . push args
+ 303     68/push  " "/imm32
+ 304     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 305     # . . call
+ 306     e8/call  write-buffered/disp32
+ 307     # . . discard args
+ 308     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 309     # loop
+ 310     e9/jump  $convert:word-loop/disp32
+ 311 $convert:next-line:
+ 312     # write-buffered(out, "\n")
+ 313     # . . push args
+ 314     68/push  Newline/imm32
+ 315     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 316     # . . call
+ 317     e8/call  write-buffered/disp32
+ 318     # . . discard args
+ 319     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 320     # loop
+ 321     e9/jump  $convert:line-loop/disp32
+ 322 $convert:break:
+ 323     # flush(out)
+ 324     # . . push args
+ 325     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 326     # . . call
+ 327     e8/call  flush/disp32
+ 328     # . . discard args
+ 329     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 330 $convert:end:
+ 331     # . reclaim locals
+ 332     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x214/imm32       # add to ESP
+ 333     # . restore registers
+ 334     5b/pop-to-EBX
+ 335     5a/pop-to-EDX
+ 336     59/pop-to-ECX
+ 337     58/pop-to-EAX
+ 338     # . epilog
+ 339     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 340     5d/pop-to-EBP
+ 341     c3/return
+ 342 
+ 343 $convert:error1:
+ 344     # print(stderr, "error: '" EAX "' only permitted within '*(...)' in '" line "'")
+ 345     # . write-buffered(Stderr, "error: '")
+ 346     # . . push args
+ 347     68/push  "error: '"/imm32
+ 348     68/push  Stderr/imm32
+ 349     # . . call
+ 350     e8/call  write-buffered/disp32
+ 351     # . . discard args
+ 352     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 353     # . write-byte-buffered(Stderr, EAX)
+ 354     # . . push args
+ 355     50/push-EAX
+ 356     68/push  Stderr/imm32
+ 357     # . . call
+ 358     e8/call  write-byte-buffered/disp32
+ 359     # . . discard args
+ 360     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 361     # . write-buffered(Stderr, "' only permitted within '*(...)' in '")
+ 362     # . . push args
+ 363     68/push  "' only permitted within '*(...)' in '"/imm32
+ 364     68/push  Stderr/imm32
+ 365     # . . call
+ 366     e8/call  write-buffered/disp32
+ 367     # . . discard args
+ 368     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 369     # . write-stream-data(Stderr, line)
+ 370     # . . push args
+ 371     51/push-ECX
+ 372     68/push  Stderr/imm32
+ 373     # . . call
+ 374     e8/call  write-stream-data/disp32
+ 375     # . . discard args
+ 376     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 377     # . write-buffered(Stderr, "'")
+ 378     # . . push args
+ 379     68/push  "'"/imm32
+ 380     68/push  Stderr/imm32
+ 381     # . . call
+ 382     e8/call  write-buffered/disp32
+ 383     # . . discard args
+ 384     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 385     # . flush(Stderr)
+ 386     # . . push args
+ 387     68/push  Stderr/imm32
+ 388     # . . call
+ 389     e8/call  flush/disp32
+ 390     # . . discard args
+ 391     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 392     # . syscall(exit, 1)
+ 393     bb/copy-to-EBX  1/imm32
+ 394     b8/copy-to-EAX  1/imm32/exit
+ 395     cd/syscall  0x80/imm8
+ 396     # never gets here
+ 397 
+ 398 test-convert-passes-most-words-through:
+ 399     # . prolog
+ 400     55/push-EBP
+ 401     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 402     # setup
+ 403     # . clear-stream(_test-input-stream)
+ 404     # . . push args
+ 405     68/push  _test-input-stream/imm32
+ 406     # . . call
+ 407     e8/call  clear-stream/disp32
+ 408     # . . discard args
+ 409     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 410     # . clear-stream(_test-input-buffered-file+4)
+ 411     # . . push args
+ 412     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 413     05/add-to-EAX  4/imm32
+ 414     50/push-EAX
+ 415     # . . call
+ 416     e8/call  clear-stream/disp32
+ 417     # . . discard args
+ 418     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 419     # . clear-stream(_test-output-stream)
+ 420     # . . push args
+ 421     68/push  _test-output-stream/imm32
+ 422     # . . call
+ 423     e8/call  clear-stream/disp32
+ 424     # . . discard args
+ 425     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 426     # . clear-stream(_test-output-buffered-file+4)
+ 427     # . . push args
+ 428     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 429     05/add-to-EAX  4/imm32
+ 430     50/push-EAX
+ 431     # . . call
+ 432     e8/call  clear-stream/disp32
+ 433     # . . discard args
+ 434     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 435     # initialize input
+ 436     # . write(_test-input-stream, "== abcd 0x1")
+ 437     # . . push args
+ 438     68/push  "== abcd 0x1"/imm32
+ 439     68/push  _test-input-stream/imm32
+ 440     # . . call
+ 441     e8/call  write/disp32
+ 442     # . . discard args
+ 443     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 444     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 445     # . . push args
+ 446     68/push  _test-output-buffered-file/imm32
+ 447     68/push  _test-input-buffered-file/imm32
+ 448     # . . call
+ 449     e8/call  convert/disp32
+ 450     # . . discard args
+ 451     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 452     # check that the line just passed through
+ 453     # . flush(_test-output-buffered-file)
+ 454     # . . push args
+ 455     68/push  _test-output-buffered-file/imm32
+ 456     # . . call
+ 457     e8/call  flush/disp32
+ 458     # . . discard args
+ 459     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 460 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 486     # . check-stream-equal(_test-output-stream, "== abcd 0x1 \n", msg)
+ 487     # . . push args
+ 488     68/push  "F - test-convert-passes-most-words-through"/imm32
+ 489     68/push  "== abcd 0x1 \n"/imm32
+ 490     68/push  _test-output-stream/imm32
+ 491     # . . call
+ 492     e8/call  check-stream-equal/disp32
+ 493     # . . discard args
+ 494     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 495     # . epilog
+ 496     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 497     5d/pop-to-EBP
+ 498     c3/return
+ 499 
+ 500 test-convert-direct-mode:
+ 501     # . prolog
+ 502     55/push-EBP
+ 503     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 504     # setup
+ 505     # . clear-stream(_test-input-stream)
+ 506     # . . push args
+ 507     68/push  _test-input-stream/imm32
+ 508     # . . call
+ 509     e8/call  clear-stream/disp32
+ 510     # . . discard args
+ 511     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 512     # . clear-stream(_test-input-buffered-file+4)
+ 513     # . . push args
+ 514     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 515     05/add-to-EAX  4/imm32
+ 516     50/push-EAX
+ 517     # . . call
+ 518     e8/call  clear-stream/disp32
+ 519     # . . discard args
+ 520     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 521     # . clear-stream(_test-output-stream)
+ 522     # . . push args
+ 523     68/push  _test-output-stream/imm32
+ 524     # . . call
+ 525     e8/call  clear-stream/disp32
+ 526     # . . discard args
+ 527     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 528     # . clear-stream(_test-output-buffered-file+4)
+ 529     # . . push args
+ 530     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 531     05/add-to-EAX  4/imm32
+ 532     50/push-EAX
+ 533     # . . call
+ 534     e8/call  clear-stream/disp32
+ 535     # . . discard args
+ 536     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 537     # initialize input
+ 538     # . write(_test-input-stream, "ab %ecx")
+ 539     # . . push args
+ 540     68/push  "ab %ecx"/imm32
+ 541     68/push  _test-input-stream/imm32
+ 542     # . . call
+ 543     e8/call  write/disp32
+ 544     # . . discard args
+ 545     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 546     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 547     # . . push args
+ 548     68/push  _test-output-buffered-file/imm32
+ 549     68/push  _test-input-buffered-file/imm32
+ 550     # . . call
+ 551     e8/call  convert/disp32
+ 552     # . . discard args
+ 553     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 554     # check that the line just passed through
+ 555     # . flush(_test-output-buffered-file)
+ 556     # . . push args
+ 557     68/push  _test-output-buffered-file/imm32
+ 558     # . . call
+ 559     e8/call  flush/disp32
+ 560     # . . discard args
+ 561     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 562 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 588     # . check-stream-equal(_test-output-stream, "ab 3/mod/direct 0x00000001/rm32 \n", msg)
+ 589     # . . push args
+ 590     68/push  "F - test-convert-direct-mode"/imm32
+ 591     68/push  "ab 3/mod/direct 0x00000001/rm32 \n"/imm32
+ 592     68/push  _test-output-stream/imm32
+ 593     # . . call
+ 594     e8/call  check-stream-equal/disp32
+ 595     # . . discard args
+ 596     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 597     # . epilog
+ 598     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 599     5d/pop-to-EBP
+ 600     c3/return
+ 601 
+ 602 test-convert-register-indirect-mode:
+ 603     # . prolog
+ 604     55/push-EBP
+ 605     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 606     # setup
+ 607     # . clear-stream(_test-input-stream)
+ 608     # . . push args
+ 609     68/push  _test-input-stream/imm32
+ 610     # . . call
+ 611     e8/call  clear-stream/disp32
+ 612     # . . discard args
+ 613     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 614     # . clear-stream(_test-input-buffered-file+4)
+ 615     # . . push args
+ 616     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 617     05/add-to-EAX  4/imm32
+ 618     50/push-EAX
+ 619     # . . call
+ 620     e8/call  clear-stream/disp32
+ 621     # . . discard args
+ 622     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 623     # . clear-stream(_test-output-stream)
+ 624     # . . push args
+ 625     68/push  _test-output-stream/imm32
+ 626     # . . call
+ 627     e8/call  clear-stream/disp32
+ 628     # . . discard args
+ 629     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 630     # . clear-stream(_test-output-buffered-file+4)
+ 631     # . . push args
+ 632     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 633     05/add-to-EAX  4/imm32
+ 634     50/push-EAX
+ 635     # . . call
+ 636     e8/call  clear-stream/disp32
+ 637     # . . discard args
+ 638     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 639     # initialize input
+ 640     # . write(_test-input-stream, "ab *ecx")
+ 641     # . . push args
+ 642     68/push  "ab *ecx"/imm32
+ 643     68/push  _test-input-stream/imm32
+ 644     # . . call
+ 645     e8/call  write/disp32
+ 646     # . . discard args
+ 647     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 648     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 649     # . . push args
+ 650     68/push  _test-output-buffered-file/imm32
+ 651     68/push  _test-input-buffered-file/imm32
+ 652     # . . call
+ 653     e8/call  convert/disp32
+ 654     # . . discard args
+ 655     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 656     # check that the line just passed through
+ 657     # . flush(_test-output-buffered-file)
+ 658     # . . push args
+ 659     68/push  _test-output-buffered-file/imm32
+ 660     # . . call
+ 661     e8/call  flush/disp32
+ 662     # . . discard args
+ 663     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 664 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 690     # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 0x00000001/rm32 \n", msg)
+ 691     # . . push args
+ 692     68/push  "F - test-convert-indirect-mode"/imm32
+ 693     68/push  "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32
+ 694     68/push  _test-output-stream/imm32
+ 695     # . . call
+ 696     e8/call  check-stream-equal/disp32
+ 697     # . . discard args
+ 698     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 699     # . epilog
+ 700     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 701     5d/pop-to-EBP
+ 702     c3/return
+ 703 
+ 704 test-convert-register-indirect-mode-without-displacement:
+ 705     # . prolog
+ 706     55/push-EBP
+ 707     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 708     # setup
+ 709     # . clear-stream(_test-input-stream)
+ 710     # . . push args
+ 711     68/push  _test-input-stream/imm32
+ 712     # . . call
+ 713     e8/call  clear-stream/disp32
+ 714     # . . discard args
+ 715     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 716     # . clear-stream(_test-input-buffered-file+4)
+ 717     # . . push args
+ 718     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 719     05/add-to-EAX  4/imm32
+ 720     50/push-EAX
+ 721     # . . call
+ 722     e8/call  clear-stream/disp32
+ 723     # . . discard args
+ 724     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 725     # . clear-stream(_test-output-stream)
+ 726     # . . push args
+ 727     68/push  _test-output-stream/imm32
+ 728     # . . call
+ 729     e8/call  clear-stream/disp32
+ 730     # . . discard args
+ 731     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 732     # . clear-stream(_test-output-buffered-file+4)
+ 733     # . . push args
+ 734     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 735     05/add-to-EAX  4/imm32
+ 736     50/push-EAX
+ 737     # . . call
+ 738     e8/call  clear-stream/disp32
+ 739     # . . discard args
+ 740     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 741     # initialize input
+ 742     # . write(_test-input-stream, "ab *(ecx)")
+ 743     # . . push args
+ 744     68/push  "ab *(ecx)"/imm32
+ 745     68/push  _test-input-stream/imm32
+ 746     # . . call
+ 747     e8/call  write/disp32
+ 748     # . . discard args
+ 749     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 750     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 751     # . . push args
+ 752     68/push  _test-output-buffered-file/imm32
+ 753     68/push  _test-input-buffered-file/imm32
+ 754     # . . call
+ 755     e8/call  convert/disp32
+ 756     # . . discard args
+ 757     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 758     # check that the line just passed through
+ 759     # . flush(_test-output-buffered-file)
+ 760     # . . push args
+ 761     68/push  _test-output-buffered-file/imm32
+ 762     # . . call
+ 763     e8/call  flush/disp32
+ 764     # . . discard args
+ 765     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 766 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 792     # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 1/rm32 \n", msg)
+ 793     # . . push args
+ 794     68/push  "F - test-convert-indirect-mode-without-displacement"/imm32
+ 795     68/push  "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32
+ 796     68/push  _test-output-stream/imm32
+ 797     # . . call
+ 798     e8/call  check-stream-equal/disp32
+ 799     # . . discard args
+ 800     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 801     # . epilog
+ 802     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 803     5d/pop-to-EBP
+ 804     c3/return
+ 805 
+ 806 test-convert-register-indirect-mode-with-displacement:
+ 807     # . prolog
+ 808     55/push-EBP
+ 809     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 810     # setup
+ 811     # . clear-stream(_test-input-stream)
+ 812     # . . push args
+ 813     68/push  _test-input-stream/imm32
+ 814     # . . call
+ 815     e8/call  clear-stream/disp32
+ 816     # . . discard args
+ 817     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 818     # . clear-stream(_test-input-buffered-file+4)
+ 819     # . . push args
+ 820     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 821     05/add-to-EAX  4/imm32
+ 822     50/push-EAX
+ 823     # . . call
+ 824     e8/call  clear-stream/disp32
+ 825     # . . discard args
+ 826     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 827     # . clear-stream(_test-output-stream)
+ 828     # . . push args
+ 829     68/push  _test-output-stream/imm32
+ 830     # . . call
+ 831     e8/call  clear-stream/disp32
+ 832     # . . discard args
+ 833     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 834     # . clear-stream(_test-output-buffered-file+4)
+ 835     # . . push args
+ 836     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 837     05/add-to-EAX  4/imm32
+ 838     50/push-EAX
+ 839     # . . call
+ 840     e8/call  clear-stream/disp32
+ 841     # . . discard args
+ 842     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 843     # initialize input
+ 844     # . write(_test-input-stream, "ab *(ecx+4)")
+ 845     # . . push args
+ 846     68/push  "ab *(ecx+4)"/imm32
+ 847     68/push  _test-input-stream/imm32
+ 848     # . . call
+ 849     e8/call  write/disp32
+ 850     # . . discard args
+ 851     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 852     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 853     # . . push args
+ 854     68/push  _test-output-buffered-file/imm32
+ 855     68/push  _test-input-buffered-file/imm32
+ 856     # . . call
+ 857     e8/call  convert/disp32
+ 858     # . . discard args
+ 859     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 860     # check that the line just passed through
+ 861     # . flush(_test-output-buffered-file)
+ 862     # . . push args
+ 863     68/push  _test-output-buffered-file/imm32
+ 864     # . . call
+ 865     e8/call  flush/disp32
+ 866     # . . discard args
+ 867     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 868 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 894     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 1/rm32 4/disp32 \n", msg)
+ 895     # . . push args
+ 896     68/push  "F - test-convert-indirect-mode-with-displacement"/imm32
+ 897     68/push  "ab 2/mod/*+disp32 0x00000001/rm32 0x00000004/disp32 \n"/imm32
+ 898     68/push  _test-output-stream/imm32
+ 899     # . . call
+ 900     e8/call  check-stream-equal/disp32
+ 901     # . . discard args
+ 902     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 903     # . epilog
+ 904     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 905     5d/pop-to-EBP
+ 906     c3/return
+ 907 
+ 908 # boss level
+ 909 test-convert-register-indirect-mode-with-sib-byte:
+ 910     # . prolog
+ 911     55/push-EBP
+ 912     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 913     # setup
+ 914     # . clear-stream(_test-input-stream)
+ 915     # . . push args
+ 916     68/push  _test-input-stream/imm32
+ 917     # . . call
+ 918     e8/call  clear-stream/disp32
+ 919     # . . discard args
+ 920     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 921     # . clear-stream(_test-input-buffered-file+4)
+ 922     # . . push args
+ 923     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 924     05/add-to-EAX  4/imm32
+ 925     50/push-EAX
+ 926     # . . call
+ 927     e8/call  clear-stream/disp32
+ 928     # . . discard args
+ 929     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 930     # . clear-stream(_test-output-stream)
+ 931     # . . push args
+ 932     68/push  _test-output-stream/imm32
+ 933     # . . call
+ 934     e8/call  clear-stream/disp32
+ 935     # . . discard args
+ 936     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 937     # . clear-stream(_test-output-buffered-file+4)
+ 938     # . . push args
+ 939     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 940     05/add-to-EAX  4/imm32
+ 941     50/push-EAX
+ 942     # . . call
+ 943     e8/call  clear-stream/disp32
+ 944     # . . discard args
+ 945     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 946     # initialize input
+ 947     # . write(_test-input-stream, "ab *(ecx + edx<<3 + 4)")
+ 948     # . . push args
+ 949     68/push  "ab *(ecx + edx<<3 + 4)"/imm32
+ 950     68/push  _test-input-stream/imm32
+ 951     # . . call
+ 952     e8/call  write/disp32
+ 953     # . . discard args
+ 954     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 955     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 956     # . . push args
+ 957     68/push  _test-output-buffered-file/imm32
+ 958     68/push  _test-input-buffered-file/imm32
+ 959     # . . call
+ 960     e8/call  convert/disp32
+ 961     # . . discard args
+ 962     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 963     # check that the line just passed through
+ 964     # . flush(_test-output-buffered-file)
+ 965     # . . push args
+ 966     68/push  _test-output-buffered-file/imm32
+ 967     # . . call
+ 968     e8/call  flush/disp32
+ 969     # . . discard args
+ 970     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 971 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 997     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale 4/disp32 \n", msg)
+ 998     # . . push args
+ 999     68/push  "F - test-convert-indirect-mode-with-sib-byte"/imm32
+1000     68/push  "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0x00000004/disp32 \n"/imm32
+1001     68/push  _test-output-stream/imm32
+1002     # . . call
+1003     e8/call  check-stream-equal/disp32
+1004     # . . discard args
+1005     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1006     # . epilog
+1007     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1008     5d/pop-to-EBP
+1009     c3/return
+1010 
+1011 test-convert-register-indirect-mode-with-sib-byte-negative-displacement:
+1012     # . prolog
+1013     55/push-EBP
+1014     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1015     # setup
+1016     # . clear-stream(_test-input-stream)
+1017     # . . push args
+1018     68/push  _test-input-stream/imm32
+1019     # . . call
+1020     e8/call  clear-stream/disp32
+1021     # . . discard args
+1022     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1023     # . clear-stream(_test-input-buffered-file+4)
+1024     # . . push args
+1025     b8/copy-to-EAX  _test-input-buffered-file/imm32
+1026     05/add-to-EAX  4/imm32
+1027     50/push-EAX
+1028     # . . call
+1029     e8/call  clear-stream/disp32
+1030     # . . discard args
+1031     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1032     # . clear-stream(_test-output-stream)
+1033     # . . push args
+1034     68/push  _test-output-stream/imm32
+1035     # . . call
+1036     e8/call  clear-stream/disp32
+1037     # . . discard args
+1038     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1039     # . clear-stream(_test-output-buffered-file+4)
+1040     # . . push args
+1041     b8/copy-to-EAX  _test-output-buffered-file/imm32
+1042     05/add-to-EAX  4/imm32
+1043     50/push-EAX
+1044     # . . call
+1045     e8/call  clear-stream/disp32
+1046     # . . discard args
+1047     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1048     # initialize input
+1049     # . write(_test-input-stream, "ab *(ecx + edx<<3 - 4)")
+1050     # . . push args
+1051     68/push  "ab *(ecx + edx<<3 - 4)"/imm32
+1052     68/push  _test-input-stream/imm32
+1053     # . . call
+1054     e8/call  write/disp32
+1055     # . . discard args
+1056     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1057     # convert(_test-input-buffered-file, _test-output-buffered-file)
+1058     # . . push args
+1059     68/push  _test-output-buffered-file/imm32
+1060     68/push  _test-input-buffered-file/imm32
+1061     # . . call
+1062     e8/call  convert/disp32
+1063     # . . discard args
+1064     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1065     # check that the line just passed through
+1066     # . flush(_test-output-buffered-file)
+1067     # . . push args
+1068     68/push  _test-output-buffered-file/imm32
+1069     # . . call
+1070     e8/call  flush/disp32
+1071     # . . discard args
+1072     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1073 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+1099     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale -4/disp32 \n", msg)
+1100     # . . push args
+1101     68/push  "F - test-convert-indirect-mode-with-sib-byte-negative-displacement"/imm32
+1102     68/push  "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0xfffffffc/disp32 \n"/imm32
+1103     68/push  _test-output-stream/imm32
+1104     # . . call
+1105     e8/call  check-stream-equal/disp32
+1106     # . . discard args
+1107     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1108     # . epilog
+1109     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1110     5d/pop-to-EBP
+1111     c3/return
+1112 
+1113 # beware: modifies 'word'
+1114 emit-direct-mode:  # word : (address slice), out : (address buffered-file)
+1115     # . prolog
+1116     55/push-EBP
+1117     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1118     # . save registers
+1119     50/push-EAX
+1120     # ++word->start
+1121     # . EAX = word
+1122     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
+1123     # . ++(*EAX)
+1124     ff          0/subop/increment   0/mod/indirect  0/rm32/EAX    .           .             .           .           .               .                 # increment *EAX
+1125     # reg-num/EAX = get-slice(Registers, word, row-size=8)
+1126     # . . push args
+1127     68/push  "Registers"/imm32
+1128     68/push  8/imm32/row-size
+1129     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1130     68/push  Registers/imm32
+1131     # . . call
+1132     e8/call  get-slice/disp32
+1133     # . . discard args
+1134     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+1135     # write-buffered(out, "3/mod/direct ")
+1136     # . . push args
+1137     68/push  "3/mod/direct "/imm32
+1138     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1139     # . . call
+1140     e8/call  write-buffered/disp32
+1141     # . . discard args
+1142     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1143     # print-int32-buffered(out, *EAX)
+1144     # . . push args
+1145     ff          6/subop/push        0/mod/indirect  0/rm32/EAX    .           .             .           .           .               .                 # push *EAX
+1146     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1147     # . . call
+1148     e8/call  print-int32-buffered/disp32
+1149     # . . discard args
+1150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1151     # write-buffered(out, "/rm32")
+1152     # . . push args
+1153     68/push  "/rm32"/imm32
+1154     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1155     # . . call
+1156     e8/call  write-buffered/disp32
+1157     # . . discard args
+1158     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1159 $emit-direct-mode:end:
+1160     # . restore registers
+1161     58/pop-to-EAX
+1162     # . epilog
+1163     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1164     5d/pop-to-EBP
+1165     c3/return
+1166 
+1167 test-emit-direct-mode:
+1168     # . prolog
+1169     55/push-EBP
+1170     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1171     # setup
+1172     # . clear-stream(_test-output-stream)
+1173     # . . push args
+1174     68/push  _test-output-stream/imm32
+1175     # . . call
+1176     e8/call  clear-stream/disp32
+1177     # . . discard args
+1178     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1179     # . clear-stream(_test-output-buffered-file+4)
+1180     # . . push args
+1181     b8/copy-to-EAX  _test-output-buffered-file/imm32
+1182     05/add-to-EAX  4/imm32
+1183     50/push-EAX
+1184     # . . call
+1185     e8/call  clear-stream/disp32
+1186     # . . discard args
+1187     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1188     # var slice/ECX = "%eax"
+1189     b8/copy-to-EAX  "%eax"/imm32
+1190     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1191     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1192     05/add-to-EAX  4/imm32
+1193     # . ECX = {EAX, ECX}
+1194     51/push-ECX
+1195     50/push-EAX
+1196     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1197     # emit-direct-mode(str, _test-output-buffered-file)
+1198     # . . push args
+1199     68/push  _test-output-buffered-file/imm32
+1200     51/push-ECX
+1201     # . . call
+1202     e8/call  emit-direct-mode/disp32
+1203     # . . discard args
+1204     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32         # add to ESP
+1205     # . flush(_test-output-buffered-file)
+1206     # . . push args
+1207     68/push  _test-output-buffered-file/imm32
+1208     # . . call
+1209     e8/call  flush/disp32
+1210     # . . discard args
+1211     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1212 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+1238     # check-stream-equal(_test-output-stream, "3/mod/direct 0/rm32", msg)
+1239     # . . push args
+1240     68/push  "F - test-emit-direct-mode/0"/imm32
+1241     68/push  "3/mod/direct 0x00000000/rm32"/imm32
+1242     68/push  _test-output-stream/imm32
+1243     # . . call
+1244     e8/call  check-stream-equal/disp32
+1245     # . . discard args
+1246     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1247     # . epilog
+1248     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1249     5d/pop-to-EBP
+1250     c3/return
+1251 
+1252 test-emit-direct-mode-2:
+1253     # . prolog
+1254     55/push-EBP
+1255     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1256     # setup
+1257     # . clear-stream(_test-output-stream)
+1258     # . . push args
+1259     68/push  _test-output-stream/imm32
+1260     # . . call
+1261     e8/call  clear-stream/disp32
+1262     # . . discard args
+1263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1264     # . clear-stream(_test-output-buffered-file+4)
+1265     # . . push args
+1266     b8/copy-to-EAX  _test-output-buffered-file/imm32
+1267     05/add-to-EAX  4/imm32
+1268     50/push-EAX
+1269     # . . call
+1270     e8/call  clear-stream/disp32
+1271     # . . discard args
+1272     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1273     # var slice/ECX = "%edi"
+1274     b8/copy-to-EAX  "%edi"/imm32
+1275     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1276     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1277     05/add-to-EAX  4/imm32
+1278     # . ECX = {EAX, ECX}
+1279     51/push-ECX
+1280     50/push-EAX
+1281     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1282     # emit-direct-mode(str/ECX, _test-output-buffered-file)
+1283     # . . push args
+1284     68/push  _test-output-buffered-file/imm32
+1285     51/push-ECX
+1286     # . . call
+1287     e8/call  emit-direct-mode/disp32
+1288     # . . discard args
+1289     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32         # add to ESP
+1290     # . flush(_test-output-buffered-file)
+1291     # . . push args
+1292     68/push  _test-output-buffered-file/imm32
+1293     # . . call
+1294     e8/call  flush/disp32
+1295     # . . discard args
+1296     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1297 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+1323     # check-stream-equal(_test-output-stream, "3/mod/direct 7/rm32", msg)
+1324     # . . push args
+1325     68/push  "F - test-emit-direct-mode/1"/imm32
+1326     68/push  "3/mod/direct 0x00000007/rm32"/imm32
+1327     68/push  _test-output-stream/imm32
+1328     # . . call
+1329     e8/call  check-stream-equal/disp32
+1330     # . . discard args
+1331     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1332     # . epilog
+1333     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1334     5d/pop-to-EBP
+1335     c3/return
+1336 
+1337 # (re)compute the bounds of the next word or parenthetical expression in the line
+1338 # return empty string on reaching end of file
+1339 #
+1340 # error messages considered:
+1341 #   * ...                   -> error: no space after '*'
+1342 #   *(...                   -> error: *(...) expression must be all on a single line
+1343 next-word-or-expression:  # line : (address stream byte), out : (address slice)
+1344     # . prolog
+1345     55/push-EBP
+1346     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1347     # . save registers
+1348     50/push-EAX
+1349     51/push-ECX
+1350     56/push-ESI
+1351     57/push-EDI
+1352     # ESI = line
+1353     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+1354     # EDI = out
+1355     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
+1356     # skip-chars-matching(line, ' ')
+1357     # . . push args
+1358     68/push  0x20/imm32/space
+1359     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1360     # . . call
+1361     e8/call  skip-chars-matching/disp32
+1362     # . . discard args
+1363     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1364 $next-word-or-expression:check0:
+1365     # if (line->read >= line->write) clear out and return
+1366     # . EAX = line->read
+1367     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ESI+4) to EAX
+1368     # . if (EAX < line->write) goto next check
+1369     3b/compare                      0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # compare EAX with *ESI
+1370     7c/jump-if-lesser  $next-word-or-expression:check-for-comment/disp8
+1371     # . return out = {0, 0}
+1372     c7          0/subop/copy        0/mod/direct    7/rm32/EDI    .           .             .           .           .               0/imm32           # copy to *EDI
+1373     c7          0/subop/copy        1/mod/*+disp8   7/rm32/EDI    .           .             .           .           4/disp8         0/imm32           # copy to *(EDI+4)
+1374     eb/jump  $next-word-or-expression:end/disp8
+1375 $next-word-or-expression:check-for-comment:
+1376     # out->start = &line->data[line->read]
+1377     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+1378     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
+1379     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
+1380     # if (line->data[line->read] != '#') goto next check
+1381     # . EAX = line->data[line->read]
+1382     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+1383     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+1384     # . compare
+1385     3d/compare-EAX-and  0x23/imm32/pound
+1386     75/jump-if-not-equal  $next-word-or-expression:check-for-paren/disp8
+1387 $next-word-or-expression:comment:
+1388     # out->end = &line->data[line->write]
+1389     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+1390     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  0/index/EAX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+EAX+12 to EAX
+1391     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
+1392     # line->read = line->write  # skip rest of line
+1393     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+1394     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(ESI+4)
+1395     # return
+1396     eb/jump  $next-word-or-expression:end/disp8
+1397 $next-word-or-expression:check-for-paren:
+1398     # if (line->data[line->read] != '*') goto next check
+1399     # . EAX = line->data[line->read]
+1400     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+1401     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+1402     # . compare
+1403     3d/compare-EAX-and  0x2a/imm32/asterisk
+1404     75/jump-if-not-equal  $next-word-or-expression:regular-word/disp8
+1405     # if (line->data[line->read] == ' ') goto error1
+1406     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xd/disp8       .                 # copy byte at *(ESI+ECX+12+1) to AL
+1407     # . compare
+1408     3d/compare-EAX-and  0x20/imm32/space
+1409     74/jump-if-equal  $next-word-or-expression:error1/disp8
+1410     # if (line->data[line->read] != '(') goto regular word
+1411     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xd/disp8       .                 # copy byte at *(ESI+ECX+12+1) to AL
+1412     # . compare
+1413     3d/compare-EAX-and  0x28/imm32/open-paren
+1414     75/jump-if-not-equal  $next-word-or-expression:regular-word/disp8
+1415 $next-word-or-expression:paren:
+1416     # skip-until-close-paren(line)
+1417     # . . push args
+1418     56/push-ESI
+1419     # . . call
+1420     e8/call  skip-until-close-paren/disp32
+1421     # . . discard args
+1422     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1423     # if (line->data[line->read] != ')') goto error2
+1424     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+1425     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+1426     # . compare
+1427     3d/compare-EAX-and  0x29/imm32/close-paren
+1428     75/jump-if-not-equal  $next-word-or-expression:error2/disp8
+1429     # skip ')'
+1430     ff          0/subop/increment   1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # increment *(ESI+4)
+1431     # fall through
+1432 $next-word-or-expression:regular-word:
+1433     # skip-chars-not-matching-whitespace(line)  # including trailing newline
+1434     # . . push args
+1435     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1436     # . . call
+1437     e8/call  skip-chars-not-matching-whitespace/disp32
+1438     # . . discard args
+1439     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1440     # out->end = &line->data[line->read]
+1441     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+1442     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
+1443     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
+1444 $next-word-or-expression:end:
+1445     # . restore registers
+1446     5f/pop-to-EDI
+1447     5e/pop-to-ESI
+1448     59/pop-to-ECX
+1449     58/pop-to-EAX
+1450     # . epilog
+1451     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1452     5d/pop-to-EBP
+1453     c3/return
+1454 
+1455 $next-word-or-expression:error1:
+1456     # print(stderr, "error: no space allowed after '*' in '" line "'")
+1457     # . write-buffered(Stderr, "error: no space allowed after '*' in '")
+1458     # . . push args
+1459     68/push  "error: no space allowed after '*' in '"/imm32
+1460     68/push  Stderr/imm32
+1461     # . . call
+1462     e8/call  write-buffered/disp32
+1463     # . . discard args
+1464     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1465     # . write-stream-data(Stderr, line)
+1466     # . . push args
+1467     56/push-ESI
+1468     68/push  Stderr/imm32
+1469     # . . call
+1470     e8/call  write-stream-data/disp32
+1471     # . . discard args
+1472     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1473     # . write-buffered(Stderr, "'")
+1474     # . . push args
+1475     68/push  "'"/imm32
+1476     68/push  Stderr/imm32
+1477     # . . call
+1478     e8/call  write-buffered/disp32
+1479     # . . discard args
+1480     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1481     # . flush(Stderr)
+1482     # . . push args
+1483     68/push  Stderr/imm32
+1484     # . . call
+1485     e8/call  flush/disp32
+1486     # . . discard args
+1487     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1488     # . syscall(exit, 1)
+1489     bb/copy-to-EBX  1/imm32
+1490     b8/copy-to-EAX  1/imm32/exit
+1491     cd/syscall  0x80/imm8
+1492     # never gets here
+1493 
+1494 $next-word-or-expression:error2:
+1495     # print(stderr, "error: no space allowed after '*' in '" line "'")
+1496     # . write-buffered(Stderr, "error: *(...) expression must be all on a single line in '")
+1497     # . . push args
+1498     68/push  "error: *(...) expression must be all on a single line in '"/imm32
+1499     68/push  Stderr/imm32
+1500     # . . call
+1501     e8/call  write-buffered/disp32
+1502     # . . discard args
+1503     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1504     # . write-stream-data(Stderr, line)
+1505     # . . push args
+1506     56/push-ESI
+1507     68/push  Stderr/imm32
+1508     # . . call
+1509     e8/call  write-stream-data/disp32
+1510     # . . discard args
+1511     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1512     # . write-buffered(Stderr, "'")
+1513     # . . push args
+1514     68/push  "'"/imm32
+1515     68/push  Stderr/imm32
+1516     # . . call
+1517     e8/call  write-buffered/disp32
+1518     # . . discard args
+1519     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1520     # . flush(Stderr)
+1521     # . . push args
+1522     68/push  Stderr/imm32
+1523     # . . call
+1524     e8/call  flush/disp32
+1525     # . . discard args
+1526     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1527     # . syscall(exit, 1)
+1528     bb/copy-to-EBX  1/imm32
+1529     b8/copy-to-EAX  1/imm32/exit
+1530     cd/syscall  0x80/imm8
+1531     # never gets here
+1532 
+1533 test-next-word-or-expression:
+1534     # . prolog
+1535     55/push-EBP
+1536     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1537     # setup
+1538     # . clear-stream(_test-input-stream)
+1539     # . . push args
+1540     68/push  _test-input-stream/imm32
+1541     # . . call
+1542     e8/call  clear-stream/disp32
+1543     # . . discard args
+1544     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1545     # var slice/ECX = {0, 0}
+1546     68/push  0/imm32/end
+1547     68/push  0/imm32/start
+1548     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1549     # write(_test-input-stream, "  ab")
+1550     # . . push args
+1551     68/push  "  ab"/imm32
+1552     68/push  _test-input-stream/imm32
+1553     # . . call
+1554     e8/call  write/disp32
+1555     # . . discard args
+1556     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1557     # next-word-or-expression(_test-input-stream, slice)
+1558     # . . push args
+1559     51/push-ECX
+1560     68/push  _test-input-stream/imm32
+1561     # . . call
+1562     e8/call  next-word-or-expression/disp32
+1563     # . . discard args
+1564     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1565     # check-ints-equal(_test-input-stream->read, 4, msg)
+1566     # . . push args
+1567     68/push  "F - test-next-word-or-expression/updates-stream-read-correctly"/imm32
+1568     68/push  4/imm32
+1569     b8/copy-to-EAX  _test-input-stream/imm32
+1570     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+1571     # . . call
+1572     e8/call  check-ints-equal/disp32
+1573     # . . discard args
+1574     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1575     # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
+1576     # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
+1577     # . . push args
+1578     68/push  "F - test-next-word-or-expression: start"/imm32
+1579     68/push  0xe/imm32
+1580     # . . push slice->start - _test-input-stream
+1581     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+1582     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1583     50/push-EAX
+1584     # . . call
+1585     e8/call  check-ints-equal/disp32
+1586     # . . discard args
+1587     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1588     # check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
+1589     # . check-ints-equal(slice->end - _test-input-stream, 16, msg)
+1590     # . . push args
+1591     68/push  "F - test-next-word-or-expression: end"/imm32
+1592     68/push  0x10/imm32
+1593     # . . push slice->end - _test-input-stream
+1594     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1595     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1596     50/push-EAX
+1597     # . . call
+1598     e8/call  check-ints-equal/disp32
+1599     # . . discard args
+1600     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1601     # . epilog
+1602     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1603     5d/pop-to-EBP
+1604     c3/return
+1605 
+1606 test-next-word-or-expression-returns-whole-comment:
+1607     # . prolog
+1608     55/push-EBP
+1609     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1610     # setup
+1611     # . clear-stream(_test-input-stream)
+1612     # . . push args
+1613     68/push  _test-input-stream/imm32
+1614     # . . call
+1615     e8/call  clear-stream/disp32
+1616     # . . discard args
+1617     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1618     # var slice/ECX = {0, 0}
+1619     68/push  0/imm32/end
+1620     68/push  0/imm32/start
+1621     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1622     # write(_test-input-stream, "  # a")
+1623     # . . push args
+1624     68/push  "  # a"/imm32
+1625     68/push  _test-input-stream/imm32
+1626     # . . call
+1627     e8/call  write/disp32
+1628     # . . discard args
+1629     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1630     # next-word-or-expression(_test-input-stream, slice)
+1631     # . . push args
+1632     51/push-ECX
+1633     68/push  _test-input-stream/imm32
+1634     # . . call
+1635     e8/call  next-word-or-expression/disp32
+1636     # . . discard args
+1637     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1638     # check-ints-equal(_test-input-stream->read, 5, msg)
+1639     # . . push args
+1640     68/push  "F - test-next-word-or-expression-returns-whole-comment/updates-stream-read-correctly"/imm32
+1641     68/push  5/imm32
+1642     b8/copy-to-EAX  _test-input-stream/imm32
+1643     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+1644     # . . call
+1645     e8/call  check-ints-equal/disp32
+1646     # . . discard args
+1647     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1648     # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
+1649     # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
+1650     # . . push args
+1651     68/push  "F - test-next-word-or-expression-returns-whole-comment: start"/imm32
+1652     68/push  0xe/imm32
+1653     # . . push slice->start - _test-input-stream
+1654     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+1655     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1656     50/push-EAX
+1657     # . . call
+1658     e8/call  check-ints-equal/disp32
+1659     # . . discard args
+1660     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1661     # check-ints-equal(slice->end - _test-input-stream->data, 5, msg)
+1662     # . check-ints-equal(slice->end - _test-input-stream, 17, msg)
+1663     # . . push args
+1664     68/push  "F - test-next-word-or-expression-returns-whole-comment: end"/imm32
+1665     68/push  0x11/imm32
+1666     # . . push slice->end - _test-input-stream
+1667     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1668     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1669     50/push-EAX
+1670     # . . call
+1671     e8/call  check-ints-equal/disp32
+1672     # . . discard args
+1673     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1674     # . epilog
+1675     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1676     5d/pop-to-EBP
+1677     c3/return
+1678 
+1679 test-next-word-or-expression-returns-empty-expression-on-eof:
+1680     # . prolog
+1681     55/push-EBP
+1682     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1683     # setup
+1684     # . clear-stream(_test-input-stream)
+1685     # . . push args
+1686     68/push  _test-input-stream/imm32
+1687     # . . call
+1688     e8/call  clear-stream/disp32
+1689     # . . discard args
+1690     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1691     # var slice/ECX = {0, 0}
+1692     68/push  0/imm32/end
+1693     68/push  0/imm32/start
+1694     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1695     # write nothing to _test-input-stream
+1696     # next-word-or-expression(_test-input-stream, slice)
+1697     # . . push args
+1698     51/push-ECX
+1699     68/push  _test-input-stream/imm32
+1700     # . . call
+1701     e8/call  next-word-or-expression/disp32
+1702     # . . discard args
+1703     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1704     # check-ints-equal(slice->end - slice->start, 0, msg)
+1705     # . . push args
+1706     68/push  "F - test-next-word-or-expression-returns-empty-expression-on-eof"/imm32
+1707     68/push  0/imm32
+1708     # . . push slice->end - slice->start
+1709     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1710     2b/subtract                     0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract *ECX from EAX
+1711     50/push-EAX
+1712     # . . call
+1713     e8/call  check-ints-equal/disp32
+1714     # . . discard args
+1715     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1716     # . epilog
+1717     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1718     5d/pop-to-EBP
+1719     c3/return
+1720 
+1721 test-next-word-or-expression-returns-whole-expression:
+1722     # . prolog
+1723     55/push-EBP
+1724     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1725     # setup
+1726     # . clear-stream(_test-input-stream)
+1727     # . . push args
+1728     68/push  _test-input-stream/imm32
+1729     # . . call
+1730     e8/call  clear-stream/disp32
+1731     # . . discard args
+1732     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1733     # var slice/ECX = {0, 0}
+1734     68/push  0/imm32/end
+1735     68/push  0/imm32/start
+1736     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1737     # write(_test-input-stream, " *(a b)/imm32 ")
+1738     # . . push args
+1739     68/push  " *(a b)/imm32 "/imm32
+1740     68/push  _test-input-stream/imm32
+1741     # . . call
+1742     e8/call  write/disp32
+1743     # . . discard args
+1744     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1745     # next-word-or-expression(_test-input-stream, slice)
+1746     # . . push args
+1747     51/push-ECX
+1748     68/push  _test-input-stream/imm32
+1749     # . . call
+1750     e8/call  next-word-or-expression/disp32
+1751     # . . discard args
+1752     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1753     # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
+1754     # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
+1755     # . . push args
+1756     68/push  "F - test-next-word-or-expression-returns-whole-expression: start"/imm32
+1757     68/push  0xd/imm32
+1758     # . . push slice->start - _test-input-stream
+1759     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+1760     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1761     50/push-EAX
+1762     # . . call
+1763     e8/call  check-ints-equal/disp32
+1764     # . . discard args
+1765     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1766     # check-ints-equal(slice->end - _test-input-stream->data, 13, msg)
+1767     # . check-ints-equal(slice->end - _test-input-stream, 25, msg)
+1768     # . . push args
+1769     68/push  "F - test-next-word-or-expression-returns-whole-expression: end"/imm32
+1770     68/push  0x19/imm32
+1771     # . . push slice->end - _test-input-stream
+1772     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1773     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1774     50/push-EAX
+1775     # . . call
+1776     e8/call  check-ints-equal/disp32
+1777     # . . discard args
+1778     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1779     # . epilog
+1780     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1781     5d/pop-to-EBP
+1782     c3/return
+1783 
+1784 # Grammar:
+1785 #   *reg                    -> 0/mod reg/rm32
+1786 #   *(reg)                  -> 0/mod reg/rm32
+1787 #   *(reg+disp)             -> 2/mod reg/rm32 disp/disp32
+1788 #   *(reg1+reg2<<s)         -> 2/mod 4/rm32 reg1/base reg2/index s/scale 0/disp32
+1789 #   *(reg1+reg2<<s+disp)    -> 2/mod 4/rm32 reg1/base reg2/index s/scale disp/disp32
+1790 # Intermediate structure: base, index, scale, disp
+1791 # Default values: base: 0, index: 4 (none), scale: 0, disp: 0
+1792 # beware: modifies 'word'
+1793 parse-effective-address:  # word : (address slice) -> base/EAX, index/ECX, scale/EDX, disp/EBX
+1794     # pseudocode:
+1795     #   ++word->start to skip '*'
+1796     #   initialize defaults: base=0, index=4, scale=0, disp=0
+1797     #   if (*word->start != '(') {
+1798     #     base = get-slice(Registers, word, row-size=8)
+1799     #     return
+1800     #   }
+1801     #   # compound expressions
+1802     #   skip whitespace
+1803     #   read register into base
+1804     #   skip whitespace
+1805     #   if (*word->start == ')') goto end
+1806     #   if (*word->start == '-') goto displacement
+1807     #   if (*word->start != '+') goto error2
+1808     #   ++word->start to skip '+'
+1809     #   skip whitespace
+1810     #   if next 3 characters don't make a register, goto displacement
+1811     #   read register into index
+1812     #   skip whitespace
+1813     #   if (*word->start == ')') goto end
+1814     #   if (*word->start == '<') {
+1815     #     ++word->start to skip '<'
+1816     #     if (*word->start != '<') goto error3
+1817     #     ++word->start to skip '<'
+1818     #     skip whitespace
+1819     #     read integer into scale
+1820     #     skip whitespace
+1821     #     if (*word->start == ')') goto end
+1822     #   }
+1823     #   if (*word->start not in '+' '-') goto error4
+1824     # displacement:
+1825     #   read integer into disp
+1826     #   skip whitespace
+1827     #   if (*word->start != ')') goto error5
+1828     # . prolog
+1829     55/push-EBP
+1830     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1831     # . save registers
+1832     56/push-ESI
+1833     57/push-EDI
+1834     # ESI = word
+1835     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+1836     # ++word->start to skip '*'
+1837     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1838     # initialize defaults
+1839     # base is in EDI; we'll move it to EAX just before we return
+1840     bf/copy-to-EDI  0/imm32
+1841     b9/copy-to-ECX  4/imm32/no-index
+1842     ba/copy-to-EDX  0/imm32/.scale
+1843     bb/copy-to-EBX  0/imm32/disp
+1844 $parse-effective-address:check-for-simple-register:
+1845     # if (*word->start == '(') goto compound expression
+1846     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+1847     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+1848     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+1849     3d/compare-EAX-and  0x28/imm32/open-paren
+1850     74/jump-if-equal  $parse-effective-address:compound-expression/disp8
+1851 $parse-effective-address:simple-register:
+1852     # base = get-slice(Registers, word, row-size=8)
+1853     # . EAX = get-slice(Registers, word, row-size=8)
+1854     # . . push args
+1855     68/push  "Registers"/imm32
+1856     68/push  8/imm32/row-size
+1857     56/push-ESI
+1858     68/push  Registers/imm32
+1859     # . . call
+1860     e8/call  get-slice/disp32
+1861     # . . discard args
+1862     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+1863     # . base = *EAX
+1864     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy *EAX to EDI
+1865     # return
+1866     e9/jump  $parse-effective-address:end/disp32
+1867 $parse-effective-address:compound-expression:
+1868     # ++word->start to skip '('
+1869     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1870     # skip whitespace
+1871     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1872     # . . push args
+1873     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1874     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1875     # . . call
+1876     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1877     # . . discard args
+1878     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1879     # . word->start = EAX
+1880     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1881     # read register into base
+1882     # . EAX = next-register(word)
+1883     # . . push args
+1884     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1885     # . . call
+1886     e8/call  next-register/disp32
+1887     # . . discard args
+1888     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1889     # . EDI = *EAX
+1890     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy *EAX to EDI
+1891     # skip whitespace
+1892     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1893     # . . push args
+1894     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1895     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1896     # . . call
+1897     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1898     # . . discard args
+1899     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1900     # . word->start = EAX
+1901     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1902     # if (*word->start == ')') goto end
+1903     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+1904     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+1905     3d/compare-EAX-and  0x29/imm32/close-paren
+1906     0f 84/jump-if-equal  $parse-effective-address:end/disp32
+1907     # if (*word->start == '-') goto displacement
+1908     3d/compare-EAX-and  0x2d/imm32/minus
+1909     0f 84/jump-if-equal  $parse-effective-address:displacement/disp32
+1910     # if (*word->start != '+') goto error2
+1911 $parse-effective-address:check-for-index:
+1912     # ++word->start to skip '+'
+1913     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1914     # skip whitespace
+1915     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1916     # . . push args
+1917     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1918     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1919     # . . call
+1920     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1921     # . . discard args
+1922     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1923     # . word->start = EAX
+1924     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1925 $parse-effective-address:resolve-ambiguity:
+1926     # if next 3 characters don't make a register, goto displacement
+1927     # . spill ECX
+1928     51/push-ECX
+1929     # . var tmp/ECX = {word->start, word->start+3}
+1930     # . . ECX = word->start
+1931     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy EAX to ECX
+1932     # . . EAX = word->start+3
+1933     05/add-to-EAX  3/imm32
+1934     # . . push
+1935     50/push-EAX
+1936     51/push-ECX
+1937     # . . copy ESP to ECX
+1938     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1939     # . EAX = maybe-get-slice(Register, tmp, row-size=8)
+1940     # . . push args
+1941     68/push  8/imm32/row-size
+1942     51/push-ECX
+1943     68/push  Registers/imm32
+1944     # . . call
+1945     e8/call  maybe-get-slice/disp32
+1946     # . . discard args
+1947     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1948     # . reclaim tmp
+1949     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1950     # . restore ECX
+1951     59/pop-to-ECX
+1952     # . if (EAX == 0) goto displacement
+1953     3d/compare-EAX-and  0/imm32
+1954     0f 84/jump-if-equal  $parse-effective-address:displacement/disp32
+1955 $parse-effective-address:index:
+1956     # read register into index
+1957     # . EAX = next-register(word)
+1958     # . . push args
+1959     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1960     # . . call
+1961     e8/call  next-register/disp32
+1962     # . . discard args
+1963     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1964     # . ECX = *EAX
+1965     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1966     # skip whitespace
+1967     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1968     # . . push args
+1969     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1970     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1971     # . . call
+1972     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1973     # . . discard args
+1974     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1975     # . word->start = EAX
+1976     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1977     # if (*word->start == ')') goto end
+1978     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+1979     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+1980     3d/compare-EAX-and  0x29/imm32/close-paren
+1981     74/jump-if-equal  $parse-effective-address:end/disp8
+1982 $parse-effective-address:check-for-scale:
+1983     # if (*word->start != '<') goto next check
+1984     3d/compare-EAX-and  0x3c/imm32/less-than
+1985     75/jump-if-not-equal  $parse-effective-address:check-for-displacement/disp8
+1986     # ++word->start to skip '<'
+1987     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1988     # if (*word->start != '<') goto error3
+1989     # ++word->start to skip '<'
+1990     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1991     # skip whitespace
+1992     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1993     # . . push args
+1994     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1995     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1996     # . . call
+1997     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1998     # . . discard args
+1999     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2000     # . word->start = EAX
+2001     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+2002 $parse-effective-address:scale:
+2003     # read positive integer into scale
+2004     # . EAX = next-positive-hex-int(word)
+2005     # . . push args
+2006     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2007     # . . call
+2008     e8/call  next-positive-hex-int/disp32
+2009     # . . discard args
+2010     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2011     # . EDX = EAX
+2012     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           0/r32/EAX   .               .                 # copy EAX to EDX
+2013     # skip whitespace
+2014     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+2015     # . . push args
+2016     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+2017     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+2018     # . . call
+2019     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+2020     # . . discard args
+2021     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2022     # . word->start = EAX
+2023     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+2024     # if (*word->start == ')') goto end
+2025     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+2026     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+2027     3d/compare-EAX-and  0x29/imm32/close-paren
+2028     74/jump-if-equal  $parse-effective-address:end/disp8
+2029 $parse-effective-address:check-for-displacement:
+2030     # if (*word->start not in '+' '-') goto error4
+2031 $parse-effective-address:displacement:
+2032     # read integer into disp
+2033     # . EAX = next-hex-int(word)
+2034     # . . push args
+2035     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2036     # . . call
+2037     e8/call  next-hex-int/disp32
+2038     # . . discard args
+2039     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2040     # . EBX = EAX
+2041     89/copy                         3/mod/direct    3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # copy EAX to EBX
+2042     # skip whitespace
+2043     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+2044     # . . push args
+2045     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+2046     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+2047     # . . call
+2048     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+2049     # . . discard args
+2050     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2051     # . word->start = EAX
+2052     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+2053     # if (*word->start != ')') goto error5
+2054 $parse-effective-address:end:
+2055     # return base in EAX
+2056     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy EDI to EAX
+2057     # . restore registers
+2058     5f/pop-to-EDI
+2059     5e/pop-to-ESI
+2060     # . epilog
+2061     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2062     5d/pop-to-EBP
+2063     c3/return
+2064 
+2065 # assumes 'in' starts with a register name, and returns pointer to its code
+2066 # side-effect: modifies 'in' to scan past the initial register name
+2067 next-register:  # in : (address slice) -> reg/EAX : int
+2068     # . prolog
+2069     55/push-EBP
+2070     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2071     # . save registers
+2072     51/push-ECX
+2073     56/push-ESI
+2074     # ESI = in
+2075     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+2076     # var reg-slice/ECX : (address slice) = {in->start, in->start + 3}
+2077     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+2078     05/add-to-EAX  3/imm32
+2079     50/push-EAX
+2080     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+2081     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2082     # in->start += 3
+2083     81          0/subop/add         0/mod/indirect  6/rm32/ESI    .           .             .           .           .               3/imm32           # add to *ESI
+2084     # EAX = get-slice(Registers, word, row-size=8)
+2085     # . . push args
+2086     68/push  "next-register"/imm32
+2087     68/push  8/imm32/row-size
+2088     51/push-ECX
+2089     68/push  Registers/imm32
+2090     # . . call
+2091     e8/call  get-slice/disp32
+2092     # . . discard args
+2093     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+2094 $next-register:end:
+2095     # reclaim locals
+2096     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2097     # . restore registers
+2098     5e/pop-to-ESI
+2099     59/pop-to-ECX
+2100     # . epilog
+2101     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2102     5d/pop-to-EBP
+2103     c3/return
+2104 
+2105 test-parse-effective-address-simple:
+2106     # . prolog
+2107     55/push-EBP
+2108     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2109     # var slice/ECX = "*esi"
+2110     b8/copy-to-EAX  "*esi"/imm32
+2111     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2112     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2113     05/add-to-EAX  4/imm32
+2114     # . ECX = {EAX, ECX}
+2115     51/push-ECX
+2116     50/push-EAX
+2117     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2118     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2119     # . . push args
+2120     51/push-ECX
+2121     # . . call
+2122     e8/call  parse-effective-address/disp32
+2123     # . . discard args
+2124     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2125     # slice clobbered beyond this point
+2126     # check-ints-equal(EAX, 6, msg)
+2127     # . . push args
+2128     68/push  "F - test-parse-effective-address-simple/base"/imm32
+2129     68/push  6/imm32/ESI
+2130     50/push-EAX
+2131     # . . call
+2132     e8/call  check-ints-equal/disp32
+2133     # . . discard args
+2134     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2135     # check-ints-equal(ECX, 4, msg)
+2136     # . . push args
+2137     68/push  "F - test-parse-effective-address-simple/index"/imm32
+2138     68/push  4/imm32/none
+2139     51/push-ECX
+2140     # . . call
+2141     e8/call  check-ints-equal/disp32
+2142     # . . discard args
+2143     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2144     # check-ints-equal(EDX, 0, msg)
+2145     # . . push args
+2146     68/push  "F - test-parse-effective-address-simple/scale"/imm32
+2147     68/push  0/imm32/none
+2148     52/push-EDX
+2149     # . . call
+2150     e8/call  check-ints-equal/disp32
+2151     # . . discard args
+2152     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2153     # check-ints-equal(EBX, 0, msg)
+2154     # . . push args
+2155     68/push  "F - test-parse-effective-address-simple/displacement"/imm32
+2156     68/push  0/imm32/none
+2157     53/push-EBX
+2158     # . . call
+2159     e8/call  check-ints-equal/disp32
+2160     # . . discard args
+2161     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2162     # . epilog
+2163     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2164     5d/pop-to-EBP
+2165     c3/return
+2166 
+2167 test-parse-effective-address-base:
+2168     # . prolog
+2169     55/push-EBP
+2170     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2171     # var slice/ECX = "*(esi  )"
+2172     b8/copy-to-EAX  "*(esi  )"/imm32
+2173     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2174     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2175     05/add-to-EAX  4/imm32
+2176     # . ECX = {EAX, ECX}
+2177     51/push-ECX
+2178     50/push-EAX
+2179     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2180     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2181     # . . push args
+2182     51/push-ECX
+2183     # . . call
+2184     e8/call  parse-effective-address/disp32
+2185     # . . discard args
+2186     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2187     # slice clobbered beyond this point
+2188     # check-ints-equal(EAX, 6, msg)
+2189     # . . push args
+2190     68/push  "F - test-parse-effective-address-base/base"/imm32
+2191     68/push  6/imm32/ESI
+2192     50/push-EAX
+2193     # . . call
+2194     e8/call  check-ints-equal/disp32
+2195     # . . discard args
+2196     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2197     # check-ints-equal(ECX, 4, msg)
+2198     # . . push args
+2199     68/push  "F - test-parse-effective-address-base/index"/imm32
+2200     68/push  4/imm32/none
+2201     51/push-ECX
+2202     # . . call
+2203     e8/call  check-ints-equal/disp32
+2204     # . . discard args
+2205     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2206     # check-ints-equal(EDX, 0, msg)
+2207     # . . push args
+2208     68/push  "F - test-parse-effective-address-base/scale"/imm32
+2209     68/push  0/imm32/none
+2210     52/push-EDX
+2211     # . . call
+2212     e8/call  check-ints-equal/disp32
+2213     # . . discard args
+2214     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2215     # check-ints-equal(EBX, 0, msg)
+2216     # . . push args
+2217     68/push  "F - test-parse-effective-address-base/displacement"/imm32
+2218     68/push  0/imm32/none
+2219     53/push-EBX
+2220     # . . call
+2221     e8/call  check-ints-equal/disp32
+2222     # . . discard args
+2223     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2224     # . epilog
+2225     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2226     5d/pop-to-EBP
+2227     c3/return
+2228 
+2229 test-parse-effective-address-base-displacement:
+2230     # . prolog
+2231     55/push-EBP
+2232     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2233     # var slice/ECX = "*(esi+3)"
+2234     b8/copy-to-EAX  "*(esi+3)"/imm32
+2235     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2236     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2237     05/add-to-EAX  4/imm32
+2238     # . ECX = {EAX, ECX}
+2239     51/push-ECX
+2240     50/push-EAX
+2241     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2242     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2243     # . . push args
+2244     51/push-ECX
+2245     # . . call
+2246     e8/call  parse-effective-address/disp32
+2247     # . . discard args
+2248     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2249     # slice clobbered beyond this point
+2250     # check-ints-equal(EAX, 6, msg)
+2251     # . . push args
+2252     68/push  "F - test-parse-effective-address-base-displacement/base"/imm32
+2253     68/push  6/imm32/ESI
+2254     50/push-EAX
+2255     # . . call
+2256     e8/call  check-ints-equal/disp32
+2257     # . . discard args
+2258     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2259     # check-ints-equal(ECX, 4, msg)
+2260     # . . push args
+2261     68/push  "F - test-parse-effective-address-base-displacement/index"/imm32
+2262     68/push  4/imm32/none
+2263     51/push-ECX
+2264     # . . call
+2265     e8/call  check-ints-equal/disp32
+2266     # . . discard args
+2267     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2268     # check-ints-equal(EDX, 0, msg)
+2269     # . . push args
+2270     68/push  "F - test-parse-effective-address-base-displacement/scale"/imm32
+2271     68/push  0/imm32/none
+2272     52/push-EDX
+2273     # . . call
+2274     e8/call  check-ints-equal/disp32
+2275     # . . discard args
+2276     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2277     # check-ints-equal(EBX, 3, msg)
+2278     # . . push args
+2279     68/push  "F - test-parse-effective-address-base-displacement/displacement"/imm32
+2280     68/push  3/imm32
+2281     53/push-EBX
+2282     # . . call
+2283     e8/call  check-ints-equal/disp32
+2284     # . . discard args
+2285     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2286     # . epilog
+2287     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2288     5d/pop-to-EBP
+2289     c3/return
+2290 
+2291 test-parse-effective-address-base-negative-displacement:
+2292     # . prolog
+2293     55/push-EBP
+2294     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2295     # var slice/ECX = "*(esi-3)"
+2296     b8/copy-to-EAX  "*(esi-3)"/imm32
+2297     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2298     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2299     05/add-to-EAX  4/imm32
+2300     # . ECX = {EAX, ECX}
+2301     51/push-ECX
+2302     50/push-EAX
+2303     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2304     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2305     # . . push args
+2306     51/push-ECX
+2307     # . . call
+2308     e8/call  parse-effective-address/disp32
+2309     # . . discard args
+2310     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2311     # slice clobbered beyond this point
+2312     # check-ints-equal(EAX, 6, msg)
+2313     # . . push args
+2314     68/push  "F - test-parse-effective-address-base-negative-displacement/base"/imm32
+2315     68/push  6/imm32/ESI
+2316     50/push-EAX
+2317     # . . call
+2318     e8/call  check-ints-equal/disp32
+2319     # . . discard args
+2320     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2321     # check-ints-equal(ECX, 4, msg)
+2322     # . . push args
+2323     68/push  "F - test-parse-effective-address-base-negative-displacement/index"/imm32
+2324     68/push  4/imm32/none
+2325     51/push-ECX
+2326     # . . call
+2327     e8/call  check-ints-equal/disp32
+2328     # . . discard args
+2329     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2330     # check-ints-equal(EDX, 0, msg)
+2331     # . . push args
+2332     68/push  "F - test-parse-effective-address-base-negative-displacement/scale"/imm32
+2333     68/push  0/imm32/none
+2334     52/push-EDX
+2335     # . . call
+2336     e8/call  check-ints-equal/disp32
+2337     # . . discard args
+2338     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2339     # check-ints-equal(EBX, -3, msg)
+2340     # . . push args
+2341     68/push  "F - test-parse-effective-address-base-negative-displacement/displacement"/imm32
+2342     68/push  -3/imm32
+2343     53/push-EBX
+2344     # . . call
+2345     e8/call  check-ints-equal/disp32
+2346     # . . discard args
+2347     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2348     # . epilog
+2349     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2350     5d/pop-to-EBP
+2351     c3/return
+2352 
+2353 test-parse-effective-address-base-index:
+2354     # . prolog
+2355     55/push-EBP
+2356     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2357     # var slice/ECX = "*(esi+ecx)"
+2358     b8/copy-to-EAX  "*(esi+ecx)"/imm32
+2359     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2360     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2361     05/add-to-EAX  4/imm32
+2362     # . ECX = {EAX, ECX}
+2363     51/push-ECX
+2364     50/push-EAX
+2365     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2366     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2367     # . . push args
+2368     51/push-ECX
+2369     # . . call
+2370     e8/call  parse-effective-address/disp32
+2371     # . . discard args
+2372     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2373     # slice clobbered beyond this point
+2374     # check-ints-equal(EAX, 6, msg)
+2375     # . . push args
+2376     68/push  "F - test-parse-effective-address-base-index/base"/imm32
+2377     68/push  6/imm32/ESI
+2378     50/push-EAX
+2379     # . . call
+2380     e8/call  check-ints-equal/disp32
+2381     # . . discard args
+2382     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2383     # check-ints-equal(ECX, 1, msg)
+2384     # . . push args
+2385     68/push  "F - test-parse-effective-address-base-index/index"/imm32
+2386     68/push  1/imm32/none
+2387     51/push-ECX
+2388     # . . call
+2389     e8/call  check-ints-equal/disp32
+2390     # . . discard args
+2391     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2392     # check-ints-equal(EDX, 0, msg)
+2393     # . . push args
+2394     68/push  "F - test-parse-effective-address-base-index/scale"/imm32
+2395     68/push  0/imm32/none
+2396     52/push-EDX
+2397     # . . call
+2398     e8/call  check-ints-equal/disp32
+2399     # . . discard args
+2400     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2401     # check-ints-equal(EBX, 0, msg)
+2402     # . . push args
+2403     68/push  "F - test-parse-effective-address-base-index/displacement"/imm32
+2404     68/push  0/imm32
+2405     53/push-EBX
+2406     # . . call
+2407     e8/call  check-ints-equal/disp32
+2408     # . . discard args
+2409     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2410     # . epilog
+2411     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2412     5d/pop-to-EBP
+2413     c3/return
+2414 
+2415 test-parse-effective-address-base-index-scale:
+2416     # . prolog
+2417     55/push-EBP
+2418     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2419     # var slice/ECX = "*(esi+ecx<<2)"
+2420     b8/copy-to-EAX  "*(esi+ecx<<2)"/imm32
+2421     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2422     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2423     05/add-to-EAX  4/imm32
+2424     # . ECX = {EAX, ECX}
+2425     51/push-ECX
+2426     50/push-EAX
+2427     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2428     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2429     # . . push args
+2430     51/push-ECX
+2431     # . . call
+2432     e8/call  parse-effective-address/disp32
+2433     # . . discard args
+2434     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2435     # slice clobbered beyond this point
+2436     # check-ints-equal(EAX, 6, msg)
+2437     # . . push args
+2438     68/push  "F - test-parse-effective-address-base-index-scale/base"/imm32
+2439     68/push  6/imm32/ESI
+2440     50/push-EAX
+2441     # . . call
+2442     e8/call  check-ints-equal/disp32
+2443     # . . discard args
+2444     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2445     # check-ints-equal(ECX, 1, msg)
+2446     # . . push args
+2447     68/push  "F - test-parse-effective-address-base-index-scale/index"/imm32
+2448     68/push  1/imm32/none
+2449     51/push-ECX
+2450     # . . call
+2451     e8/call  check-ints-equal/disp32
+2452     # . . discard args
+2453     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2454     # check-ints-equal(EDX, 2, msg)
+2455     # . . push args
+2456     68/push  "F - test-parse-effective-address-base-index-scale/scale"/imm32
+2457     68/push  2/imm32
+2458     52/push-EDX
+2459     # . . call
+2460     e8/call  check-ints-equal/disp32
+2461     # . . discard args
+2462     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2463     # check-ints-equal(EBX, 0, msg)
+2464     # . . push args
+2465     68/push  "F - test-parse-effective-address-base-index-scale/displacement"/imm32
+2466     68/push  0/imm32
+2467     53/push-EBX
+2468     # . . call
+2469     e8/call  check-ints-equal/disp32
+2470     # . . discard args
+2471     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2472     # . epilog
+2473     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2474     5d/pop-to-EBP
+2475     c3/return
+2476 
+2477 test-parse-effective-address-base-index-scale-displacement:
+2478     # . prolog
+2479     55/push-EBP
+2480     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2481     # var slice/ECX = "*(esi + ecx<<2 - 0x34)"
+2482     b8/copy-to-EAX  "*(esi + ecx<<2 - 0x34)"/imm32
+2483     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2484     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2485     05/add-to-EAX  4/imm32
+2486     # . ECX = {EAX, ECX}
+2487     51/push-ECX
+2488     50/push-EAX
+2489     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2490     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2491     # . . push args
+2492     51/push-ECX
+2493     # . . call
+2494     e8/call  parse-effective-address/disp32
+2495     # . . discard args
+2496     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2497     # slice clobbered beyond this point
+2498     # check-ints-equal(EAX, 6, msg)
+2499     # . . push args
+2500     68/push  "F - test-parse-effective-address-base-index-scale/base"/imm32
+2501     68/push  6/imm32/ESI
+2502     50/push-EAX
+2503     # . . call
+2504     e8/call  check-ints-equal/disp32
+2505     # . . discard args
+2506     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2507     # check-ints-equal(ECX, 1, msg)
+2508     # . . push args
+2509     68/push  "F - test-parse-effective-address-base-index-scale/index"/imm32
+2510     68/push  1/imm32/none
+2511     51/push-ECX
+2512     # . . call
+2513     e8/call  check-ints-equal/disp32
+2514     # . . discard args
+2515     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2516     # check-ints-equal(EDX, 2, msg)
+2517     # . . push args
+2518     68/push  "F - test-parse-effective-address-base-index-scale/scale"/imm32
+2519     68/push  2/imm32
+2520     52/push-EDX
+2521     # . . call
+2522     e8/call  check-ints-equal/disp32
+2523     # . . discard args
+2524     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2525     # check-ints-equal(EBX, -0x34, msg)
+2526     # . . push args
+2527     68/push  "F - test-parse-effective-address-base-index-scale/displacement"/imm32
+2528     68/push  -0x34/imm32
+2529     53/push-EBX
+2530     # . . call
+2531     e8/call  check-ints-equal/disp32
+2532     # . . discard args
+2533     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2534     # . epilog
+2535     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2536     5d/pop-to-EBP
+2537     c3/return
+2538 
+2539 # Code generation:
+2540 #   if index is none and disp is 0, then mod = 0 and rm32 = base
+2541 #   if index is none, then mod = 2 and rm32 = base and disp32 = disp
+2542 #   if index is not none, then mod = 2 and rm32 = 4 and base = base and index = index and disp32 = disp
+2543 emit-indirect-mode:  # out : (address buffered-file), base : int, index : int, scale : int, disp : int
+2544     # . prolog
+2545     55/push-EBP
+2546     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2547 $emit-indirect-mode:check-for-sib:
+2548     # if (index == 4/none) goto next check
+2549     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      4/imm32           # compare *(EBP+16)
+2550     0f 84/jump-if-equal  $emit-indirect-mode:check-for-disp/disp32
+2551 $emit-indirect-mode:emit-sib:
+2552     # emit(out, "2/mod/indirect 4/rm32/sib " base "/base " index "/index " scale "/scale " disp "/disp32")
+2553     # . write-buffered(out, "2/mod/*+disp32 4/rm32/sib ")
+2554     # . . push args
+2555     68/push  "2/mod/*+disp32 4/rm32/sib "/imm32
+2556     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2557     # . . call
+2558     e8/call  write-buffered/disp32
+2559     # . . discard args
+2560     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2561     # . print-int32-buffered(out, base)
+2562     # . . push args
+2563     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+2564     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2565     # . . call
+2566     e8/call  print-int32-buffered/disp32
+2567     # . . discard args
+2568     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2569     # . write-buffered(out, "/base ")
+2570     # . . push args
+2571     68/push  "/base "/imm32
+2572     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2573     # . . call
+2574     e8/call  write-buffered/disp32
+2575     # . . discard args
+2576     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2577     # . print-int32-buffered(out, index)
+2578     # . . push args
+2579     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
+2580     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2581     # . . call
+2582     e8/call  print-int32-buffered/disp32
+2583     # . . discard args
+2584     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2585     # . write-buffered(out, "/index ")
+2586     # . . push args
+2587     68/push  "/index "/imm32
+2588     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2589     # . . call
+2590     e8/call  write-buffered/disp32
+2591     # . . discard args
+2592     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2593     # . print-int32-buffered(out, scale)
+2594     # . . push args
+2595     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
+2596     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2597     # . . call
+2598     e8/call  print-int32-buffered/disp32
+2599     # . . discard args
+2600     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2601     # . write-buffered(out, "/scale ")
+2602     # . . push args
+2603     68/push  "/scale "/imm32
+2604     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2605     # . . call
+2606     e8/call  write-buffered/disp32
+2607     # . . discard args
+2608     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2609     # . print-int32-buffered(out, disp)
+2610     # . . push args
+2611     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+2612     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2613     # . . call
+2614     e8/call  print-int32-buffered/disp32
+2615     # . . discard args
+2616     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2617     # . write-buffered(out, "/disp32")
+2618     # . . push args
+2619     68/push  "/disp32"/imm32
+2620     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2621     # . . call
+2622     e8/call  write-buffered/disp32
+2623     # . . discard args
+2624     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2625     e9/jump  $emit-indirect-mode:end/disp32
+2626 $emit-indirect-mode:check-for-disp:
+2627     # if (disp == 0) goto next check
+2628     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      0/imm32           # compare *(EBP+24)
+2629     74/jump-if-equal  $emit-indirect-mode:emit-indirect/disp8
+2630 $emit-indirect-mode:emit-disp:
+2631     # emit(out, "2/mod/*+disp32 " base "/rm32 " disp "/disp32")
+2632     # . write-buffered(out, "2/mod/*+disp32 ")
+2633     # . . push args
+2634     68/push  "2/mod/*+disp32 "/imm32
+2635     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2636     # . . call
+2637     e8/call  write-buffered/disp32
+2638     # . . discard args
+2639     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2640     # . print-int32-buffered(out, base)
+2641     # . . push args
+2642     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+2643     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2644     # . . call
+2645     e8/call  print-int32-buffered/disp32
+2646     # . . discard args
+2647     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2648     # . write-buffered(out, "/rm32 ")
+2649     # . . push args
+2650     68/push  "/rm32 "/imm32
+2651     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2652     # . . call
+2653     e8/call  write-buffered/disp32
+2654     # . . discard args
+2655     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2656     # . print-int32-buffered(out, disp)
+2657     # . . push args
+2658     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+2659     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2660     # . . call
+2661     e8/call  print-int32-buffered/disp32
+2662     # . . discard args
+2663     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2664     # . write-buffered(out, "/disp32")
+2665     # . . push args
+2666     68/push  "/disp32"/imm32
+2667     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2668     # . . call
+2669     e8/call  write-buffered/disp32
+2670     # . . discard args
+2671     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2672     eb/jump  $emit-indirect-mode:end/disp8
+2673 $emit-indirect-mode:emit-indirect:
+2674     # emit(out, "0/mod/indirect " base "/rm32")
+2675     # . write-buffered(out, "0/mod/indirect ")
+2676     # . . push args
+2677     68/push  "0/mod/indirect "/imm32
+2678     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2679     # . . call
+2680     e8/call  write-buffered/disp32
+2681     # . . discard args
+2682     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2683     # . print-int32-buffered(out, base)
+2684     # . . push args
+2685     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+2686     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2687     # . . call
+2688     e8/call  print-int32-buffered/disp32
+2689     # . . discard args
+2690     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2691     # . write-buffered(out, "/rm32")
+2692     # . . push args
+2693     68/push  "/rm32"/imm32
+2694     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2695     # . . call
+2696     e8/call  write-buffered/disp32
+2697     # . . discard args
+2698     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2699 $emit-indirect-mode:end:
+2700     # . epilog
+2701     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2702     5d/pop-to-EBP
+2703     c3/return
+2704 
+2705 test-emit-indirect-mode:
+2706     # . prolog
+2707     55/push-EBP
+2708     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2709     # setup
+2710     # . clear-stream(_test-output-stream)
+2711     # . . push args
+2712     68/push  _test-output-stream/imm32
+2713     # . . call
+2714     e8/call  clear-stream/disp32
+2715     # . . discard args
+2716     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2717     # . clear-stream(_test-output-buffered-file+4)
+2718     # . . push args
+2719     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2720     05/add-to-EAX  4/imm32
+2721     50/push-EAX
+2722     # . . call
+2723     e8/call  clear-stream/disp32
+2724     # . . discard args
+2725     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2726     # emit-indirect-mode(_test-output-buffered-file, 0, 4/none, 0, 0)
+2727     # . . write args
+2728     68/push  0/imm32/.disp
+2729     68/push  0/imm32/.scale
+2730     68/push  4/imm32/.index/none
+2731     68/push  0/imm32/.base
+2732     68/push  _test-output-buffered-file/imm32
+2733     # . . call
+2734     e8/call  emit-indirect-mode/disp32
+2735     # . . discard args
+2736     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2737     # . flush(_test-output-buffered-file)
+2738     # . . push args
+2739     68/push  _test-output-buffered-file/imm32
+2740     # . . call
+2741     e8/call  flush/disp32
+2742     # . . discard args
+2743     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2744 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+2770     # check-stream-equal(_test-output-stream, "0/mod/indirect 0/rm32", msg)
+2771     # . . push args
+2772     68/push  "F - test-emit-indirect-mode"/imm32
+2773     68/push  "0/mod/indirect 0x00000000/rm32"/imm32
+2774     68/push  _test-output-stream/imm32
+2775     # . . call
+2776     e8/call  check-stream-equal/disp32
+2777     # . . discard args
+2778     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2779     # . epilog
+2780     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2781     5d/pop-to-EBP
+2782     c3/return
+2783 
+2784 test-emit-indirect-mode-2:
+2785     # . prolog
+2786     55/push-EBP
+2787     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2788     # setup
+2789     # . clear-stream(_test-output-stream)
+2790     # . . push args
+2791     68/push  _test-output-stream/imm32
+2792     # . . call
+2793     e8/call  clear-stream/disp32
+2794     # . . discard args
+2795     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2796     # . clear-stream(_test-output-buffered-file+4)
+2797     # . . push args
+2798     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2799     05/add-to-EAX  4/imm32
+2800     50/push-EAX
+2801     # . . call
+2802     e8/call  clear-stream/disp32
+2803     # . . discard args
+2804     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2805     # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 0)
+2806     # . . write args
+2807     68/push  0/imm32/.disp
+2808     68/push  0/imm32/.scale
+2809     68/push  4/imm32/.index/none
+2810     68/push  7/imm32/.base
+2811     68/push  _test-output-buffered-file/imm32
+2812     # . . call
+2813     e8/call  emit-indirect-mode/disp32
+2814     # . . discard args
+2815     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2816     # . flush(_test-output-buffered-file)
+2817     # . . push args
+2818     68/push  _test-output-buffered-file/imm32
+2819     # . . call
+2820     e8/call  flush/disp32
+2821     # . . discard args
+2822     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2823 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+2849     # check-stream-equal(_test-output-stream, "0/mod/indirect 7/rm32", msg)
+2850     # . . push args
+2851     68/push  "F - test-emit-indirect-mode-2"/imm32
+2852     68/push  "0/mod/indirect 0x00000007/rm32"/imm32
+2853     68/push  _test-output-stream/imm32
+2854     # . . call
+2855     e8/call  check-stream-equal/disp32
+2856     # . . discard args
+2857     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2858     # . epilog
+2859     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2860     5d/pop-to-EBP
+2861     c3/return
+2862 
+2863 test-emit-indirect-mode-with-disp:
+2864     # . prolog
+2865     55/push-EBP
+2866     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2867     # setup
+2868     # . clear-stream(_test-output-stream)
+2869     # . . push args
+2870     68/push  _test-output-stream/imm32
+2871     # . . call
+2872     e8/call  clear-stream/disp32
+2873     # . . discard args
+2874     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2875     # . clear-stream(_test-output-buffered-file+4)
+2876     # . . push args
+2877     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2878     05/add-to-EAX  4/imm32
+2879     50/push-EAX
+2880     # . . call
+2881     e8/call  clear-stream/disp32
+2882     # . . discard args
+2883     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2884     # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 4)
+2885     # . . write args
+2886     68/push  4/imm32/.disp
+2887     68/push  0/imm32/.scale
+2888     68/push  4/imm32/.index/none
+2889     68/push  6/imm32/.base
+2890     68/push  _test-output-buffered-file/imm32
+2891     # . . call
+2892     e8/call  emit-indirect-mode/disp32
+2893     # . . discard args
+2894     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2895     # . flush(_test-output-buffered-file)
+2896     # . . push args
+2897     68/push  _test-output-buffered-file/imm32
+2898     # . . call
+2899     e8/call  flush/disp32
+2900     # . . discard args
+2901     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2902 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+2928     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 4/disp32", msg)
+2929     # . . push args
+2930     68/push  "F - test-emit-indirect-mode-with-disp"/imm32
+2931     68/push  "2/mod/*+disp32 0x00000006/rm32 0x00000004/disp32"/imm32
+2932     68/push  _test-output-stream/imm32
+2933     # . . call
+2934     e8/call  check-stream-equal/disp32
+2935     # . . discard args
+2936     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2937     # . epilog
+2938     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2939     5d/pop-to-EBP
+2940     c3/return
+2941 
+2942 test-emit-indirect-mode-with-disp-negative:
+2943     # . prolog
+2944     55/push-EBP
+2945     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2946     # setup
+2947     # . clear-stream(_test-output-stream)
+2948     # . . push args
+2949     68/push  _test-output-stream/imm32
+2950     # . . call
+2951     e8/call  clear-stream/disp32
+2952     # . . discard args
+2953     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2954     # . clear-stream(_test-output-buffered-file+4)
+2955     # . . push args
+2956     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2957     05/add-to-EAX  4/imm32
+2958     50/push-EAX
+2959     # . . call
+2960     e8/call  clear-stream/disp32
+2961     # . . discard args
+2962     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2963     # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, -4)
+2964     # . . write args
+2965     68/push  -4/imm32/.disp
+2966     68/push  0/imm32/.scale
+2967     68/push  4/imm32/.index/none
+2968     68/push  6/imm32/.base
+2969     68/push  _test-output-buffered-file/imm32
+2970     # . . call
+2971     e8/call  emit-indirect-mode/disp32
+2972     # . . discard args
+2973     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2974     # . flush(_test-output-buffered-file)
+2975     # . . push args
+2976     68/push  _test-output-buffered-file/imm32
+2977     # . . call
+2978     e8/call  flush/disp32
+2979     # . . discard args
+2980     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2981 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+3007     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 -4/disp32", msg)
+3008     # . . push args
+3009     68/push  "F - test-emit-indirect-mode-with-disp"/imm32
+3010     68/push  "2/mod/*+disp32 0x00000006/rm32 0xfffffffc/disp32"/imm32
+3011     68/push  _test-output-stream/imm32
+3012     # . . call
+3013     e8/call  check-stream-equal/disp32
+3014     # . . discard args
+3015     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3016     # . epilog
+3017     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3018     5d/pop-to-EBP
+3019     c3/return
+3020 
+3021 test-emit-indirect-mode-with-sib:
+3022     # . prolog
+3023     55/push-EBP
+3024     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3025     # setup
+3026     # . clear-stream(_test-output-stream)
+3027     # . . push args
+3028     68/push  _test-output-stream/imm32
+3029     # . . call
+3030     e8/call  clear-stream/disp32
+3031     # . . discard args
+3032     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3033     # . clear-stream(_test-output-buffered-file+4)
+3034     # . . push args
+3035     b8/copy-to-EAX  _test-output-buffered-file/imm32
+3036     05/add-to-EAX  4/imm32
+3037     50/push-EAX
+3038     # . . call
+3039     e8/call  clear-stream/disp32
+3040     # . . discard args
+3041     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3042     # emit-indirect-mode(_test-output-buffered-file, 6/base, 1/index, 2/scale, 4/disp)
+3043     # . . write args
+3044     68/push  4/imm32/.disp
+3045     68/push  2/imm32/.scale
+3046     68/push  1/imm32/.index
+3047     68/push  6/imm32/.base
+3048     68/push  _test-output-buffered-file/imm32
+3049     # . . call
+3050     e8/call  emit-indirect-mode/disp32
+3051     # . . discard args
+3052     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+3053     # . flush(_test-output-buffered-file)
+3054     # . . push args
+3055     68/push  _test-output-buffered-file/imm32
+3056     # . . call
+3057     e8/call  flush/disp32
+3058     # . . discard args
+3059     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3060 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+3086     # check-stream-equal(_test-output-stream, "2/mod/indirect 4/rm32/sib 6/base 1/index 2/scale 4/disp", msg)
+3087     # . . push args
+3088     68/push  "F - test-emit-indirect-mode-with-sib"/imm32
+3089     68/push  "2/mod/*+disp32 4/rm32/sib 0x00000006/base 0x00000001/index 0x00000002/scale 0x00000004/disp32"/imm32
+3090     68/push  _test-output-stream/imm32
+3091     # . . call
+3092     e8/call  check-stream-equal/disp32
+3093     # . . discard args
+3094     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3095     # . epilog
+3096     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3097     5d/pop-to-EBP
+3098     c3/return
+3099 
+3100 # update line->read to ')'
+3101 # line->read ends at ')'
+3102 skip-until-close-paren:  # line : (address stream)
+3103     # . prolog
+3104     55/push-EBP
+3105     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3106     # . save registers
+3107     50/push-EAX
+3108     51/push-ECX
+3109     52/push-EDX
+3110     # ECX = line
+3111     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
+3112     # EAX = skip-until-close-paren-in-slice(&line->data[line->read], &line->data[line->write])
+3113     # . . push &line->data[line->write]
+3114     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .                         2/r32/EDX   8/disp8         .                 # copy *(ECX+8) to EDX
+3115     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   0xc/disp8       .                 # copy ECX+EDX+12 to EDX
+3116     52/push-EDX
+3117     # . . push &line->data[line->read]
+3118     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .                         2/r32/EDX   4/disp8         .                 # copy *(ECX+4) to EDX
+3119     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   0xc/disp8       .                 # copy ECX+EDX+12 to EDX
+3120     52/push-EDX
+3121     # . . call
+3122     e8/call  skip-until-close-paren-in-slice/disp32
+3123     # . . discard args
+3124     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3125     # line->read = EAX - line->data
+3126     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+3127     2d/subtract-from-EAX  0xc/imm32
+3128     89/copy                         1/mod/*+disp8   1/rm32/ECX    .           .                         0/r32/EAX   4/disp8         .                 # copy EAX to *(ECX+4)
+3129 $skip-until-close-paren:end:
+3130     # . restore registers
+3131     5a/pop-to-EDX
+3132     59/pop-to-ECX
+3133     58/pop-to-EAX
+3134     # . epilog
+3135     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3136     5d/pop-to-EBP
+3137     c3/return
+3138 
+3139 test-skip-until-close-paren:
+3140     # . prolog
+3141     55/push-EBP
+3142     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3143     # setup
+3144     # . clear-stream(_test-input-stream)
+3145     # . . push args
+3146     68/push  _test-input-stream/imm32
+3147     # . . call
+3148     e8/call  clear-stream/disp32
+3149     # . . discard args
+3150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3151     # . write(_test-input-stream, "*(abc) def")
+3152     # .                   indices:  0123 45
+3153     # . . push args
+3154     68/push  "*(abc) def"/imm32
+3155     68/push  _test-input-stream/imm32
+3156     # . . call
+3157     e8/call  write/disp32
+3158     # . . discard args
+3159     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3160     # precondition: line->read == 0
+3161     # . . push args
+3162     68/push  "F - test-skip-until-close-paren/precondition"/imm32
+3163     68/push  0/imm32
+3164     b8/copy-to-EAX  _test-input-stream/imm32
+3165     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3166     # . . call
+3167     e8/call  check-ints-equal/disp32
+3168     # . . discard args
+3169     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3170     # skip-until-close-paren(_test-input-stream)
+3171     # . . push args
+3172     68/push  _test-input-stream/imm32
+3173     # . . call
+3174     e8/call  skip-until-close-paren/disp32
+3175     # . . discard args
+3176     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3177     # check-ints-equal(line->read, 5, msg)
+3178     # . . push args
+3179     68/push  "F - test-skip-until-close-paren"/imm32
+3180     68/push  5/imm32
+3181     b8/copy-to-EAX  _test-input-stream/imm32
+3182     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3183     # . . call
+3184     e8/call  check-ints-equal/disp32
+3185     # . . discard args
+3186     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3187     # . epilog
+3188     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3189     5d/pop-to-EBP
+3190     c3/return
+3191 
+3192 test-skip-until-close-paren-ignores-spaces:
+3193     # . prolog
+3194     55/push-EBP
+3195     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3196     # setup
+3197     # . clear-stream(_test-input-stream)
+3198     # . . push args
+3199     68/push  _test-input-stream/imm32
+3200     # . . call
+3201     e8/call  clear-stream/disp32
+3202     # . . discard args
+3203     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3204     # . write(_test-input-stream, "*(a b)/yz")
+3205     # . . push args
+3206     68/push  "*(a b)/yz"/imm32
+3207     68/push  _test-input-stream/imm32
+3208     # . . call
+3209     e8/call  write/disp32
+3210     # . . discard args
+3211     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3212     # precondition: line->read == 0
+3213     # . . push args
+3214     68/push  "F - test-skip-until-close-paren-ignores-spaces/precondition"/imm32
+3215     68/push  0/imm32
+3216     b8/copy-to-EAX  _test-input-stream/imm32
+3217     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3218     # . . call
+3219     e8/call  check-ints-equal/disp32
+3220     # . . discard args
+3221     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3222     # skip-until-close-paren(_test-input-stream)
+3223     # . . push args
+3224     68/push  _test-input-stream/imm32
+3225     # . . call
+3226     e8/call  skip-until-close-paren/disp32
+3227     # . . discard args
+3228     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3229     # check-ints-equal(line->read, 5, msg)
+3230     # . . push args
+3231     68/push  "F - test-skip-until-close-paren-ignores-spaces"/imm32
+3232     68/push  5/imm32
+3233     b8/copy-to-EAX  _test-input-stream/imm32
+3234     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3235     # . . call
+3236     e8/call  check-ints-equal/disp32
+3237     # . . discard args
+3238     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3239     # . epilog
+3240     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3241     5d/pop-to-EBP
+3242     c3/return
+3243 
+3244 test-skip-until-close-paren-works-from-mid-stream:
+3245     # . prolog
+3246     55/push-EBP
+3247     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3248     # setup
+3249     # . clear-stream(_test-input-stream)
+3250     # . . push args
+3251     68/push  _test-input-stream/imm32
+3252     # . . call
+3253     e8/call  clear-stream/disp32
+3254     # . . discard args
+3255     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3256     # . write(_test-input-stream, "0 *(a b)/yz")
+3257     # . . push args
+3258     68/push  "0 *(a b)/yz"/imm32
+3259     68/push  _test-input-stream/imm32
+3260     # . . call
+3261     e8/call  write/disp32
+3262     # . . discard args
+3263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3264     # precondition: _test-input-stream->read == 2
+3265     c7          0/subop/copy        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         2/imm32           # copy to *(EAX+4)
+3266     # skip-until-close-paren(_test-input-stream)
+3267     # . . push args
+3268     68/push  _test-input-stream/imm32
+3269     # . . call
+3270     e8/call  skip-until-close-paren/disp32
+3271     # . . discard args
+3272     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3273     # check-ints-equal(_test-input-stream->read, 7, msg)
+3274     # . . push args
+3275     68/push  "F - test-skip-until-close-paren-works-from-mid-stream"/imm32
+3276     68/push  7/imm32
+3277     b8/copy-to-EAX  _test-input-stream/imm32
+3278     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3279     # . . call
+3280     e8/call  check-ints-equal/disp32
+3281     # . . discard args
+3282     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3283     # . epilog
+3284     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3285     5d/pop-to-EBP
+3286     c3/return
+3287 
+3288 skip-until-close-paren-in-slice:  # curr : (address byte), end : (address byte) -> new_curr/EAX
+3289     # . prolog
+3290     55/push-EBP
+3291     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3292     # . save registers
+3293     51/push-ECX
+3294     52/push-EDX
+3295     # ECX = curr
+3296     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
+3297     # EDX = end
+3298     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         2/r32/EDX   0xc/disp8         .               # copy *(EBP+12) to EDX
+3299     # EAX = 0
+3300     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3301     # skip initial dquote
+3302     41/increment-ECX
+3303 $skip-until-close-paren-in-slice:loop:
+3304     # if (curr >= end) break
+3305     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3306     73/jump-if-greater-unsigned-or-equal  $skip-until-close-paren-in-slice:break/disp8
+3307     # AL = *curr
+3308     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3309 $skip-until-close-paren-in-slice:check-close:
+3310     # if (EAX == ')') break
+3311     3d/compare-EAX-and  0x29/imm32/close-paren
+3312     74/jump-if-equal  $skip-until-close-paren-in-slice:break/disp8
+3313     # ++curr
+3314     41/increment-ECX
+3315     eb/jump  $skip-until-close-paren-in-slice:loop/disp8
+3316 $skip-until-close-paren-in-slice:break:
+3317     # return curr
+3318     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy ECX to EAX
+3319 $skip-until-close-paren-in-slice:end:
+3320     # . restore registers
+3321     5a/pop-to-EDX
+3322     59/pop-to-ECX
+3323     # . epilog
+3324     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3325     5d/pop-to-EBP
+3326     c3/return
+3327 
+3328 test-skip-until-close-paren-in-slice:
+3329     # . prolog
+3330     55/push-EBP
+3331     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3332     # setup: (EAX..ECX) = "*(abc) def"
+3333     b8/copy-to-EAX  "*(abc) def"/imm32
+3334     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3335     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3336     05/add-to-EAX  4/imm32
+3337     # EAX = skip-until-close-paren-in-slice(EAX, ECX)
+3338     # . . push args
+3339     51/push-ECX
+3340     50/push-EAX
+3341     # . . call
+3342     e8/call  skip-until-close-paren-in-slice/disp32
+3343     # . . discard args
+3344     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3345     # check-ints-equal(ECX-EAX, 5, msg)  # EAX is at the ')'
+3346     # . . push args
+3347     68/push  "F - test-skip-until-close-paren-in-slice"/imm32
+3348     68/push  5/imm32
+3349     # . . push ECX-EAX
+3350     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+3351     51/push-ECX
+3352     # . . call
+3353     e8/call  check-ints-equal/disp32
+3354     # . . discard args
+3355     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3356     # . epilog
+3357     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3358     5d/pop-to-EBP
+3359     c3/return
+3360 
+3361 test-skip-until-close-paren-in-slice-ignores-spaces:
+3362     # . prolog
+3363     55/push-EBP
+3364     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3365     # setup: (EAX..ECX) = "*(a b)/yz"
+3366     b8/copy-to-EAX  "*(a b)/yz"/imm32
+3367     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3368     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3369     05/add-to-EAX  4/imm32
+3370     # EAX = skip-until-close-paren-in-slice(EAX, ECX)
+3371     # . . push args
+3372     51/push-ECX
+3373     50/push-EAX
+3374     # . . call
+3375     e8/call  skip-until-close-paren-in-slice/disp32
+3376     # . . discard args
+3377     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3378     # check-ints-equal(ECX-EAX, 4, msg)  # EAX is at the ')'
+3379     # . . push args
+3380     68/push  "F - test-skip-until-close-paren-in-slice-ignores-spaces"/imm32
+3381     68/push  4/imm32
+3382     # . . push ECX-EAX
+3383     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+3384     51/push-ECX
+3385     # . . call
+3386     e8/call  check-ints-equal/disp32
+3387     # . . discard args
+3388     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3389     # . epilog
+3390     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3391     5d/pop-to-EBP
+3392     c3/return
+3393 
+3394 test-skip-until-close-paren-in-slice-stops-at-end:
+3395     # . prolog
+3396     55/push-EBP
+3397     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3398     # setup: (EAX..ECX) = "*(abc"  # unbalanced dquote
+3399     b8/copy-to-EAX  "*(abc"/imm32
+3400     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3401     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3402     05/add-to-EAX  4/imm32
+3403     # EAX = skip-until-close-paren-in-slice(EAX, ECX)
+3404     # . . push args
+3405     51/push-ECX
+3406     50/push-EAX
+3407     # . . call
+3408     e8/call  skip-until-close-paren-in-slice/disp32
+3409     # . . discard args
+3410     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3411     # check-ints-equal(ECX-EAX, 0, msg)  # skipped to end of slice
+3412     # . . push args
+3413     68/push  "F - test-skip-until-close-paren-in-slice-stops-at-end"/imm32
+3414     68/push  0/imm32
+3415     # . . push ECX-EAX
+3416     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+3417     51/push-ECX
+3418     # . . call
+3419     e8/call  check-ints-equal/disp32
+3420     # . . discard args
+3421     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3422     # . epilog
+3423     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3424     5d/pop-to-EBP
+3425     c3/return
+3426 
+3427 # assumes 'in' starts with optional '+' or '-', optional whitespace, and an unsigned integer
+3428 # returns the value of the integer
+3429 # side-effect: modifies 'in' to skip past the integer
+3430 next-hex-int:  # in : (address slice) -> result/EAX
+3431     # . prolog
+3432     55/push-EBP
+3433     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3434     # . save registers
+3435     51/push-ECX
+3436     52/push-EDX
+3437     53/push-EBX
+3438     56/push-ESI
+3439     57/push-EDI
+3440     # result/EDI = 0
+3441     31/xor                          3/mod/direct    7/rm32/EDI    .           .             .           7/r32/EDI   .               .                 # clear EDI
+3442     # ESI = in
+3443     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+3444     # EDX = in->end
+3445     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           2/r32/EDX   4/disp8         .                 # copy *(ESI+4) to EDX
+3446     # curr/ECX = in->start
+3447     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
+3448     # negate?/EBX = false
+3449     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+3450     # EAX = *curr
+3451     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3452     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3453 $next-hex-int:positive:
+3454     # if (*curr == '+') ++curr
+3455     3d/compare-EAX-and  0x2b/imm32/+
+3456     75/jump-if-not-equal  $next-hex-int:negative/disp8
+3457     # . ++curr
+3458     41/increment-ECX
+3459     eb/jump  $next-hex-int:skip-whitespace/disp8
+3460 $next-hex-int:negative:
+3461     # else if (*curr == '-') ++curr, negate = true
+3462     3d/compare-EAX-and  0x2d/imm32/-
+3463     75/jump-if-not-equal  $next-hex-int:skip-whitespace/disp8
+3464 $next-hex-int:need-to-negate:
+3465     # . ++curr
+3466     41/increment-ECX
+3467     # . negate = true
+3468     bb/copy-to-EBX  1/imm32/true
+3469     # fall through
+3470 $next-hex-int:skip-whitespace:
+3471     # spill EAX
+3472     50/push-EAX
+3473     # EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+3474     # . . push args
+3475     52/push-EDX
+3476     51/push-ECX
+3477     # . . call
+3478     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+3479     # . . discard args
+3480     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3481     # ECX = EAX
+3482     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy EAX to ECX
+3483     # restore EAX
+3484     58/pop-to-EAX
+3485 $next-hex-int:initial-0:
+3486     # skip past leading '0x'
+3487     # . if (*curr != '0') jump to loop
+3488     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3489     3d/compare-EAX-and  0x30/imm32/0
+3490     75/jump-if-not-equal  $next-hex-int:loop/disp8
+3491     # . ++curr
+3492     41/increment-ECX
+3493 $next-hex-int:initial-0x:
+3494     # . if (curr >= in->end) return result
+3495     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3496     73/jump-if-greater-or-equal-unsigned  $next-hex-int:end/disp8
+3497     # . if (*curr != 'x') jump to loop  # the previous '0' is still valid so doesn't need to be checked again
+3498     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3499     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3500     3d/compare-EAX-and  0x78/imm32/x
+3501     75/jump-if-not-equal  $next-hex-int:loop/disp8
+3502     # . ++curr
+3503     41/increment-ECX
+3504 $next-hex-int:loop:
+3505     # if (curr >= in->end) break
+3506     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3507     73/jump-if-greater-or-equal-unsigned  $next-hex-int:break/disp8
+3508     # if (!is-hex-digit?(*curr)) break
+3509     # . EAX = *curr
+3510     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3511     # . EAX = is-hex-digit?(*curr)
+3512     # . . push args
+3513     50/push-EAX
+3514     # . . call
+3515     e8/call  is-hex-digit?/disp32
+3516     # . . discard args
+3517     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3518     # . if (EAX == 0) break
+3519     3d/compare-EAX-and  0/imm32
+3520     74/jump-if-equal  $next-hex-int:break/disp8
+3521     # EAX = from-hex-char(*curr)
+3522     # . . copy arg to EAX
+3523     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3524     # . . call
+3525     e8/call  from-hex-char/disp32
+3526     # result = result * 16 + EAX
+3527     c1/shift    4/subop/left        3/mod/direct    7/rm32/EDI    .           .             .           .           .               4/imm8            # shift EDI left by 4 bits
+3528     01/add                          3/mod/direct    7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # add EAX to EDI
+3529     # ++curr
+3530     41/increment-ECX
+3531     # loop
+3532     eb/jump  $next-hex-int:loop/disp8
+3533 $next-hex-int:break:
+3534     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0/imm32           # compare EBX
+3535     74/jump-if-equal  $next-hex-int:end/disp8
+3536 $next-hex-int:negate:
+3537     f7          3/subop/negate      3/mod/direct    7/rm32/EDI    .           .             .           .           .               .                 # negate EDI
+3538 $next-hex-int:end:
+3539     # word->start = curr
+3540     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy ECX to *ESI
+3541     # return EDI
+3542     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy EDI to EAX
+3543     # . restore registers
+3544     5f/pop-to-EDI
+3545     5e/pop-to-ESI
+3546     5b/pop-to-EBX
+3547     5a/pop-to-EDX
+3548     59/pop-to-ECX
+3549     # . epilog
+3550     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3551     5d/pop-to-EBP
+3552     c3/return
+3553 
+3554 $next-hex-int:abort:
+3555     # . _write(2/stderr, error)
+3556     # . . push args
+3557     68/push  "next-hex-int: invalid hex char: "/imm32
+3558     68/push  2/imm32/stderr
+3559     # . . call
+3560     e8/call  _write/disp32
+3561     # . . discard args
+3562     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3563     # . clear-stream(Stderr+4)
+3564     # . . save EAX
+3565     50/push-EAX
+3566     # . . push args
+3567     b8/copy-to-EAX  Stderr/imm32
+3568     05/add-to-EAX  4/imm32
+3569     50/push-EAX
+3570     # . . call
+3571     e8/call  clear-stream/disp32
+3572     # . . discard args
+3573     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3574     # . . restore EAX
+3575     58/pop-to-EAX
+3576     # . print-int32-buffered(Stderr, EAX)
+3577     # . . push args
+3578     50/push-EAX
+3579     68/push  Stderr/imm32
+3580     # . . call
+3581     e8/call  print-int32-buffered/disp32
+3582     # . . discard args
+3583     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3584     # . flush(Stderr)
+3585     # . . push args
+3586     68/push  Stderr/imm32
+3587     # . . call
+3588     e8/call  flush/disp32
+3589     # . . discard args
+3590     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3591     # . _write(2/stderr, "\n")
+3592     # . . push args
+3593     68/push  "\n"/imm32
+3594     68/push  2/imm32/stderr
+3595     # . . call
+3596     e8/call  _write/disp32
+3597     # . . discard args
+3598     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3599     # . syscall(exit, 1)
+3600     bb/copy-to-EBX  1/imm32
+3601     b8/copy-to-EAX  1/imm32/exit
+3602     cd/syscall  0x80/imm8
+3603     # never gets here
+3604 
+3605 test-next-hex-int-single-digit:
+3606     # . prolog
+3607     55/push-EBP
+3608     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3609     # (EAX..ECX) = "+a)"
+3610     b8/copy-to-EAX  "+a)"/imm32
+3611     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3612     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3613     05/add-to-EAX  4/imm32
+3614     # var slice/ECX = {EAX, ECX}
+3615     51/push-ECX
+3616     50/push-EAX
+3617     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3618     # EAX = next-hex-int(slice)
+3619     # . . push args
+3620     51/push-ECX
+3621     # . . call
+3622     e8/call  next-hex-int/disp32
+3623     # . . discard args
+3624     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3625     # check-ints-equal(EAX, 0xa, msg)
+3626     # . . push args
+3627     68/push  "F - test-next-hex-int-single-digit"/imm32
+3628     68/push  0xa/imm32
+3629     50/push-EAX
+3630     # . . call
+3631     e8/call  check-ints-equal/disp32
+3632     # . . discard args
+3633     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3634     # . epilog
+3635     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3636     5d/pop-to-EBP
+3637     c3/return
+3638 
+3639 test-next-hex-int-multi-digit:
+3640     # . prolog
+3641     55/push-EBP
+3642     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3643     # (EAX..ECX) = "+ 34a)"
+3644     b8/copy-to-EAX  "+ 34a)"/imm32
+3645     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3646     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3647     05/add-to-EAX  4/imm32
+3648     # var slice/ECX = {EAX, ECX}
+3649     51/push-ECX
+3650     50/push-EAX
+3651     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3652     # EAX = next-hex-int(slice)
+3653     # . . push args
+3654     51/push-ECX
+3655     # . . call
+3656     e8/call  next-hex-int/disp32
+3657     # . . discard args
+3658     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3659     # check-ints-equal(EAX, 0x34a, msg)
+3660     # . . push args
+3661     68/push  "F - test-next-hex-int-multi-digit"/imm32
+3662     68/push  0x34a/imm32
+3663     50/push-EAX
+3664     # . . call
+3665     e8/call  check-ints-equal/disp32
+3666     # . . discard args
+3667     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3668     # . epilog
+3669     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3670     5d/pop-to-EBP
+3671     c3/return
+3672 
+3673 test-next-hex-int-0x-prefix:
+3674     # . prolog
+3675     55/push-EBP
+3676     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3677     # (EAX..ECX) = "+0x34)"
+3678     b8/copy-to-EAX  "+0x34)"/imm32
+3679     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3680     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3681     05/add-to-EAX  4/imm32
+3682     # var slice/ECX = {EAX, ECX}
+3683     51/push-ECX
+3684     50/push-EAX
+3685     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3686     # EAX = next-hex-int(slice)
+3687     # . . push args
+3688     51/push-ECX
+3689     # . . call
+3690     e8/call  next-hex-int/disp32
+3691     # . . discard args
+3692     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3693     # check-ints-equal(EAX, 0x34, msg)
+3694     # . . push args
+3695     68/push  "F - test-next-hex-int-0x-prefix"/imm32
+3696     68/push  0x34/imm32
+3697     50/push-EAX
+3698     # . . call
+3699     e8/call  check-ints-equal/disp32
+3700     # . . discard args
+3701     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3702     # . epilog
+3703     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3704     5d/pop-to-EBP
+3705     c3/return
+3706 
+3707 test-next-hex-int-zero:
+3708     # . prolog
+3709     55/push-EBP
+3710     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3711     # (EAX..ECX) = "+0)"
+3712     b8/copy-to-EAX  "+0)"/imm32
+3713     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3714     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3715     05/add-to-EAX  4/imm32
+3716     # var slice/ECX = {EAX, ECX}
+3717     51/push-ECX
+3718     50/push-EAX
+3719     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3720     # EAX = next-hex-int(slice)
+3721     # . . push args
+3722     51/push-ECX
+3723     # . . call
+3724     e8/call  next-hex-int/disp32
+3725     # . . discard args
+3726     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3727     # check-ints-equal(EAX, 0, msg)
+3728     # . . push args
+3729     68/push  "F - test-next-hex-int-zero"/imm32
+3730     68/push  0/imm32
+3731     50/push-EAX
+3732     # . . call
+3733     e8/call  check-ints-equal/disp32
+3734     # . . discard args
+3735     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3736     # . epilog
+3737     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3738     5d/pop-to-EBP
+3739     c3/return
+3740 
+3741 test-next-hex-int-0-prefix:
+3742     # . prolog
+3743     55/push-EBP
+3744     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3745     # (EAX..ECX) = "+ 03)"
+3746     b8/copy-to-EAX  "+ 03)"/imm32
+3747     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3748     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3749     05/add-to-EAX  4/imm32
+3750     # var slice/ECX = {EAX, ECX}
+3751     51/push-ECX
+3752     50/push-EAX
+3753     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3754     # EAX = next-hex-int(slice)
+3755     # . . push args
+3756     51/push-ECX
+3757     # . . call
+3758     e8/call  next-hex-int/disp32
+3759     # . . discard args
+3760     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3761     # check-ints-equal(EAX, 3, msg)
+3762     # . . push args
+3763     68/push  "F - test-next-hex-int-0-prefix"/imm32
+3764     68/push  3/imm32
+3765     50/push-EAX
+3766     # . . call
+3767     e8/call  check-ints-equal/disp32
+3768     # . . discard args
+3769     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3770     # . epilog
+3771     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3772     5d/pop-to-EBP
+3773     c3/return
+3774 
+3775 test-next-hex-int-negative:
+3776     # . prolog
+3777     55/push-EBP
+3778     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3779     # (EAX..ECX) = "-03)"
+3780     b8/copy-to-EAX  "-03)"/imm32
+3781     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3782     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3783     05/add-to-EAX  4/imm32
+3784     # var slice/ECX = {EAX, ECX}
+3785     51/push-ECX
+3786     50/push-EAX
+3787     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3788     # EAX = next-hex-int(slice)
+3789     # . . push args
+3790     51/push-ECX
+3791     # . . call
+3792     e8/call  next-hex-int/disp32
+3793     # . . discard args
+3794     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3795     # check-ints-equal(EAX, -3, msg)
+3796     # . . push args
+3797     68/push  "F - test-next-hex-int-negative"/imm32
+3798     68/push  -3/imm32
+3799     50/push-EAX
+3800     # . . call
+3801     e8/call  check-ints-equal/disp32
+3802     # . . discard args
+3803     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3804     # . epilog
+3805     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3806     5d/pop-to-EBP
+3807     c3/return
+3808 
+3809 test-next-hex-int-negative-with-space:
+3810     # . prolog
+3811     55/push-EBP
+3812     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3813     # (EAX..ECX) = "- 03)"
+3814     b8/copy-to-EAX  "- 03)"/imm32
+3815     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3816     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3817     05/add-to-EAX  4/imm32
+3818     # var slice/ECX = {EAX, ECX}
+3819     51/push-ECX
+3820     50/push-EAX
+3821     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3822     # EAX = next-hex-int(slice)
+3823     # . . push args
+3824     51/push-ECX
+3825     # . . call
+3826     e8/call  next-hex-int/disp32
+3827     # . . discard args
+3828     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3829     # check-ints-equal(EAX, -3, msg)
+3830     # . . push args
+3831     68/push  "F - test-next-hex-int-negative-with-space"/imm32
+3832     68/push  -3/imm32
+3833     50/push-EAX
+3834     # . . call
+3835     e8/call  check-ints-equal/disp32
+3836     # . . discard args
+3837     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3838     # . epilog
+3839     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3840     5d/pop-to-EBP
+3841     c3/return
+3842 
+3843 # assumes 'in' starts a positive unsigned integer
+3844 # returns the value of the integer
+3845 # side-effect: modifies 'in' to skip past the integer
+3846 next-positive-hex-int:  # in : (address slice) -> result/EAX
+3847     # . prolog
+3848     55/push-EBP
+3849     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3850     # . save registers
+3851     51/push-ECX
+3852     52/push-EDX
+3853     53/push-EBX
+3854     56/push-ESI
+3855     57/push-EDI
+3856     # result/EDI = 0
+3857     31/xor                          3/mod/direct    7/rm32/EDI    .           .             .           7/r32/EDI   .               .                 # clear EDI
+3858     # ESI = in
+3859     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+3860     # EDX = in->end
+3861     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           2/r32/EDX   4/disp8         .                 # copy *(ESI+4) to EDX
+3862     # curr/ECX = in->start
+3863     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
+3864     # negate?/EBX = false
+3865     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+3866     # EAX = *curr
+3867     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3868     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3869 $next-positive-hex-int:initial-0:
+3870     # skip past leading '0x'
+3871     # . if (*curr != '0') jump to loop
+3872     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3873     3d/compare-EAX-and  0x30/imm32/0
+3874     75/jump-if-not-equal  $next-positive-hex-int:loop/disp8
+3875     # . ++curr
+3876     41/increment-ECX
+3877 $next-positive-hex-int:initial-0x:
+3878     # . if (curr >= in->end) return result
+3879     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3880     73/jump-if-greater-or-equal-unsigned  $next-positive-hex-int:end/disp8
+3881     # . if (*curr != 'x') jump to loop  # the previous '0' is still valid so doesn't need to be checked again
+3882     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3883     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3884     3d/compare-EAX-and  0x78/imm32/x
+3885     75/jump-if-not-equal  $next-positive-hex-int:loop/disp8
+3886     # . ++curr
+3887     41/increment-ECX
+3888 $next-positive-hex-int:loop:
+3889     # if (curr >= in->end) break
+3890     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3891     73/jump-if-greater-or-equal-unsigned  $next-positive-hex-int:end/disp8
+3892     # if (!is-hex-digit?(*curr)) break
+3893     # . EAX = *curr
+3894     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3895     # . EAX = is-hex-digit?(*curr)
+3896     # . . push args
+3897     50/push-EAX
+3898     # . . call
+3899     e8/call  is-hex-digit?/disp32
+3900     # . . discard args
+3901     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3902     # . if (EAX == 0) break
+3903     3d/compare-EAX-and  0/imm32
+3904     74/jump-if-equal  $next-positive-hex-int:end/disp8
+3905     # EAX = from-hex-char(*curr)
+3906     # . . copy arg to EAX
+3907     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3908     # . . call
+3909     e8/call  from-hex-char/disp32
+3910     # result = result * 16 + EAX
+3911     c1/shift    4/subop/left        3/mod/direct    7/rm32/EDI    .           .             .           .           .               4/imm8            # shift EDI left by 4 bits
+3912     01/add                          3/mod/direct    7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # add EAX to EDI
+3913     # ++curr
+3914     41/increment-ECX
+3915     # loop
+3916     eb/jump  $next-positive-hex-int:loop/disp8
+3917 $next-positive-hex-int:end:
+3918     # word->start = curr
+3919     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy ECX to *ESI
+3920     # return EDI
+3921     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy EDI to EAX
+3922     # . restore registers
+3923     5f/pop-to-EDI
+3924     5e/pop-to-ESI
+3925     5b/pop-to-EBX
+3926     5a/pop-to-EDX
+3927     59/pop-to-ECX
+3928     # . epilog
+3929     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3930     5d/pop-to-EBP
+3931     c3/return
+3932 
+3933 test-next-positive-hex-int-single-digit:
+3934     # . prolog
+3935     55/push-EBP
+3936     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3937     # (EAX..ECX) = "a)"
+3938     b8/copy-to-EAX  "a)"/imm32
+3939     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3940     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3941     05/add-to-EAX  4/imm32
+3942     # var slice/ECX = {EAX, ECX}
+3943     51/push-ECX
+3944     50/push-EAX
+3945     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3946     # EAX = next-positive-hex-int(slice)
+3947     # . . push args
+3948     51/push-ECX
+3949     # . . call
+3950     e8/call  next-positive-hex-int/disp32
+3951     # . . discard args
+3952     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3953     # check-ints-equal(EAX, 0xa, msg)
+3954     # . . push args
+3955     68/push  "F - test-next-positive-hex-int-single-digit"/imm32
+3956     68/push  0xa/imm32
+3957     50/push-EAX
+3958     # . . call
+3959     e8/call  check-ints-equal/disp32
+3960     # . . discard args
+3961     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3962     # . epilog
+3963     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3964     5d/pop-to-EBP
+3965     c3/return
+3966 
+3967 test-next-positive-hex-int-multi-digit:
+3968     # . prolog
+3969     55/push-EBP
+3970     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3971     # (EAX..ECX) = "34a)"
+3972     b8/copy-to-EAX  "34a)"/imm32
+3973     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3974     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3975     05/add-to-EAX  4/imm32
+3976     # var slice/ECX = {EAX, ECX}
+3977     51/push-ECX
+3978     50/push-EAX
+3979     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3980     # EAX = next-positive-hex-int(slice)
+3981     # . . push args
+3982     51/push-ECX
+3983     # . . call
+3984     e8/call  next-positive-hex-int/disp32
+3985     # . . discard args
+3986     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3987     # check-ints-equal(EAX, 0x34a, msg)
+3988     # . . push args
+3989     68/push  "F - test-next-positive-hex-int-multi-digit"/imm32
+3990     68/push  0x34a/imm32
+3991     50/push-EAX
+3992     # . . call
+3993     e8/call  check-ints-equal/disp32
+3994     # . . discard args
+3995     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3996     # . epilog
+3997     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3998     5d/pop-to-EBP
+3999     c3/return
+4000 
+4001 test-next-positive-hex-int-0x-prefix:
+4002     # . prolog
+4003     55/push-EBP
+4004     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+4005     # (EAX..ECX) = "0x34)"
+4006     b8/copy-to-EAX  "0x34)"/imm32
+4007     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+4008     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+4009     05/add-to-EAX  4/imm32
+4010     # var slice/ECX = {EAX, ECX}
+4011     51/push-ECX
+4012     50/push-EAX
+4013     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+4014     # EAX = next-positive-hex-int(slice)
+4015     # . . push args
+4016     51/push-ECX
+4017     # . . call
+4018     e8/call  next-positive-hex-int/disp32
+4019     # . . discard args
+4020     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+4021     # check-ints-equal(EAX, 0x34, msg)
+4022     # . . push args
+4023     68/push  "F - test-next-positive-hex-int-0x-prefix"/imm32
+4024     68/push  0x34/imm32
+4025     50/push-EAX
+4026     # . . call
+4027     e8/call  check-ints-equal/disp32
+4028     # . . discard args
+4029     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+4030     # . epilog
+4031     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+4032     5d/pop-to-EBP
+4033     c3/return
+4034 
+4035 test-next-positive-hex-int-zero:
+4036     # . prolog
+4037     55/push-EBP
+4038     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+4039     # (EAX..ECX) = "0"
+4040     b8/copy-to-EAX  "0"/imm32
+4041     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+4042     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+4043     05/add-to-EAX  4/imm32
+4044     # var slice/ECX = {EAX, ECX}
+4045     51/push-ECX
+4046     50/push-EAX
+4047     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+4048     # EAX = next-positive-hex-int(slice)
+4049     # . . push args
+4050     51/push-ECX
+4051     # . . call
+4052     e8/call  next-positive-hex-int/disp32
+4053     # . . discard args
+4054     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+4055     # check-ints-equal(EAX, 0, msg)
+4056     # . . push args
+4057     68/push  "F - test-next-positive-hex-int-zero"/imm32
+4058     68/push  0/imm32
+4059     50/push-EAX
+4060     # . . call
+4061     e8/call  check-ints-equal/disp32
+4062     # . . discard args
+4063     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+4064     # . epilog
+4065     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+4066     5d/pop-to-EBP
+4067     c3/return
+4068 
+4069 test-next-positive-hex-int-0-prefix:
+4070     # . prolog
+4071     55/push-EBP
+4072     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+4073     # (EAX..ECX) = "03)"
+4074     b8/copy-to-EAX  "03)"/imm32
+4075     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+4076     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+4077     05/add-to-EAX  4/imm32
+4078     # var slice/ECX = {EAX, ECX}
+4079     51/push-ECX
+4080     50/push-EAX
+4081     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+4082     # EAX = next-positive-hex-int(slice)
+4083     # . . push args
+4084     51/push-ECX
+4085     # . . call
+4086     e8/call  next-positive-hex-int/disp32
+4087     # . . discard args
+4088     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+4089     # check-ints-equal(EAX, 3, msg)
+4090     # . . push args
+4091     68/push  "F - test-next-positive-hex-int-0-prefix"/imm32
+4092     68/push  3/imm32
+4093     50/push-EAX
+4094     # . . call
+4095     e8/call  check-ints-equal/disp32
+4096     # . . discard args
+4097     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+4098     # . epilog
+4099     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+4100     5d/pop-to-EBP
+4101     c3/return
+4102 
+4103 == data
+4104 Registers:  # (table string int)
+4105   # a table is a stream
+4106   0x40/imm32/write
+4107   0/imm32/read
+4108   0x40/imm32/length
+4109   # data
+4110   "eax"/imm32  0/imm32
+4111   "ecx"/imm32  1/imm32
+4112   "edx"/imm32  2/imm32
+4113   "ebx"/imm32  3/imm32
+4114   "esp"/imm32  4/imm32
+4115   "ebp"/imm32  5/imm32
+4116   "esi"/imm32  6/imm32
+4117   "edi"/imm32  7/imm32
+4118 
+4119 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/dquotes.subx.html b/html/apps/dquotes.subx.html index 417b324b..ecffb4d6 100644 --- a/html/apps/dquotes.subx.html +++ b/html/apps/dquotes.subx.html @@ -14,18 +14,18 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.Folded { color: #080808; background-color: #949494; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } -.subxFunction { color: #af5f00; text-decoration: underline; } +.Folded { color: #080808; background-color: #949494; } .Constant { color: #008787; } .subxMinorFunction { color: #875f5f; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -233,7 +233,7 @@ if ('onhashchange' in window) { 170 52/push-EDX 171 51/push-ECX 172 # . . call - 173 e8/call next-word-or-string/disp32 + 173 e8/call next-word-or-string/disp32 174 # . . discard args 175 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 176 $convert:check1: @@ -259,2358 +259,2359 @@ if ('onhashchange' in window) { 196 3d/compare-EAX-and 0x23/imm32/hash 197 74/jump-if-equal $convert:word-loop/disp8 198 $convert:check-for-string-literal: - 199 3d/compare-EAX-and 0x22/imm32/dquote - 200 75/jump-if-not-equal $convert:regular-word/disp8 - 201 $convert:string-literal: - 202 # process-string-literal(word-slice, out, new-data-segment) - 203 # . . push args - 204 57/push-EDI - 205 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 206 52/push-EDX - 207 # . . call - 208 e8/call process-string-literal/disp32 - 209 # . . discard args - 210 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 211 # continue - 212 eb/jump $convert:next-word/disp8 - 213 $convert:regular-word: - 214 # write-slice-buffered(out, word-slice) - 215 # . . push args - 216 52/push-EDX - 217 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 218 # . . call - 219 e8/call write-slice-buffered/disp32 - 220 # . . discard args - 221 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 222 # fall through - 223 $convert:next-word: - 224 # write-buffered(out, " ") - 225 # . . push args - 226 68/push " "/imm32 - 227 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 228 # . . call - 229 e8/call write-buffered/disp32 - 230 # . . discard args - 231 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 232 # loop - 233 eb/jump $convert:word-loop/disp8 - 234 $convert:next-line: - 235 # write-buffered(out, "\n") - 236 # . . push args - 237 68/push Newline/imm32 - 238 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 239 # . . call - 240 e8/call write-buffered/disp32 - 241 # . . discard args - 242 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 243 # loop - 244 e9/jump $convert:line-loop/disp32 - 245 $convert:break: - 246 # write-stream-data(out, new-data-segment) - 247 # . . push args - 248 57/push-EDI - 249 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 250 # . . call - 251 e8/call write-stream-data/disp32 - 252 # . . discard args - 253 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 254 # flush(out) - 255 # . . push args - 256 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 257 # . . call - 258 e8/call flush/disp32 - 259 # . . discard args - 260 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 261 $convert:end: - 262 # . reclaim locals - 263 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP - 264 # . restore registers - 265 5f/pop-to-EDI - 266 5e/pop-to-ESI - 267 5b/pop-to-EBX - 268 5a/pop-to-EDX - 269 59/pop-to-ECX - 270 58/pop-to-EAX - 271 # . epilog - 272 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 273 5d/pop-to-EBP - 274 c3/return - 275 - 276 # Write out 'string-literal' in a new format to 'out-segment', assign it a new - 277 # label, and write the new label out to 'out'. - 278 process-string-literal: # string-literal : (address slice), out : (address buffered-file), out-segment : (address stream) - 279 # pseudocode: - 280 # print(out-segment, "_string#{Next-string-literal}:\n") - 281 # emit-string-literal-data(out-segment, string-literal) - 282 # print(out, "_string#{Next-string-literal}") - 283 # emit-metadata(out, string-literal) - 284 # ++ *Next-string-literal - 285 # - 286 # . prolog - 287 55/push-EBP - 288 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 289 # . save registers - 290 51/push-ECX - 291 # var int32-stream/ECX = stream(10) # number of decimal digits a 32-bit number can have - 292 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa/imm32 # subtract from ESP - 293 68/push 0xa/imm32/decimal-digits-in-32bit-number - 294 68/push 0/imm32/read - 295 68/push 0/imm32/write - 296 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 297 # print(out-segment, "_string#{Next-string-literal}:\n") - 298 # . write(out-segment, "_string") - 299 # . . push args - 300 68/push "_string"/imm32 - 301 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 302 # . . call - 303 e8/call write/disp32 - 304 # . . discard args - 305 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 306 # . print-int32-decimal(out-segment, *Next-string-literal) - 307 # . . push args - 308 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal - 309 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 310 # . . call - 311 e8/call print-int32-decimal/disp32 - 312 # . . discard args - 313 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 314 # . write(out-segment, ":\n") - 315 # . . push args - 316 68/push ":\n"/imm32 - 317 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 318 # . . call - 319 e8/call write/disp32 - 320 # . . discard args - 321 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 322 # emit-string-literal-data(out-segment, string-literal) - 323 # . . push args - 324 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x8/disp8 . # push *(EBP+8) - 325 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 326 # . . call - 327 e8/call emit-string-literal-data/disp32 - 328 # . . discard args - 329 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 330 # write(out-segment, "\n") - 331 # . . push args - 332 68/push Newline/imm32 - 333 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 334 # . . call - 335 e8/call write/disp32 - 336 # . . discard args - 337 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 338 # print(out, "_string#{Next-string-literal}") - 339 # . write-buffered(out, "_string") - 340 # . . push args - 341 68/push "_string"/imm32 - 342 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 343 # . . call - 344 e8/call write-buffered/disp32 - 345 # . . discard args - 346 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 347 # . print-int32-decimal(int32-stream, *Next-string-literal) - 348 # . . push args - 349 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal - 350 51/push-ECX - 351 # . . call - 352 e8/call print-int32-decimal/disp32 - 353 # . . discard args - 354 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 355 # . write-stream-data(out, int32-stream) - 356 # . . push args - 357 51/push-ECX - 358 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 359 # . . call - 360 e8/call write-stream-data/disp32 - 361 # . . discard args - 362 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 363 # emit-metadata(out, string-literal) - 364 # . . push args - 365 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 366 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 367 # . . call - 368 e8/call emit-metadata/disp32 - 369 # . . discard args - 370 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 371 # ++ *Next-string-literal - 372 ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # increment *Num-test-failures - 373 $process-string-literal:end: - 374 # . reclaim locals - 375 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x16/imm32 # add to ESP - 376 # . restore registers - 377 59/pop-to-ECX - 378 # . epilog - 379 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 380 5d/pop-to-EBP - 381 c3/return - 382 - 383 test-convert-is-idempotent-by-default: - 384 # . prolog - 385 55/push-EBP - 386 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 387 # setup - 388 # . clear-stream(_test-input-stream) - 389 # . . push args - 390 68/push _test-input-stream/imm32 - 391 # . . call - 392 e8/call clear-stream/disp32 - 393 # . . discard args - 394 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 395 # . clear-stream(_test-input-buffered-file+4) - 396 # . . push args - 397 b8/copy-to-EAX _test-input-buffered-file/imm32 - 398 05/add-to-EAX 4/imm32 - 399 50/push-EAX - 400 # . . call - 401 e8/call clear-stream/disp32 - 402 # . . discard args - 403 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 404 # . clear-stream(_test-output-stream) - 405 # . . push args - 406 68/push _test-output-stream/imm32 - 407 # . . call - 408 e8/call clear-stream/disp32 - 409 # . . discard args - 410 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 411 # . clear-stream(_test-output-buffered-file+4) - 412 # . . push args - 413 b8/copy-to-EAX _test-output-buffered-file/imm32 - 414 05/add-to-EAX 4/imm32 - 415 50/push-EAX - 416 # . . call - 417 e8/call clear-stream/disp32 - 418 # . . discard args - 419 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 420 # initialize input (meta comments in parens) - 421 # # comment 1 - 422 # # comment 2 indented - 423 # == code 0x1 (new segment) - 424 # # comment 3 inside a segment - 425 # 1 - 426 # (empty line) - 427 # 2 3 # comment 4 inline with other contents - 428 # == data 0x2 (new segment) - 429 # 4 5/imm32 - 430 # . write(_test-input-stream, "# comment 1\n") - 431 # . . push args - 432 68/push "# comment 1\n"/imm32 - 433 68/push _test-input-stream/imm32 - 434 # . . call - 435 e8/call write/disp32 - 436 # . . discard args - 437 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 438 # . write(_test-input-stream, " # comment 2 indented\n") - 439 # . . push args - 440 68/push " # comment 2 indented\n"/imm32 - 441 68/push _test-input-stream/imm32 - 442 # . . call - 443 e8/call write/disp32 - 444 # . . discard args - 445 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 446 # . write(_test-input-stream, "== code 0x1\n") - 447 # . . push args - 448 68/push "== code 0x1\n"/imm32 - 449 68/push _test-input-stream/imm32 - 450 # . . call - 451 e8/call write/disp32 - 452 # . . discard args - 453 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 454 # . write(_test-input-stream, "# comment 3 inside a segment\n") - 455 # . . push args - 456 68/push "# comment 3 inside a segment\n"/imm32 - 457 68/push _test-input-stream/imm32 - 458 # . . call - 459 e8/call write/disp32 - 460 # . . discard args - 461 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 462 # . write(_test-input-stream, "1\n") - 463 # . . push args - 464 68/push "1\n"/imm32 - 465 68/push _test-input-stream/imm32 - 466 # . . call - 467 e8/call write/disp32 - 468 # . . discard args - 469 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 470 # . write(_test-input-stream, "\n") # empty line - 471 # . . push args - 472 68/push "\n"/imm32 - 473 68/push _test-input-stream/imm32 - 474 # . . call - 475 e8/call write/disp32 - 476 # . . discard args - 477 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 478 # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") - 479 # . . push args - 480 68/push "2 3 # comment 4 inline with other contents\n"/imm32 - 481 68/push _test-input-stream/imm32 - 482 # . . call - 483 e8/call write/disp32 - 484 # . . discard args - 485 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 486 # . write(_test-input-stream, "== data 0x2\n") - 487 # . . push args - 488 68/push "== data 0x2\n"/imm32 - 489 68/push _test-input-stream/imm32 - 490 # . . call - 491 e8/call write/disp32 - 492 # . . discard args - 493 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 494 # . write(_test-input-stream, "4 5/imm32\n") - 495 # . . push args - 496 68/push "4 5/imm32\n"/imm32 - 497 68/push _test-input-stream/imm32 - 498 # . . call - 499 e8/call write/disp32 - 500 # . . discard args - 501 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 502 # convert(_test-input-buffered-file, _test-output-buffered-file) - 503 # . . push args - 504 68/push _test-output-buffered-file/imm32 - 505 68/push _test-input-buffered-file/imm32 - 506 # . . call - 507 e8/call convert/disp32 - 508 # . . discard args - 509 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 510 # . flush(_test-output-buffered-file) - 511 # . . push args - 512 68/push _test-output-buffered-file/imm32 - 513 # . . call - 514 e8/call flush/disp32 - 515 # . . discard args - 516 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 517 # check output - 518 # (comment dropped for now) + 199 # if (slice-starts-with?(word-slice, '"')) continue + 200 3d/compare-EAX-and 0x22/imm32/dquote + 201 75/jump-if-not-equal $convert:regular-word/disp8 + 202 $convert:string-literal: + 203 # process-string-literal(word-slice, out, new-data-segment) + 204 # . . push args + 205 57/push-EDI + 206 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 207 52/push-EDX + 208 # . . call + 209 e8/call process-string-literal/disp32 + 210 # . . discard args + 211 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 212 # continue + 213 eb/jump $convert:next-word/disp8 + 214 $convert:regular-word: + 215 # write-slice-buffered(out, word-slice) + 216 # . . push args + 217 52/push-EDX + 218 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 219 # . . call + 220 e8/call write-slice-buffered/disp32 + 221 # . . discard args + 222 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 223 # fall through + 224 $convert:next-word: + 225 # write-buffered(out, " ") + 226 # . . push args + 227 68/push " "/imm32 + 228 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 229 # . . call + 230 e8/call write-buffered/disp32 + 231 # . . discard args + 232 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 233 # loop + 234 eb/jump $convert:word-loop/disp8 + 235 $convert:next-line: + 236 # write-buffered(out, "\n") + 237 # . . push args + 238 68/push Newline/imm32 + 239 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 240 # . . call + 241 e8/call write-buffered/disp32 + 242 # . . discard args + 243 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 244 # loop + 245 e9/jump $convert:line-loop/disp32 + 246 $convert:break: + 247 # write-stream-data(out, new-data-segment) + 248 # . . push args + 249 57/push-EDI + 250 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 251 # . . call + 252 e8/call write-stream-data/disp32 + 253 # . . discard args + 254 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 255 # flush(out) + 256 # . . push args + 257 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 258 # . . call + 259 e8/call flush/disp32 + 260 # . . discard args + 261 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 262 $convert:end: + 263 # . reclaim locals + 264 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP + 265 # . restore registers + 266 5f/pop-to-EDI + 267 5e/pop-to-ESI + 268 5b/pop-to-EBX + 269 5a/pop-to-EDX + 270 59/pop-to-ECX + 271 58/pop-to-EAX + 272 # . epilog + 273 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 274 5d/pop-to-EBP + 275 c3/return + 276 + 277 # Write out 'string-literal' in a new format to 'out-segment', assign it a new + 278 # label, and write the new label out to 'out'. + 279 process-string-literal: # string-literal : (address slice), out : (address buffered-file), out-segment : (address stream) + 280 # pseudocode: + 281 # print(out-segment, "_string#{Next-string-literal}:\n") + 282 # emit-string-literal-data(out-segment, string-literal) + 283 # print(out, "_string#{Next-string-literal}") + 284 # emit-metadata(out, string-literal) + 285 # ++ *Next-string-literal + 286 # + 287 # . prolog + 288 55/push-EBP + 289 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 290 # . save registers + 291 51/push-ECX + 292 # var int32-stream/ECX = stream(10) # number of decimal digits a 32-bit number can have + 293 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa/imm32 # subtract from ESP + 294 68/push 0xa/imm32/decimal-digits-in-32bit-number + 295 68/push 0/imm32/read + 296 68/push 0/imm32/write + 297 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 298 # print(out-segment, "_string#{Next-string-literal}:\n") + 299 # . write(out-segment, "_string") + 300 # . . push args + 301 68/push "_string"/imm32 + 302 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + 303 # . . call + 304 e8/call write/disp32 + 305 # . . discard args + 306 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 307 # . print-int32-decimal(out-segment, *Next-string-literal) + 308 # . . push args + 309 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal + 310 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + 311 # . . call + 312 e8/call print-int32-decimal/disp32 + 313 # . . discard args + 314 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 315 # . write(out-segment, ":\n") + 316 # . . push args + 317 68/push ":\n"/imm32 + 318 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + 319 # . . call + 320 e8/call write/disp32 + 321 # . . discard args + 322 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 323 # emit-string-literal-data(out-segment, string-literal) + 324 # . . push args + 325 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x8/disp8 . # push *(EBP+8) + 326 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + 327 # . . call + 328 e8/call emit-string-literal-data/disp32 + 329 # . . discard args + 330 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 331 # write(out-segment, "\n") + 332 # . . push args + 333 68/push Newline/imm32 + 334 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + 335 # . . call + 336 e8/call write/disp32 + 337 # . . discard args + 338 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 339 # print(out, "_string#{Next-string-literal}") + 340 # . write-buffered(out, "_string") + 341 # . . push args + 342 68/push "_string"/imm32 + 343 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 344 # . . call + 345 e8/call write-buffered/disp32 + 346 # . . discard args + 347 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 348 # . print-int32-decimal(int32-stream, *Next-string-literal) + 349 # . . push args + 350 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal + 351 51/push-ECX + 352 # . . call + 353 e8/call print-int32-decimal/disp32 + 354 # . . discard args + 355 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 356 # . write-stream-data(out, int32-stream) + 357 # . . push args + 358 51/push-ECX + 359 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 360 # . . call + 361 e8/call write-stream-data/disp32 + 362 # . . discard args + 363 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 364 # emit-metadata(out, string-literal) + 365 # . . push args + 366 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 367 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 368 # . . call + 369 e8/call emit-metadata/disp32 + 370 # . . discard args + 371 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 372 # ++ *Next-string-literal + 373 ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # increment *Num-test-failures + 374 $process-string-literal:end: + 375 # . reclaim locals + 376 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x16/imm32 # add to ESP + 377 # . restore registers + 378 59/pop-to-ECX + 379 # . epilog + 380 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 381 5d/pop-to-EBP + 382 c3/return + 383 + 384 test-convert-is-idempotent-by-default: + 385 # . prolog + 386 55/push-EBP + 387 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 388 # setup + 389 # . clear-stream(_test-input-stream) + 390 # . . push args + 391 68/push _test-input-stream/imm32 + 392 # . . call + 393 e8/call clear-stream/disp32 + 394 # . . discard args + 395 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 396 # . clear-stream(_test-input-buffered-file+4) + 397 # . . push args + 398 b8/copy-to-EAX _test-input-buffered-file/imm32 + 399 05/add-to-EAX 4/imm32 + 400 50/push-EAX + 401 # . . call + 402 e8/call clear-stream/disp32 + 403 # . . discard args + 404 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 405 # . clear-stream(_test-output-stream) + 406 # . . push args + 407 68/push _test-output-stream/imm32 + 408 # . . call + 409 e8/call clear-stream/disp32 + 410 # . . discard args + 411 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 412 # . clear-stream(_test-output-buffered-file+4) + 413 # . . push args + 414 b8/copy-to-EAX _test-output-buffered-file/imm32 + 415 05/add-to-EAX 4/imm32 + 416 50/push-EAX + 417 # . . call + 418 e8/call clear-stream/disp32 + 419 # . . discard args + 420 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 421 # initialize input (meta comments in parens) + 422 # # comment 1 + 423 # # comment 2 indented + 424 # == code 0x1 (new segment) + 425 # # comment 3 inside a segment + 426 # 1 + 427 # (empty line) + 428 # 2 3 # comment 4 inline with other contents + 429 # == data 0x2 (new segment) + 430 # 4 5/imm32 + 431 # . write(_test-input-stream, "# comment 1\n") + 432 # . . push args + 433 68/push "# comment 1\n"/imm32 + 434 68/push _test-input-stream/imm32 + 435 # . . call + 436 e8/call write/disp32 + 437 # . . discard args + 438 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 439 # . write(_test-input-stream, " # comment 2 indented\n") + 440 # . . push args + 441 68/push " # comment 2 indented\n"/imm32 + 442 68/push _test-input-stream/imm32 + 443 # . . call + 444 e8/call write/disp32 + 445 # . . discard args + 446 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 447 # . write(_test-input-stream, "== code 0x1\n") + 448 # . . push args + 449 68/push "== code 0x1\n"/imm32 + 450 68/push _test-input-stream/imm32 + 451 # . . call + 452 e8/call write/disp32 + 453 # . . discard args + 454 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 455 # . write(_test-input-stream, "# comment 3 inside a segment\n") + 456 # . . push args + 457 68/push "# comment 3 inside a segment\n"/imm32 + 458 68/push _test-input-stream/imm32 + 459 # . . call + 460 e8/call write/disp32 + 461 # . . discard args + 462 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 463 # . write(_test-input-stream, "1\n") + 464 # . . push args + 465 68/push "1\n"/imm32 + 466 68/push _test-input-stream/imm32 + 467 # . . call + 468 e8/call write/disp32 + 469 # . . discard args + 470 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 471 # . write(_test-input-stream, "\n") # empty line + 472 # . . push args + 473 68/push "\n"/imm32 + 474 68/push _test-input-stream/imm32 + 475 # . . call + 476 e8/call write/disp32 + 477 # . . discard args + 478 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 479 # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") + 480 # . . push args + 481 68/push "2 3 # comment 4 inline with other contents\n"/imm32 + 482 68/push _test-input-stream/imm32 + 483 # . . call + 484 e8/call write/disp32 + 485 # . . discard args + 486 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 487 # . write(_test-input-stream, "== data 0x2\n") + 488 # . . push args + 489 68/push "== data 0x2\n"/imm32 + 490 68/push _test-input-stream/imm32 + 491 # . . call + 492 e8/call write/disp32 + 493 # . . discard args + 494 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 495 # . write(_test-input-stream, "4 5/imm32\n") + 496 # . . push args + 497 68/push "4 5/imm32\n"/imm32 + 498 68/push _test-input-stream/imm32 + 499 # . . call + 500 e8/call write/disp32 + 501 # . . discard args + 502 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 503 # convert(_test-input-buffered-file, _test-output-buffered-file) + 504 # . . push args + 505 68/push _test-output-buffered-file/imm32 + 506 68/push _test-input-buffered-file/imm32 + 507 # . . call + 508 e8/call convert/disp32 + 509 # . . discard args + 510 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 511 # . flush(_test-output-buffered-file) + 512 # . . push args + 513 68/push _test-output-buffered-file/imm32 + 514 # . . call + 515 e8/call flush/disp32 + 516 # . . discard args + 517 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 518 # check output 519 # (comment dropped for now) - 520 # == code 0x1 - 521 # (comment dropped for now) - 522 # 1 - 523 # (comment dropped for now) - 524 # 2 3 - 525 # == data 0x2 - 526 # 4 5/imm32 - 527 # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. - 528 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- - 554 # . check-next-stream-line-equal(_test-output-stream, "", msg) - 555 # . . push args - 556 68/push "F - test-convert-is-idempotent-by-default/0"/imm32 - 557 68/push ""/imm32 - 558 68/push _test-output-stream/imm32 - 559 # . . call - 560 e8/call check-next-stream-line-equal/disp32 - 561 # . . discard args - 562 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 563 # . check-next-stream-line-equal(_test-output-stream, "", msg) - 564 # . . push args - 565 68/push "F - test-convert-is-idempotent-by-default/1"/imm32 - 566 68/push ""/imm32 - 567 68/push _test-output-stream/imm32 - 568 # . . call - 569 e8/call check-next-stream-line-equal/disp32 - 570 # . . discard args - 571 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 572 # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) - 573 # . . push args - 574 68/push "F - test-convert-is-idempotent-by-default/2"/imm32 - 575 68/push "== code 0x1 "/imm32 - 576 68/push _test-output-stream/imm32 - 577 # . . call - 578 e8/call check-next-stream-line-equal/disp32 - 579 # . . discard args - 580 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 581 # . check-next-stream-line-equal(_test-output-stream, "", msg) - 582 # . . push args - 583 68/push "F - test-convert-is-idempotent-by-default/3"/imm32 - 584 68/push ""/imm32 - 585 68/push _test-output-stream/imm32 - 586 # . . call - 587 e8/call check-next-stream-line-equal/disp32 - 588 # . . discard args - 589 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 590 # . check-next-stream-line-equal(_test-output-stream, "1 ", msg) - 591 # . . push args - 592 68/push "F - test-convert-is-idempotent-by-default/4"/imm32 - 593 68/push "1 "/imm32 - 594 68/push _test-output-stream/imm32 - 595 # . . call - 596 e8/call check-next-stream-line-equal/disp32 - 597 # . . discard args - 598 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 599 # . check-next-stream-line-equal(_test-output-stream, "", msg) - 600 # . . push args - 601 68/push "F - test-convert-is-idempotent-by-default/5"/imm32 - 602 68/push ""/imm32 - 603 68/push _test-output-stream/imm32 - 604 # . . call - 605 e8/call check-next-stream-line-equal/disp32 - 606 # . . discard args - 607 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 608 # . check-next-stream-line-equal(_test-output-stream, "2 3 ", msg) - 609 # . . push args - 610 68/push "F - test-convert-is-idempotent-by-default/6"/imm32 - 611 68/push "2 3 "/imm32 - 612 68/push _test-output-stream/imm32 - 613 # . . call - 614 e8/call check-next-stream-line-equal/disp32 - 615 # . . discard args - 616 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 617 # . check-next-stream-line-equal(_test-output-stream, "== data 0x2 ", msg) - 618 # . . push args - 619 68/push "F - test-convert-is-idempotent-by-default/7"/imm32 - 620 68/push "== data 0x2 "/imm32 - 621 68/push _test-output-stream/imm32 - 622 # . . call - 623 e8/call check-next-stream-line-equal/disp32 - 624 # . . discard args - 625 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 626 # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32 ", msg) - 627 # . . push args - 628 68/push "F - test-convert-is-idempotent-by-default/8"/imm32 - 629 68/push "4 5/imm32 "/imm32 - 630 68/push _test-output-stream/imm32 - 631 # . . call - 632 e8/call check-next-stream-line-equal/disp32 - 633 # . . discard args - 634 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 635 # . epilog - 636 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 637 5d/pop-to-EBP - 638 c3/return - 639 - 640 test-convert-processes-string-literals: - 641 # . prolog - 642 55/push-EBP - 643 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 644 # setup - 645 # . clear-stream(_test-input-stream) - 646 # . . push args - 647 68/push _test-input-stream/imm32 - 648 # . . call - 649 e8/call clear-stream/disp32 - 650 # . . discard args - 651 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 652 # . clear-stream(_test-input-buffered-file+4) - 653 # . . push args - 654 b8/copy-to-EAX _test-input-buffered-file/imm32 - 655 05/add-to-EAX 4/imm32 - 656 50/push-EAX - 657 # . . call - 658 e8/call clear-stream/disp32 - 659 # . . discard args - 660 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 661 # . clear-stream(_test-output-stream) - 662 # . . push args - 663 68/push _test-output-stream/imm32 - 664 # . . call - 665 e8/call clear-stream/disp32 - 666 # . . discard args - 667 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 668 # . clear-stream(_test-output-buffered-file+4) - 669 # . . push args - 670 b8/copy-to-EAX _test-output-buffered-file/imm32 - 671 05/add-to-EAX 4/imm32 - 672 50/push-EAX - 673 # . . call - 674 e8/call clear-stream/disp32 - 675 # . . discard args - 676 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 677 # initialize input (meta comments in parens) - 678 # == code (new segment) - 679 # 1 "a"/x - 680 # 2 "bc"/y - 681 68/push "== code 0x1\n"/imm32 - 682 68/push _test-input-stream/imm32 - 683 # . . call - 684 e8/call write/disp32 - 685 # . . discard args - 686 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 687 # . write(_test-input-stream, "1 \"a\"/x\n") - 688 # . . push args - 689 68/push "1 \"a\"/x\n"/imm32 - 690 68/push _test-input-stream/imm32 - 691 # . . call - 692 e8/call write/disp32 - 693 # . . discard args - 694 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 695 # . write(_test-input-stream, "2 \"bc\"/y\n") - 696 # . . push args - 697 68/push "2 \"bc\"/y\n"/imm32 - 698 68/push _test-input-stream/imm32 - 699 # . . call - 700 e8/call write/disp32 - 701 # . . discard args - 702 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 703 # convert(_test-input-buffered-file, _test-output-buffered-file) - 704 # . . push args - 705 68/push _test-output-buffered-file/imm32 - 706 68/push _test-input-buffered-file/imm32 - 707 # . . call - 708 e8/call convert/disp32 - 709 # . . discard args - 710 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 711 # . flush(_test-output-buffered-file) - 712 # . . push args - 713 68/push _test-output-buffered-file/imm32 - 714 # . . call - 715 e8/call flush/disp32 - 716 # . . discard args - 717 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 718 # check output - 719 # == code 0x1 - 720 # 1 _string1/x - 721 # 2 _string2/y - 722 # == data - 723 # _string1: - 724 # 1/imm32 61/a - 725 # _string2: - 726 # 2/imm32 62/b 63/c - 727 # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. - 728 # - 729 # Open question: how to make this check more robust. - 730 # We don't actually care what the auto-generated string variables are - 731 # called. We just want to make sure instructions using string literals - 732 # switch to a string variable with the right value. - 733 # (Modifying string literals completely off the radar for now.) - 734 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- - 767 # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) - 768 # . . push args - 769 68/push "F - test-convert-processes-string-literals/0"/imm32 - 770 68/push "== code 0x1 "/imm32 - 771 68/push _test-output-stream/imm32 - 772 # . . call - 773 e8/call check-next-stream-line-equal/disp32 - 774 # . . discard args - 775 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 776 # . check-next-stream-line-equal(_test-output-stream, "1 _string1/x ", msg) - 777 # . . push args - 778 68/push "F - test-convert-processes-string-literals/1"/imm32 - 779 68/push "1 _string1/x "/imm32 - 780 68/push _test-output-stream/imm32 - 781 # . . call - 782 e8/call check-next-stream-line-equal/disp32 - 783 # . . discard args - 784 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 785 # . check-next-stream-line-equal(_test-output-stream, "2 _string2/y ", msg) - 786 # . . push args - 787 68/push "F - test-convert-processes-string-literals/2"/imm32 - 788 68/push "2 _string2/y "/imm32 - 789 68/push _test-output-stream/imm32 - 790 # . . call - 791 e8/call check-next-stream-line-equal/disp32 - 792 # . . discard args - 793 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 794 # . check-next-stream-line-equal(_test-output-stream, "== data", msg) - 795 # . . push args - 796 68/push "F - test-convert-processes-string-literals/3"/imm32 - 797 68/push "== data"/imm32 - 798 68/push _test-output-stream/imm32 - 799 # . . call - 800 e8/call check-next-stream-line-equal/disp32 - 801 # . . discard args - 802 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 803 # . check-next-stream-line-equal(_test-output-stream, "_string1: ", msg) - 804 # . . push args - 805 68/push "F - test-convert-processes-string-literals/4"/imm32 - 806 68/push "_string1:"/imm32 - 807 68/push _test-output-stream/imm32 - 808 # . . call - 809 e8/call check-next-stream-line-equal/disp32 - 810 # . . discard args - 811 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 812 # . check-next-stream-line-equal(_test-output-stream, "1/imm32 61/a ", msg) - 813 # . . push args - 814 68/push "F - test-convert-processes-string-literals/5"/imm32 - 815 68/push "0x00000001/imm32 61/a "/imm32 - 816 68/push _test-output-stream/imm32 - 817 # . . call - 818 e8/call check-next-stream-line-equal/disp32 - 819 # . . discard args - 820 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 821 # . check-next-stream-line-equal(_test-output-stream, "_string2: ", msg) - 822 # . . push args - 823 68/push "F - test-convert-processes-string-literals/6"/imm32 - 824 68/push "_string2:"/imm32 - 825 68/push _test-output-stream/imm32 - 826 # . . call - 827 e8/call check-next-stream-line-equal/disp32 - 828 # . . discard args - 829 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 830 # . check-next-stream-line-equal(_test-output-stream, "2/imm32 62/b 63/c ", msg) - 831 # . . push args - 832 68/push "F - test-convert-processes-string-literals/7"/imm32 - 833 68/push "0x00000002/imm32 62/b 63/c "/imm32 - 834 68/push _test-output-stream/imm32 - 835 # . . call - 836 e8/call check-next-stream-line-equal/disp32 - 837 # . . discard args - 838 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 839 # . epilog - 840 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 841 5d/pop-to-EBP - 842 c3/return - 843 - 844 # generate the data segment contents byte by byte for a given slice - 845 emit-string-literal-data: # out : (address stream), word : (address slice) - 846 # pseudocode - 847 # len = string-length-at-start-of-slice(word->start, word->end) - 848 # print(out, "#{len}/imm32 ") - 849 # curr = word->start - 850 # ++curr # skip '"' - 851 # while true - 852 # if (curr >= word->end) break - 853 # c = *curr - 854 # if (c == '"') break - 855 # if (c == '\') { - 856 # ++curr - 857 # c = *curr - 858 # if (c == 'n') - 859 # c = newline - 860 # } - 861 # append-byte-hex(out, c) - 862 # if c is alphanumeric: - 863 # write(out, "/") - 864 # append-byte(out, c) - 865 # write(out, " ") - 866 # ++curr - 867 # - 868 # . prolog - 869 55/push-EBP - 870 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 871 # . save registers - 872 50/push-EAX - 873 51/push-ECX - 874 52/push-EDX - 875 56/push-ESI - 876 # ESI = word - 877 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - 878 # curr/EDX = word->start - 879 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 880 # max/ESI = word->end - 881 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI - 882 $emit-string-literal-data:emit-length: - 883 # len/EAX = string-length-at-start-of-slice(word->start, word->end) - 884 # . . push args - 885 56/push-ESI - 886 52/push-EDX - 887 # . . call - 888 e8/call string-length-at-start-of-slice/disp32 - 889 # . . discard args - 890 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 891 # print(out, "#{len}/imm32 ") - 892 # . print-int32(out, len) - 893 # . . push args - 894 50/push-EAX - 895 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 896 # . . call - 897 e8/call print-int32/disp32 - 898 # . . discard args - 899 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 900 # . write(out, "/imm32 ") - 901 # . . push args - 902 68/push "/imm32 "/imm32 - 903 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 904 # . . call - 905 e8/call write/disp32 - 906 # . . discard args - 907 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 908 $emit-string-literal-data:loop-init: - 909 # ++curr # skip initial '"' - 910 42/increment-EDX - 911 # c/ECX = 0 - 912 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX - 913 $emit-string-literal-data:loop: - 914 # if (curr >= max) break - 915 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI - 916 0f 83/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp32 - 917 # CL = *curr - 918 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL - 919 # if (c == '"') break - 920 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x22/imm32/dquote # compare ECX - 921 74/jump-if-equal $emit-string-literal-data:end/disp8 - 922 # if (c != '\') goto emit - 923 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x5c/imm32/backslash # compare ECX - 924 75/jump-if-not-equal $emit-string-literal-data:emit/disp8 - 925 # ++curr - 926 42/increment-EDX - 927 # if (curr >= max) break - 928 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI - 929 73/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp8 - 930 # c = *curr - 931 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL - 932 # if (c == 'n') c = newline - 933 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x6e/imm32/n # compare ECX - 934 75/jump-if-not-equal $emit-string-literal-data:emit/disp8 - 935 b9/copy-to-ECX 0x0a/imm32/newline - 936 $emit-string-literal-data:emit: - 937 # append-byte-hex(out, CL) - 938 # . . push args - 939 51/push-ECX - 940 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 941 # . . call - 942 e8/call append-byte-hex/disp32 - 943 # . . discard args - 944 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 945 # if (is-alphanumeric?(*curr)) print(out, "/#{*curr}") - 946 # . EAX = is-alphanumeric?(CL) - 947 # . . push args - 948 51/push-ECX - 949 # . . call - 950 e8/call is-alphanumeric?/disp32 - 951 # . . discard args - 952 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 953 # . if (EAX == 0) goto char-done - 954 3d/compare-EAX-and 0/imm32 - 955 74/jump-if-equal $emit-string-literal-data:char-done/disp8 - 956 # . write(out, "/") - 957 # . . push args - 958 68/push Slash/imm32 - 959 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 960 # . . call - 961 e8/call write/disp32 - 962 # . . discard args - 963 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 964 # . append-byte(out, *curr) - 965 # . . push args - 966 51/push-ECX - 967 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 968 # . . call - 969 e8/call append-byte/disp32 - 970 # . . discard args - 971 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 972 $emit-string-literal-data:char-done: - 973 # write(out, " ") - 974 # . . push args - 975 68/push Space/imm32 - 976 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 977 # . . call - 978 e8/call write/disp32 - 979 # . . discard args - 980 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 981 # ++curr - 982 42/increment-EDX - 983 e9/jump $emit-string-literal-data:loop/disp32 - 984 $emit-string-literal-data:end: - 985 # . restore registers - 986 5e/pop-to-ESI - 987 5a/pop-to-EDX - 988 59/pop-to-ECX - 989 58/pop-to-EAX - 990 # . epilog - 991 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 992 5d/pop-to-EBP - 993 c3/return - 994 - 995 is-alphanumeric?: # c : int -> EAX : boolean - 996 # . prolog - 997 55/push-EBP - 998 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 999 # EAX = c -1000 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX -1001 # if (EAX < '0') return false -1002 3d/compare-EAX-with 0x30/imm32/0 -1003 7c/jump-if-lesser $is-alphanumeric?:false/disp8 -1004 # if (EAX <= '9') return true -1005 3d/compare-EAX-with 0x39/imm32/9 -1006 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 -1007 # if (EAX < 'A') return false -1008 3d/compare-EAX-with 0x41/imm32/A -1009 7c/jump-if-lesser $is-alphanumeric?:false/disp8 -1010 # if (EAX <= 'Z') return true -1011 3d/compare-EAX-with 0x5a/imm32/Z -1012 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 -1013 # if (EAX < 'a') return false -1014 3d/compare-EAX-with 0x61/imm32/a -1015 7c/jump-if-lesser $is-alphanumeric?:false/disp8 -1016 # if (EAX <= 'z') return true -1017 3d/compare-EAX-with 0x7a/imm32/z -1018 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 -1019 # return false -1020 $is-alphanumeric?:false: -1021 b8/copy-to-EAX 0/imm32/false -1022 eb/jump $is-alphanumeric?:end/disp8 -1023 $is-alphanumeric?:true: -1024 b8/copy-to-EAX 1/imm32/true -1025 $is-alphanumeric?:end: -1026 # . epilog -1027 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1028 5d/pop-to-EBP -1029 c3/return -1030 -1031 test-emit-string-literal-data: -1032 # . prolog -1033 55/push-EBP -1034 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1035 # setup -1036 # . clear-stream(_test-output-stream) -1037 # . . push args -1038 68/push _test-output-stream/imm32 -1039 # . . call -1040 e8/call clear-stream/disp32 -1041 # . . discard args -1042 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1043 # var slice/ECX = '"abc"/d' -1044 68/push _test-slice-abc-limit/imm32 -1045 68/push _test-slice-abc/imm32 -1046 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1047 # emit-string-literal-data(_test-output-stream, slice) -1048 # . . push args -1049 51/push-ECX -1050 68/push _test-output-stream/imm32 -1051 # . . call -1052 e8/call emit-string-literal-data/disp32 -1053 # . . discard args -1054 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1055 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -1081 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 62/b 63/c ", msg) -1082 # . . push args -1083 68/push "F - test-emit-string-literal-data"/imm32 -1084 68/push "0x00000003/imm32 61/a 62/b 63/c "/imm32 -1085 68/push _test-output-stream/imm32 -1086 # . . call -1087 e8/call check-stream-equal/disp32 -1088 # . . discard args -1089 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1090 # . epilog -1091 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1092 5d/pop-to-EBP -1093 c3/return -1094 -1095 test-emit-string-literal-data-empty: -1096 # . prolog -1097 55/push-EBP -1098 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1099 # setup -1100 # . clear-stream(_test-output-stream) -1101 # . . push args -1102 68/push _test-output-stream/imm32 -1103 # . . call -1104 e8/call clear-stream/disp32 -1105 # . . discard args -1106 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1107 # var slice/ECX = '""' -1108 68/push 0/imm32/end -1109 68/push 0/imm32/start -1110 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1111 # emit-string-literal-data(_test-output-stream, slice) -1112 # . . push args -1113 51/push-ECX -1114 68/push _test-output-stream/imm32 -1115 # . . call -1116 e8/call emit-string-literal-data/disp32 -1117 # . . discard args -1118 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1119 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -1145 # . check-stream-equal(_test-output-stream, "0/imm32 ", msg) -1146 # . . push args -1147 68/push "F - test-emit-string-literal-data-empty"/imm32 -1148 68/push "0x00000000/imm32 "/imm32 -1149 68/push _test-output-stream/imm32 -1150 # . . call -1151 e8/call check-stream-equal/disp32 -1152 # . . discard args -1153 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1154 # . epilog -1155 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1156 5d/pop-to-EBP -1157 c3/return -1158 -1159 # just to keep things simple -1160 test-emit-string-literal-data-no-metadata-for-non-alphanumerics: -1161 # . prolog -1162 55/push-EBP -1163 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1164 # setup -1165 # . clear-stream(_test-output-stream) -1166 # . . push args -1167 68/push _test-output-stream/imm32 -1168 # . . call -1169 e8/call clear-stream/disp32 -1170 # . . discard args -1171 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1172 # var slice/ECX = '"a b"' -1173 68/push _test-slice-a-space-b-limit/imm32 -1174 68/push _test-slice-a-space-b/imm32 -1175 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1176 # emit-string-literal-data(_test-output-stream, slice) -1177 # . . push args -1178 51/push-ECX -1179 68/push _test-output-stream/imm32 -1180 # . . call -1181 e8/call emit-string-literal-data/disp32 -1182 # . . discard args -1183 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1184 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -1210 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints -1211 # . . push args -1212 68/push "F - test-emit-string-literal-data-no-metadata-for-non-alphanumerics"/imm32 -1213 68/push "0x00000003/imm32 61/a 20 62/b "/imm32 -1214 68/push _test-output-stream/imm32 -1215 # . . call -1216 e8/call check-stream-equal/disp32 -1217 # . . discard args -1218 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1219 # . epilog -1220 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1221 5d/pop-to-EBP -1222 c3/return -1223 -1224 test-emit-string-literal-data-handles-escape-sequences: -1225 # . prolog -1226 55/push-EBP -1227 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1228 # setup -1229 # . clear-stream(_test-output-stream) -1230 # . . push args -1231 68/push _test-output-stream/imm32 -1232 # . . call -1233 e8/call clear-stream/disp32 -1234 # . . discard args -1235 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1236 # var slice/ECX = '"a\"b"' -1237 68/push _test-slice-a-dquote-b-limit/imm32 -1238 68/push _test-slice-a-dquote-b/imm32 -1239 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1240 # emit-string-literal-data(_test-output-stream, slice) -1241 # . . push args -1242 51/push-ECX -1243 68/push _test-output-stream/imm32 -1244 # . . call -1245 e8/call emit-string-literal-data/disp32 -1246 # . . discard args -1247 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1248 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -1274 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 22 62/b ", msg) -1275 # . . push args -1276 68/push "F - test-emit-string-literal-data-handles-escape-sequences"/imm32 -1277 68/push "0x00000003/imm32 61/a 22 62/b "/imm32 -1278 68/push _test-output-stream/imm32 -1279 # . . call -1280 e8/call check-stream-equal/disp32 -1281 # . . discard args -1282 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1283 # . epilog -1284 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1285 5d/pop-to-EBP -1286 c3/return -1287 -1288 test-emit-string-literal-data-handles-newline-escape: -1289 # . prolog -1290 55/push-EBP -1291 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1292 # setup -1293 # . clear-stream(_test-output-stream) -1294 # . . push args -1295 68/push _test-output-stream/imm32 -1296 # . . call -1297 e8/call clear-stream/disp32 -1298 # . . discard args -1299 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1300 # var slice/ECX = '"a\nb"' -1301 68/push _test-slice-a-newline-b-limit/imm32 -1302 68/push _test-slice-a-newline-b/imm32 -1303 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1304 # emit-string-literal-data(_test-output-stream, slice) -1305 # . . push args -1306 51/push-ECX -1307 68/push _test-output-stream/imm32 -1308 # . . call -1309 e8/call emit-string-literal-data/disp32 -1310 # . . discard args -1311 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1312 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -1338 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 0a 62/b ", msg) -1339 # . . push args -1340 68/push "F - test-emit-string-literal-data-handles-newline-escape"/imm32 -1341 68/push "0x00000003/imm32 61/a 0a 62/b "/imm32 -1342 68/push _test-output-stream/imm32 -1343 # . . call -1344 e8/call check-stream-equal/disp32 -1345 # . . discard args -1346 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1347 # . epilog -1348 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1349 5d/pop-to-EBP -1350 c3/return -1351 -1352 # emit everything from a word except the initial datum -1353 emit-metadata: # out : (address buffered-file), word : (address slice) -1354 # pseudocode -1355 # var slice = {0, word->end} -1356 # curr = word->start -1357 # if *curr == '"' -1358 # curr = skip-string-in-slice(curr, word->end) -1359 # else -1360 # while true -1361 # if curr == word->end -1362 # return -1363 # if *curr == '/' -1364 # break -1365 # ++curr -1366 # slice->start = curr -1367 # write-slice-buffered(out, slice) -1368 # -1369 # . prolog -1370 55/push-EBP -1371 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1372 # . save registers -1373 50/push-EAX -1374 51/push-ECX -1375 52/push-EDX -1376 53/push-EBX -1377 56/push-ESI -1378 # ESI = word -1379 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI -1380 # curr/ECX = word->start -1381 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX -1382 # end/EDX = word->end -1383 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 4/disp8 . # copy *(ESI+4) to EDX -1384 # var slice/EBX = {0, end} -1385 52/push-EDX -1386 68/push 0/imm32 -1387 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX -1388 # EAX = 0 -1389 b8/copy-to-EAX 0/imm32 -1390 $emit-metadata:check-for-string-literal: -1391 # - if (*curr == '"') curr = skip-string-in-slice(curr, end) -1392 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL -1393 3d/compare-EAX-and 0x22/imm32/dquote -1394 75/jump-if-not-equal $emit-metadata:skip-datum-loop/disp8 -1395 $emit-metadata:skip-string-literal: -1396 # . EAX = skip-string-in-slice(curr, end) -1397 # . . push args -1398 52/push-EDX -1399 51/push-ECX -1400 # . . call -1401 e8/call skip-string-in-slice/disp32 -1402 # . . discard args -1403 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1404 # . curr = EAX -1405 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX -1406 eb/jump $emit-metadata:emit/disp8 -1407 $emit-metadata:skip-datum-loop: -1408 # - otherwise scan for '/' -1409 # if (curr == end) return -1410 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX and EDX -1411 74/jump-if-equal $emit-metadata:end/disp8 -1412 # if (*curr == '/') break -1413 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL -1414 3d/compare-EAX-and 0x2f/imm32/slash -1415 74/jump-if-equal $emit-metadata:emit/disp8 -1416 # ++curr -1417 41/increment-ECX -1418 eb/jump $emit-metadata:skip-datum-loop/disp8 -1419 $emit-metadata:emit: -1420 # slice->start = ECX -1421 89/copy 0/mod/indirect 3/rm32/EBX . . . 1/r32/ECX . . # copy ECX to *EBX -1422 # write-slice-buffered(out, slice) -1423 # . . push args -1424 53/push-EBX -1425 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1426 # . . call -1427 e8/call write-slice-buffered/disp32 -1428 # . . discard args -1429 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . 8/imm32 . # add to ESP -1430 $emit-metadata:end: -1431 # . reclaim locals -1432 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . 8/imm32 . # add to ESP -1433 # . restore registers -1434 5e/pop-to-ESI -1435 5b/pop-to-EBX -1436 5a/pop-to-EDX -1437 59/pop-to-ECX -1438 58/pop-to-EAX -1439 # . epilog -1440 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1441 5d/pop-to-EBP -1442 c3/return -1443 -1444 test-emit-metadata: -1445 # . prolog -1446 55/push-EBP -1447 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1448 # setup -1449 # . clear-stream(_test-output-stream) -1450 # . . push args -1451 68/push _test-output-stream/imm32 -1452 # . . call -1453 e8/call clear-stream/disp32 -1454 # . . discard args -1455 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1456 # . clear-stream(_test-output-buffered-file+4) -1457 # . . push args -1458 b8/copy-to-EAX _test-output-buffered-file/imm32 -1459 05/add-to-EAX 4/imm32 -1460 50/push-EAX -1461 # . . call -1462 e8/call clear-stream/disp32 -1463 # . . discard args -1464 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1465 # (EAX..ECX) = "abc/def" -1466 b8/copy-to-EAX "abc/def"/imm32 -1467 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1468 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1469 05/add-to-EAX 4/imm32 -1470 # var slice/ECX = {EAX, ECX} -1471 51/push-ECX -1472 50/push-EAX -1473 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1474 # emit-metadata(_test-output-buffered-file, slice) -1475 # . . push args -1476 51/push-ECX -1477 68/push _test-output-buffered-file/imm32 -1478 # . . call -1479 e8/call emit-metadata/disp32 -1480 # . . discard args -1481 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1482 # flush(_test-output-buffered-file) -1483 # . . push args -1484 68/push _test-output-buffered-file/imm32 -1485 # . . call -1486 e8/call flush/disp32 -1487 # . . discard args -1488 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1489 # check-stream-equal(_test-output-stream, "/def", msg) # important that there's no leading space -1490 # . . push args -1491 68/push "F - test-emit-metadata"/imm32 -1492 68/push "/def"/imm32 -1493 68/push _test-output-stream/imm32 -1494 # . . call -1495 e8/call check-stream-equal/disp32 -1496 # . . discard args -1497 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1498 # . epilog -1499 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1500 5d/pop-to-EBP -1501 c3/return -1502 -1503 test-emit-metadata-none: -1504 # . prolog -1505 55/push-EBP -1506 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1507 # setup -1508 # . clear-stream(_test-output-stream) -1509 # . . push args -1510 68/push _test-output-stream/imm32 -1511 # . . call -1512 e8/call clear-stream/disp32 -1513 # . . discard args -1514 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1515 # . clear-stream(_test-output-buffered-file+4) -1516 # . . push args -1517 b8/copy-to-EAX _test-output-buffered-file/imm32 -1518 05/add-to-EAX 4/imm32 -1519 50/push-EAX -1520 # . . call -1521 e8/call clear-stream/disp32 -1522 # . . discard args -1523 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1524 # (EAX..ECX) = "abc" -1525 b8/copy-to-EAX "abc"/imm32 -1526 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1527 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1528 05/add-to-EAX 4/imm32 -1529 # var slice/ECX = {EAX, ECX} -1530 51/push-ECX -1531 50/push-EAX -1532 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1533 # emit-metadata(_test-output-buffered-file, slice) -1534 # . . push args -1535 51/push-ECX -1536 68/push _test-output-buffered-file/imm32 -1537 # . . call -1538 e8/call emit-metadata/disp32 -1539 # . . discard args -1540 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1541 # flush(_test-output-buffered-file) -1542 # . . push args -1543 68/push _test-output-buffered-file/imm32 -1544 # . . call -1545 e8/call flush/disp32 -1546 # . . discard args -1547 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1548 # check-stream-equal(_test-output-stream, "", msg) -1549 # . . push args -1550 68/push "F - test-emit-metadata-none"/imm32 -1551 68/push ""/imm32 -1552 68/push _test-output-stream/imm32 -1553 # . . call -1554 e8/call check-stream-equal/disp32 -1555 # . . discard args -1556 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1557 # . epilog -1558 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1559 5d/pop-to-EBP -1560 c3/return -1561 -1562 test-emit-metadata-multiple: -1563 # . prolog -1564 55/push-EBP -1565 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1566 # setup -1567 # . clear-stream(_test-output-stream) -1568 # . . push args -1569 68/push _test-output-stream/imm32 -1570 # . . call -1571 e8/call clear-stream/disp32 -1572 # . . discard args -1573 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1574 # . clear-stream(_test-output-buffered-file+4) -1575 # . . push args -1576 b8/copy-to-EAX _test-output-buffered-file/imm32 -1577 05/add-to-EAX 4/imm32 -1578 50/push-EAX -1579 # . . call -1580 e8/call clear-stream/disp32 -1581 # . . discard args -1582 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1583 # (EAX..ECX) = "abc/def/ghi" -1584 b8/copy-to-EAX "abc/def/ghi"/imm32 -1585 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1586 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1587 05/add-to-EAX 4/imm32 -1588 # var slice/ECX = {EAX, ECX} -1589 51/push-ECX -1590 50/push-EAX -1591 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1592 # emit-metadata(_test-output-buffered-file, slice) -1593 # . . push args -1594 51/push-ECX -1595 68/push _test-output-buffered-file/imm32 -1596 # . . call -1597 e8/call emit-metadata/disp32 -1598 # . . discard args -1599 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1600 # flush(_test-output-buffered-file) -1601 # . . push args -1602 68/push _test-output-buffered-file/imm32 -1603 # . . call -1604 e8/call flush/disp32 -1605 # . . discard args -1606 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1607 # check-stream-equal(_test-output-stream, "/def/ghi", msg) # important that there's no leading space -1608 # . . push args -1609 68/push "F - test-emit-metadata-multiple"/imm32 -1610 68/push "/def/ghi"/imm32 -1611 68/push _test-output-stream/imm32 -1612 # . . call -1613 e8/call check-stream-equal/disp32 -1614 # . . discard args -1615 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1616 # . epilog -1617 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1618 5d/pop-to-EBP -1619 c3/return -1620 -1621 test-emit-metadata-when-no-datum: -1622 # . prolog -1623 55/push-EBP -1624 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1625 # setup -1626 # . clear-stream(_test-output-stream) -1627 # . . push args -1628 68/push _test-output-stream/imm32 -1629 # . . call -1630 e8/call clear-stream/disp32 -1631 # . . discard args -1632 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1633 # . clear-stream(_test-output-buffered-file+4) -1634 # . . push args -1635 b8/copy-to-EAX _test-output-buffered-file/imm32 -1636 05/add-to-EAX 4/imm32 -1637 50/push-EAX -1638 # . . call -1639 e8/call clear-stream/disp32 -1640 # . . discard args -1641 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1642 # var slice/ECX = "/abc" -1643 b8/copy-to-EAX "/abc"/imm32 -1644 # . push end/ECX -1645 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1646 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1647 51/push-ECX -1648 # . push curr/EAX -1649 05/add-to-EAX 4/imm32 -1650 50/push-EAX -1651 # . save stack pointer -1652 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1653 # emit-metadata(_test-output-buffered-file, slice) -1654 # . . push args -1655 51/push-ECX -1656 68/push _test-output-buffered-file/imm32 -1657 # . . call -1658 e8/call emit-metadata/disp32 -1659 # . . discard args -1660 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1661 # flush(_test-output-buffered-file) -1662 # . . push args -1663 68/push _test-output-buffered-file/imm32 -1664 # . . call -1665 e8/call flush/disp32 -1666 # . . discard args -1667 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1668 # check-stream-equal(_test-output-stream, "/abc", msg) # nothing skipped -1669 # . . push args -1670 68/push "F - test-emit-metadata-when-no-datum"/imm32 -1671 68/push "/abc"/imm32 -1672 68/push _test-output-stream/imm32 -1673 # . . call -1674 e8/call check-stream-equal/disp32 -1675 # . . discard args -1676 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1677 # . epilog -1678 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1679 5d/pop-to-EBP -1680 c3/return -1681 -1682 test-emit-metadata-in-string-literal: -1683 # . prolog -1684 55/push-EBP -1685 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1686 # setup -1687 # . clear-stream(_test-output-stream) -1688 # . . push args -1689 68/push _test-output-stream/imm32 -1690 # . . call -1691 e8/call clear-stream/disp32 -1692 # . . discard args -1693 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1694 # . clear-stream(_test-output-buffered-file+4) -1695 # . . push args -1696 b8/copy-to-EAX _test-output-buffered-file/imm32 -1697 05/add-to-EAX 4/imm32 -1698 50/push-EAX -1699 # . . call -1700 e8/call clear-stream/disp32 -1701 # . . discard args -1702 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1703 # var slice/ECX = "\"abc/def\"/ghi" -1704 68/push _test-slice-literal-string-with-limit/imm32 -1705 68/push _test-slice-literal-string/imm32/start -1706 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1707 # emit-metadata(_test-output-buffered-file, slice) -1708 # . . push args -1709 51/push-ECX -1710 68/push _test-output-buffered-file/imm32 -1711 # . . call -1712 e8/call emit-metadata/disp32 -1713 # . . discard args -1714 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1715 # flush(_test-output-buffered-file) -1716 # . . push args -1717 68/push _test-output-buffered-file/imm32 -1718 # . . call -1719 e8/call flush/disp32 -1720 # . . discard args -1721 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1722 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -1748 # check-stream-equal(_test-output-stream, "/ghi", msg) # important that there's no leading space -1749 # . . push args -1750 68/push "F - test-emit-metadata-in-string-literal"/imm32 -1751 68/push "/ghi"/imm32 -1752 68/push _test-output-stream/imm32 -1753 # . . call -1754 e8/call check-stream-equal/disp32 -1755 # . . discard args -1756 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1757 # . epilog -1758 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1759 5d/pop-to-EBP -1760 c3/return -1761 -1762 # (re)compute the bounds of the next word in the line -1763 # return empty string on reaching end of file -1764 next-word-or-string: # line : (address stream byte), out : (address slice) -1765 # . prolog -1766 55/push-EBP -1767 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1768 # . save registers -1769 50/push-EAX -1770 51/push-ECX -1771 56/push-ESI -1772 57/push-EDI -1773 # ESI = line -1774 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -1775 # EDI = out -1776 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI -1777 # skip-chars-matching(line, ' ') -1778 # . . push args -1779 68/push 0x20/imm32/space -1780 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1781 # . . call -1782 e8/call skip-chars-matching/disp32 -1783 # . . discard args -1784 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1785 $next-word-or-string:check0: -1786 # if (line->read >= line->write) clear out and return -1787 # . EAX = line->read -1788 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX -1789 # . if (EAX < line->write) goto next check -1790 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI -1791 7c/jump-if-lesser $next-word-or-string:check-for-comment/disp8 -1792 # . return out = {0, 0} -1793 c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI -1794 c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) -1795 eb/jump $next-word-or-string:end/disp8 -1796 $next-word-or-string:check-for-comment: -1797 # out->start = &line->data[line->read] -1798 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX -1799 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX -1800 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI -1801 # if line->data[line->read] == '#' -1802 # . EAX = line->data[line->read] -1803 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -1804 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL -1805 # . compare -1806 3d/compare-EAX-and 0x23/imm32/pound -1807 75/jump-if-not-equal $next-word-or-string:check-for-string-literal/disp8 -1808 $next-word-or-string:comment: -1809 # out->end = &line->data[line->write] -1810 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX -1811 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX -1812 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) -1813 # line->read = line->write # skip rest of line -1814 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX -1815 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) -1816 # return -1817 eb/jump $next-word-or-string:end/disp8 -1818 $next-word-or-string:check-for-string-literal: -1819 # if line->data[line->read] == '"' -1820 # . EAX = line->data[line->read] -1821 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -1822 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL -1823 # . compare -1824 3d/compare-EAX-and 0x22/imm32/dquote -1825 75/jump-if-not-equal $next-word-or-string:regular-word/disp8 -1826 $next-word-or-string:string-literal: -1827 # skip-string(line) -1828 # . . push args -1829 56/push-ESI -1830 # . . call -1831 e8/call skip-string/disp32 -1832 # . . discard args -1833 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1834 # fall through -1835 $next-word-or-string:regular-word: -1836 # skip-chars-not-matching-whitespace(line) # including trailing newline -1837 # . . push args -1838 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1839 # . . call -1840 e8/call skip-chars-not-matching-whitespace/disp32 -1841 # . . discard args -1842 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1843 # out->end = &line->data[line->read] -1844 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX -1845 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX -1846 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) -1847 $next-word-or-string:end: -1848 # . restore registers -1849 5f/pop-to-EDI -1850 5e/pop-to-ESI -1851 59/pop-to-ECX -1852 58/pop-to-EAX -1853 # . epilog -1854 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1855 5d/pop-to-EBP -1856 c3/return -1857 -1858 test-next-word-or-string: -1859 # . prolog -1860 55/push-EBP -1861 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1862 # setup -1863 # . clear-stream(_test-input-stream) -1864 # . . push args -1865 68/push _test-input-stream/imm32 -1866 # . . call -1867 e8/call clear-stream/disp32 -1868 # . . discard args -1869 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1870 # var slice/ECX = {0, 0} -1871 68/push 0/imm32/end -1872 68/push 0/imm32/start -1873 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1874 # write(_test-input-stream, " ab") -1875 # . . push args -1876 68/push " ab"/imm32 -1877 68/push _test-input-stream/imm32 -1878 # . . call -1879 e8/call write/disp32 -1880 # . . discard args -1881 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1882 # next-word-or-string(_test-input-stream, slice) -1883 # . . push args -1884 51/push-ECX -1885 68/push _test-input-stream/imm32 -1886 # . . call -1887 e8/call next-word-or-string/disp32 -1888 # . . discard args -1889 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1890 # check-ints-equal(_test-input-stream->read, 4, msg) -1891 # . . push args -1892 68/push "F - test-next-word-or-string/updates-stream-read-correctly"/imm32 -1893 68/push 4/imm32 -1894 b8/copy-to-EAX _test-input-stream/imm32 -1895 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -1896 # . . call -1897 e8/call check-ints-equal/disp32 -1898 # . . discard args -1899 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1900 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) -1901 # . check-ints-equal(slice->start - _test-input-stream, 14, msg) -1902 # . . push args -1903 68/push "F - test-next-word-or-string: start"/imm32 -1904 68/push 0xe/imm32 -1905 # . . push slice->start - _test-input-stream -1906 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -1907 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -1908 50/push-EAX -1909 # . . call -1910 e8/call check-ints-equal/disp32 -1911 # . . discard args -1912 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1913 # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) -1914 # . check-ints-equal(slice->end - _test-input-stream, 16, msg) -1915 # . . push args -1916 68/push "F - test-next-word-or-string: end"/imm32 -1917 68/push 0x10/imm32 -1918 # . . push slice->end - _test-input-stream -1919 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1920 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -1921 50/push-EAX -1922 # . . call -1923 e8/call check-ints-equal/disp32 -1924 # . . discard args -1925 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1926 # . epilog -1927 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1928 5d/pop-to-EBP -1929 c3/return -1930 -1931 test-next-word-or-string-returns-whole-comment: -1932 # . prolog -1933 55/push-EBP -1934 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1935 # setup -1936 # . clear-stream(_test-input-stream) -1937 # . . push args -1938 68/push _test-input-stream/imm32 -1939 # . . call -1940 e8/call clear-stream/disp32 -1941 # . . discard args -1942 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1943 # var slice/ECX = {0, 0} -1944 68/push 0/imm32/end -1945 68/push 0/imm32/start -1946 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1947 # write(_test-input-stream, " # a") -1948 # . . push args -1949 68/push " # a"/imm32 -1950 68/push _test-input-stream/imm32 -1951 # . . call -1952 e8/call write/disp32 -1953 # . . discard args -1954 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1955 # next-word-or-string(_test-input-stream, slice) -1956 # . . push args -1957 51/push-ECX -1958 68/push _test-input-stream/imm32 -1959 # . . call -1960 e8/call next-word-or-string/disp32 -1961 # . . discard args -1962 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1963 # check-ints-equal(_test-input-stream->read, 5, msg) -1964 # . . push args -1965 68/push "F - test-next-word-or-string-returns-whole-comment/updates-stream-read-correctly"/imm32 -1966 68/push 5/imm32 -1967 b8/copy-to-EAX _test-input-stream/imm32 -1968 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -1969 # . . call -1970 e8/call check-ints-equal/disp32 -1971 # . . discard args -1972 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1973 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) -1974 # . check-ints-equal(slice->start - _test-input-stream, 14, msg) -1975 # . . push args -1976 68/push "F - test-next-word-or-string-returns-whole-comment: start"/imm32 -1977 68/push 0xe/imm32 -1978 # . . push slice->start - _test-input-stream -1979 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -1980 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -1981 50/push-EAX -1982 # . . call -1983 e8/call check-ints-equal/disp32 -1984 # . . discard args -1985 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1986 # check-ints-equal(slice->end - _test-input-stream->data, 5, msg) -1987 # . check-ints-equal(slice->end - _test-input-stream, 17, msg) -1988 # . . push args -1989 68/push "F - test-next-word-or-string-returns-whole-comment: end"/imm32 -1990 68/push 0x11/imm32 -1991 # . . push slice->end - _test-input-stream -1992 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1993 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -1994 50/push-EAX -1995 # . . call -1996 e8/call check-ints-equal/disp32 -1997 # . . discard args -1998 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1999 # . epilog -2000 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2001 5d/pop-to-EBP -2002 c3/return -2003 -2004 test-next-word-or-string-returns-empty-string-on-eof: -2005 # . prolog -2006 55/push-EBP -2007 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2008 # setup -2009 # . clear-stream(_test-input-stream) -2010 # . . push args -2011 68/push _test-input-stream/imm32 -2012 # . . call -2013 e8/call clear-stream/disp32 -2014 # . . discard args -2015 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2016 # var slice/ECX = {0, 0} -2017 68/push 0/imm32/end -2018 68/push 0/imm32/start -2019 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2020 # write nothing to _test-input-stream -2021 # next-word-or-string(_test-input-stream, slice) -2022 # . . push args -2023 51/push-ECX -2024 68/push _test-input-stream/imm32 -2025 # . . call -2026 e8/call next-word-or-string/disp32 -2027 # . . discard args -2028 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2029 # check-ints-equal(slice->end - slice->start, 0, msg) -2030 # . . push args -2031 68/push "F - test-next-word-or-string-returns-empty-string-on-eof"/imm32 -2032 68/push 0/imm32 -2033 # . . push slice->end - slice->start -2034 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -2035 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX -2036 50/push-EAX -2037 # . . call -2038 e8/call check-ints-equal/disp32 -2039 # . . discard args -2040 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2041 # . epilog -2042 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2043 5d/pop-to-EBP -2044 c3/return -2045 -2046 test-next-word-or-string-returns-whole-string: -2047 # . prolog -2048 55/push-EBP -2049 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2050 # setup -2051 # . clear-stream(_test-input-stream) -2052 # . . push args -2053 68/push _test-input-stream/imm32 -2054 # . . call -2055 e8/call clear-stream/disp32 -2056 # . . discard args -2057 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2058 # var slice/ECX = {0, 0} -2059 68/push 0/imm32/end -2060 68/push 0/imm32/start -2061 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2062 # write(_test-input-stream, " \"a b\"/imm32 ") -2063 # . . push args -2064 68/push " \"a b\"/imm32 "/imm32 -2065 68/push _test-input-stream/imm32 -2066 # . . call -2067 e8/call write/disp32 -2068 # . . discard args -2069 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2070 # next-word-or-string(_test-input-stream, slice) -2071 # . . push args -2072 51/push-ECX -2073 68/push _test-input-stream/imm32 -2074 # . . call -2075 e8/call next-word-or-string/disp32 -2076 # . . discard args -2077 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2078 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) -2079 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) -2080 # . . push args -2081 68/push "F - test-next-word-or-string-returns-whole-string: start"/imm32 -2082 68/push 0xd/imm32 -2083 # . . push slice->start - _test-input-stream -2084 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -2085 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -2086 50/push-EAX -2087 # . . call -2088 e8/call check-ints-equal/disp32 -2089 # . . discard args -2090 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2091 # check-ints-equal(slice->end - _test-input-stream->data, 12, msg) -2092 # . check-ints-equal(slice->end - _test-input-stream, 24, msg) -2093 # . . push args -2094 68/push "F - test-next-word-or-string-returns-whole-string: end"/imm32 -2095 68/push 0x18/imm32 -2096 # . . push slice->end - _test-input-stream -2097 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -2098 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -2099 50/push-EAX -2100 # . . call -2101 e8/call check-ints-equal/disp32 -2102 # . . discard args -2103 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2104 # . epilog -2105 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2106 5d/pop-to-EBP -2107 c3/return -2108 -2109 test-next-word-or-string-returns-string-with-escapes: -2110 # . prolog -2111 55/push-EBP -2112 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2113 # setup -2114 # . clear-stream(_test-input-stream) -2115 # . . push args -2116 68/push _test-input-stream/imm32 -2117 # . . call -2118 e8/call clear-stream/disp32 -2119 # . . discard args -2120 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2121 # var slice/ECX = {0, 0} -2122 68/push 0/imm32/end -2123 68/push 0/imm32/start -2124 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2125 # write(_test-input-stream, " \"a\\\"b\"/x") -2126 # . . push args -2127 68/push " \"a\\\"b\"/x"/imm32 -2128 68/push _test-input-stream/imm32 -2129 # . . call -2130 e8/call write/disp32 -2131 # . . discard args -2132 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2133 # next-word-or-string(_test-input-stream, slice) -2134 # . . push args -2135 51/push-ECX -2136 68/push _test-input-stream/imm32 -2137 # . . call -2138 e8/call next-word-or-string/disp32 -2139 # . . discard args -2140 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2141 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) -2142 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) -2143 # . . push args -2144 68/push "F - test-next-word-or-string-returns-string-with-escapes: start"/imm32 -2145 68/push 0xd/imm32 -2146 # . . push slice->start - _test-input-stream -2147 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -2148 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -2149 50/push-EAX -2150 # . . call -2151 e8/call check-ints-equal/disp32 -2152 # . . discard args -2153 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2154 # check-ints-equal(slice->end - _test-input-stream->data, 9, msg) -2155 # . check-ints-equal(slice->end - _test-input-stream, 21, msg) -2156 # . . push args -2157 68/push "F - test-next-word-or-string-returns-string-with-escapes: end"/imm32 -2158 68/push 0x15/imm32 -2159 # . . push slice->end - _test-input-stream -2160 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -2161 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX -2162 50/push-EAX -2163 # . . call -2164 e8/call check-ints-equal/disp32 -2165 # . . discard args -2166 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2167 # . epilog -2168 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2169 5d/pop-to-EBP -2170 c3/return -2171 -2172 # update line->read to end of string literal surrounded by double quotes -2173 # line->read must start out at a double-quote -2174 skip-string: # line : (address stream) -2175 # . prolog -2176 55/push-EBP -2177 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2178 # . save registers -2179 50/push-EAX -2180 51/push-ECX -2181 52/push-EDX -2182 # ECX = line -2183 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX -2184 # EAX = skip-string-in-slice(&line->data[line->read], &line->data[line->write]) -2185 # . . push &line->data[line->write] -2186 8b/copy 1/mod/*+disp8 1/rm32/ECX . . 2/r32/EDX 8/disp8 . # copy *(ECX+8) to EDX -2187 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ECX+EDX+12 to EDX -2188 52/push-EDX -2189 # . . push &line->data[line->read] -2190 8b/copy 1/mod/*+disp8 1/rm32/ECX . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX -2191 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ECX+EDX+12 to EDX -2192 52/push-EDX -2193 # . . call -2194 e8/call skip-string-in-slice/disp32 -2195 # . . discard args -2196 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2197 # line->read = EAX - line->data -2198 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX -2199 2d/subtract-from-EAX 0xc/imm32 -2200 89/copy 1/mod/*+disp8 1/rm32/ECX . . 0/r32/EAX 4/disp8 . # copy EAX to *(ECX+4) -2201 $skip-string:end: -2202 # . restore registers -2203 5a/pop-to-EDX -2204 59/pop-to-ECX -2205 58/pop-to-EAX -2206 # . epilog -2207 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2208 5d/pop-to-EBP -2209 c3/return -2210 -2211 test-skip-string: -2212 # . prolog -2213 55/push-EBP -2214 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2215 # setup -2216 # . clear-stream(_test-input-stream) -2217 # . . push args -2218 68/push _test-input-stream/imm32 -2219 # . . call -2220 e8/call clear-stream/disp32 -2221 # . . discard args -2222 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2223 # . write(_test-input-stream, "\"abc\" def") -2224 # . indices: 0123 45 -2225 # . . push args -2226 68/push "\"abc\" def"/imm32 -2227 68/push _test-input-stream/imm32 -2228 # . . call -2229 e8/call write/disp32 -2230 # . . discard args -2231 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2232 # precondition: line->read == 0 -2233 # . . push args -2234 68/push "F - test-skip-string/precondition"/imm32 -2235 68/push 0/imm32 -2236 b8/copy-to-EAX _test-input-stream/imm32 -2237 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -2238 # . . call -2239 e8/call check-ints-equal/disp32 -2240 # . . discard args -2241 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2242 # skip-string(_test-input-stream) -2243 # . . push args -2244 68/push _test-input-stream/imm32 -2245 # . . call -2246 e8/call skip-string/disp32 -2247 # . . discard args -2248 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2249 # check-ints-equal(line->read, 5, msg) -2250 # . . push args -2251 68/push "F - test-skip-string"/imm32 -2252 68/push 5/imm32 -2253 b8/copy-to-EAX _test-input-stream/imm32 -2254 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -2255 # . . call -2256 e8/call check-ints-equal/disp32 -2257 # . . discard args -2258 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2259 # . epilog -2260 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2261 5d/pop-to-EBP -2262 c3/return -2263 -2264 test-skip-string-ignores-spaces: -2265 # . prolog -2266 55/push-EBP -2267 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2268 # setup -2269 # . clear-stream(_test-input-stream) -2270 # . . push args -2271 68/push _test-input-stream/imm32 -2272 # . . call -2273 e8/call clear-stream/disp32 -2274 # . . discard args -2275 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2276 # . write(_test-input-stream, "\"a b\"/yz") -2277 # . indices: 0123 45 -2278 # . . push args -2279 68/push "\"a b\"/yz"/imm32 -2280 68/push _test-input-stream/imm32 -2281 # . . call -2282 e8/call write/disp32 -2283 # . . discard args -2284 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2285 # precondition: line->read == 0 -2286 # . . push args -2287 68/push "F - test-skip-string-ignores-spaces/precondition"/imm32 -2288 68/push 0/imm32 -2289 b8/copy-to-EAX _test-input-stream/imm32 -2290 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -2291 # . . call -2292 e8/call check-ints-equal/disp32 -2293 # . . discard args -2294 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2295 # skip-string(_test-input-stream) -2296 # . . push args -2297 68/push _test-input-stream/imm32 -2298 # . . call -2299 e8/call skip-string/disp32 -2300 # . . discard args -2301 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2302 # check-ints-equal(line->read, 5, msg) -2303 # . . push args -2304 68/push "F - test-skip-string-ignores-spaces"/imm32 -2305 68/push 5/imm32 -2306 b8/copy-to-EAX _test-input-stream/imm32 -2307 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -2308 # . . call -2309 e8/call check-ints-equal/disp32 -2310 # . . discard args -2311 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2312 # . epilog -2313 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2314 5d/pop-to-EBP -2315 c3/return -2316 -2317 test-skip-string-ignores-escapes: -2318 # . prolog -2319 55/push-EBP -2320 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2321 # setup -2322 # . clear-stream(_test-input-stream) -2323 # . . push args -2324 68/push _test-input-stream/imm32 -2325 # . . call -2326 e8/call clear-stream/disp32 -2327 # . . discard args -2328 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2329 # . write(_test-input-stream, "\"a\\\"b\"/yz") -2330 # . indices: 01 2 34 56 -2331 # . . push args -2332 68/push "\"a\\\"b\"/yz"/imm32 -2333 68/push _test-input-stream/imm32 -2334 # . . call -2335 e8/call write/disp32 -2336 # . . discard args -2337 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2338 # precondition: line->read == 0 -2339 # . . push args -2340 68/push "F - test-skip-string-ignores-escapes/precondition"/imm32 -2341 68/push 0/imm32 -2342 b8/copy-to-EAX _test-input-stream/imm32 -2343 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -2344 # . . call -2345 e8/call check-ints-equal/disp32 -2346 # . . discard args -2347 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2348 # skip-string(_test-input-stream) -2349 # . . push args -2350 68/push _test-input-stream/imm32 -2351 # . . call -2352 e8/call skip-string/disp32 -2353 # . . discard args -2354 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2355 # check-ints-equal(line->read, 6, msg) -2356 # . . push args -2357 68/push "F - test-skip-string-ignores-escapes"/imm32 -2358 68/push 6/imm32 -2359 b8/copy-to-EAX _test-input-stream/imm32 -2360 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -2361 # . . call -2362 e8/call check-ints-equal/disp32 -2363 # . . discard args -2364 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2365 # . epilog -2366 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2367 5d/pop-to-EBP -2368 c3/return -2369 -2370 test-skip-string-works-from-mid-stream: -2371 # . prolog -2372 55/push-EBP -2373 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2374 # setup -2375 # . clear-stream(_test-input-stream) -2376 # . . push args -2377 68/push _test-input-stream/imm32 -2378 # . . call -2379 e8/call clear-stream/disp32 -2380 # . . discard args -2381 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2382 # . write(_test-input-stream, "0 \"a\\\"b\"/yz") -2383 # . indices: 01 2 34 56 -2384 # . . push args -2385 68/push "0 \"a\\\"b\"/yz"/imm32 -2386 68/push _test-input-stream/imm32 -2387 # . . call -2388 e8/call write/disp32 -2389 # . . discard args -2390 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2391 # precondition: line->read == 2 -2392 c7 0/subop/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 2/imm32 # copy to *(EAX+4) -2393 # skip-string(_test-input-stream) -2394 # . . push args -2395 68/push _test-input-stream/imm32 -2396 # . . call -2397 e8/call skip-string/disp32 -2398 # . . discard args -2399 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2400 # check-ints-equal(line->read, 8, msg) -2401 # . . push args -2402 68/push "F - test-skip-string-works-from-mid-stream"/imm32 -2403 68/push 8/imm32 -2404 b8/copy-to-EAX _test-input-stream/imm32 -2405 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -2406 # . . call -2407 e8/call check-ints-equal/disp32 -2408 # . . discard args -2409 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2410 # . epilog -2411 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2412 5d/pop-to-EBP -2413 c3/return -2414 -2415 skip-string-in-slice: # curr : (address byte), end : (address byte) -> new_curr/EAX -2416 # . prolog -2417 55/push-EBP -2418 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2419 # . save registers -2420 51/push-ECX -2421 52/push-EDX -2422 53/push-EBX -2423 # ECX = curr -2424 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX -2425 # EDX = end -2426 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX -2427 # EAX = 0 -2428 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -2429 # skip initial dquote -2430 41/increment-ECX -2431 $skip-string-in-slice:loop: -2432 # if (curr >= end) return curr -2433 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX -2434 73/jump-if-greater-unsigned-or-equal $skip-string-in-slice:return-curr/disp8 -2435 # AL = *curr -2436 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL -2437 $skip-string-in-slice:dquote: -2438 # if (EAX == '"') break -2439 3d/compare-EAX-and 0x22/imm32/double-quote -2440 74/jump-if-equal $skip-string-in-slice:break/disp8 -2441 $skip-string-in-slice:check-for-escape: -2442 # if (EAX == '\') escape next char -2443 3d/compare-EAX-and 0x5c/imm32/backslash -2444 75/jump-if-not-equal $skip-string-in-slice:continue/disp8 -2445 $skip-string-in-slice:escape: -2446 41/increment-ECX -2447 $skip-string-in-slice:continue: -2448 # ++curr -2449 41/increment-ECX -2450 eb/jump $skip-string-in-slice:loop/disp8 -2451 $skip-string-in-slice:break: -2452 # skip final dquote -2453 41/increment-ECX -2454 $skip-string-in-slice:return-curr: -2455 # return curr -2456 89/copy 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to EAX -2457 $skip-string-in-slice:end: -2458 # . restore registers -2459 5b/pop-to-EBX -2460 5a/pop-to-EDX -2461 59/pop-to-ECX -2462 # . epilog -2463 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2464 5d/pop-to-EBP -2465 c3/return -2466 -2467 test-skip-string-in-slice: -2468 # . prolog -2469 55/push-EBP -2470 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2471 # setup: (EAX..ECX) = "\"abc\" def" -2472 b8/copy-to-EAX "\"abc\" def"/imm32 -2473 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2474 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2475 05/add-to-EAX 4/imm32 -2476 # EAX = skip-string-in-slice(EAX, ECX) -2477 # . . push args -2478 51/push-ECX -2479 50/push-EAX -2480 # . . call -2481 e8/call skip-string-in-slice/disp32 -2482 # . . discard args -2483 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2484 # check-ints-equal(ECX-EAX, 4, msg) # number of chars remaining after the string literal -2485 # . . push args -2486 68/push "F - test-skip-string-in-slice"/imm32 -2487 68/push 4/imm32 -2488 # . . push ECX-EAX -2489 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX -2490 51/push-ECX -2491 # . . call -2492 e8/call check-ints-equal/disp32 -2493 # . . discard args -2494 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2495 # . epilog -2496 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2497 5d/pop-to-EBP -2498 c3/return -2499 -2500 test-skip-string-in-slice-ignores-spaces: -2501 # . prolog -2502 55/push-EBP -2503 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2504 # setup: (EAX..ECX) = "\"a b\"/yz" -2505 b8/copy-to-EAX "\"a b\"/yz"/imm32 -2506 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2507 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2508 05/add-to-EAX 4/imm32 -2509 # EAX = skip-string-in-slice(EAX, ECX) -2510 # . . push args -2511 51/push-ECX -2512 50/push-EAX -2513 # . . call -2514 e8/call skip-string-in-slice/disp32 -2515 # . . discard args -2516 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2517 # check-ints-equal(ECX-EAX, 3, msg) # number of chars remaining after the string literal -2518 # . . push args -2519 68/push "F - test-skip-string-in-slice-ignores-spaces"/imm32 -2520 68/push 3/imm32 -2521 # . . push ECX-EAX -2522 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX -2523 51/push-ECX -2524 # . . call -2525 e8/call check-ints-equal/disp32 -2526 # . . discard args -2527 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2528 # . epilog -2529 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2530 5d/pop-to-EBP -2531 c3/return -2532 -2533 test-skip-string-in-slice-ignores-escapes: -2534 # . prolog -2535 55/push-EBP -2536 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2537 # setup: (EAX..ECX) = "\"a\\\"b\"/yz" -2538 b8/copy-to-EAX "\"a\\\"b\"/yz"/imm32 -2539 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2540 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2541 05/add-to-EAX 4/imm32 -2542 # EAX = skip-string-in-slice(EAX, ECX) -2543 # . . push args -2544 51/push-ECX -2545 50/push-EAX -2546 # . . call -2547 e8/call skip-string-in-slice/disp32 -2548 # . . discard args -2549 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2550 # check-ints-equal(ECX-EAX, 3, msg) # number of chars remaining after the string literal -2551 # . . push args -2552 68/push "F - test-skip-string-in-slice-ignores-escapes"/imm32 -2553 68/push 3/imm32 -2554 # . . push ECX-EAX -2555 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX -2556 51/push-ECX -2557 # . . call -2558 e8/call check-ints-equal/disp32 -2559 # . . discard args -2560 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2561 # . epilog -2562 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2563 5d/pop-to-EBP -2564 c3/return -2565 -2566 test-skip-string-in-slice-stops-at-end: -2567 # . prolog -2568 55/push-EBP -2569 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2570 # setup: (EAX..ECX) = "\"abc" # unbalanced dquote -2571 b8/copy-to-EAX "\"abc"/imm32 -2572 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2573 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2574 05/add-to-EAX 4/imm32 -2575 # EAX = skip-string-in-slice(EAX, ECX) -2576 # . . push args -2577 51/push-ECX -2578 50/push-EAX -2579 # . . call -2580 e8/call skip-string-in-slice/disp32 -2581 # . . discard args -2582 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2583 # check-ints-equal(ECX-EAX, 0, msg) # skipped to end of slice -2584 # . . push args -2585 68/push "F - test-skip-string-in-slice-stops-at-end"/imm32 -2586 68/push 0/imm32 -2587 # . . push ECX-EAX -2588 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX -2589 51/push-ECX -2590 # . . call -2591 e8/call check-ints-equal/disp32 -2592 # . . discard args -2593 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2594 # . epilog -2595 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2596 5d/pop-to-EBP -2597 c3/return -2598 -2599 string-length-at-start-of-slice: # curr : (address byte), end : (address byte) -> length/EAX -2600 # . prolog -2601 55/push-EBP -2602 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2603 # . save registers -2604 51/push-ECX -2605 52/push-EDX -2606 53/push-EBX -2607 # ECX = curr -2608 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX -2609 # EDX = end -2610 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX -2611 # length/EAX = 0 -2612 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -2613 # EBX = 0 -2614 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX -2615 # skip initial dquote -2616 41/increment-ECX -2617 $string-length-at-start-of-slice:loop: -2618 # if (curr >= end) return length -2619 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX -2620 73/jump-if-greater-unsigned-or-equal $string-length-at-start-of-slice:end/disp8 -2621 # BL = *curr -2622 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 3/r32/BL . . # copy byte at *ECX to BL -2623 $string-length-at-start-of-slice:dquote: -2624 # if (EBX == '"') break -2625 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x22/imm32/dquote # compare EBX -2626 74/jump-if-equal $string-length-at-start-of-slice:end/disp8 -2627 $string-length-at-start-of-slice:check-for-escape: -2628 # if (EBX == '\') escape next char -2629 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x5c/imm32/backslash # compare EBX -2630 75/jump-if-not-equal $string-length-at-start-of-slice:continue/disp8 -2631 $string-length-at-start-of-slice:escape: -2632 # increment curr but not result -2633 41/increment-ECX -2634 $string-length-at-start-of-slice:continue: -2635 # ++result -2636 40/increment-EAX -2637 # ++curr -2638 41/increment-ECX -2639 eb/jump $string-length-at-start-of-slice:loop/disp8 -2640 $string-length-at-start-of-slice:end: -2641 # . restore registers -2642 5b/pop-to-EBX -2643 5a/pop-to-EDX -2644 59/pop-to-ECX -2645 # . epilog -2646 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2647 5d/pop-to-EBP -2648 c3/return -2649 -2650 test-string-length-at-start-of-slice: -2651 # . prolog -2652 55/push-EBP -2653 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2654 # setup: (EAX..ECX) = "\"abc\" def" -2655 b8/copy-to-EAX "\"abc\" def"/imm32 -2656 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2657 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2658 05/add-to-EAX 4/imm32 -2659 # EAX = string-length-at-start-of-slice(EAX, ECX) -2660 # . . push args -2661 51/push-ECX -2662 50/push-EAX -2663 # . . call -2664 e8/call string-length-at-start-of-slice/disp32 -2665 # . . discard args -2666 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2667 # check-ints-equal(EAX, 3, msg) -2668 # . . push args -2669 68/push "F - test-string-length-at-start-of-slice"/imm32 -2670 68/push 3/imm32 -2671 50/push-EAX -2672 # . . call -2673 e8/call check-ints-equal/disp32 -2674 # . . discard args -2675 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2676 # . epilog -2677 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2678 5d/pop-to-EBP -2679 c3/return -2680 -2681 test-string-length-at-start-of-slice-escaped: -2682 # . prolog -2683 55/push-EBP -2684 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2685 # setup: (EAX..ECX) = "\"ab\\c\" def" -2686 b8/copy-to-EAX "\"ab\\c\" def"/imm32 -2687 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2688 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2689 05/add-to-EAX 4/imm32 -2690 # EAX = string-length-at-start-of-slice(EAX, ECX) -2691 # . . push args -2692 51/push-ECX -2693 50/push-EAX -2694 # . . call -2695 e8/call string-length-at-start-of-slice/disp32 -2696 # . . discard args -2697 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2698 # check-ints-equal(EAX, 3, msg) -2699 # . . push args -2700 68/push "F - test-string-length-at-start-of-slice-escaped"/imm32 -2701 68/push 3/imm32 -2702 50/push-EAX -2703 # . . call -2704 e8/call check-ints-equal/disp32 -2705 # . . discard args -2706 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2707 # . epilog -2708 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2709 5d/pop-to-EBP -2710 c3/return -2711 -2712 == data -2713 -2714 Next-string-literal: # tracks the next auto-generated variable name -2715 1/imm32 -2716 -2717 # length-prefixed string containing just a single space -2718 Space: -2719 # size -2720 1/imm32 -2721 # data -2722 20/space -2723 -2724 # length-prefixed string containing just a single slash -2725 Slash: -2726 # size -2727 1/imm32 -2728 # data -2729 2f/slash -2730 -2731 _test-slice-abc: -2732 22/dquote 61/a 62/b 63/c 22/dquote # "abc" -2733 2f/slash 64/d -2734 _test-slice-abc-limit: -2735 -2736 _test-slice-a-space-b: -2737 22/dquote 61/a 20/space 62/b 22/dquote # "a b" -2738 _test-slice-a-space-b-limit: -2739 -2740 _test-slice-a-dquote-b: -2741 22/dquote 61/a 5c/backslash 22/dquote 62/b 22/dquote # "a\"b" -2742 _test-slice-a-dquote-b-limit: -2743 -2744 _test-slice-a-newline-b: -2745 22/dquote 61/a 5c/backslash 6e/n 62/b 22/dquote # "a\nb" -2746 _test-slice-a-newline-b-limit: -2747 -2748 # "abc/def"/ghi -2749 _test-slice-literal-string: -2750 22/dquote -2751 61/a 62/b 63/c # abc -2752 2f/slash 64/d 65/e 66/f # /def -2753 22/dquote -2754 2f/slash 67/g 68/h 69/i # /ghi -2755 _test-slice-literal-string-with-limit: -2756 -2757 # . . vim:nowrap:textwidth=0 + 520 # (comment dropped for now) + 521 # == code 0x1 + 522 # (comment dropped for now) + 523 # 1 + 524 # (comment dropped for now) + 525 # 2 3 + 526 # == data 0x2 + 527 # 4 5/imm32 + 528 # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. + 529 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- + 555 # . check-next-stream-line-equal(_test-output-stream, "", msg) + 556 # . . push args + 557 68/push "F - test-convert-is-idempotent-by-default/0"/imm32 + 558 68/push ""/imm32 + 559 68/push _test-output-stream/imm32 + 560 # . . call + 561 e8/call check-next-stream-line-equal/disp32 + 562 # . . discard args + 563 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 564 # . check-next-stream-line-equal(_test-output-stream, "", msg) + 565 # . . push args + 566 68/push "F - test-convert-is-idempotent-by-default/1"/imm32 + 567 68/push ""/imm32 + 568 68/push _test-output-stream/imm32 + 569 # . . call + 570 e8/call check-next-stream-line-equal/disp32 + 571 # . . discard args + 572 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 573 # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) + 574 # . . push args + 575 68/push "F - test-convert-is-idempotent-by-default/2"/imm32 + 576 68/push "== code 0x1 "/imm32 + 577 68/push _test-output-stream/imm32 + 578 # . . call + 579 e8/call check-next-stream-line-equal/disp32 + 580 # . . discard args + 581 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 582 # . check-next-stream-line-equal(_test-output-stream, "", msg) + 583 # . . push args + 584 68/push "F - test-convert-is-idempotent-by-default/3"/imm32 + 585 68/push ""/imm32 + 586 68/push _test-output-stream/imm32 + 587 # . . call + 588 e8/call check-next-stream-line-equal/disp32 + 589 # . . discard args + 590 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 591 # . check-next-stream-line-equal(_test-output-stream, "1 ", msg) + 592 # . . push args + 593 68/push "F - test-convert-is-idempotent-by-default/4"/imm32 + 594 68/push "1 "/imm32 + 595 68/push _test-output-stream/imm32 + 596 # . . call + 597 e8/call check-next-stream-line-equal/disp32 + 598 # . . discard args + 599 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 600 # . check-next-stream-line-equal(_test-output-stream, "", msg) + 601 # . . push args + 602 68/push "F - test-convert-is-idempotent-by-default/5"/imm32 + 603 68/push ""/imm32 + 604 68/push _test-output-stream/imm32 + 605 # . . call + 606 e8/call check-next-stream-line-equal/disp32 + 607 # . . discard args + 608 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 609 # . check-next-stream-line-equal(_test-output-stream, "2 3 ", msg) + 610 # . . push args + 611 68/push "F - test-convert-is-idempotent-by-default/6"/imm32 + 612 68/push "2 3 "/imm32 + 613 68/push _test-output-stream/imm32 + 614 # . . call + 615 e8/call check-next-stream-line-equal/disp32 + 616 # . . discard args + 617 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 618 # . check-next-stream-line-equal(_test-output-stream, "== data 0x2 ", msg) + 619 # . . push args + 620 68/push "F - test-convert-is-idempotent-by-default/7"/imm32 + 621 68/push "== data 0x2 "/imm32 + 622 68/push _test-output-stream/imm32 + 623 # . . call + 624 e8/call check-next-stream-line-equal/disp32 + 625 # . . discard args + 626 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 627 # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32 ", msg) + 628 # . . push args + 629 68/push "F - test-convert-is-idempotent-by-default/8"/imm32 + 630 68/push "4 5/imm32 "/imm32 + 631 68/push _test-output-stream/imm32 + 632 # . . call + 633 e8/call check-next-stream-line-equal/disp32 + 634 # . . discard args + 635 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 636 # . epilog + 637 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 638 5d/pop-to-EBP + 639 c3/return + 640 + 641 test-convert-processes-string-literals: + 642 # . prolog + 643 55/push-EBP + 644 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 645 # setup + 646 # . clear-stream(_test-input-stream) + 647 # . . push args + 648 68/push _test-input-stream/imm32 + 649 # . . call + 650 e8/call clear-stream/disp32 + 651 # . . discard args + 652 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 653 # . clear-stream(_test-input-buffered-file+4) + 654 # . . push args + 655 b8/copy-to-EAX _test-input-buffered-file/imm32 + 656 05/add-to-EAX 4/imm32 + 657 50/push-EAX + 658 # . . call + 659 e8/call clear-stream/disp32 + 660 # . . discard args + 661 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 662 # . clear-stream(_test-output-stream) + 663 # . . push args + 664 68/push _test-output-stream/imm32 + 665 # . . call + 666 e8/call clear-stream/disp32 + 667 # . . discard args + 668 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 669 # . clear-stream(_test-output-buffered-file+4) + 670 # . . push args + 671 b8/copy-to-EAX _test-output-buffered-file/imm32 + 672 05/add-to-EAX 4/imm32 + 673 50/push-EAX + 674 # . . call + 675 e8/call clear-stream/disp32 + 676 # . . discard args + 677 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 678 # initialize input (meta comments in parens) + 679 # == code (new segment) + 680 # 1 "a"/x + 681 # 2 "bc"/y + 682 68/push "== code 0x1\n"/imm32 + 683 68/push _test-input-stream/imm32 + 684 # . . call + 685 e8/call write/disp32 + 686 # . . discard args + 687 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 688 # . write(_test-input-stream, "1 \"a\"/x\n") + 689 # . . push args + 690 68/push "1 \"a\"/x\n"/imm32 + 691 68/push _test-input-stream/imm32 + 692 # . . call + 693 e8/call write/disp32 + 694 # . . discard args + 695 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 696 # . write(_test-input-stream, "2 \"bc\"/y\n") + 697 # . . push args + 698 68/push "2 \"bc\"/y\n"/imm32 + 699 68/push _test-input-stream/imm32 + 700 # . . call + 701 e8/call write/disp32 + 702 # . . discard args + 703 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 704 # convert(_test-input-buffered-file, _test-output-buffered-file) + 705 # . . push args + 706 68/push _test-output-buffered-file/imm32 + 707 68/push _test-input-buffered-file/imm32 + 708 # . . call + 709 e8/call convert/disp32 + 710 # . . discard args + 711 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 712 # . flush(_test-output-buffered-file) + 713 # . . push args + 714 68/push _test-output-buffered-file/imm32 + 715 # . . call + 716 e8/call flush/disp32 + 717 # . . discard args + 718 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 719 # check output + 720 # == code 0x1 + 721 # 1 _string1/x + 722 # 2 _string2/y + 723 # == data + 724 # _string1: + 725 # 1/imm32 61/a + 726 # _string2: + 727 # 2/imm32 62/b 63/c + 728 # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. + 729 # + 730 # Open question: how to make this check more robust. + 731 # We don't actually care what the auto-generated string variables are + 732 # called. We just want to make sure instructions using string literals + 733 # switch to a string variable with the right value. + 734 # (Modifying string literals completely off the radar for now.) + 735 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- + 768 # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) + 769 # . . push args + 770 68/push "F - test-convert-processes-string-literals/0"/imm32 + 771 68/push "== code 0x1 "/imm32 + 772 68/push _test-output-stream/imm32 + 773 # . . call + 774 e8/call check-next-stream-line-equal/disp32 + 775 # . . discard args + 776 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 777 # . check-next-stream-line-equal(_test-output-stream, "1 _string1/x ", msg) + 778 # . . push args + 779 68/push "F - test-convert-processes-string-literals/1"/imm32 + 780 68/push "1 _string1/x "/imm32 + 781 68/push _test-output-stream/imm32 + 782 # . . call + 783 e8/call check-next-stream-line-equal/disp32 + 784 # . . discard args + 785 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 786 # . check-next-stream-line-equal(_test-output-stream, "2 _string2/y ", msg) + 787 # . . push args + 788 68/push "F - test-convert-processes-string-literals/2"/imm32 + 789 68/push "2 _string2/y "/imm32 + 790 68/push _test-output-stream/imm32 + 791 # . . call + 792 e8/call check-next-stream-line-equal/disp32 + 793 # . . discard args + 794 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 795 # . check-next-stream-line-equal(_test-output-stream, "== data", msg) + 796 # . . push args + 797 68/push "F - test-convert-processes-string-literals/3"/imm32 + 798 68/push "== data"/imm32 + 799 68/push _test-output-stream/imm32 + 800 # . . call + 801 e8/call check-next-stream-line-equal/disp32 + 802 # . . discard args + 803 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 804 # . check-next-stream-line-equal(_test-output-stream, "_string1: ", msg) + 805 # . . push args + 806 68/push "F - test-convert-processes-string-literals/4"/imm32 + 807 68/push "_string1:"/imm32 + 808 68/push _test-output-stream/imm32 + 809 # . . call + 810 e8/call check-next-stream-line-equal/disp32 + 811 # . . discard args + 812 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 813 # . check-next-stream-line-equal(_test-output-stream, "1/imm32 61/a ", msg) + 814 # . . push args + 815 68/push "F - test-convert-processes-string-literals/5"/imm32 + 816 68/push "0x00000001/imm32 61/a "/imm32 + 817 68/push _test-output-stream/imm32 + 818 # . . call + 819 e8/call check-next-stream-line-equal/disp32 + 820 # . . discard args + 821 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 822 # . check-next-stream-line-equal(_test-output-stream, "_string2: ", msg) + 823 # . . push args + 824 68/push "F - test-convert-processes-string-literals/6"/imm32 + 825 68/push "_string2:"/imm32 + 826 68/push _test-output-stream/imm32 + 827 # . . call + 828 e8/call check-next-stream-line-equal/disp32 + 829 # . . discard args + 830 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 831 # . check-next-stream-line-equal(_test-output-stream, "2/imm32 62/b 63/c ", msg) + 832 # . . push args + 833 68/push "F - test-convert-processes-string-literals/7"/imm32 + 834 68/push "0x00000002/imm32 62/b 63/c "/imm32 + 835 68/push _test-output-stream/imm32 + 836 # . . call + 837 e8/call check-next-stream-line-equal/disp32 + 838 # . . discard args + 839 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 840 # . epilog + 841 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 842 5d/pop-to-EBP + 843 c3/return + 844 + 845 # generate the data segment contents byte by byte for a given slice + 846 emit-string-literal-data: # out : (address stream), word : (address slice) + 847 # pseudocode + 848 # len = string-length-at-start-of-slice(word->start, word->end) + 849 # print(out, "#{len}/imm32 ") + 850 # curr = word->start + 851 # ++curr # skip '"' + 852 # while true + 853 # if (curr >= word->end) break + 854 # c = *curr + 855 # if (c == '"') break + 856 # if (c == '\') { + 857 # ++curr + 858 # c = *curr + 859 # if (c == 'n') + 860 # c = newline + 861 # } + 862 # append-byte-hex(out, c) + 863 # if c is alphanumeric: + 864 # write(out, "/") + 865 # append-byte(out, c) + 866 # write(out, " ") + 867 # ++curr + 868 # + 869 # . prolog + 870 55/push-EBP + 871 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 872 # . save registers + 873 50/push-EAX + 874 51/push-ECX + 875 52/push-EDX + 876 56/push-ESI + 877 # ESI = word + 878 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI + 879 # curr/EDX = word->start + 880 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX + 881 # max/ESI = word->end + 882 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI + 883 $emit-string-literal-data:emit-length: + 884 # len/EAX = string-length-at-start-of-slice(word->start, word->end) + 885 # . . push args + 886 56/push-ESI + 887 52/push-EDX + 888 # . . call + 889 e8/call string-length-at-start-of-slice/disp32 + 890 # . . discard args + 891 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 892 # print(out, "#{len}/imm32 ") + 893 # . print-int32(out, len) + 894 # . . push args + 895 50/push-EAX + 896 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 897 # . . call + 898 e8/call print-int32/disp32 + 899 # . . discard args + 900 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 901 # . write(out, "/imm32 ") + 902 # . . push args + 903 68/push "/imm32 "/imm32 + 904 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 905 # . . call + 906 e8/call write/disp32 + 907 # . . discard args + 908 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 909 $emit-string-literal-data:loop-init: + 910 # ++curr # skip initial '"' + 911 42/increment-EDX + 912 # c/ECX = 0 + 913 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX + 914 $emit-string-literal-data:loop: + 915 # if (curr >= max) break + 916 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI + 917 0f 83/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp32 + 918 # CL = *curr + 919 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL + 920 # if (c == '"') break + 921 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x22/imm32/dquote # compare ECX + 922 74/jump-if-equal $emit-string-literal-data:end/disp8 + 923 # if (c != '\') goto emit + 924 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x5c/imm32/backslash # compare ECX + 925 75/jump-if-not-equal $emit-string-literal-data:emit/disp8 + 926 # ++curr + 927 42/increment-EDX + 928 # if (curr >= max) break + 929 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI + 930 73/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp8 + 931 # c = *curr + 932 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL + 933 # if (c == 'n') c = newline + 934 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x6e/imm32/n # compare ECX + 935 75/jump-if-not-equal $emit-string-literal-data:emit/disp8 + 936 b9/copy-to-ECX 0x0a/imm32/newline + 937 $emit-string-literal-data:emit: + 938 # append-byte-hex(out, CL) + 939 # . . push args + 940 51/push-ECX + 941 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 942 # . . call + 943 e8/call append-byte-hex/disp32 + 944 # . . discard args + 945 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 946 # if (is-alphanumeric?(*curr)) print(out, "/#{*curr}") + 947 # . EAX = is-alphanumeric?(CL) + 948 # . . push args + 949 51/push-ECX + 950 # . . call + 951 e8/call is-alphanumeric?/disp32 + 952 # . . discard args + 953 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 954 # . if (EAX == 0) goto char-done + 955 3d/compare-EAX-and 0/imm32 + 956 74/jump-if-equal $emit-string-literal-data:char-done/disp8 + 957 # . write(out, "/") + 958 # . . push args + 959 68/push Slash/imm32 + 960 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 961 # . . call + 962 e8/call write/disp32 + 963 # . . discard args + 964 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 965 # . append-byte(out, *curr) + 966 # . . push args + 967 51/push-ECX + 968 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 969 # . . call + 970 e8/call append-byte/disp32 + 971 # . . discard args + 972 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 973 $emit-string-literal-data:char-done: + 974 # write(out, " ") + 975 # . . push args + 976 68/push Space/imm32 + 977 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 978 # . . call + 979 e8/call write/disp32 + 980 # . . discard args + 981 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 982 # ++curr + 983 42/increment-EDX + 984 e9/jump $emit-string-literal-data:loop/disp32 + 985 $emit-string-literal-data:end: + 986 # . restore registers + 987 5e/pop-to-ESI + 988 5a/pop-to-EDX + 989 59/pop-to-ECX + 990 58/pop-to-EAX + 991 # . epilog + 992 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 993 5d/pop-to-EBP + 994 c3/return + 995 + 996 is-alphanumeric?: # c : int -> EAX : boolean + 997 # . prolog + 998 55/push-EBP + 999 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1000 # EAX = c +1001 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX +1002 # if (EAX < '0') return false +1003 3d/compare-EAX-with 0x30/imm32/0 +1004 7c/jump-if-lesser $is-alphanumeric?:false/disp8 +1005 # if (EAX <= '9') return true +1006 3d/compare-EAX-with 0x39/imm32/9 +1007 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 +1008 # if (EAX < 'A') return false +1009 3d/compare-EAX-with 0x41/imm32/A +1010 7c/jump-if-lesser $is-alphanumeric?:false/disp8 +1011 # if (EAX <= 'Z') return true +1012 3d/compare-EAX-with 0x5a/imm32/Z +1013 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 +1014 # if (EAX < 'a') return false +1015 3d/compare-EAX-with 0x61/imm32/a +1016 7c/jump-if-lesser $is-alphanumeric?:false/disp8 +1017 # if (EAX <= 'z') return true +1018 3d/compare-EAX-with 0x7a/imm32/z +1019 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 +1020 # return false +1021 $is-alphanumeric?:false: +1022 b8/copy-to-EAX 0/imm32/false +1023 eb/jump $is-alphanumeric?:end/disp8 +1024 $is-alphanumeric?:true: +1025 b8/copy-to-EAX 1/imm32/true +1026 $is-alphanumeric?:end: +1027 # . epilog +1028 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1029 5d/pop-to-EBP +1030 c3/return +1031 +1032 test-emit-string-literal-data: +1033 # . prolog +1034 55/push-EBP +1035 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1036 # setup +1037 # . clear-stream(_test-output-stream) +1038 # . . push args +1039 68/push _test-output-stream/imm32 +1040 # . . call +1041 e8/call clear-stream/disp32 +1042 # . . discard args +1043 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1044 # var slice/ECX = '"abc"/d' +1045 68/push _test-slice-abc-limit/imm32 +1046 68/push _test-slice-abc/imm32 +1047 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1048 # emit-string-literal-data(_test-output-stream, slice) +1049 # . . push args +1050 51/push-ECX +1051 68/push _test-output-stream/imm32 +1052 # . . call +1053 e8/call emit-string-literal-data/disp32 +1054 # . . discard args +1055 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1056 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1082 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 62/b 63/c ", msg) +1083 # . . push args +1084 68/push "F - test-emit-string-literal-data"/imm32 +1085 68/push "0x00000003/imm32 61/a 62/b 63/c "/imm32 +1086 68/push _test-output-stream/imm32 +1087 # . . call +1088 e8/call check-stream-equal/disp32 +1089 # . . discard args +1090 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1091 # . epilog +1092 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1093 5d/pop-to-EBP +1094 c3/return +1095 +1096 test-emit-string-literal-data-empty: +1097 # . prolog +1098 55/push-EBP +1099 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1100 # setup +1101 # . clear-stream(_test-output-stream) +1102 # . . push args +1103 68/push _test-output-stream/imm32 +1104 # . . call +1105 e8/call clear-stream/disp32 +1106 # . . discard args +1107 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1108 # var slice/ECX = '""' +1109 68/push 0/imm32/end +1110 68/push 0/imm32/start +1111 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1112 # emit-string-literal-data(_test-output-stream, slice) +1113 # . . push args +1114 51/push-ECX +1115 68/push _test-output-stream/imm32 +1116 # . . call +1117 e8/call emit-string-literal-data/disp32 +1118 # . . discard args +1119 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1120 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1146 # . check-stream-equal(_test-output-stream, "0/imm32 ", msg) +1147 # . . push args +1148 68/push "F - test-emit-string-literal-data-empty"/imm32 +1149 68/push "0x00000000/imm32 "/imm32 +1150 68/push _test-output-stream/imm32 +1151 # . . call +1152 e8/call check-stream-equal/disp32 +1153 # . . discard args +1154 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1155 # . epilog +1156 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1157 5d/pop-to-EBP +1158 c3/return +1159 +1160 # just to keep things simple +1161 test-emit-string-literal-data-no-metadata-for-non-alphanumerics: +1162 # . prolog +1163 55/push-EBP +1164 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1165 # setup +1166 # . clear-stream(_test-output-stream) +1167 # . . push args +1168 68/push _test-output-stream/imm32 +1169 # . . call +1170 e8/call clear-stream/disp32 +1171 # . . discard args +1172 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1173 # var slice/ECX = '"a b"' +1174 68/push _test-slice-a-space-b-limit/imm32 +1175 68/push _test-slice-a-space-b/imm32 +1176 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1177 # emit-string-literal-data(_test-output-stream, slice) +1178 # . . push args +1179 51/push-ECX +1180 68/push _test-output-stream/imm32 +1181 # . . call +1182 e8/call emit-string-literal-data/disp32 +1183 # . . discard args +1184 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1185 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1211 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints +1212 # . . push args +1213 68/push "F - test-emit-string-literal-data-no-metadata-for-non-alphanumerics"/imm32 +1214 68/push "0x00000003/imm32 61/a 20 62/b "/imm32 +1215 68/push _test-output-stream/imm32 +1216 # . . call +1217 e8/call check-stream-equal/disp32 +1218 # . . discard args +1219 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1220 # . epilog +1221 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1222 5d/pop-to-EBP +1223 c3/return +1224 +1225 test-emit-string-literal-data-handles-escape-sequences: +1226 # . prolog +1227 55/push-EBP +1228 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1229 # setup +1230 # . clear-stream(_test-output-stream) +1231 # . . push args +1232 68/push _test-output-stream/imm32 +1233 # . . call +1234 e8/call clear-stream/disp32 +1235 # . . discard args +1236 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1237 # var slice/ECX = '"a\"b"' +1238 68/push _test-slice-a-dquote-b-limit/imm32 +1239 68/push _test-slice-a-dquote-b/imm32 +1240 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1241 # emit-string-literal-data(_test-output-stream, slice) +1242 # . . push args +1243 51/push-ECX +1244 68/push _test-output-stream/imm32 +1245 # . . call +1246 e8/call emit-string-literal-data/disp32 +1247 # . . discard args +1248 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1249 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1275 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 22 62/b ", msg) +1276 # . . push args +1277 68/push "F - test-emit-string-literal-data-handles-escape-sequences"/imm32 +1278 68/push "0x00000003/imm32 61/a 22 62/b "/imm32 +1279 68/push _test-output-stream/imm32 +1280 # . . call +1281 e8/call check-stream-equal/disp32 +1282 # . . discard args +1283 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1284 # . epilog +1285 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1286 5d/pop-to-EBP +1287 c3/return +1288 +1289 test-emit-string-literal-data-handles-newline-escape: +1290 # . prolog +1291 55/push-EBP +1292 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1293 # setup +1294 # . clear-stream(_test-output-stream) +1295 # . . push args +1296 68/push _test-output-stream/imm32 +1297 # . . call +1298 e8/call clear-stream/disp32 +1299 # . . discard args +1300 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1301 # var slice/ECX = '"a\nb"' +1302 68/push _test-slice-a-newline-b-limit/imm32 +1303 68/push _test-slice-a-newline-b/imm32 +1304 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1305 # emit-string-literal-data(_test-output-stream, slice) +1306 # . . push args +1307 51/push-ECX +1308 68/push _test-output-stream/imm32 +1309 # . . call +1310 e8/call emit-string-literal-data/disp32 +1311 # . . discard args +1312 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1313 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1339 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 0a 62/b ", msg) +1340 # . . push args +1341 68/push "F - test-emit-string-literal-data-handles-newline-escape"/imm32 +1342 68/push "0x00000003/imm32 61/a 0a 62/b "/imm32 +1343 68/push _test-output-stream/imm32 +1344 # . . call +1345 e8/call check-stream-equal/disp32 +1346 # . . discard args +1347 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1348 # . epilog +1349 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1350 5d/pop-to-EBP +1351 c3/return +1352 +1353 # emit everything from a word except the initial datum +1354 emit-metadata: # out : (address buffered-file), word : (address slice) +1355 # pseudocode +1356 # var slice = {0, word->end} +1357 # curr = word->start +1358 # if *curr == '"' +1359 # curr = skip-string-in-slice(curr, word->end) +1360 # else +1361 # while true +1362 # if curr == word->end +1363 # return +1364 # if *curr == '/' +1365 # break +1366 # ++curr +1367 # slice->start = curr +1368 # write-slice-buffered(out, slice) +1369 # +1370 # . prolog +1371 55/push-EBP +1372 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1373 # . save registers +1374 50/push-EAX +1375 51/push-ECX +1376 52/push-EDX +1377 53/push-EBX +1378 56/push-ESI +1379 # ESI = word +1380 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI +1381 # curr/ECX = word->start +1382 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX +1383 # end/EDX = word->end +1384 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 4/disp8 . # copy *(ESI+4) to EDX +1385 # var slice/EBX = {0, end} +1386 52/push-EDX +1387 68/push 0/imm32 +1388 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX +1389 # EAX = 0 +1390 b8/copy-to-EAX 0/imm32 +1391 $emit-metadata:check-for-string-literal: +1392 # - if (*curr == '"') curr = skip-string-in-slice(curr, end) +1393 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL +1394 3d/compare-EAX-and 0x22/imm32/dquote +1395 75/jump-if-not-equal $emit-metadata:skip-datum-loop/disp8 +1396 $emit-metadata:skip-string-literal: +1397 # . EAX = skip-string-in-slice(curr, end) +1398 # . . push args +1399 52/push-EDX +1400 51/push-ECX +1401 # . . call +1402 e8/call skip-string-in-slice/disp32 +1403 # . . discard args +1404 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1405 # . curr = EAX +1406 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX +1407 eb/jump $emit-metadata:emit/disp8 +1408 $emit-metadata:skip-datum-loop: +1409 # - otherwise scan for '/' +1410 # if (curr == end) return +1411 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX and EDX +1412 74/jump-if-equal $emit-metadata:end/disp8 +1413 # if (*curr == '/') break +1414 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL +1415 3d/compare-EAX-and 0x2f/imm32/slash +1416 74/jump-if-equal $emit-metadata:emit/disp8 +1417 # ++curr +1418 41/increment-ECX +1419 eb/jump $emit-metadata:skip-datum-loop/disp8 +1420 $emit-metadata:emit: +1421 # slice->start = ECX +1422 89/copy 0/mod/indirect 3/rm32/EBX . . . 1/r32/ECX . . # copy ECX to *EBX +1423 # write-slice-buffered(out, slice) +1424 # . . push args +1425 53/push-EBX +1426 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1427 # . . call +1428 e8/call write-slice-buffered/disp32 +1429 # . . discard args +1430 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . 8/imm32 . # add to ESP +1431 $emit-metadata:end: +1432 # . reclaim locals +1433 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . 8/imm32 . # add to ESP +1434 # . restore registers +1435 5e/pop-to-ESI +1436 5b/pop-to-EBX +1437 5a/pop-to-EDX +1438 59/pop-to-ECX +1439 58/pop-to-EAX +1440 # . epilog +1441 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1442 5d/pop-to-EBP +1443 c3/return +1444 +1445 test-emit-metadata: +1446 # . prolog +1447 55/push-EBP +1448 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1449 # setup +1450 # . clear-stream(_test-output-stream) +1451 # . . push args +1452 68/push _test-output-stream/imm32 +1453 # . . call +1454 e8/call clear-stream/disp32 +1455 # . . discard args +1456 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1457 # . clear-stream(_test-output-buffered-file+4) +1458 # . . push args +1459 b8/copy-to-EAX _test-output-buffered-file/imm32 +1460 05/add-to-EAX 4/imm32 +1461 50/push-EAX +1462 # . . call +1463 e8/call clear-stream/disp32 +1464 # . . discard args +1465 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1466 # (EAX..ECX) = "abc/def" +1467 b8/copy-to-EAX "abc/def"/imm32 +1468 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1469 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1470 05/add-to-EAX 4/imm32 +1471 # var slice/ECX = {EAX, ECX} +1472 51/push-ECX +1473 50/push-EAX +1474 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1475 # emit-metadata(_test-output-buffered-file, slice) +1476 # . . push args +1477 51/push-ECX +1478 68/push _test-output-buffered-file/imm32 +1479 # . . call +1480 e8/call emit-metadata/disp32 +1481 # . . discard args +1482 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1483 # flush(_test-output-buffered-file) +1484 # . . push args +1485 68/push _test-output-buffered-file/imm32 +1486 # . . call +1487 e8/call flush/disp32 +1488 # . . discard args +1489 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1490 # check-stream-equal(_test-output-stream, "/def", msg) # important that there's no leading space +1491 # . . push args +1492 68/push "F - test-emit-metadata"/imm32 +1493 68/push "/def"/imm32 +1494 68/push _test-output-stream/imm32 +1495 # . . call +1496 e8/call check-stream-equal/disp32 +1497 # . . discard args +1498 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1499 # . epilog +1500 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1501 5d/pop-to-EBP +1502 c3/return +1503 +1504 test-emit-metadata-none: +1505 # . prolog +1506 55/push-EBP +1507 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1508 # setup +1509 # . clear-stream(_test-output-stream) +1510 # . . push args +1511 68/push _test-output-stream/imm32 +1512 # . . call +1513 e8/call clear-stream/disp32 +1514 # . . discard args +1515 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1516 # . clear-stream(_test-output-buffered-file+4) +1517 # . . push args +1518 b8/copy-to-EAX _test-output-buffered-file/imm32 +1519 05/add-to-EAX 4/imm32 +1520 50/push-EAX +1521 # . . call +1522 e8/call clear-stream/disp32 +1523 # . . discard args +1524 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1525 # (EAX..ECX) = "abc" +1526 b8/copy-to-EAX "abc"/imm32 +1527 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1528 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1529 05/add-to-EAX 4/imm32 +1530 # var slice/ECX = {EAX, ECX} +1531 51/push-ECX +1532 50/push-EAX +1533 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1534 # emit-metadata(_test-output-buffered-file, slice) +1535 # . . push args +1536 51/push-ECX +1537 68/push _test-output-buffered-file/imm32 +1538 # . . call +1539 e8/call emit-metadata/disp32 +1540 # . . discard args +1541 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1542 # flush(_test-output-buffered-file) +1543 # . . push args +1544 68/push _test-output-buffered-file/imm32 +1545 # . . call +1546 e8/call flush/disp32 +1547 # . . discard args +1548 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1549 # check-stream-equal(_test-output-stream, "", msg) +1550 # . . push args +1551 68/push "F - test-emit-metadata-none"/imm32 +1552 68/push ""/imm32 +1553 68/push _test-output-stream/imm32 +1554 # . . call +1555 e8/call check-stream-equal/disp32 +1556 # . . discard args +1557 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1558 # . epilog +1559 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1560 5d/pop-to-EBP +1561 c3/return +1562 +1563 test-emit-metadata-multiple: +1564 # . prolog +1565 55/push-EBP +1566 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1567 # setup +1568 # . clear-stream(_test-output-stream) +1569 # . . push args +1570 68/push _test-output-stream/imm32 +1571 # . . call +1572 e8/call clear-stream/disp32 +1573 # . . discard args +1574 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1575 # . clear-stream(_test-output-buffered-file+4) +1576 # . . push args +1577 b8/copy-to-EAX _test-output-buffered-file/imm32 +1578 05/add-to-EAX 4/imm32 +1579 50/push-EAX +1580 # . . call +1581 e8/call clear-stream/disp32 +1582 # . . discard args +1583 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1584 # (EAX..ECX) = "abc/def/ghi" +1585 b8/copy-to-EAX "abc/def/ghi"/imm32 +1586 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1587 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1588 05/add-to-EAX 4/imm32 +1589 # var slice/ECX = {EAX, ECX} +1590 51/push-ECX +1591 50/push-EAX +1592 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1593 # emit-metadata(_test-output-buffered-file, slice) +1594 # . . push args +1595 51/push-ECX +1596 68/push _test-output-buffered-file/imm32 +1597 # . . call +1598 e8/call emit-metadata/disp32 +1599 # . . discard args +1600 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1601 # flush(_test-output-buffered-file) +1602 # . . push args +1603 68/push _test-output-buffered-file/imm32 +1604 # . . call +1605 e8/call flush/disp32 +1606 # . . discard args +1607 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1608 # check-stream-equal(_test-output-stream, "/def/ghi", msg) # important that there's no leading space +1609 # . . push args +1610 68/push "F - test-emit-metadata-multiple"/imm32 +1611 68/push "/def/ghi"/imm32 +1612 68/push _test-output-stream/imm32 +1613 # . . call +1614 e8/call check-stream-equal/disp32 +1615 # . . discard args +1616 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1617 # . epilog +1618 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1619 5d/pop-to-EBP +1620 c3/return +1621 +1622 test-emit-metadata-when-no-datum: +1623 # . prolog +1624 55/push-EBP +1625 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1626 # setup +1627 # . clear-stream(_test-output-stream) +1628 # . . push args +1629 68/push _test-output-stream/imm32 +1630 # . . call +1631 e8/call clear-stream/disp32 +1632 # . . discard args +1633 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1634 # . clear-stream(_test-output-buffered-file+4) +1635 # . . push args +1636 b8/copy-to-EAX _test-output-buffered-file/imm32 +1637 05/add-to-EAX 4/imm32 +1638 50/push-EAX +1639 # . . call +1640 e8/call clear-stream/disp32 +1641 # . . discard args +1642 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1643 # var slice/ECX = "/abc" +1644 b8/copy-to-EAX "/abc"/imm32 +1645 # . push end/ECX +1646 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1647 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1648 51/push-ECX +1649 # . push curr/EAX +1650 05/add-to-EAX 4/imm32 +1651 50/push-EAX +1652 # . save stack pointer +1653 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1654 # emit-metadata(_test-output-buffered-file, slice) +1655 # . . push args +1656 51/push-ECX +1657 68/push _test-output-buffered-file/imm32 +1658 # . . call +1659 e8/call emit-metadata/disp32 +1660 # . . discard args +1661 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1662 # flush(_test-output-buffered-file) +1663 # . . push args +1664 68/push _test-output-buffered-file/imm32 +1665 # . . call +1666 e8/call flush/disp32 +1667 # . . discard args +1668 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1669 # check-stream-equal(_test-output-stream, "/abc", msg) # nothing skipped +1670 # . . push args +1671 68/push "F - test-emit-metadata-when-no-datum"/imm32 +1672 68/push "/abc"/imm32 +1673 68/push _test-output-stream/imm32 +1674 # . . call +1675 e8/call check-stream-equal/disp32 +1676 # . . discard args +1677 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1678 # . epilog +1679 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1680 5d/pop-to-EBP +1681 c3/return +1682 +1683 test-emit-metadata-in-string-literal: +1684 # . prolog +1685 55/push-EBP +1686 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1687 # setup +1688 # . clear-stream(_test-output-stream) +1689 # . . push args +1690 68/push _test-output-stream/imm32 +1691 # . . call +1692 e8/call clear-stream/disp32 +1693 # . . discard args +1694 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1695 # . clear-stream(_test-output-buffered-file+4) +1696 # . . push args +1697 b8/copy-to-EAX _test-output-buffered-file/imm32 +1698 05/add-to-EAX 4/imm32 +1699 50/push-EAX +1700 # . . call +1701 e8/call clear-stream/disp32 +1702 # . . discard args +1703 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1704 # var slice/ECX = "\"abc/def\"/ghi" +1705 68/push _test-slice-literal-string-with-limit/imm32 +1706 68/push _test-slice-literal-string/imm32/start +1707 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1708 # emit-metadata(_test-output-buffered-file, slice) +1709 # . . push args +1710 51/push-ECX +1711 68/push _test-output-buffered-file/imm32 +1712 # . . call +1713 e8/call emit-metadata/disp32 +1714 # . . discard args +1715 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1716 # flush(_test-output-buffered-file) +1717 # . . push args +1718 68/push _test-output-buffered-file/imm32 +1719 # . . call +1720 e8/call flush/disp32 +1721 # . . discard args +1722 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1723 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1749 # check-stream-equal(_test-output-stream, "/ghi", msg) # important that there's no leading space +1750 # . . push args +1751 68/push "F - test-emit-metadata-in-string-literal"/imm32 +1752 68/push "/ghi"/imm32 +1753 68/push _test-output-stream/imm32 +1754 # . . call +1755 e8/call check-stream-equal/disp32 +1756 # . . discard args +1757 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1758 # . epilog +1759 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1760 5d/pop-to-EBP +1761 c3/return +1762 +1763 # (re)compute the bounds of the next word or string literal in the line +1764 # return empty string on reaching end of file +1765 next-word-or-string: # line : (address stream byte), out : (address slice) +1766 # . prolog +1767 55/push-EBP +1768 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1769 # . save registers +1770 50/push-EAX +1771 51/push-ECX +1772 56/push-ESI +1773 57/push-EDI +1774 # ESI = line +1775 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +1776 # EDI = out +1777 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI +1778 # skip-chars-matching(line, ' ') +1779 # . . push args +1780 68/push 0x20/imm32/space +1781 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1782 # . . call +1783 e8/call skip-chars-matching/disp32 +1784 # . . discard args +1785 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1786 $next-word-or-string:check0: +1787 # if (line->read >= line->write) clear out and return +1788 # . EAX = line->read +1789 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX +1790 # . if (EAX < line->write) goto next check +1791 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI +1792 7c/jump-if-lesser $next-word-or-string:check-for-comment/disp8 +1793 # . return out = {0, 0} +1794 c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI +1795 c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) +1796 eb/jump $next-word-or-string:end/disp8 +1797 $next-word-or-string:check-for-comment: +1798 # out->start = &line->data[line->read] +1799 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX +1800 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX +1801 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI +1802 # if (line->data[line->read] != '#') goto next check +1803 # . EAX = line->data[line->read] +1804 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +1805 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL +1806 # . compare +1807 3d/compare-EAX-and 0x23/imm32/pound +1808 75/jump-if-not-equal $next-word-or-string:check-for-string-literal/disp8 +1809 $next-word-or-string:comment: +1810 # out->end = &line->data[line->write] +1811 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX +1812 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX +1813 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) +1814 # line->read = line->write # skip rest of line +1815 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX +1816 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) +1817 # return +1818 eb/jump $next-word-or-string:end/disp8 +1819 $next-word-or-string:check-for-string-literal: +1820 # if (line->data[line->read] != '"') goto next check +1821 # . EAX = line->data[line->read] +1822 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +1823 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL +1824 # . compare +1825 3d/compare-EAX-and 0x22/imm32/dquote +1826 75/jump-if-not-equal $next-word-or-string:regular-word/disp8 +1827 $next-word-or-string:string-literal: +1828 # skip-string(line) +1829 # . . push args +1830 56/push-ESI +1831 # . . call +1832 e8/call skip-string/disp32 +1833 # . . discard args +1834 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1835 # fall through +1836 $next-word-or-string:regular-word: +1837 # skip-chars-not-matching-whitespace(line) # including trailing newline +1838 # . . push args +1839 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1840 # . . call +1841 e8/call skip-chars-not-matching-whitespace/disp32 +1842 # . . discard args +1843 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1844 # out->end = &line->data[line->read] +1845 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX +1846 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX +1847 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) +1848 $next-word-or-string:end: +1849 # . restore registers +1850 5f/pop-to-EDI +1851 5e/pop-to-ESI +1852 59/pop-to-ECX +1853 58/pop-to-EAX +1854 # . epilog +1855 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1856 5d/pop-to-EBP +1857 c3/return +1858 +1859 test-next-word-or-string: +1860 # . prolog +1861 55/push-EBP +1862 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1863 # setup +1864 # . clear-stream(_test-input-stream) +1865 # . . push args +1866 68/push _test-input-stream/imm32 +1867 # . . call +1868 e8/call clear-stream/disp32 +1869 # . . discard args +1870 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1871 # var slice/ECX = {0, 0} +1872 68/push 0/imm32/end +1873 68/push 0/imm32/start +1874 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1875 # write(_test-input-stream, " ab") +1876 # . . push args +1877 68/push " ab"/imm32 +1878 68/push _test-input-stream/imm32 +1879 # . . call +1880 e8/call write/disp32 +1881 # . . discard args +1882 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1883 # next-word-or-string(_test-input-stream, slice) +1884 # . . push args +1885 51/push-ECX +1886 68/push _test-input-stream/imm32 +1887 # . . call +1888 e8/call next-word-or-string/disp32 +1889 # . . discard args +1890 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1891 # check-ints-equal(_test-input-stream->read, 4, msg) +1892 # . . push args +1893 68/push "F - test-next-word-or-string/updates-stream-read-correctly"/imm32 +1894 68/push 4/imm32 +1895 b8/copy-to-EAX _test-input-stream/imm32 +1896 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +1897 # . . call +1898 e8/call check-ints-equal/disp32 +1899 # . . discard args +1900 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1901 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) +1902 # . check-ints-equal(slice->start - _test-input-stream, 14, msg) +1903 # . . push args +1904 68/push "F - test-next-word-or-string: start"/imm32 +1905 68/push 0xe/imm32 +1906 # . . push slice->start - _test-input-stream +1907 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX +1908 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +1909 50/push-EAX +1910 # . . call +1911 e8/call check-ints-equal/disp32 +1912 # . . discard args +1913 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1914 # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) +1915 # . check-ints-equal(slice->end - _test-input-stream, 16, msg) +1916 # . . push args +1917 68/push "F - test-next-word-or-string: end"/imm32 +1918 68/push 0x10/imm32 +1919 # . . push slice->end - _test-input-stream +1920 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +1921 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +1922 50/push-EAX +1923 # . . call +1924 e8/call check-ints-equal/disp32 +1925 # . . discard args +1926 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1927 # . epilog +1928 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1929 5d/pop-to-EBP +1930 c3/return +1931 +1932 test-next-word-or-string-returns-whole-comment: +1933 # . prolog +1934 55/push-EBP +1935 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1936 # setup +1937 # . clear-stream(_test-input-stream) +1938 # . . push args +1939 68/push _test-input-stream/imm32 +1940 # . . call +1941 e8/call clear-stream/disp32 +1942 # . . discard args +1943 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1944 # var slice/ECX = {0, 0} +1945 68/push 0/imm32/end +1946 68/push 0/imm32/start +1947 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1948 # write(_test-input-stream, " # a") +1949 # . . push args +1950 68/push " # a"/imm32 +1951 68/push _test-input-stream/imm32 +1952 # . . call +1953 e8/call write/disp32 +1954 # . . discard args +1955 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1956 # next-word-or-string(_test-input-stream, slice) +1957 # . . push args +1958 51/push-ECX +1959 68/push _test-input-stream/imm32 +1960 # . . call +1961 e8/call next-word-or-string/disp32 +1962 # . . discard args +1963 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1964 # check-ints-equal(_test-input-stream->read, 5, msg) +1965 # . . push args +1966 68/push "F - test-next-word-or-string-returns-whole-comment/updates-stream-read-correctly"/imm32 +1967 68/push 5/imm32 +1968 b8/copy-to-EAX _test-input-stream/imm32 +1969 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +1970 # . . call +1971 e8/call check-ints-equal/disp32 +1972 # . . discard args +1973 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1974 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) +1975 # . check-ints-equal(slice->start - _test-input-stream, 14, msg) +1976 # . . push args +1977 68/push "F - test-next-word-or-string-returns-whole-comment: start"/imm32 +1978 68/push 0xe/imm32 +1979 # . . push slice->start - _test-input-stream +1980 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX +1981 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +1982 50/push-EAX +1983 # . . call +1984 e8/call check-ints-equal/disp32 +1985 # . . discard args +1986 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1987 # check-ints-equal(slice->end - _test-input-stream->data, 5, msg) +1988 # . check-ints-equal(slice->end - _test-input-stream, 17, msg) +1989 # . . push args +1990 68/push "F - test-next-word-or-string-returns-whole-comment: end"/imm32 +1991 68/push 0x11/imm32 +1992 # . . push slice->end - _test-input-stream +1993 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +1994 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +1995 50/push-EAX +1996 # . . call +1997 e8/call check-ints-equal/disp32 +1998 # . . discard args +1999 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2000 # . epilog +2001 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2002 5d/pop-to-EBP +2003 c3/return +2004 +2005 test-next-word-or-string-returns-empty-string-on-eof: +2006 # . prolog +2007 55/push-EBP +2008 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2009 # setup +2010 # . clear-stream(_test-input-stream) +2011 # . . push args +2012 68/push _test-input-stream/imm32 +2013 # . . call +2014 e8/call clear-stream/disp32 +2015 # . . discard args +2016 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2017 # var slice/ECX = {0, 0} +2018 68/push 0/imm32/end +2019 68/push 0/imm32/start +2020 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2021 # write nothing to _test-input-stream +2022 # next-word-or-string(_test-input-stream, slice) +2023 # . . push args +2024 51/push-ECX +2025 68/push _test-input-stream/imm32 +2026 # . . call +2027 e8/call next-word-or-string/disp32 +2028 # . . discard args +2029 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2030 # check-ints-equal(slice->end - slice->start, 0, msg) +2031 # . . push args +2032 68/push "F - test-next-word-or-string-returns-empty-string-on-eof"/imm32 +2033 68/push 0/imm32 +2034 # . . push slice->end - slice->start +2035 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +2036 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX +2037 50/push-EAX +2038 # . . call +2039 e8/call check-ints-equal/disp32 +2040 # . . discard args +2041 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2042 # . epilog +2043 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2044 5d/pop-to-EBP +2045 c3/return +2046 +2047 test-next-word-or-string-returns-whole-string: +2048 # . prolog +2049 55/push-EBP +2050 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2051 # setup +2052 # . clear-stream(_test-input-stream) +2053 # . . push args +2054 68/push _test-input-stream/imm32 +2055 # . . call +2056 e8/call clear-stream/disp32 +2057 # . . discard args +2058 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2059 # var slice/ECX = {0, 0} +2060 68/push 0/imm32/end +2061 68/push 0/imm32/start +2062 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2063 # write(_test-input-stream, " \"a b\"/imm32 ") +2064 # . . push args +2065 68/push " \"a b\"/imm32 "/imm32 +2066 68/push _test-input-stream/imm32 +2067 # . . call +2068 e8/call write/disp32 +2069 # . . discard args +2070 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2071 # next-word-or-string(_test-input-stream, slice) +2072 # . . push args +2073 51/push-ECX +2074 68/push _test-input-stream/imm32 +2075 # . . call +2076 e8/call next-word-or-string/disp32 +2077 # . . discard args +2078 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2079 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) +2080 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) +2081 # . . push args +2082 68/push "F - test-next-word-or-string-returns-whole-string: start"/imm32 +2083 68/push 0xd/imm32 +2084 # . . push slice->start - _test-input-stream +2085 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX +2086 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +2087 50/push-EAX +2088 # . . call +2089 e8/call check-ints-equal/disp32 +2090 # . . discard args +2091 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2092 # check-ints-equal(slice->end - _test-input-stream->data, 12, msg) +2093 # . check-ints-equal(slice->end - _test-input-stream, 24, msg) +2094 # . . push args +2095 68/push "F - test-next-word-or-string-returns-whole-string: end"/imm32 +2096 68/push 0x18/imm32 +2097 # . . push slice->end - _test-input-stream +2098 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +2099 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +2100 50/push-EAX +2101 # . . call +2102 e8/call check-ints-equal/disp32 +2103 # . . discard args +2104 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2105 # . epilog +2106 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2107 5d/pop-to-EBP +2108 c3/return +2109 +2110 test-next-word-or-string-returns-string-with-escapes: +2111 # . prolog +2112 55/push-EBP +2113 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2114 # setup +2115 # . clear-stream(_test-input-stream) +2116 # . . push args +2117 68/push _test-input-stream/imm32 +2118 # . . call +2119 e8/call clear-stream/disp32 +2120 # . . discard args +2121 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2122 # var slice/ECX = {0, 0} +2123 68/push 0/imm32/end +2124 68/push 0/imm32/start +2125 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2126 # write(_test-input-stream, " \"a\\\"b\"/x") +2127 # . . push args +2128 68/push " \"a\\\"b\"/x"/imm32 +2129 68/push _test-input-stream/imm32 +2130 # . . call +2131 e8/call write/disp32 +2132 # . . discard args +2133 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2134 # next-word-or-string(_test-input-stream, slice) +2135 # . . push args +2136 51/push-ECX +2137 68/push _test-input-stream/imm32 +2138 # . . call +2139 e8/call next-word-or-string/disp32 +2140 # . . discard args +2141 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2142 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) +2143 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) +2144 # . . push args +2145 68/push "F - test-next-word-or-string-returns-string-with-escapes: start"/imm32 +2146 68/push 0xd/imm32 +2147 # . . push slice->start - _test-input-stream +2148 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX +2149 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +2150 50/push-EAX +2151 # . . call +2152 e8/call check-ints-equal/disp32 +2153 # . . discard args +2154 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2155 # check-ints-equal(slice->end - _test-input-stream->data, 9, msg) +2156 # . check-ints-equal(slice->end - _test-input-stream, 21, msg) +2157 # . . push args +2158 68/push "F - test-next-word-or-string-returns-string-with-escapes: end"/imm32 +2159 68/push 0x15/imm32 +2160 # . . push slice->end - _test-input-stream +2161 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +2162 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX +2163 50/push-EAX +2164 # . . call +2165 e8/call check-ints-equal/disp32 +2166 # . . discard args +2167 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2168 # . epilog +2169 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2170 5d/pop-to-EBP +2171 c3/return +2172 +2173 # update line->read to end of string literal surrounded by double quotes +2174 # line->read must start out at a double-quote +2175 skip-string: # line : (address stream) +2176 # . prolog +2177 55/push-EBP +2178 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2179 # . save registers +2180 50/push-EAX +2181 51/push-ECX +2182 52/push-EDX +2183 # ECX = line +2184 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX +2185 # EAX = skip-string-in-slice(&line->data[line->read], &line->data[line->write]) +2186 # . . push &line->data[line->write] +2187 8b/copy 1/mod/*+disp8 1/rm32/ECX . . 2/r32/EDX 8/disp8 . # copy *(ECX+8) to EDX +2188 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ECX+EDX+12 to EDX +2189 52/push-EDX +2190 # . . push &line->data[line->read] +2191 8b/copy 1/mod/*+disp8 1/rm32/ECX . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX +2192 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ECX+EDX+12 to EDX +2193 52/push-EDX +2194 # . . call +2195 e8/call skip-string-in-slice/disp32 +2196 # . . discard args +2197 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2198 # line->read = EAX - line->data +2199 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX +2200 2d/subtract-from-EAX 0xc/imm32 +2201 89/copy 1/mod/*+disp8 1/rm32/ECX . . 0/r32/EAX 4/disp8 . # copy EAX to *(ECX+4) +2202 $skip-string:end: +2203 # . restore registers +2204 5a/pop-to-EDX +2205 59/pop-to-ECX +2206 58/pop-to-EAX +2207 # . epilog +2208 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2209 5d/pop-to-EBP +2210 c3/return +2211 +2212 test-skip-string: +2213 # . prolog +2214 55/push-EBP +2215 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2216 # setup +2217 # . clear-stream(_test-input-stream) +2218 # . . push args +2219 68/push _test-input-stream/imm32 +2220 # . . call +2221 e8/call clear-stream/disp32 +2222 # . . discard args +2223 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2224 # . write(_test-input-stream, "\"abc\" def") +2225 # . indices: 0123 45 +2226 # . . push args +2227 68/push "\"abc\" def"/imm32 +2228 68/push _test-input-stream/imm32 +2229 # . . call +2230 e8/call write/disp32 +2231 # . . discard args +2232 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2233 # precondition: line->read == 0 +2234 # . . push args +2235 68/push "F - test-skip-string/precondition"/imm32 +2236 68/push 0/imm32 +2237 b8/copy-to-EAX _test-input-stream/imm32 +2238 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +2239 # . . call +2240 e8/call check-ints-equal/disp32 +2241 # . . discard args +2242 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2243 # skip-string(_test-input-stream) +2244 # . . push args +2245 68/push _test-input-stream/imm32 +2246 # . . call +2247 e8/call skip-string/disp32 +2248 # . . discard args +2249 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2250 # check-ints-equal(line->read, 5, msg) +2251 # . . push args +2252 68/push "F - test-skip-string"/imm32 +2253 68/push 5/imm32 +2254 b8/copy-to-EAX _test-input-stream/imm32 +2255 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +2256 # . . call +2257 e8/call check-ints-equal/disp32 +2258 # . . discard args +2259 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2260 # . epilog +2261 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2262 5d/pop-to-EBP +2263 c3/return +2264 +2265 test-skip-string-ignores-spaces: +2266 # . prolog +2267 55/push-EBP +2268 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2269 # setup +2270 # . clear-stream(_test-input-stream) +2271 # . . push args +2272 68/push _test-input-stream/imm32 +2273 # . . call +2274 e8/call clear-stream/disp32 +2275 # . . discard args +2276 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2277 # . write(_test-input-stream, "\"a b\"/yz") +2278 # . indices: 0123 45 +2279 # . . push args +2280 68/push "\"a b\"/yz"/imm32 +2281 68/push _test-input-stream/imm32 +2282 # . . call +2283 e8/call write/disp32 +2284 # . . discard args +2285 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2286 # precondition: line->read == 0 +2287 # . . push args +2288 68/push "F - test-skip-string-ignores-spaces/precondition"/imm32 +2289 68/push 0/imm32 +2290 b8/copy-to-EAX _test-input-stream/imm32 +2291 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +2292 # . . call +2293 e8/call check-ints-equal/disp32 +2294 # . . discard args +2295 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2296 # skip-string(_test-input-stream) +2297 # . . push args +2298 68/push _test-input-stream/imm32 +2299 # . . call +2300 e8/call skip-string/disp32 +2301 # . . discard args +2302 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2303 # check-ints-equal(line->read, 5, msg) +2304 # . . push args +2305 68/push "F - test-skip-string-ignores-spaces"/imm32 +2306 68/push 5/imm32 +2307 b8/copy-to-EAX _test-input-stream/imm32 +2308 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +2309 # . . call +2310 e8/call check-ints-equal/disp32 +2311 # . . discard args +2312 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2313 # . epilog +2314 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2315 5d/pop-to-EBP +2316 c3/return +2317 +2318 test-skip-string-ignores-escapes: +2319 # . prolog +2320 55/push-EBP +2321 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2322 # setup +2323 # . clear-stream(_test-input-stream) +2324 # . . push args +2325 68/push _test-input-stream/imm32 +2326 # . . call +2327 e8/call clear-stream/disp32 +2328 # . . discard args +2329 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2330 # . write(_test-input-stream, "\"a\\\"b\"/yz") +2331 # . indices: 01 2 34 56 +2332 # . . push args +2333 68/push "\"a\\\"b\"/yz"/imm32 +2334 68/push _test-input-stream/imm32 +2335 # . . call +2336 e8/call write/disp32 +2337 # . . discard args +2338 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2339 # precondition: line->read == 0 +2340 # . . push args +2341 68/push "F - test-skip-string-ignores-escapes/precondition"/imm32 +2342 68/push 0/imm32 +2343 b8/copy-to-EAX _test-input-stream/imm32 +2344 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +2345 # . . call +2346 e8/call check-ints-equal/disp32 +2347 # . . discard args +2348 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2349 # skip-string(_test-input-stream) +2350 # . . push args +2351 68/push _test-input-stream/imm32 +2352 # . . call +2353 e8/call skip-string/disp32 +2354 # . . discard args +2355 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2356 # check-ints-equal(line->read, 6, msg) +2357 # . . push args +2358 68/push "F - test-skip-string-ignores-escapes"/imm32 +2359 68/push 6/imm32 +2360 b8/copy-to-EAX _test-input-stream/imm32 +2361 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +2362 # . . call +2363 e8/call check-ints-equal/disp32 +2364 # . . discard args +2365 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2366 # . epilog +2367 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2368 5d/pop-to-EBP +2369 c3/return +2370 +2371 test-skip-string-works-from-mid-stream: +2372 # . prolog +2373 55/push-EBP +2374 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2375 # setup +2376 # . clear-stream(_test-input-stream) +2377 # . . push args +2378 68/push _test-input-stream/imm32 +2379 # . . call +2380 e8/call clear-stream/disp32 +2381 # . . discard args +2382 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2383 # . write(_test-input-stream, "0 \"a\\\"b\"/yz") +2384 # . indices: 01 2 34 56 +2385 # . . push args +2386 68/push "0 \"a\\\"b\"/yz"/imm32 +2387 68/push _test-input-stream/imm32 +2388 # . . call +2389 e8/call write/disp32 +2390 # . . discard args +2391 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2392 # precondition: line->read == 2 +2393 c7 0/subop/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 2/imm32 # copy to *(EAX+4) +2394 # skip-string(_test-input-stream) +2395 # . . push args +2396 68/push _test-input-stream/imm32 +2397 # . . call +2398 e8/call skip-string/disp32 +2399 # . . discard args +2400 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2401 # check-ints-equal(line->read, 8, msg) +2402 # . . push args +2403 68/push "F - test-skip-string-works-from-mid-stream"/imm32 +2404 68/push 8/imm32 +2405 b8/copy-to-EAX _test-input-stream/imm32 +2406 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +2407 # . . call +2408 e8/call check-ints-equal/disp32 +2409 # . . discard args +2410 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2411 # . epilog +2412 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2413 5d/pop-to-EBP +2414 c3/return +2415 +2416 skip-string-in-slice: # curr : (address byte), end : (address byte) -> new_curr/EAX +2417 # . prolog +2418 55/push-EBP +2419 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2420 # . save registers +2421 51/push-ECX +2422 52/push-EDX +2423 53/push-EBX +2424 # ECX = curr +2425 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX +2426 # EDX = end +2427 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX +2428 # EAX = 0 +2429 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +2430 # skip initial dquote +2431 41/increment-ECX +2432 $skip-string-in-slice:loop: +2433 # if (curr >= end) return curr +2434 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX +2435 73/jump-if-greater-unsigned-or-equal $skip-string-in-slice:return-curr/disp8 +2436 # AL = *curr +2437 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL +2438 $skip-string-in-slice:dquote: +2439 # if (EAX == '"') break +2440 3d/compare-EAX-and 0x22/imm32/double-quote +2441 74/jump-if-equal $skip-string-in-slice:break/disp8 +2442 $skip-string-in-slice:check-for-escape: +2443 # if (EAX == '\') escape next char +2444 3d/compare-EAX-and 0x5c/imm32/backslash +2445 75/jump-if-not-equal $skip-string-in-slice:continue/disp8 +2446 $skip-string-in-slice:escape: +2447 41/increment-ECX +2448 $skip-string-in-slice:continue: +2449 # ++curr +2450 41/increment-ECX +2451 eb/jump $skip-string-in-slice:loop/disp8 +2452 $skip-string-in-slice:break: +2453 # skip final dquote +2454 41/increment-ECX +2455 $skip-string-in-slice:return-curr: +2456 # return curr +2457 89/copy 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to EAX +2458 $skip-string-in-slice:end: +2459 # . restore registers +2460 5b/pop-to-EBX +2461 5a/pop-to-EDX +2462 59/pop-to-ECX +2463 # . epilog +2464 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2465 5d/pop-to-EBP +2466 c3/return +2467 +2468 test-skip-string-in-slice: +2469 # . prolog +2470 55/push-EBP +2471 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2472 # setup: (EAX..ECX) = "\"abc\" def" +2473 b8/copy-to-EAX "\"abc\" def"/imm32 +2474 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2475 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2476 05/add-to-EAX 4/imm32 +2477 # EAX = skip-string-in-slice(EAX, ECX) +2478 # . . push args +2479 51/push-ECX +2480 50/push-EAX +2481 # . . call +2482 e8/call skip-string-in-slice/disp32 +2483 # . . discard args +2484 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2485 # check-ints-equal(ECX-EAX, 4, msg) # number of chars remaining after the string literal +2486 # . . push args +2487 68/push "F - test-skip-string-in-slice"/imm32 +2488 68/push 4/imm32 +2489 # . . push ECX-EAX +2490 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +2491 51/push-ECX +2492 # . . call +2493 e8/call check-ints-equal/disp32 +2494 # . . discard args +2495 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2496 # . epilog +2497 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2498 5d/pop-to-EBP +2499 c3/return +2500 +2501 test-skip-string-in-slice-ignores-spaces: +2502 # . prolog +2503 55/push-EBP +2504 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2505 # setup: (EAX..ECX) = "\"a b\"/yz" +2506 b8/copy-to-EAX "\"a b\"/yz"/imm32 +2507 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2508 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2509 05/add-to-EAX 4/imm32 +2510 # EAX = skip-string-in-slice(EAX, ECX) +2511 # . . push args +2512 51/push-ECX +2513 50/push-EAX +2514 # . . call +2515 e8/call skip-string-in-slice/disp32 +2516 # . . discard args +2517 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2518 # check-ints-equal(ECX-EAX, 3, msg) # number of chars remaining after the string literal +2519 # . . push args +2520 68/push "F - test-skip-string-in-slice-ignores-spaces"/imm32 +2521 68/push 3/imm32 +2522 # . . push ECX-EAX +2523 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +2524 51/push-ECX +2525 # . . call +2526 e8/call check-ints-equal/disp32 +2527 # . . discard args +2528 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2529 # . epilog +2530 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2531 5d/pop-to-EBP +2532 c3/return +2533 +2534 test-skip-string-in-slice-ignores-escapes: +2535 # . prolog +2536 55/push-EBP +2537 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2538 # setup: (EAX..ECX) = "\"a\\\"b\"/yz" +2539 b8/copy-to-EAX "\"a\\\"b\"/yz"/imm32 +2540 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2541 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2542 05/add-to-EAX 4/imm32 +2543 # EAX = skip-string-in-slice(EAX, ECX) +2544 # . . push args +2545 51/push-ECX +2546 50/push-EAX +2547 # . . call +2548 e8/call skip-string-in-slice/disp32 +2549 # . . discard args +2550 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2551 # check-ints-equal(ECX-EAX, 3, msg) # number of chars remaining after the string literal +2552 # . . push args +2553 68/push "F - test-skip-string-in-slice-ignores-escapes"/imm32 +2554 68/push 3/imm32 +2555 # . . push ECX-EAX +2556 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +2557 51/push-ECX +2558 # . . call +2559 e8/call check-ints-equal/disp32 +2560 # . . discard args +2561 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2562 # . epilog +2563 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2564 5d/pop-to-EBP +2565 c3/return +2566 +2567 test-skip-string-in-slice-stops-at-end: +2568 # . prolog +2569 55/push-EBP +2570 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2571 # setup: (EAX..ECX) = "\"abc" # unbalanced dquote +2572 b8/copy-to-EAX "\"abc"/imm32 +2573 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2574 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2575 05/add-to-EAX 4/imm32 +2576 # EAX = skip-string-in-slice(EAX, ECX) +2577 # . . push args +2578 51/push-ECX +2579 50/push-EAX +2580 # . . call +2581 e8/call skip-string-in-slice/disp32 +2582 # . . discard args +2583 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2584 # check-ints-equal(ECX-EAX, 0, msg) # skipped to end of slice +2585 # . . push args +2586 68/push "F - test-skip-string-in-slice-stops-at-end"/imm32 +2587 68/push 0/imm32 +2588 # . . push ECX-EAX +2589 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +2590 51/push-ECX +2591 # . . call +2592 e8/call check-ints-equal/disp32 +2593 # . . discard args +2594 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2595 # . epilog +2596 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2597 5d/pop-to-EBP +2598 c3/return +2599 +2600 string-length-at-start-of-slice: # curr : (address byte), end : (address byte) -> length/EAX +2601 # . prolog +2602 55/push-EBP +2603 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2604 # . save registers +2605 51/push-ECX +2606 52/push-EDX +2607 53/push-EBX +2608 # ECX = curr +2609 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX +2610 # EDX = end +2611 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX +2612 # length/EAX = 0 +2613 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +2614 # EBX = 0 +2615 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +2616 # skip initial dquote +2617 41/increment-ECX +2618 $string-length-at-start-of-slice:loop: +2619 # if (curr >= end) return length +2620 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX +2621 73/jump-if-greater-unsigned-or-equal $string-length-at-start-of-slice:end/disp8 +2622 # BL = *curr +2623 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 3/r32/BL . . # copy byte at *ECX to BL +2624 $string-length-at-start-of-slice:dquote: +2625 # if (EBX == '"') break +2626 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x22/imm32/dquote # compare EBX +2627 74/jump-if-equal $string-length-at-start-of-slice:end/disp8 +2628 $string-length-at-start-of-slice:check-for-escape: +2629 # if (EBX == '\') escape next char +2630 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x5c/imm32/backslash # compare EBX +2631 75/jump-if-not-equal $string-length-at-start-of-slice:continue/disp8 +2632 $string-length-at-start-of-slice:escape: +2633 # increment curr but not result +2634 41/increment-ECX +2635 $string-length-at-start-of-slice:continue: +2636 # ++result +2637 40/increment-EAX +2638 # ++curr +2639 41/increment-ECX +2640 eb/jump $string-length-at-start-of-slice:loop/disp8 +2641 $string-length-at-start-of-slice:end: +2642 # . restore registers +2643 5b/pop-to-EBX +2644 5a/pop-to-EDX +2645 59/pop-to-ECX +2646 # . epilog +2647 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2648 5d/pop-to-EBP +2649 c3/return +2650 +2651 test-string-length-at-start-of-slice: +2652 # . prolog +2653 55/push-EBP +2654 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2655 # setup: (EAX..ECX) = "\"abc\" def" +2656 b8/copy-to-EAX "\"abc\" def"/imm32 +2657 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2658 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2659 05/add-to-EAX 4/imm32 +2660 # EAX = string-length-at-start-of-slice(EAX, ECX) +2661 # . . push args +2662 51/push-ECX +2663 50/push-EAX +2664 # . . call +2665 e8/call string-length-at-start-of-slice/disp32 +2666 # . . discard args +2667 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2668 # check-ints-equal(EAX, 3, msg) +2669 # . . push args +2670 68/push "F - test-string-length-at-start-of-slice"/imm32 +2671 68/push 3/imm32 +2672 50/push-EAX +2673 # . . call +2674 e8/call check-ints-equal/disp32 +2675 # . . discard args +2676 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2677 # . epilog +2678 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2679 5d/pop-to-EBP +2680 c3/return +2681 +2682 test-string-length-at-start-of-slice-escaped: +2683 # . prolog +2684 55/push-EBP +2685 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2686 # setup: (EAX..ECX) = "\"ab\\c\" def" +2687 b8/copy-to-EAX "\"ab\\c\" def"/imm32 +2688 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2689 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2690 05/add-to-EAX 4/imm32 +2691 # EAX = string-length-at-start-of-slice(EAX, ECX) +2692 # . . push args +2693 51/push-ECX +2694 50/push-EAX +2695 # . . call +2696 e8/call string-length-at-start-of-slice/disp32 +2697 # . . discard args +2698 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2699 # check-ints-equal(EAX, 3, msg) +2700 # . . push args +2701 68/push "F - test-string-length-at-start-of-slice-escaped"/imm32 +2702 68/push 3/imm32 +2703 50/push-EAX +2704 # . . call +2705 e8/call check-ints-equal/disp32 +2706 # . . discard args +2707 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2708 # . epilog +2709 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2710 5d/pop-to-EBP +2711 c3/return +2712 +2713 == data +2714 +2715 Next-string-literal: # tracks the next auto-generated variable name +2716 1/imm32 +2717 +2718 # length-prefixed string containing just a single space +2719 Space: +2720 # size +2721 1/imm32 +2722 # data +2723 20/space +2724 +2725 # length-prefixed string containing just a single slash +2726 Slash: +2727 # size +2728 1/imm32 +2729 # data +2730 2f/slash +2731 +2732 _test-slice-abc: +2733 22/dquote 61/a 62/b 63/c 22/dquote # "abc" +2734 2f/slash 64/d +2735 _test-slice-abc-limit: +2736 +2737 _test-slice-a-space-b: +2738 22/dquote 61/a 20/space 62/b 22/dquote # "a b" +2739 _test-slice-a-space-b-limit: +2740 +2741 _test-slice-a-dquote-b: +2742 22/dquote 61/a 5c/backslash 22/dquote 62/b 22/dquote # "a\"b" +2743 _test-slice-a-dquote-b-limit: +2744 +2745 _test-slice-a-newline-b: +2746 22/dquote 61/a 5c/backslash 6e/n 62/b 22/dquote # "a\nb" +2747 _test-slice-a-newline-b-limit: +2748 +2749 # "abc/def"/ghi +2750 _test-slice-literal-string: +2751 22/dquote +2752 61/a 62/b 63/c # abc +2753 2f/slash 64/d 65/e 66/f # /def +2754 22/dquote +2755 2f/slash 67/g 68/h 69/i # /ghi +2756 _test-slice-literal-string-with-limit: +2757 +2758 # . . vim:nowrap:textwidth=0 diff --git a/html/apps/factorial.subx.html b/html/apps/factorial.subx.html index eff79035..780c9ce1 100644 --- a/html/apps/factorial.subx.html +++ b/html/apps/factorial.subx.html @@ -14,16 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> diff --git a/html/apps/handle.subx.html b/html/apps/handle.subx.html index 64a784c6..6b660afa 100644 --- a/html/apps/handle.subx.html +++ b/html/apps/handle.subx.html @@ -14,18 +14,18 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } -.subxTest { color: #5f8700; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } -.LineNr { } -.subxH1Comment { color: #005faf; text-decoration: underline; } -.SpecialChar { color: #d70000; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } .subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } +.LineNr { } +.SpecialChar { color: #d70000; } +.subxS1Comment { color: #0000af; } +.CommentedCode { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.subxMinorFunction { color: #875f5f; } +.Constant { color: #008787; } +.subxTest { color: #5f8700; } --> diff --git a/html/apps/hex.subx.html b/html/apps/hex.subx.html index 2a0245ac..214b5e33 100644 --- a/html/apps/hex.subx.html +++ b/html/apps/hex.subx.html @@ -14,17 +14,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } +.subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -286,14 +285,14 @@ if ('onhashchange' in window) { 224 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 225 # . clear-stream(_test-error-stream) 226 # . . push args - 227 68/push _test-error-stream/imm32 + 227 68/push _test-error-stream/imm32 228 # . . call 229 e8/call clear-stream/disp32 230 # . . discard args 231 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 232 # . clear-stream(_test-error-buffered-file+4) 233 # . . push args - 234 b8/copy-to-EAX _test-error-buffered-file/imm32 + 234 b8/copy-to-EAX _test-error-buffered-file/imm32 235 05/add-to-EAX 4/imm32 236 50/push-EAX 237 # . . call @@ -318,13 +317,13 @@ if ('onhashchange' in window) { 256 68/push 0xc/imm32/nbytes-of-args-for-convert-next-octet 257 51/push-ECX/ed 258 # . . call - 259 e8/call tailor-exit-descriptor/disp32 + 259 e8/call tailor-exit-descriptor/disp32 260 # . . discard args 261 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 262 # EAX = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed) 263 # . . push args 264 51/push-ECX/ed - 265 68/push _test-error-buffered-file/imm32 + 265 68/push _test-error-buffered-file/imm32 266 68/push _test-buffered-file/imm32 267 # . . call 268 e8/call convert-next-octet/disp32 @@ -388,14 +387,14 @@ if ('onhashchange' in window) { 326 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 327 # . clear-stream(_test-error-stream) 328 # . . push args - 329 68/push _test-error-stream/imm32 + 329 68/push _test-error-stream/imm32 330 # . . call 331 e8/call clear-stream/disp32 332 # . . discard args 333 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 334 # . clear-stream(_test-error-buffered-file+4) 335 # . . push args - 336 b8/copy-to-EAX _test-error-buffered-file/imm32 + 336 b8/copy-to-EAX _test-error-buffered-file/imm32 337 05/add-to-EAX 4/imm32 338 50/push-EAX 339 # . . call @@ -412,13 +411,13 @@ if ('onhashchange' in window) { 350 68/push 0xc/imm32/nbytes-of-args-for-convert-next-octet 351 51/push-ECX/ed 352 # . . call - 353 e8/call tailor-exit-descriptor/disp32 + 353 e8/call tailor-exit-descriptor/disp32 354 # . . discard args 355 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 356 # EAX = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed) 357 # . . push args 358 51/push-ECX/ed - 359 68/push _test-error-buffered-file/imm32 + 359 68/push _test-error-buffered-file/imm32 360 68/push _test-buffered-file/imm32 361 # . . call 362 e8/call convert-next-octet/disp32 @@ -482,14 +481,14 @@ if ('onhashchange' in window) { 420 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 421 # . clear-stream(_test-error-stream) 422 # . . push args - 423 68/push _test-error-stream/imm32 + 423 68/push _test-error-stream/imm32 424 # . . call 425 e8/call clear-stream/disp32 426 # . . discard args 427 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 428 # . clear-stream(_test-error-buffered-file+4) 429 # . . push args - 430 b8/copy-to-EAX _test-error-buffered-file/imm32 + 430 b8/copy-to-EAX _test-error-buffered-file/imm32 431 05/add-to-EAX 4/imm32 432 50/push-EAX 433 # . . call @@ -514,13 +513,13 @@ if ('onhashchange' in window) { 452 68/push 0xc/imm32/nbytes-of-args-for-convert-next-octet 453 51/push-ECX/ed 454 # . . call - 455 e8/call tailor-exit-descriptor/disp32 + 455 e8/call tailor-exit-descriptor/disp32 456 # . . discard args 457 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 458 # EAX = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed) 459 # . . push args 460 51/push-ECX/ed - 461 68/push _test-error-buffered-file/imm32 + 461 68/push _test-error-buffered-file/imm32 462 68/push _test-buffered-file/imm32 463 # . . call 464 e8/call convert-next-octet/disp32 @@ -655,14 +654,14 @@ if ('onhashchange' in window) { 593 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 594 # . clear-stream(_test-error-stream) 595 # . . push args - 596 68/push _test-error-stream/imm32 + 596 68/push _test-error-stream/imm32 597 # . . call 598 e8/call clear-stream/disp32 599 # . . discard args 600 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 601 # . clear-stream(_test-error-buffered-file+4) 602 # . . push args - 603 b8/copy-to-EAX _test-error-buffered-file/imm32 + 603 b8/copy-to-EAX _test-error-buffered-file/imm32 604 05/add-to-EAX 4/imm32 605 50/push-EAX 606 # . . call @@ -687,13 +686,13 @@ if ('onhashchange' in window) { 625 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 626 51/push-ECX/ed 627 # . . call - 628 e8/call tailor-exit-descriptor/disp32 + 628 e8/call tailor-exit-descriptor/disp32 629 # . . discard args 630 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 631 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 632 # . . push args 633 51/push-ECX/ed - 634 68/push _test-error-buffered-file/imm32 + 634 68/push _test-error-buffered-file/imm32 635 68/push _test-buffered-file/imm32 636 # . . call 637 e8/call scan-next-byte/disp32 @@ -757,14 +756,14 @@ if ('onhashchange' in window) { 695 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 696 # . clear-stream(_test-error-stream) 697 # . . push args - 698 68/push _test-error-stream/imm32 + 698 68/push _test-error-stream/imm32 699 # . . call 700 e8/call clear-stream/disp32 701 # . . discard args 702 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 703 # . clear-stream(_test-error-buffered-file+4) 704 # . . push args - 705 b8/copy-to-EAX _test-error-buffered-file/imm32 + 705 b8/copy-to-EAX _test-error-buffered-file/imm32 706 05/add-to-EAX 4/imm32 707 50/push-EAX 708 # . . call @@ -789,13 +788,13 @@ if ('onhashchange' in window) { 727 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 728 51/push-ECX/ed 729 # . . call - 730 e8/call tailor-exit-descriptor/disp32 + 730 e8/call tailor-exit-descriptor/disp32 731 # . . discard args 732 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 733 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 734 # . . push args 735 51/push-ECX/ed - 736 68/push _test-error-buffered-file/imm32 + 736 68/push _test-error-buffered-file/imm32 737 68/push _test-buffered-file/imm32 738 # . . call 739 e8/call scan-next-byte/disp32 @@ -859,14 +858,14 @@ if ('onhashchange' in window) { 797 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 798 # . clear-stream(_test-error-stream) 799 # . . push args - 800 68/push _test-error-stream/imm32 + 800 68/push _test-error-stream/imm32 801 # . . call 802 e8/call clear-stream/disp32 803 # . . discard args 804 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 805 # . clear-stream(_test-error-buffered-file+4) 806 # . . push args - 807 b8/copy-to-EAX _test-error-buffered-file/imm32 + 807 b8/copy-to-EAX _test-error-buffered-file/imm32 808 05/add-to-EAX 4/imm32 809 50/push-EAX 810 # . . call @@ -899,13 +898,13 @@ if ('onhashchange' in window) { 837 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 838 51/push-ECX/ed 839 # . . call - 840 e8/call tailor-exit-descriptor/disp32 + 840 e8/call tailor-exit-descriptor/disp32 841 # . . discard args 842 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 843 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 844 # . . push args 845 51/push-ECX/ed - 846 68/push _test-error-buffered-file/imm32 + 846 68/push _test-error-buffered-file/imm32 847 68/push _test-buffered-file/imm32 848 # . . call 849 e8/call scan-next-byte/disp32 @@ -969,14 +968,14 @@ if ('onhashchange' in window) { 907 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 908 # . clear-stream(_test-error-stream) 909 # . . push args - 910 68/push _test-error-stream/imm32 + 910 68/push _test-error-stream/imm32 911 # . . call 912 e8/call clear-stream/disp32 913 # . . discard args 914 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 915 # . clear-stream(_test-error-buffered-file+4) 916 # . . push args - 917 b8/copy-to-EAX _test-error-buffered-file/imm32 + 917 b8/copy-to-EAX _test-error-buffered-file/imm32 918 05/add-to-EAX 4/imm32 919 50/push-EAX 920 # . . call @@ -1009,13 +1008,13 @@ if ('onhashchange' in window) { 947 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 948 51/push-ECX/ed 949 # . . call - 950 e8/call tailor-exit-descriptor/disp32 + 950 e8/call tailor-exit-descriptor/disp32 951 # . . discard args 952 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 953 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 954 # . . push args 955 51/push-ECX/ed - 956 68/push _test-error-buffered-file/imm32 + 956 68/push _test-error-buffered-file/imm32 957 68/push _test-buffered-file/imm32 958 # . . call 959 e8/call scan-next-byte/disp32 @@ -1079,14 +1078,14 @@ if ('onhashchange' in window) { 1017 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1018 # . clear-stream(_test-error-stream) 1019 # . . push args -1020 68/push _test-error-stream/imm32 +1020 68/push _test-error-stream/imm32 1021 # . . call 1022 e8/call clear-stream/disp32 1023 # . . discard args 1024 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1025 # . clear-stream(_test-error-buffered-file+4) 1026 # . . push args -1027 b8/copy-to-EAX _test-error-buffered-file/imm32 +1027 b8/copy-to-EAX _test-error-buffered-file/imm32 1028 05/add-to-EAX 4/imm32 1029 50/push-EAX 1030 # . . call @@ -1119,13 +1118,13 @@ if ('onhashchange' in window) { 1057 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 1058 51/push-ECX/ed 1059 # . . call -1060 e8/call tailor-exit-descriptor/disp32 +1060 e8/call tailor-exit-descriptor/disp32 1061 # . . discard args 1062 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1063 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 1064 # . . push args 1065 51/push-ECX/ed -1066 68/push _test-error-buffered-file/imm32 +1066 68/push _test-error-buffered-file/imm32 1067 68/push _test-buffered-file/imm32 1068 # . . call 1069 e8/call scan-next-byte/disp32 @@ -1189,14 +1188,14 @@ if ('onhashchange' in window) { 1127 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1128 # . clear-stream(_test-error-stream) 1129 # . . push args -1130 68/push _test-error-stream/imm32 +1130 68/push _test-error-stream/imm32 1131 # . . call 1132 e8/call clear-stream/disp32 1133 # . . discard args 1134 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1135 # . clear-stream(_test-error-buffered-file+4) 1136 # . . push args -1137 b8/copy-to-EAX _test-error-buffered-file/imm32 +1137 b8/copy-to-EAX _test-error-buffered-file/imm32 1138 05/add-to-EAX 4/imm32 1139 50/push-EAX 1140 # . . call @@ -1221,13 +1220,13 @@ if ('onhashchange' in window) { 1159 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 1160 51/push-ECX/ed 1161 # . . call -1162 e8/call tailor-exit-descriptor/disp32 +1162 e8/call tailor-exit-descriptor/disp32 1163 # . . discard args 1164 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1165 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 1166 # . . push args 1167 51/push-ECX/ed -1168 68/push _test-error-buffered-file/imm32 +1168 68/push _test-error-buffered-file/imm32 1169 68/push _test-buffered-file/imm32 1170 # . . call 1171 e8/call scan-next-byte/disp32 @@ -1291,14 +1290,14 @@ if ('onhashchange' in window) { 1229 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1230 # . clear-stream(_test-error-stream) 1231 # . . push args -1232 68/push _test-error-stream/imm32 +1232 68/push _test-error-stream/imm32 1233 # . . call 1234 e8/call clear-stream/disp32 1235 # . . discard args 1236 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1237 # . clear-stream(_test-error-buffered-file+4) 1238 # . . push args -1239 b8/copy-to-EAX _test-error-buffered-file/imm32 +1239 b8/copy-to-EAX _test-error-buffered-file/imm32 1240 05/add-to-EAX 4/imm32 1241 50/push-EAX 1242 # . . call @@ -1315,13 +1314,13 @@ if ('onhashchange' in window) { 1253 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 1254 51/push-ECX/ed 1255 # . . call -1256 e8/call tailor-exit-descriptor/disp32 +1256 e8/call tailor-exit-descriptor/disp32 1257 # . . discard args 1258 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1259 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 1260 # . . push args 1261 51/push-ECX/ed -1262 68/push _test-error-buffered-file/imm32 +1262 68/push _test-error-buffered-file/imm32 1263 68/push _test-buffered-file/imm32 1264 # . . call 1265 e8/call scan-next-byte/disp32 @@ -1385,14 +1384,14 @@ if ('onhashchange' in window) { 1323 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1324 # . clear-stream(_test-error-stream) 1325 # . . push args -1326 68/push _test-error-stream/imm32 +1326 68/push _test-error-stream/imm32 1327 # . . call 1328 e8/call clear-stream/disp32 1329 # . . discard args 1330 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1331 # . clear-stream(_test-error-buffered-file+4) 1332 # . . push args -1333 b8/copy-to-EAX _test-error-buffered-file/imm32 +1333 b8/copy-to-EAX _test-error-buffered-file/imm32 1334 05/add-to-EAX 4/imm32 1335 50/push-EAX 1336 # . . call @@ -1417,13 +1416,13 @@ if ('onhashchange' in window) { 1355 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte 1356 51/push-ECX/ed 1357 # . . call -1358 e8/call tailor-exit-descriptor/disp32 +1358 e8/call tailor-exit-descriptor/disp32 1359 # . . discard args 1360 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1361 # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) 1362 # . . push args 1363 51/push-ECX/ed -1364 68/push _test-error-buffered-file/imm32 +1364 68/push _test-error-buffered-file/imm32 1365 68/push _test-buffered-file/imm32 1366 # . . call 1367 e8/call scan-next-byte/disp32 @@ -1542,39 +1541,7 @@ if ('onhashchange' in window) { 1480 # . end 1481 c3/return 1482 -1483 == data -1484 -1485 _test-error-stream: -1486 # current write index -1487 0/imm32 -1488 # current read index -1489 0/imm32 -1490 # line -1491 0x80/imm32 # 128 bytes -1492 # data (8 lines x 16 bytes/line) -1493 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1494 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1495 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1496 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1497 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1498 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1499 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -1501 -1502 # a test buffered file for _test-error-stream -1503 _test-error-buffered-file: -1504 # file descriptor or (address stream) -1505 _test-error-stream/imm32 -1506 # current write index -1507 0/imm32 -1508 # current read index -1509 0/imm32 -1510 # length -1511 6/imm32 -1512 # data -1513 00 00 00 00 00 00 # 6 bytes -1514 -1515 # . . vim:nowrap:textwidth=0 +1483 # . . vim:nowrap:textwidth=0 diff --git a/html/apps/pack.subx.html b/html/apps/pack.subx.html index 0f49d205..6b647e6f 100644 --- a/html/apps/pack.subx.html +++ b/html/apps/pack.subx.html @@ -14,17 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } .subxTest { color: #5f8700; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Folded { color: #080808; background-color: #949494; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -120,7 +120,7 @@ if ('onhashchange' in window) { 58 # configure ed to really exit() 59 # . ed->target = 0 60 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - 61 # return convert(Stdin, 1/stdout, 2/stderr, ed) + 61 # return convert(Stdin, Stdout, Stderr, ed) 62 # . . push args 63 50/push-EAX/ed 64 68/push Stderr/imm32 @@ -349,14 +349,14 @@ if ('onhashchange' in window) { 394 # setup 395 # . clear-stream(_test-input-stream) 396 # . . push args - 397 68/push _test-input-stream/imm32 + 397 68/push _test-input-stream/imm32 398 # . . call 399 e8/call clear-stream/disp32 400 # . . discard args 401 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 402 # . clear-stream(_test-input-buffered-file+4) 403 # . . push args - 404 b8/copy-to-EAX _test-input-buffered-file/imm32 + 404 b8/copy-to-EAX _test-input-buffered-file/imm32 405 05/add-to-EAX 4/imm32 406 50/push-EAX 407 # . . call @@ -365,14 +365,14 @@ if ('onhashchange' in window) { 410 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 411 # . clear-stream(_test-output-stream) 412 # . . push args - 413 68/push _test-output-stream/imm32 + 413 68/push _test-output-stream/imm32 414 # . . call 415 e8/call clear-stream/disp32 416 # . . discard args 417 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 418 # . clear-stream(_test-output-buffered-file+4) 419 # . . push args - 420 b8/copy-to-EAX _test-output-buffered-file/imm32 + 420 b8/copy-to-EAX _test-output-buffered-file/imm32 421 05/add-to-EAX 4/imm32 422 50/push-EAX 423 # . . call @@ -382,8 +382,8 @@ if ('onhashchange' in window) { 427 # write nothing to input 428 # convert(_test-input-buffered-file, _test-output-buffered-file) 429 # . . push args - 430 68/push _test-output-buffered-file/imm32 - 431 68/push _test-input-buffered-file/imm32 + 430 68/push _test-output-buffered-file/imm32 + 431 68/push _test-input-buffered-file/imm32 432 # . . call 433 e8/call convert/disp32 434 # . . discard args @@ -391,7 +391,7 @@ if ('onhashchange' in window) { 436 # check that the line just passed through 437 # . flush(_test-output-buffered-file) 438 # . . push args - 439 68/push _test-output-buffered-file/imm32 + 439 68/push _test-output-buffered-file/imm32 440 # . . call 441 e8/call flush/disp32 442 # . . discard args @@ -400,7 +400,7 @@ if ('onhashchange' in window) { 445 # . . push args 446 68/push "F - test-convert-passes-empty-lines-through"/imm32 447 68/push ""/imm32 - 448 68/push _test-output-stream/imm32 + 448 68/push _test-output-stream/imm32 449 # . . call 450 e8/call check-stream-equal/disp32 451 # . . discard args @@ -418,14 +418,14 @@ if ('onhashchange' in window) { 463 # setup 464 # . clear-stream(_test-input-stream) 465 # . . push args - 466 68/push _test-input-stream/imm32 + 466 68/push _test-input-stream/imm32 467 # . . call 468 e8/call clear-stream/disp32 469 # . . discard args 470 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 471 # . clear-stream(_test-input-buffered-file+4) 472 # . . push args - 473 b8/copy-to-EAX _test-input-buffered-file/imm32 + 473 b8/copy-to-EAX _test-input-buffered-file/imm32 474 05/add-to-EAX 4/imm32 475 50/push-EAX 476 # . . call @@ -434,14 +434,14 @@ if ('onhashchange' in window) { 479 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 480 # . clear-stream(_test-output-stream) 481 # . . push args - 482 68/push _test-output-stream/imm32 + 482 68/push _test-output-stream/imm32 483 # . . call 484 e8/call clear-stream/disp32 485 # . . discard args 486 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 487 # . clear-stream(_test-output-buffered-file+4) 488 # . . push args - 489 b8/copy-to-EAX _test-output-buffered-file/imm32 + 489 b8/copy-to-EAX _test-output-buffered-file/imm32 490 05/add-to-EAX 4/imm32 491 50/push-EAX 492 # . . call @@ -452,15 +452,15 @@ if ('onhashchange' in window) { 497 # . write(_test-input-stream, " ") 498 # . . push args 499 68/push " "/imm32 - 500 68/push _test-input-stream/imm32 + 500 68/push _test-input-stream/imm32 501 # . . call 502 e8/call write/disp32 503 # . . discard args 504 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 505 # convert(_test-input-buffered-file, _test-output-buffered-file) 506 # . . push args - 507 68/push _test-output-buffered-file/imm32 - 508 68/push _test-input-buffered-file/imm32 + 507 68/push _test-output-buffered-file/imm32 + 508 68/push _test-input-buffered-file/imm32 509 # . . call 510 e8/call convert/disp32 511 # . . discard args @@ -468,7 +468,7 @@ if ('onhashchange' in window) { 513 # check that the line just passed through 514 # . flush(_test-output-buffered-file) 515 # . . push args - 516 68/push _test-output-buffered-file/imm32 + 516 68/push _test-output-buffered-file/imm32 517 # . . call 518 e8/call flush/disp32 519 # . . discard args @@ -477,7 +477,7 @@ if ('onhashchange' in window) { 522 # . . push args 523 68/push "F - test-convert-passes-with-just-whitespace-through"/imm32 524 68/push " "/imm32 - 525 68/push _test-output-stream/imm32 + 525 68/push _test-output-stream/imm32 526 # . . call 527 e8/call check-next-stream-line-equal/disp32 528 # . . discard args @@ -495,14 +495,14 @@ if ('onhashchange' in window) { 540 # setup 541 # . clear-stream(_test-input-stream) 542 # . . push args - 543 68/push _test-input-stream/imm32 + 543 68/push _test-input-stream/imm32 544 # . . call 545 e8/call clear-stream/disp32 546 # . . discard args 547 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 548 # . clear-stream(_test-input-buffered-file+4) 549 # . . push args - 550 b8/copy-to-EAX _test-input-buffered-file/imm32 + 550 b8/copy-to-EAX _test-input-buffered-file/imm32 551 05/add-to-EAX 4/imm32 552 50/push-EAX 553 # . . call @@ -511,14 +511,14 @@ if ('onhashchange' in window) { 556 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 557 # . clear-stream(_test-output-stream) 558 # . . push args - 559 68/push _test-output-stream/imm32 + 559 68/push _test-output-stream/imm32 560 # . . call 561 e8/call clear-stream/disp32 562 # . . discard args 563 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 564 # . clear-stream(_test-output-buffered-file+4) 565 # . . push args - 566 b8/copy-to-EAX _test-output-buffered-file/imm32 + 566 b8/copy-to-EAX _test-output-buffered-file/imm32 567 05/add-to-EAX 4/imm32 568 50/push-EAX 569 # . . call @@ -529,15 +529,15 @@ if ('onhashchange' in window) { 574 # . write(_test-input-stream, "== abcd 0x1") 575 # . . push args 576 68/push "== abcd 0x1"/imm32 - 577 68/push _test-input-stream/imm32 + 577 68/push _test-input-stream/imm32 578 # . . call 579 e8/call write/disp32 580 # . . discard args 581 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 582 # convert(_test-input-buffered-file, _test-output-buffered-file) 583 # . . push args - 584 68/push _test-output-buffered-file/imm32 - 585 68/push _test-input-buffered-file/imm32 + 584 68/push _test-output-buffered-file/imm32 + 585 68/push _test-input-buffered-file/imm32 586 # . . call 587 e8/call convert/disp32 588 # . . discard args @@ -545,7 +545,7 @@ if ('onhashchange' in window) { 590 # check that the line just passed through 591 # . flush(_test-output-buffered-file) 592 # . . push args - 593 68/push _test-output-buffered-file/imm32 + 593 68/push _test-output-buffered-file/imm32 594 # . . call 595 e8/call flush/disp32 596 # . . discard args @@ -554,7 +554,7 @@ if ('onhashchange' in window) { 599 # . . push args 600 68/push "F - test-convert-passes-segment-headers-through"/imm32 601 68/push "== abcd 0x1"/imm32 - 602 68/push _test-output-stream/imm32 + 602 68/push _test-output-stream/imm32 603 # . . call 604 e8/call check-stream-equal/disp32 605 # . . discard args @@ -572,14 +572,14 @@ if ('onhashchange' in window) { 617 # setup 618 # . clear-stream(_test-input-stream) 619 # . . push args - 620 68/push _test-input-stream/imm32 + 620 68/push _test-input-stream/imm32 621 # . . call 622 e8/call clear-stream/disp32 623 # . . discard args 624 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 625 # . clear-stream(_test-input-buffered-file+4) 626 # . . push args - 627 b8/copy-to-EAX _test-input-buffered-file/imm32 + 627 b8/copy-to-EAX _test-input-buffered-file/imm32 628 05/add-to-EAX 4/imm32 629 50/push-EAX 630 # . . call @@ -588,14 +588,14 @@ if ('onhashchange' in window) { 633 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 634 # . clear-stream(_test-output-stream) 635 # . . push args - 636 68/push _test-output-stream/imm32 + 636 68/push _test-output-stream/imm32 637 # . . call 638 e8/call clear-stream/disp32 639 # . . discard args 640 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 641 # . clear-stream(_test-output-buffered-file+4) 642 # . . push args - 643 b8/copy-to-EAX _test-output-buffered-file/imm32 + 643 b8/copy-to-EAX _test-output-buffered-file/imm32 644 05/add-to-EAX 4/imm32 645 50/push-EAX 646 # . . call @@ -609,7 +609,7 @@ if ('onhashchange' in window) { 654 # . write(_test-input-stream, "== code 0x1") 655 # . . push args 656 68/push "== code 0x1\n"/imm32 - 657 68/push _test-input-stream/imm32 + 657 68/push _test-input-stream/imm32 658 # . . call 659 e8/call write/disp32 660 # . . discard args @@ -617,7 +617,7 @@ if ('onhashchange' in window) { 662 # . write(_test-input-stream, "== data 0x2\n") 663 # . . push args 664 68/push "== data 0x2\n"/imm32 - 665 68/push _test-input-stream/imm32 + 665 68/push _test-input-stream/imm32 666 # . . call 667 e8/call write/disp32 668 # . . discard args @@ -625,15 +625,15 @@ if ('onhashchange' in window) { 670 # . write(_test-input-stream, "3 4/imm32\n") 671 # . . push args 672 68/push "3 4/imm32\n"/imm32 - 673 68/push _test-input-stream/imm32 + 673 68/push _test-input-stream/imm32 674 # . . call 675 e8/call write/disp32 676 # . . discard args 677 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 678 # convert(_test-input-buffered-file, _test-output-buffered-file) 679 # . . push args - 680 68/push _test-output-buffered-file/imm32 - 681 68/push _test-input-buffered-file/imm32 + 680 68/push _test-output-buffered-file/imm32 + 681 68/push _test-input-buffered-file/imm32 682 # . . call 683 e8/call convert/disp32 684 # . . discard args @@ -642,7 +642,7 @@ if ('onhashchange' in window) { 687 +-- 26 lines: #? # debug print --------------------------------------------------------------------------------------------------------------------------- 713 # . flush(_test-output-buffered-file) 714 # . . push args - 715 68/push _test-output-buffered-file/imm32 + 715 68/push _test-output-buffered-file/imm32 716 # . . call 717 e8/call flush/disp32 718 # . . discard args @@ -651,7 +651,7 @@ if ('onhashchange' in window) { 721 # . . push args 722 68/push "F - test-convert-in-data-segment/0"/imm32 723 68/push "== code 0x1"/imm32 - 724 68/push _test-output-stream/imm32 + 724 68/push _test-output-stream/imm32 725 # . . call 726 e8/call check-next-stream-line-equal/disp32 727 # . . discard args @@ -660,7 +660,7 @@ if ('onhashchange' in window) { 730 # . . push args 731 68/push "F - test-convert-in-data-segment/1"/imm32 732 68/push "== data 0x2"/imm32 - 733 68/push _test-output-stream/imm32 + 733 68/push _test-output-stream/imm32 734 # . . call 735 e8/call check-next-stream-line-equal/disp32 736 # . . discard args @@ -669,7 +669,7 @@ if ('onhashchange' in window) { 739 # . . push args 740 68/push "F - test-convert-in-data-segment/2"/imm32 741 68/push "03 04 00 00 00 "/imm32 - 742 68/push _test-output-stream/imm32 + 742 68/push _test-output-stream/imm32 743 # . . call 744 e8/call check-next-stream-line-equal/disp32 745 # . . discard args @@ -687,14 +687,14 @@ if ('onhashchange' in window) { 757 # setup 758 # . clear-stream(_test-input-stream) 759 # . . push args - 760 68/push _test-input-stream/imm32 + 760 68/push _test-input-stream/imm32 761 # . . call 762 e8/call clear-stream/disp32 763 # . . discard args 764 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 765 # . clear-stream(_test-input-buffered-file+4) 766 # . . push args - 767 b8/copy-to-EAX _test-input-buffered-file/imm32 + 767 b8/copy-to-EAX _test-input-buffered-file/imm32 768 05/add-to-EAX 4/imm32 769 50/push-EAX 770 # . . call @@ -703,14 +703,14 @@ if ('onhashchange' in window) { 773 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 774 # . clear-stream(_test-output-stream) 775 # . . push args - 776 68/push _test-output-stream/imm32 + 776 68/push _test-output-stream/imm32 777 # . . call 778 e8/call clear-stream/disp32 779 # . . discard args 780 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 781 # . clear-stream(_test-output-buffered-file+4) 782 # . . push args - 783 b8/copy-to-EAX _test-output-buffered-file/imm32 + 783 b8/copy-to-EAX _test-output-buffered-file/imm32 784 05/add-to-EAX 4/imm32 785 50/push-EAX 786 # . . call @@ -726,7 +726,7 @@ if ('onhashchange' in window) { 796 # . write(_test-input-stream, "== code 0x1\n") 797 # . . push args 798 68/push "== code 0x1\n"/imm32 - 799 68/push _test-input-stream/imm32 + 799 68/push _test-input-stream/imm32 800 # . . call 801 e8/call write/disp32 802 # . . discard args @@ -734,7 +734,7 @@ if ('onhashchange' in window) { 804 # . write(_test-input-stream, "e8/call 20/disp32\n") 805 # . . push args 806 68/push "e8/call 20/disp32\n"/imm32 - 807 68/push _test-input-stream/imm32 + 807 68/push _test-input-stream/imm32 808 # . . call 809 e8/call write/disp32 810 # . . discard args @@ -742,7 +742,7 @@ if ('onhashchange' in window) { 812 # . write(_test-input-stream, "68/push 0x20/imm8\n") 813 # . . push args 814 68/push "68/push 0x20/imm8\n"/imm32 - 815 68/push _test-input-stream/imm32 + 815 68/push _test-input-stream/imm32 816 # . . call 817 e8/call write/disp32 818 # . . discard args @@ -750,7 +750,7 @@ if ('onhashchange' in window) { 820 # . write(_test-input-stream, "== data 0x2\n") 821 # . . push args 822 68/push "== data 0x2\n"/imm32 - 823 68/push _test-input-stream/imm32 + 823 68/push _test-input-stream/imm32 824 # . . call 825 e8/call write/disp32 826 # . . discard args @@ -758,15 +758,15 @@ if ('onhashchange' in window) { 828 # . write(_test-input-stream, "3 4/imm32\n") 829 # . . push args 830 68/push "3 4/imm32\n"/imm32 - 831 68/push _test-input-stream/imm32 + 831 68/push _test-input-stream/imm32 832 # . . call 833 e8/call write/disp32 834 # . . discard args 835 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 836 # convert(_test-input-buffered-file, _test-output-buffered-file) 837 # . . push args - 838 68/push _test-output-buffered-file/imm32 - 839 68/push _test-input-buffered-file/imm32 + 838 68/push _test-output-buffered-file/imm32 + 839 68/push _test-input-buffered-file/imm32 840 # . . call 841 e8/call convert/disp32 842 # . . discard args @@ -780,7 +780,7 @@ if ('onhashchange' in window) { 850 +-- 26 lines: #? # debug print --------------------------------------------------------------------------------------------------------------------------- 876 # . flush(_test-output-buffered-file) 877 # . . push args - 878 68/push _test-output-buffered-file/imm32 + 878 68/push _test-output-buffered-file/imm32 879 # . . call 880 e8/call flush/disp32 881 # . . discard args @@ -789,7 +789,7 @@ if ('onhashchange' in window) { 884 # . . push args 885 68/push "F - test-convert-code-and-data-segments/0"/imm32 886 68/push "== code 0x1"/imm32 - 887 68/push _test-output-stream/imm32 + 887 68/push _test-output-stream/imm32 888 # . . call 889 e8/call check-next-stream-line-equal/disp32 890 # . . discard args @@ -798,7 +798,7 @@ if ('onhashchange' in window) { 893 # . . push args 894 68/push "F - test-convert-code-and-data-segments/1"/imm32 895 68/push "e8 20 00 00 00 # e8/call 20/disp32"/imm32 - 896 68/push _test-output-stream/imm32 + 896 68/push _test-output-stream/imm32 897 # . . call 898 e8/call check-next-stream-line-equal/disp32 899 # . . discard args @@ -807,7 +807,7 @@ if ('onhashchange' in window) { 902 # . . push args 903 68/push "F - test-convert-code-and-data-segments/2"/imm32 904 68/push "68 20 # 68/push 0x20/imm8"/imm32 - 905 68/push _test-output-stream/imm32 + 905 68/push _test-output-stream/imm32 906 # . . call 907 e8/call check-next-stream-line-equal/disp32 908 # . . discard args @@ -816,7 +816,7 @@ if ('onhashchange' in window) { 911 # . . push args 912 68/push "F - test-convert-code-and-data-segments/3"/imm32 913 68/push "== data 0x2"/imm32 - 914 68/push _test-output-stream/imm32 + 914 68/push _test-output-stream/imm32 915 # . . call 916 e8/call check-next-stream-line-equal/disp32 917 # . . discard args @@ -825,7 +825,7 @@ if ('onhashchange' in window) { 920 # . . push args 921 68/push "F - test-convert-code-and-data-segments/4"/imm32 922 68/push "03 04 00 00 00 "/imm32 - 923 68/push _test-output-stream/imm32 + 923 68/push _test-output-stream/imm32 924 # . . call 925 e8/call check-next-stream-line-equal/disp32 926 # . . discard args @@ -995,21 +995,21 @@ if ('onhashchange' in window) { 1156 # setup 1157 # . clear-stream(_test-input-stream) 1158 # . . push args -1159 68/push _test-input-stream/imm32 +1159 68/push _test-input-stream/imm32 1160 # . . call 1161 e8/call clear-stream/disp32 1162 # . . discard args 1163 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1164 # . clear-stream(_test-output-stream) 1165 # . . push args -1166 68/push _test-output-stream/imm32 +1166 68/push _test-output-stream/imm32 1167 # . . call 1168 e8/call clear-stream/disp32 1169 # . . discard args 1170 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1171 # . clear-stream(_test-output-buffered-file+4) 1172 # . . push args -1173 b8/copy-to-EAX _test-output-buffered-file/imm32 +1173 b8/copy-to-EAX _test-output-buffered-file/imm32 1174 05/add-to-EAX 4/imm32 1175 50/push-EAX 1176 # . . call @@ -1020,15 +1020,15 @@ if ('onhashchange' in window) { 1181 # . write(_test-input-stream, "# abcd") 1182 # . . push args 1183 68/push "# abcd"/imm32 -1184 68/push _test-input-stream/imm32 +1184 68/push _test-input-stream/imm32 1185 # . . call 1186 e8/call write/disp32 1187 # . . discard args 1188 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1189 # convert-data(_test-input-stream, _test-output-buffered-file) 1190 # . . push args -1191 68/push _test-output-buffered-file/imm32 -1192 68/push _test-input-stream/imm32 +1191 68/push _test-output-buffered-file/imm32 +1192 68/push _test-input-stream/imm32 1193 # . . call 1194 e8/call convert-data/disp32 1195 # . . discard args @@ -1036,7 +1036,7 @@ if ('onhashchange' in window) { 1197 # check that the line just passed through 1198 # . flush(_test-output-buffered-file) 1199 # . . push args -1200 68/push _test-output-buffered-file/imm32 +1200 68/push _test-output-buffered-file/imm32 1201 # . . call 1202 e8/call flush/disp32 1203 # . . discard args @@ -1046,7 +1046,7 @@ if ('onhashchange' in window) { 1232 # . . push args 1233 68/push "F - test-convert-data-passes-comments-through"/imm32 1234 68/push "# abcd"/imm32 -1235 68/push _test-output-stream/imm32 +1235 68/push _test-output-stream/imm32 1236 # . . call 1237 e8/call check-stream-equal/disp32 1238 # . . discard args @@ -1064,21 +1064,21 @@ if ('onhashchange' in window) { 1250 # setup 1251 # . clear-stream(_test-input-stream) 1252 # . . push args -1253 68/push _test-input-stream/imm32 +1253 68/push _test-input-stream/imm32 1254 # . . call 1255 e8/call clear-stream/disp32 1256 # . . discard args 1257 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1258 # . clear-stream(_test-output-stream) 1259 # . . push args -1260 68/push _test-output-stream/imm32 +1260 68/push _test-output-stream/imm32 1261 # . . call 1262 e8/call clear-stream/disp32 1263 # . . discard args 1264 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1265 # . clear-stream(_test-output-buffered-file+4) 1266 # . . push args -1267 b8/copy-to-EAX _test-output-buffered-file/imm32 +1267 b8/copy-to-EAX _test-output-buffered-file/imm32 1268 05/add-to-EAX 4/imm32 1269 50/push-EAX 1270 # . . call @@ -1089,15 +1089,15 @@ if ('onhashchange' in window) { 1275 # . write(_test-input-stream, "ab: # cd") 1276 # . . push args 1277 68/push "ab: # cd"/imm32 -1278 68/push _test-input-stream/imm32 +1278 68/push _test-input-stream/imm32 1279 # . . call 1280 e8/call write/disp32 1281 # . . discard args 1282 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1283 # convert-data(_test-input-stream, _test-output-buffered-file) 1284 # . . push args -1285 68/push _test-output-buffered-file/imm32 -1286 68/push _test-input-stream/imm32 +1285 68/push _test-output-buffered-file/imm32 +1286 68/push _test-input-stream/imm32 1287 # . . call 1288 e8/call convert-data/disp32 1289 # . . discard args @@ -1105,7 +1105,7 @@ if ('onhashchange' in window) { 1291 # check that the line just passed through 1292 # . flush(_test-output-buffered-file) 1293 # . . push args -1294 68/push _test-output-buffered-file/imm32 +1294 68/push _test-output-buffered-file/imm32 1295 # . . call 1296 e8/call flush/disp32 1297 # . . discard args @@ -1114,7 +1114,7 @@ if ('onhashchange' in window) { 1300 # . . push args 1301 68/push "F - test-convert-data-passes-labels-through"/imm32 1302 68/push "ab: # cd"/imm32 -1303 68/push _test-output-stream/imm32 +1303 68/push _test-output-stream/imm32 1304 # . . call 1305 e8/call check-stream-equal/disp32 1306 # . . discard args @@ -1133,21 +1133,21 @@ if ('onhashchange' in window) { 1319 # setup 1320 # . clear-stream(_test-input-stream) 1321 # . . push args -1322 68/push _test-input-stream/imm32 +1322 68/push _test-input-stream/imm32 1323 # . . call 1324 e8/call clear-stream/disp32 1325 # . . discard args 1326 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1327 # . clear-stream(_test-output-stream) 1328 # . . push args -1329 68/push _test-output-stream/imm32 +1329 68/push _test-output-stream/imm32 1330 # . . call 1331 e8/call clear-stream/disp32 1332 # . . discard args 1333 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1334 # . clear-stream(_test-output-buffered-file+4) 1335 # . . push args -1336 b8/copy-to-EAX _test-output-buffered-file/imm32 +1336 b8/copy-to-EAX _test-output-buffered-file/imm32 1337 05/add-to-EAX 4/imm32 1338 50/push-EAX 1339 # . . call @@ -1158,15 +1158,15 @@ if ('onhashchange' in window) { 1344 # . write(_test-input-stream, "abcd/imm32") 1345 # . . push args 1346 68/push "abcd/imm32"/imm32 -1347 68/push _test-input-stream/imm32 +1347 68/push _test-input-stream/imm32 1348 # . . call 1349 e8/call write/disp32 1350 # . . discard args 1351 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1352 # convert-data(_test-input-stream, _test-output-buffered-file) 1353 # . . push args -1354 68/push _test-output-buffered-file/imm32 -1355 68/push _test-input-stream/imm32 +1354 68/push _test-output-buffered-file/imm32 +1355 68/push _test-input-stream/imm32 1356 # . . call 1357 e8/call convert-data/disp32 1358 # . . discard args @@ -1174,7 +1174,7 @@ if ('onhashchange' in window) { 1360 # check that the line just passed through 1361 # . flush(_test-output-buffered-file) 1362 # . . push args -1363 68/push _test-output-buffered-file/imm32 +1363 68/push _test-output-buffered-file/imm32 1364 # . . call 1365 e8/call flush/disp32 1366 # . . discard args @@ -1183,7 +1183,7 @@ if ('onhashchange' in window) { 1369 # . . push args 1370 68/push "F - test-convert-data-passes-names-through"/imm32 1371 68/push "abcd/imm32 \n"/imm32 -1372 68/push _test-output-stream/imm32 +1372 68/push _test-output-stream/imm32 1373 # . . call 1374 e8/call check-stream-equal/disp32 1375 # . . discard args @@ -1201,21 +1201,21 @@ if ('onhashchange' in window) { 1387 # setup 1388 # . clear-stream(_test-input-stream) 1389 # . . push args -1390 68/push _test-input-stream/imm32 +1390 68/push _test-input-stream/imm32 1391 # . . call 1392 e8/call clear-stream/disp32 1393 # . . discard args 1394 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1395 # . clear-stream(_test-output-stream) 1396 # . . push args -1397 68/push _test-output-stream/imm32 +1397 68/push _test-output-stream/imm32 1398 # . . call 1399 e8/call clear-stream/disp32 1400 # . . discard args 1401 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1402 # . clear-stream(_test-output-buffered-file+4) 1403 # . . push args -1404 b8/copy-to-EAX _test-output-buffered-file/imm32 +1404 b8/copy-to-EAX _test-output-buffered-file/imm32 1405 05/add-to-EAX 4/imm32 1406 50/push-EAX 1407 # . . call @@ -1226,15 +1226,15 @@ if ('onhashchange' in window) { 1412 # . write(_test-input-stream, "30/imm32") 1413 # . . push args 1414 68/push "30/imm32"/imm32 -1415 68/push _test-input-stream/imm32 +1415 68/push _test-input-stream/imm32 1416 # . . call 1417 e8/call write/disp32 1418 # . . discard args 1419 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1420 # convert-data(_test-input-stream, _test-output-buffered-file) 1421 # . . push args -1422 68/push _test-output-buffered-file/imm32 -1423 68/push _test-input-stream/imm32 +1422 68/push _test-output-buffered-file/imm32 +1423 68/push _test-input-stream/imm32 1424 # . . call 1425 e8/call convert-data/disp32 1426 # . . discard args @@ -1242,7 +1242,7 @@ if ('onhashchange' in window) { 1428 # check that 4 bytes were written 1429 # . flush(_test-output-buffered-file) 1430 # . . push args -1431 68/push _test-output-buffered-file/imm32 +1431 68/push _test-output-buffered-file/imm32 1432 # . . call 1433 e8/call flush/disp32 1434 # . . discard args @@ -1251,7 +1251,7 @@ if ('onhashchange' in window) { 1437 # . . push args 1438 68/push "F - test-convert-data-handles-imm32"/imm32 1439 68/push "30 00 00 00 \n"/imm32 -1440 68/push _test-output-stream/imm32 +1440 68/push _test-output-stream/imm32 1441 # . . call 1442 e8/call check-stream-equal/disp32 1443 # . . discard args @@ -1270,21 +1270,21 @@ if ('onhashchange' in window) { 1456 # setup 1457 # . clear-stream(_test-input-stream) 1458 # . . push args -1459 68/push _test-input-stream/imm32 +1459 68/push _test-input-stream/imm32 1460 # . . call 1461 e8/call clear-stream/disp32 1462 # . . discard args 1463 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1464 # . clear-stream(_test-output-stream) 1465 # . . push args -1466 68/push _test-output-stream/imm32 +1466 68/push _test-output-stream/imm32 1467 # . . call 1468 e8/call clear-stream/disp32 1469 # . . discard args 1470 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1471 # . clear-stream(_test-output-buffered-file+4) 1472 # . . push args -1473 b8/copy-to-EAX _test-output-buffered-file/imm32 +1473 b8/copy-to-EAX _test-output-buffered-file/imm32 1474 05/add-to-EAX 4/imm32 1475 50/push-EAX 1476 # . . call @@ -1295,15 +1295,15 @@ if ('onhashchange' in window) { 1481 # . write(_test-input-stream, "30/imm16") 1482 # . . push args 1483 68/push "30/imm16"/imm32 -1484 68/push _test-input-stream/imm32 +1484 68/push _test-input-stream/imm32 1485 # . . call 1486 e8/call write/disp32 1487 # . . discard args 1488 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1489 # convert-data(_test-input-stream, _test-output-buffered-file) 1490 # . . push args -1491 68/push _test-output-buffered-file/imm32 -1492 68/push _test-input-stream/imm32 +1491 68/push _test-output-buffered-file/imm32 +1492 68/push _test-input-stream/imm32 1493 # . . call 1494 e8/call convert-data/disp32 1495 # . . discard args @@ -1311,7 +1311,7 @@ if ('onhashchange' in window) { 1497 # check that a single byte was written (imm16 is not a valid operand type) 1498 # . flush(_test-output-buffered-file) 1499 # . . push args -1500 68/push _test-output-buffered-file/imm32 +1500 68/push _test-output-buffered-file/imm32 1501 # . . call 1502 e8/call flush/disp32 1503 # . . discard args @@ -1320,7 +1320,7 @@ if ('onhashchange' in window) { 1506 # . . push args 1507 68/push "F - test-convert-data-handles-single-byte"/imm32 1508 68/push "30 \n"/imm32 -1509 68/push _test-output-stream/imm32 +1509 68/push _test-output-stream/imm32 1510 # . . call 1511 e8/call check-stream-equal/disp32 1512 # . . discard args @@ -1338,21 +1338,21 @@ if ('onhashchange' in window) { 1524 # setup 1525 # . clear-stream(_test-input-stream) 1526 # . . push args -1527 68/push _test-input-stream/imm32 +1527 68/push _test-input-stream/imm32 1528 # . . call 1529 e8/call clear-stream/disp32 1530 # . . discard args 1531 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1532 # . clear-stream(_test-output-stream) 1533 # . . push args -1534 68/push _test-output-stream/imm32 +1534 68/push _test-output-stream/imm32 1535 # . . call 1536 e8/call clear-stream/disp32 1537 # . . discard args 1538 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1539 # . clear-stream(_test-output-buffered-file+4) 1540 # . . push args -1541 b8/copy-to-EAX _test-output-buffered-file/imm32 +1541 b8/copy-to-EAX _test-output-buffered-file/imm32 1542 05/add-to-EAX 4/imm32 1543 50/push-EAX 1544 # . . call @@ -1363,15 +1363,15 @@ if ('onhashchange' in window) { 1549 # . write(_test-input-stream, "1 2") 1550 # . . push args 1551 68/push "1 2"/imm32 -1552 68/push _test-input-stream/imm32 +1552 68/push _test-input-stream/imm32 1553 # . . call 1554 e8/call write/disp32 1555 # . . discard args 1556 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1557 # convert-data(_test-input-stream, _test-output-buffered-file) 1558 # . . push args -1559 68/push _test-output-buffered-file/imm32 -1560 68/push _test-input-stream/imm32 +1559 68/push _test-output-buffered-file/imm32 +1560 68/push _test-input-stream/imm32 1561 # . . call 1562 e8/call convert-data/disp32 1563 # . . discard args @@ -1379,7 +1379,7 @@ if ('onhashchange' in window) { 1565 # check output 1566 # . flush(_test-output-buffered-file) 1567 # . . push args -1568 68/push _test-output-buffered-file/imm32 +1568 68/push _test-output-buffered-file/imm32 1569 # . . call 1570 e8/call flush/disp32 1571 # . . discard args @@ -1388,7 +1388,7 @@ if ('onhashchange' in window) { 1574 # . . push args 1575 68/push "F - test-convert-data-multiple-bytes"/imm32 1576 68/push "01 02 \n"/imm32 -1577 68/push _test-output-stream/imm32 +1577 68/push _test-output-stream/imm32 1578 # . . call 1579 e8/call check-stream-equal/disp32 1580 # . . discard args @@ -1406,21 +1406,21 @@ if ('onhashchange' in window) { 1592 # setup 1593 # . clear-stream(_test-input-stream) 1594 # . . push args -1595 68/push _test-input-stream/imm32 +1595 68/push _test-input-stream/imm32 1596 # . . call 1597 e8/call clear-stream/disp32 1598 # . . discard args 1599 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1600 # . clear-stream(_test-output-stream) 1601 # . . push args -1602 68/push _test-output-stream/imm32 +1602 68/push _test-output-stream/imm32 1603 # . . call 1604 e8/call clear-stream/disp32 1605 # . . discard args 1606 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1607 # . clear-stream(_test-output-buffered-file+4) 1608 # . . push args -1609 b8/copy-to-EAX _test-output-buffered-file/imm32 +1609 b8/copy-to-EAX _test-output-buffered-file/imm32 1610 05/add-to-EAX 4/imm32 1611 50/push-EAX 1612 # . . call @@ -1431,15 +1431,15 @@ if ('onhashchange' in window) { 1617 # . write(_test-input-stream, "30 abcd/o") 1618 # . . push args 1619 68/push "30 abcd/o"/imm32 -1620 68/push _test-input-stream/imm32 +1620 68/push _test-input-stream/imm32 1621 # . . call 1622 e8/call write/disp32 1623 # . . discard args 1624 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1625 # convert-data(_test-input-stream, _test-output-buffered-file) 1626 # . . push args -1627 68/push _test-output-buffered-file/imm32 -1628 68/push _test-input-stream/imm32 +1627 68/push _test-output-buffered-file/imm32 +1628 68/push _test-input-stream/imm32 1629 # . . call 1630 e8/call convert-data/disp32 1631 # . . discard args @@ -1447,7 +1447,7 @@ if ('onhashchange' in window) { 1633 # check output 1634 # . flush(_test-output-buffered-file) 1635 # . . push args -1636 68/push _test-output-buffered-file/imm32 +1636 68/push _test-output-buffered-file/imm32 1637 # . . call 1638 e8/call flush/disp32 1639 # . . discard args @@ -1456,7 +1456,7 @@ if ('onhashchange' in window) { 1642 # . . push args 1643 68/push "F - test-convert-data-byte-then-name"/imm32 1644 68/push "30 abcd/o \n"/imm32 -1645 68/push _test-output-stream/imm32 +1645 68/push _test-output-stream/imm32 1646 # . . call 1647 e8/call check-stream-equal/disp32 1648 # . . discard args @@ -1474,21 +1474,21 @@ if ('onhashchange' in window) { 1660 # setup 1661 # . clear-stream(_test-input-stream) 1662 # . . push args -1663 68/push _test-input-stream/imm32 +1663 68/push _test-input-stream/imm32 1664 # . . call 1665 e8/call clear-stream/disp32 1666 # . . discard args 1667 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1668 # . clear-stream(_test-output-stream) 1669 # . . push args -1670 68/push _test-output-stream/imm32 +1670 68/push _test-output-stream/imm32 1671 # . . call 1672 e8/call clear-stream/disp32 1673 # . . discard args 1674 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1675 # . clear-stream(_test-output-buffered-file+4) 1676 # . . push args -1677 b8/copy-to-EAX _test-output-buffered-file/imm32 +1677 b8/copy-to-EAX _test-output-buffered-file/imm32 1678 05/add-to-EAX 4/imm32 1679 50/push-EAX 1680 # . . call @@ -1499,15 +1499,15 @@ if ('onhashchange' in window) { 1685 # . write(_test-input-stream, "30 abcd/o 42e1/imm32") 1686 # . . push args 1687 68/push "30 abcd/o 42e1/imm32"/imm32 -1688 68/push _test-input-stream/imm32 +1688 68/push _test-input-stream/imm32 1689 # . . call 1690 e8/call write/disp32 1691 # . . discard args 1692 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1693 # convert-data(_test-input-stream, _test-output-buffered-file) 1694 # . . push args -1695 68/push _test-output-buffered-file/imm32 -1696 68/push _test-input-stream/imm32 +1695 68/push _test-output-buffered-file/imm32 +1696 68/push _test-input-stream/imm32 1697 # . . call 1698 e8/call convert-data/disp32 1699 # . . discard args @@ -1515,7 +1515,7 @@ if ('onhashchange' in window) { 1701 # check output 1702 # . flush(_test-output-buffered-file) 1703 # . . push args -1704 68/push _test-output-buffered-file/imm32 +1704 68/push _test-output-buffered-file/imm32 1705 # . . call 1706 e8/call flush/disp32 1707 # . . discard args @@ -1525,7 +1525,7 @@ if ('onhashchange' in window) { 1736 # . . push args 1737 68/push "F - test-convert-data-multiple-words"/imm32 1738 68/push "30 abcd/o e1 42 00 00 \n"/imm32 -1739 68/push _test-output-stream/imm32 +1739 68/push _test-output-stream/imm32 1740 # . . call 1741 e8/call check-stream-equal/disp32 1742 # . . discard args @@ -1543,21 +1543,21 @@ if ('onhashchange' in window) { 1754 # setup 1755 # . clear-stream(_test-input-stream) 1756 # . . push args -1757 68/push _test-input-stream/imm32 +1757 68/push _test-input-stream/imm32 1758 # . . call 1759 e8/call clear-stream/disp32 1760 # . . discard args 1761 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1762 # . clear-stream(_test-output-stream) 1763 # . . push args -1764 68/push _test-output-stream/imm32 +1764 68/push _test-output-stream/imm32 1765 # . . call 1766 e8/call clear-stream/disp32 1767 # . . discard args 1768 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 1769 # . clear-stream(_test-output-buffered-file+4) 1770 # . . push args -1771 b8/copy-to-EAX _test-output-buffered-file/imm32 +1771 b8/copy-to-EAX _test-output-buffered-file/imm32 1772 05/add-to-EAX 4/imm32 1773 50/push-EAX 1774 # . . call @@ -1568,15 +1568,15 @@ if ('onhashchange' in window) { 1779 # . write(_test-input-stream, "30/imm32 # comment") 1780 # . . push args 1781 68/push "30/imm32 # comment"/imm32 -1782 68/push _test-input-stream/imm32 +1782 68/push _test-input-stream/imm32 1783 # . . call 1784 e8/call write/disp32 1785 # . . discard args 1786 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 1787 # convert-data(_test-input-stream, _test-output-buffered-file) 1788 # . . push args -1789 68/push _test-output-buffered-file/imm32 -1790 68/push _test-input-stream/imm32 +1789 68/push _test-output-buffered-file/imm32 +1790 68/push _test-input-stream/imm32 1791 # . . call 1792 e8/call convert-data/disp32 1793 # . . discard args @@ -1584,7 +1584,7 @@ if ('onhashchange' in window) { 1795 # check output 1796 # . flush(_test-output-buffered-file) 1797 # . . push args -1798 68/push _test-output-buffered-file/imm32 +1798 68/push _test-output-buffered-file/imm32 1799 # . . call 1800 e8/call flush/disp32 1801 # . . discard args @@ -1594,7 +1594,7 @@ if ('onhashchange' in window) { 1830 # . . push args 1831 68/push "F - test-convert-data-trailing-comment"/imm32 1832 68/push "30 00 00 00 # comment"/imm32 -1833 68/push _test-output-stream/imm32 +1833 68/push _test-output-stream/imm32 1834 # . . call 1835 e8/call check-stream-equal/disp32 1836 # . . discard args @@ -2861,21 +2861,21 @@ if ('onhashchange' in window) { 3368 # setup 3369 # . clear-stream(_test-input-stream) 3370 # . . push args -3371 68/push _test-input-stream/imm32 +3371 68/push _test-input-stream/imm32 3372 # . . call 3373 e8/call clear-stream/disp32 3374 # . . discard args 3375 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3376 # . clear-stream(_test-output-stream) 3377 # . . push args -3378 68/push _test-output-stream/imm32 +3378 68/push _test-output-stream/imm32 3379 # . . call 3380 e8/call clear-stream/disp32 3381 # . . discard args 3382 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3383 # . clear-stream(_test-output-buffered-file+4) 3384 # . . push args -3385 b8/copy-to-EAX _test-output-buffered-file/imm32 +3385 b8/copy-to-EAX _test-output-buffered-file/imm32 3386 05/add-to-EAX 4/imm32 3387 50/push-EAX 3388 # . . call @@ -2886,15 +2886,15 @@ if ('onhashchange' in window) { 3393 # . write(_test-input-stream, "# abcd") 3394 # . . push args 3395 68/push "# abcd"/imm32 -3396 68/push _test-input-stream/imm32 +3396 68/push _test-input-stream/imm32 3397 # . . call 3398 e8/call write/disp32 3399 # . . discard args 3400 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 3401 # convert-instruction(_test-input-stream, _test-output-buffered-file) 3402 # . . push args -3403 68/push _test-output-buffered-file/imm32 -3404 68/push _test-input-stream/imm32 +3403 68/push _test-output-buffered-file/imm32 +3404 68/push _test-input-stream/imm32 3405 # . . call 3406 e8/call convert-instruction/disp32 3407 # . . discard args @@ -2902,7 +2902,7 @@ if ('onhashchange' in window) { 3409 # check that the line just passed through 3410 # . flush(_test-output-buffered-file) 3411 # . . push args -3412 68/push _test-output-buffered-file/imm32 +3412 68/push _test-output-buffered-file/imm32 3413 # . . call 3414 e8/call flush/disp32 3415 # . . discard args @@ -2911,7 +2911,7 @@ if ('onhashchange' in window) { 3418 # . . push args 3419 68/push "F - test-convert-instruction-passes-comments-through"/imm32 3420 68/push "# abcd"/imm32 -3421 68/push _test-output-stream/imm32 +3421 68/push _test-output-stream/imm32 3422 # . . call 3423 e8/call check-stream-equal/disp32 3424 # . . discard args @@ -2929,21 +2929,21 @@ if ('onhashchange' in window) { 3436 # setup 3437 # . clear-stream(_test-input-stream) 3438 # . . push args -3439 68/push _test-input-stream/imm32 +3439 68/push _test-input-stream/imm32 3440 # . . call 3441 e8/call clear-stream/disp32 3442 # . . discard args 3443 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3444 # . clear-stream(_test-output-stream) 3445 # . . push args -3446 68/push _test-output-stream/imm32 +3446 68/push _test-output-stream/imm32 3447 # . . call 3448 e8/call clear-stream/disp32 3449 # . . discard args 3450 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3451 # . clear-stream(_test-output-buffered-file+4) 3452 # . . push args -3453 b8/copy-to-EAX _test-output-buffered-file/imm32 +3453 b8/copy-to-EAX _test-output-buffered-file/imm32 3454 05/add-to-EAX 4/imm32 3455 50/push-EAX 3456 # . . call @@ -2954,15 +2954,15 @@ if ('onhashchange' in window) { 3461 # . write(_test-input-stream, "ab: # cd") 3462 # . . push args 3463 68/push "ab: # cd"/imm32 -3464 68/push _test-input-stream/imm32 +3464 68/push _test-input-stream/imm32 3465 # . . call 3466 e8/call write/disp32 3467 # . . discard args 3468 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 3469 # convert-instruction(_test-input-stream, _test-output-buffered-file) 3470 # . . push args -3471 68/push _test-output-buffered-file/imm32 -3472 68/push _test-input-stream/imm32 +3471 68/push _test-output-buffered-file/imm32 +3472 68/push _test-input-stream/imm32 3473 # . . call 3474 e8/call convert-instruction/disp32 3475 # . . discard args @@ -2970,7 +2970,7 @@ if ('onhashchange' in window) { 3477 # check that the line just passed through 3478 # . flush(_test-output-buffered-file) 3479 # . . push args -3480 68/push _test-output-buffered-file/imm32 +3480 68/push _test-output-buffered-file/imm32 3481 # . . call 3482 e8/call flush/disp32 3483 # . . discard args @@ -2979,7 +2979,7 @@ if ('onhashchange' in window) { 3486 # . . push args 3487 68/push "F - test-convert-instruction-passes-labels-through"/imm32 3488 68/push "ab: # cd"/imm32 -3489 68/push _test-output-stream/imm32 +3489 68/push _test-output-stream/imm32 3490 # . . call 3491 e8/call check-stream-equal/disp32 3492 # . . discard args @@ -2997,21 +2997,21 @@ if ('onhashchange' in window) { 3504 # setup 3505 # . clear-stream(_test-input-stream) 3506 # . . push args -3507 68/push _test-input-stream/imm32 +3507 68/push _test-input-stream/imm32 3508 # . . call 3509 e8/call clear-stream/disp32 3510 # . . discard args 3511 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3512 # . clear-stream(_test-output-stream) 3513 # . . push args -3514 68/push _test-output-stream/imm32 +3514 68/push _test-output-stream/imm32 3515 # . . call 3516 e8/call clear-stream/disp32 3517 # . . discard args 3518 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3519 # . clear-stream(_test-output-buffered-file+4) 3520 # . . push args -3521 b8/copy-to-EAX _test-output-buffered-file/imm32 +3521 b8/copy-to-EAX _test-output-buffered-file/imm32 3522 05/add-to-EAX 4/imm32 3523 50/push-EAX 3524 # . . call @@ -3022,15 +3022,15 @@ if ('onhashchange' in window) { 3529 # . write(_test-input-stream, "ab/cd # comment") 3530 # . . push args 3531 68/push "ab/cd # comment"/imm32 -3532 68/push _test-input-stream/imm32 +3532 68/push _test-input-stream/imm32 3533 # . . call 3534 e8/call write/disp32 3535 # . . discard args 3536 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 3537 # convert-instruction(_test-input-stream, _test-output-buffered-file) 3538 # . . push args -3539 68/push _test-output-buffered-file/imm32 -3540 68/push _test-input-stream/imm32 +3539 68/push _test-output-buffered-file/imm32 +3540 68/push _test-input-stream/imm32 3541 # . . call 3542 e8/call convert-instruction/disp32 3543 # . . discard args @@ -3038,7 +3038,7 @@ if ('onhashchange' in window) { 3545 # check output 3546 # . flush(_test-output-buffered-file) 3547 # . . push args -3548 68/push _test-output-buffered-file/imm32 +3548 68/push _test-output-buffered-file/imm32 3549 # . . call 3550 e8/call flush/disp32 3551 # . . discard args @@ -3048,7 +3048,7 @@ if ('onhashchange' in window) { 3580 # . . push args 3581 68/push "F - test-convert-instruction-handles-single-opcode"/imm32 3582 68/push "ab # ab/cd # comment"/imm32 -3583 68/push _test-output-stream/imm32 +3583 68/push _test-output-stream/imm32 3584 # . . call 3585 e8/call check-stream-equal/disp32 3586 # . . discard args @@ -3066,21 +3066,21 @@ if ('onhashchange' in window) { 3598 # setup 3599 # . clear-stream(_test-input-stream) 3600 # . . push args -3601 68/push _test-input-stream/imm32 +3601 68/push _test-input-stream/imm32 3602 # . . call 3603 e8/call clear-stream/disp32 3604 # . . discard args 3605 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3606 # . clear-stream(_test-output-stream) 3607 # . . push args -3608 68/push _test-output-stream/imm32 +3608 68/push _test-output-stream/imm32 3609 # . . call 3610 e8/call clear-stream/disp32 3611 # . . discard args 3612 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3613 # . clear-stream(_test-output-buffered-file+4) 3614 # . . push args -3615 b8/copy-to-EAX _test-output-buffered-file/imm32 +3615 b8/copy-to-EAX _test-output-buffered-file/imm32 3616 05/add-to-EAX 4/imm32 3617 50/push-EAX 3618 # . . call @@ -3091,15 +3091,15 @@ if ('onhashchange' in window) { 3623 # . write(_test-input-stream, "0f/m1 ab/m2 # comment") 3624 # . . push args 3625 68/push "0f/m1 ab/m2 # comment"/imm32 -3626 68/push _test-input-stream/imm32 +3626 68/push _test-input-stream/imm32 3627 # . . call 3628 e8/call write/disp32 3629 # . . discard args 3630 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 3631 # convert-instruction(_test-input-stream, _test-output-buffered-file) 3632 # . . push args -3633 68/push _test-output-buffered-file/imm32 -3634 68/push _test-input-stream/imm32 +3633 68/push _test-output-buffered-file/imm32 +3634 68/push _test-input-stream/imm32 3635 # . . call 3636 e8/call convert-instruction/disp32 3637 # . . discard args @@ -3107,7 +3107,7 @@ if ('onhashchange' in window) { 3639 # check output 3640 # . flush(_test-output-buffered-file) 3641 # . . push args -3642 68/push _test-output-buffered-file/imm32 +3642 68/push _test-output-buffered-file/imm32 3643 # . . call 3644 e8/call flush/disp32 3645 # . . discard args @@ -3117,7 +3117,7 @@ if ('onhashchange' in window) { 3674 # . . push args 3675 68/push "F - test-convert-instruction-handles-0f-opcode"/imm32 3676 68/push "0f ab # 0f/m1 ab/m2 # comment"/imm32 -3677 68/push _test-output-stream/imm32 +3677 68/push _test-output-stream/imm32 3678 # . . call 3679 e8/call check-stream-equal/disp32 3680 # . . discard args @@ -3135,21 +3135,21 @@ if ('onhashchange' in window) { 3692 # setup 3693 # . clear-stream(_test-input-stream) 3694 # . . push args -3695 68/push _test-input-stream/imm32 +3695 68/push _test-input-stream/imm32 3696 # . . call 3697 e8/call clear-stream/disp32 3698 # . . discard args 3699 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3700 # . clear-stream(_test-output-stream) 3701 # . . push args -3702 68/push _test-output-stream/imm32 +3702 68/push _test-output-stream/imm32 3703 # . . call 3704 e8/call clear-stream/disp32 3705 # . . discard args 3706 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3707 # . clear-stream(_test-output-buffered-file+4) 3708 # . . push args -3709 b8/copy-to-EAX _test-output-buffered-file/imm32 +3709 b8/copy-to-EAX _test-output-buffered-file/imm32 3710 05/add-to-EAX 4/imm32 3711 50/push-EAX 3712 # . . call @@ -3160,15 +3160,15 @@ if ('onhashchange' in window) { 3717 # . write(_test-input-stream, "f2/m1 ab/m2 # comment") 3718 # . . push args 3719 68/push "f2/m1 ab/m2 # comment"/imm32 -3720 68/push _test-input-stream/imm32 +3720 68/push _test-input-stream/imm32 3721 # . . call 3722 e8/call write/disp32 3723 # . . discard args 3724 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 3725 # convert-instruction(_test-input-stream, _test-output-buffered-file) 3726 # . . push args -3727 68/push _test-output-buffered-file/imm32 -3728 68/push _test-input-stream/imm32 +3727 68/push _test-output-buffered-file/imm32 +3728 68/push _test-input-stream/imm32 3729 # . . call 3730 e8/call convert-instruction/disp32 3731 # . . discard args @@ -3176,7 +3176,7 @@ if ('onhashchange' in window) { 3733 # check output 3734 # . flush(_test-output-buffered-file) 3735 # . . push args -3736 68/push _test-output-buffered-file/imm32 +3736 68/push _test-output-buffered-file/imm32 3737 # . . call 3738 e8/call flush/disp32 3739 # . . discard args @@ -3186,7 +3186,7 @@ if ('onhashchange' in window) { 3768 # . . push args 3769 68/push "F - test-convert-instruction-handles-f2-opcode"/imm32 3770 68/push "f2 ab # f2/m1 ab/m2 # comment"/imm32 -3771 68/push _test-output-stream/imm32 +3771 68/push _test-output-stream/imm32 3772 # . . call 3773 e8/call check-stream-equal/disp32 3774 # . . discard args @@ -3204,21 +3204,21 @@ if ('onhashchange' in window) { 3786 # setup 3787 # . clear-stream(_test-input-stream) 3788 # . . push args -3789 68/push _test-input-stream/imm32 +3789 68/push _test-input-stream/imm32 3790 # . . call 3791 e8/call clear-stream/disp32 3792 # . . discard args 3793 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3794 # . clear-stream(_test-output-stream) 3795 # . . push args -3796 68/push _test-output-stream/imm32 +3796 68/push _test-output-stream/imm32 3797 # . . call 3798 e8/call clear-stream/disp32 3799 # . . discard args 3800 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3801 # . clear-stream(_test-output-buffered-file+4) 3802 # . . push args -3803 b8/copy-to-EAX _test-output-buffered-file/imm32 +3803 b8/copy-to-EAX _test-output-buffered-file/imm32 3804 05/add-to-EAX 4/imm32 3805 50/push-EAX 3806 # . . call @@ -3229,15 +3229,15 @@ if ('onhashchange' in window) { 3811 # . write(_test-input-stream, "f3/m1 ab/m2 # comment") 3812 # . . push args 3813 68/push "f3/m1 ab/m2 # comment"/imm32 -3814 68/push _test-input-stream/imm32 +3814 68/push _test-input-stream/imm32 3815 # . . call 3816 e8/call write/disp32 3817 # . . discard args 3818 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 3819 # convert-instruction(_test-input-stream, _test-output-buffered-file) 3820 # . . push args -3821 68/push _test-output-buffered-file/imm32 -3822 68/push _test-input-stream/imm32 +3821 68/push _test-output-buffered-file/imm32 +3822 68/push _test-input-stream/imm32 3823 # . . call 3824 e8/call convert-instruction/disp32 3825 # . . discard args @@ -3245,7 +3245,7 @@ if ('onhashchange' in window) { 3827 # check output 3828 # . flush(_test-output-buffered-file) 3829 # . . push args -3830 68/push _test-output-buffered-file/imm32 +3830 68/push _test-output-buffered-file/imm32 3831 # . . call 3832 e8/call flush/disp32 3833 # . . discard args @@ -3255,7 +3255,7 @@ if ('onhashchange' in window) { 3862 # . . push args 3863 68/push "F - test-convert-instruction-handles-f3-opcode"/imm32 3864 68/push "f3 ab # f3/m1 ab/m2 # comment"/imm32 -3865 68/push _test-output-stream/imm32 +3865 68/push _test-output-stream/imm32 3866 # . . call 3867 e8/call check-stream-equal/disp32 3868 # . . discard args @@ -3273,21 +3273,21 @@ if ('onhashchange' in window) { 3880 # setup 3881 # . clear-stream(_test-input-stream) 3882 # . . push args -3883 68/push _test-input-stream/imm32 +3883 68/push _test-input-stream/imm32 3884 # . . call 3885 e8/call clear-stream/disp32 3886 # . . discard args 3887 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3888 # . clear-stream(_test-output-stream) 3889 # . . push args -3890 68/push _test-output-stream/imm32 +3890 68/push _test-output-stream/imm32 3891 # . . call 3892 e8/call clear-stream/disp32 3893 # . . discard args 3894 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3895 # . clear-stream(_test-output-buffered-file+4) 3896 # . . push args -3897 b8/copy-to-EAX _test-output-buffered-file/imm32 +3897 b8/copy-to-EAX _test-output-buffered-file/imm32 3898 05/add-to-EAX 4/imm32 3899 50/push-EAX 3900 # . . call @@ -3298,15 +3298,15 @@ if ('onhashchange' in window) { 3905 # . write(_test-input-stream, "f2/m1 0f/m2 ab/m3 # comment") 3906 # . . push args 3907 68/push "f2/m1 0f/m2 ab/m3 # comment"/imm32 -3908 68/push _test-input-stream/imm32 +3908 68/push _test-input-stream/imm32 3909 # . . call 3910 e8/call write/disp32 3911 # . . discard args 3912 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 3913 # convert-instruction(_test-input-stream, _test-output-buffered-file) 3914 # . . push args -3915 68/push _test-output-buffered-file/imm32 -3916 68/push _test-input-stream/imm32 +3915 68/push _test-output-buffered-file/imm32 +3916 68/push _test-input-stream/imm32 3917 # . . call 3918 e8/call convert-instruction/disp32 3919 # . . discard args @@ -3314,7 +3314,7 @@ if ('onhashchange' in window) { 3921 # check output 3922 # . flush(_test-output-buffered-file) 3923 # . . push args -3924 68/push _test-output-buffered-file/imm32 +3924 68/push _test-output-buffered-file/imm32 3925 # . . call 3926 e8/call flush/disp32 3927 # . . discard args @@ -3324,7 +3324,7 @@ if ('onhashchange' in window) { 3956 # . . push args 3957 68/push "F - test-convert-instruction-handles-f2-0f-opcode"/imm32 3958 68/push "f2 0f ab # f2/m1 0f/m2 ab/m3 # comment"/imm32 -3959 68/push _test-output-stream/imm32 +3959 68/push _test-output-stream/imm32 3960 # . . call 3961 e8/call check-stream-equal/disp32 3962 # . . discard args @@ -3342,21 +3342,21 @@ if ('onhashchange' in window) { 3974 # setup 3975 # . clear-stream(_test-input-stream) 3976 # . . push args -3977 68/push _test-input-stream/imm32 +3977 68/push _test-input-stream/imm32 3978 # . . call 3979 e8/call clear-stream/disp32 3980 # . . discard args 3981 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3982 # . clear-stream(_test-output-stream) 3983 # . . push args -3984 68/push _test-output-stream/imm32 +3984 68/push _test-output-stream/imm32 3985 # . . call 3986 e8/call clear-stream/disp32 3987 # . . discard args 3988 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 3989 # . clear-stream(_test-output-buffered-file+4) 3990 # . . push args -3991 b8/copy-to-EAX _test-output-buffered-file/imm32 +3991 b8/copy-to-EAX _test-output-buffered-file/imm32 3992 05/add-to-EAX 4/imm32 3993 50/push-EAX 3994 # . . call @@ -3367,15 +3367,15 @@ if ('onhashchange' in window) { 3999 # . write(_test-input-stream, "f3/m1 0f/m2 ab/m3 # comment") 4000 # . . push args 4001 68/push "f3/m1 0f/m2 ab/m3 # comment"/imm32 -4002 68/push _test-input-stream/imm32 +4002 68/push _test-input-stream/imm32 4003 # . . call 4004 e8/call write/disp32 4005 # . . discard args 4006 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4007 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4008 # . . push args -4009 68/push _test-output-buffered-file/imm32 -4010 68/push _test-input-stream/imm32 +4009 68/push _test-output-buffered-file/imm32 +4010 68/push _test-input-stream/imm32 4011 # . . call 4012 e8/call convert-instruction/disp32 4013 # . . discard args @@ -3383,7 +3383,7 @@ if ('onhashchange' in window) { 4015 # check output 4016 # . flush(_test-output-buffered-file) 4017 # . . push args -4018 68/push _test-output-buffered-file/imm32 +4018 68/push _test-output-buffered-file/imm32 4019 # . . call 4020 e8/call flush/disp32 4021 # . . discard args @@ -3393,7 +3393,7 @@ if ('onhashchange' in window) { 4050 # . . push args 4051 68/push "F - test-convert-instruction-handles-f3-0f-opcode"/imm32 4052 68/push "f3 0f ab # f3/m1 0f/m2 ab/m3 # comment"/imm32 -4053 68/push _test-output-stream/imm32 +4053 68/push _test-output-stream/imm32 4054 # . . call 4055 e8/call check-stream-equal/disp32 4056 # . . discard args @@ -3411,21 +3411,21 @@ if ('onhashchange' in window) { 4068 # setup 4069 # . clear-stream(_test-input-stream) 4070 # . . push args -4071 68/push _test-input-stream/imm32 +4071 68/push _test-input-stream/imm32 4072 # . . call 4073 e8/call clear-stream/disp32 4074 # . . discard args 4075 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4076 # . clear-stream(_test-output-stream) 4077 # . . push args -4078 68/push _test-output-stream/imm32 +4078 68/push _test-output-stream/imm32 4079 # . . call 4080 e8/call clear-stream/disp32 4081 # . . discard args 4082 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4083 # . clear-stream(_test-output-buffered-file+4) 4084 # . . push args -4085 b8/copy-to-EAX _test-output-buffered-file/imm32 +4085 b8/copy-to-EAX _test-output-buffered-file/imm32 4086 05/add-to-EAX 4/imm32 4087 50/push-EAX 4088 # . . call @@ -3436,15 +3436,15 @@ if ('onhashchange' in window) { 4093 # . write(_test-input-stream, "ab/m1 cd/m2 # comment") 4094 # . . push args 4095 68/push "ab/m1 cd/m2 # comment"/imm32 -4096 68/push _test-input-stream/imm32 +4096 68/push _test-input-stream/imm32 4097 # . . call 4098 e8/call write/disp32 4099 # . . discard args 4100 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4101 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4102 # . . push args -4103 68/push _test-output-buffered-file/imm32 -4104 68/push _test-input-stream/imm32 +4103 68/push _test-output-buffered-file/imm32 +4104 68/push _test-input-stream/imm32 4105 # . . call 4106 e8/call convert-instruction/disp32 4107 # . . discard args @@ -3452,7 +3452,7 @@ if ('onhashchange' in window) { 4109 # check output 4110 # . flush(_test-output-buffered-file) 4111 # . . push args -4112 68/push _test-output-buffered-file/imm32 +4112 68/push _test-output-buffered-file/imm32 4113 # . . call 4114 e8/call flush/disp32 4115 # . . discard args @@ -3462,7 +3462,7 @@ if ('onhashchange' in window) { 4144 # . . push args 4145 68/push "F - test-convert-instruction-handles-unused-opcodes"/imm32 4146 68/push "ab # ab/m1 cd/m2 # comment"/imm32 -4147 68/push _test-output-stream/imm32 +4147 68/push _test-output-stream/imm32 4148 # . . call 4149 e8/call check-stream-equal/disp32 4150 # . . discard args @@ -3480,21 +3480,21 @@ if ('onhashchange' in window) { 4162 # setup 4163 # . clear-stream(_test-input-stream) 4164 # . . push args -4165 68/push _test-input-stream/imm32 +4165 68/push _test-input-stream/imm32 4166 # . . call 4167 e8/call clear-stream/disp32 4168 # . . discard args 4169 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4170 # . clear-stream(_test-output-stream) 4171 # . . push args -4172 68/push _test-output-stream/imm32 +4172 68/push _test-output-stream/imm32 4173 # . . call 4174 e8/call clear-stream/disp32 4175 # . . discard args 4176 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4177 # . clear-stream(_test-output-buffered-file+4) 4178 # . . push args -4179 b8/copy-to-EAX _test-output-buffered-file/imm32 +4179 b8/copy-to-EAX _test-output-buffered-file/imm32 4180 05/add-to-EAX 4/imm32 4181 50/push-EAX 4182 # . . call @@ -3505,15 +3505,15 @@ if ('onhashchange' in window) { 4187 # . write(_test-input-stream, "f2/m1 ab/m2 cd/m3 # comment") 4188 # . . push args 4189 68/push "f2/m1 ab/m2 cd/m3 # comment"/imm32 -4190 68/push _test-input-stream/imm32 +4190 68/push _test-input-stream/imm32 4191 # . . call 4192 e8/call write/disp32 4193 # . . discard args 4194 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4195 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4196 # . . push args -4197 68/push _test-output-buffered-file/imm32 -4198 68/push _test-input-stream/imm32 +4197 68/push _test-output-buffered-file/imm32 +4198 68/push _test-input-stream/imm32 4199 # . . call 4200 e8/call convert-instruction/disp32 4201 # . . discard args @@ -3521,7 +3521,7 @@ if ('onhashchange' in window) { 4203 # check output 4204 # . flush(_test-output-buffered-file) 4205 # . . push args -4206 68/push _test-output-buffered-file/imm32 +4206 68/push _test-output-buffered-file/imm32 4207 # . . call 4208 e8/call flush/disp32 4209 # . . discard args @@ -3531,7 +3531,7 @@ if ('onhashchange' in window) { 4238 # . . push args 4239 68/push "F - test-convert-instruction-handles-unused-second-opcodes"/imm32 4240 68/push "f2 ab # f2/m1 ab/m2 cd/m3 # comment"/imm32 -4241 68/push _test-output-stream/imm32 +4241 68/push _test-output-stream/imm32 4242 # . . call 4243 e8/call check-stream-equal/disp32 4244 # . . discard args @@ -3549,21 +3549,21 @@ if ('onhashchange' in window) { 4256 # setup 4257 # . clear-stream(_test-input-stream) 4258 # . . push args -4259 68/push _test-input-stream/imm32 +4259 68/push _test-input-stream/imm32 4260 # . . call 4261 e8/call clear-stream/disp32 4262 # . . discard args 4263 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4264 # . clear-stream(_test-output-stream) 4265 # . . push args -4266 68/push _test-output-stream/imm32 +4266 68/push _test-output-stream/imm32 4267 # . . call 4268 e8/call clear-stream/disp32 4269 # . . discard args 4270 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4271 # . clear-stream(_test-output-buffered-file+4) 4272 # . . push args -4273 b8/copy-to-EAX _test-output-buffered-file/imm32 +4273 b8/copy-to-EAX _test-output-buffered-file/imm32 4274 05/add-to-EAX 4/imm32 4275 50/push-EAX 4276 # . . call @@ -3574,15 +3574,15 @@ if ('onhashchange' in window) { 4281 # . write(_test-input-stream, "f3/m1 ab/m2 cd/m3 # comment") 4282 # . . push args 4283 68/push "f3/m1 ab/m2 cd/m3 # comment"/imm32 -4284 68/push _test-input-stream/imm32 +4284 68/push _test-input-stream/imm32 4285 # . . call 4286 e8/call write/disp32 4287 # . . discard args 4288 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4289 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4290 # . . push args -4291 68/push _test-output-buffered-file/imm32 -4292 68/push _test-input-stream/imm32 +4291 68/push _test-output-buffered-file/imm32 +4292 68/push _test-input-stream/imm32 4293 # . . call 4294 e8/call convert-instruction/disp32 4295 # . . discard args @@ -3590,7 +3590,7 @@ if ('onhashchange' in window) { 4297 # check output 4298 # . flush(_test-output-buffered-file) 4299 # . . push args -4300 68/push _test-output-buffered-file/imm32 +4300 68/push _test-output-buffered-file/imm32 4301 # . . call 4302 e8/call flush/disp32 4303 # . . discard args @@ -3600,7 +3600,7 @@ if ('onhashchange' in window) { 4332 # . . push args 4333 68/push "F - test-convert-instruction-handles-unused-second-opcodes"/imm32 4334 68/push "f3 ab # f3/m1 ab/m2 cd/m3 # comment"/imm32 -4335 68/push _test-output-stream/imm32 +4335 68/push _test-output-stream/imm32 4336 # . . call 4337 e8/call check-stream-equal/disp32 4338 # . . discard args @@ -3618,21 +3618,21 @@ if ('onhashchange' in window) { 4350 # setup 4351 # . clear-stream(_test-input-stream) 4352 # . . push args -4353 68/push _test-input-stream/imm32 +4353 68/push _test-input-stream/imm32 4354 # . . call 4355 e8/call clear-stream/disp32 4356 # . . discard args 4357 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4358 # . clear-stream(_test-output-stream) 4359 # . . push args -4360 68/push _test-output-stream/imm32 +4360 68/push _test-output-stream/imm32 4361 # . . call 4362 e8/call clear-stream/disp32 4363 # . . discard args 4364 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4365 # . clear-stream(_test-output-buffered-file+4) 4366 # . . push args -4367 b8/copy-to-EAX _test-output-buffered-file/imm32 +4367 b8/copy-to-EAX _test-output-buffered-file/imm32 4368 05/add-to-EAX 4/imm32 4369 50/push-EAX 4370 # . . call @@ -3643,15 +3643,15 @@ if ('onhashchange' in window) { 4375 # . write(_test-input-stream, "8b/copy 0/mod 0/rm32 1/r32") 4376 # . . push args 4377 68/push "8b/copy 0/mod 0/rm32 1/r32"/imm32 -4378 68/push _test-input-stream/imm32 +4378 68/push _test-input-stream/imm32 4379 # . . call 4380 e8/call write/disp32 4381 # . . discard args 4382 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4383 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4384 # . . push args -4385 68/push _test-output-buffered-file/imm32 -4386 68/push _test-input-stream/imm32 +4385 68/push _test-output-buffered-file/imm32 +4386 68/push _test-input-stream/imm32 4387 # . . call 4388 e8/call convert-instruction/disp32 4389 # . . discard args @@ -3659,7 +3659,7 @@ if ('onhashchange' in window) { 4391 # check output 4392 # . flush(_test-output-buffered-file) 4393 # . . push args -4394 68/push _test-output-buffered-file/imm32 +4394 68/push _test-output-buffered-file/imm32 4395 # . . call 4396 e8/call flush/disp32 4397 # . . discard args @@ -3669,7 +3669,7 @@ if ('onhashchange' in window) { 4426 # . . push args 4427 68/push "F - test-convert-instruction-emits-modrm-byte"/imm32 4428 68/push "8b 08 # 8b/copy 0/mod 0/rm32 1/r32"/imm32 -4429 68/push _test-output-stream/imm32 +4429 68/push _test-output-stream/imm32 4430 # . . call 4431 e8/call check-stream-equal/disp32 4432 # . . discard args @@ -3686,21 +3686,21 @@ if ('onhashchange' in window) { 4443 # setup 4444 # . clear-stream(_test-input-stream) 4445 # . . push args -4446 68/push _test-input-stream/imm32 +4446 68/push _test-input-stream/imm32 4447 # . . call 4448 e8/call clear-stream/disp32 4449 # . . discard args 4450 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4451 # . clear-stream(_test-output-stream) 4452 # . . push args -4453 68/push _test-output-stream/imm32 +4453 68/push _test-output-stream/imm32 4454 # . . call 4455 e8/call clear-stream/disp32 4456 # . . discard args 4457 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4458 # . clear-stream(_test-output-buffered-file+4) 4459 # . . push args -4460 b8/copy-to-EAX _test-output-buffered-file/imm32 +4460 b8/copy-to-EAX _test-output-buffered-file/imm32 4461 05/add-to-EAX 4/imm32 4462 50/push-EAX 4463 # . . call @@ -3711,22 +3711,22 @@ if ('onhashchange' in window) { 4468 # . write(_test-input-stream, "01/add 3/mod/direct 3/rm32/EBX 1/r32/ECX") 4469 # . . push args 4470 68/push "01/add 3/mod/direct 3/rm32/EBX 1/r32/ECX"/imm32 -4471 68/push _test-input-stream/imm32 +4471 68/push _test-input-stream/imm32 4472 # . . call 4473 e8/call write/disp32 4474 # . . discard args 4475 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4476 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4477 # . . push args -4478 68/push _test-output-buffered-file/imm32 -4479 68/push _test-input-stream/imm32 +4478 68/push _test-output-buffered-file/imm32 +4479 68/push _test-input-stream/imm32 4480 # . . call 4481 e8/call convert-instruction/disp32 4482 # . . discard args 4483 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4484 # . flush(_test-output-buffered-file) 4485 # . . push args -4486 68/push _test-output-buffered-file/imm32 +4486 68/push _test-output-buffered-file/imm32 4487 # . . call 4488 e8/call flush/disp32 4489 # . . discard args @@ -3737,7 +3737,7 @@ if ('onhashchange' in window) { 4519 # . . push args 4520 68/push "F - test-convert-instruction-foo"/imm32 4521 68/push "01 cb # 01/add 3/mod/direct 3/rm32/EBX 1/r32/ECX"/imm32 -4522 68/push _test-output-stream/imm32 +4522 68/push _test-output-stream/imm32 4523 # . . call 4524 e8/call check-stream-equal/disp32 4525 # . . discard args @@ -3755,21 +3755,21 @@ if ('onhashchange' in window) { 4537 # setup 4538 # . clear-stream(_test-input-stream) 4539 # . . push args -4540 68/push _test-input-stream/imm32 +4540 68/push _test-input-stream/imm32 4541 # . . call 4542 e8/call clear-stream/disp32 4543 # . . discard args 4544 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4545 # . clear-stream(_test-output-stream) 4546 # . . push args -4547 68/push _test-output-stream/imm32 +4547 68/push _test-output-stream/imm32 4548 # . . call 4549 e8/call clear-stream/disp32 4550 # . . discard args 4551 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4552 # . clear-stream(_test-output-buffered-file+4) 4553 # . . push args -4554 b8/copy-to-EAX _test-output-buffered-file/imm32 +4554 b8/copy-to-EAX _test-output-buffered-file/imm32 4555 05/add-to-EAX 4/imm32 4556 50/push-EAX 4557 # . . call @@ -3780,15 +3780,15 @@ if ('onhashchange' in window) { 4562 # . write(_test-input-stream, "ff 6/subop/push 0/mod 0/rm32") 4563 # . . push args 4564 68/push "ff 6/subop/push 0/mod 0/rm32"/imm32 -4565 68/push _test-input-stream/imm32 +4565 68/push _test-input-stream/imm32 4566 # . . call 4567 e8/call write/disp32 4568 # . . discard args 4569 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4570 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4571 # . . push args -4572 68/push _test-output-buffered-file/imm32 -4573 68/push _test-input-stream/imm32 +4572 68/push _test-output-buffered-file/imm32 +4573 68/push _test-input-stream/imm32 4574 # . . call 4575 e8/call convert-instruction/disp32 4576 # . . discard args @@ -3796,7 +3796,7 @@ if ('onhashchange' in window) { 4578 # check output 4579 # . flush(_test-output-buffered-file) 4580 # . . push args -4581 68/push _test-output-buffered-file/imm32 +4581 68/push _test-output-buffered-file/imm32 4582 # . . call 4583 e8/call flush/disp32 4584 # . . discard args @@ -3806,7 +3806,7 @@ if ('onhashchange' in window) { 4613 # . . push args 4614 68/push "F - test-convert-instruction-emits-modrm-byte-from-subop"/imm32 4615 68/push "ff 30 # ff 6/subop/push 0/mod 0/rm32"/imm32 -4616 68/push _test-output-stream/imm32 +4616 68/push _test-output-stream/imm32 4617 # . . call 4618 e8/call check-stream-equal/disp32 4619 # . . discard args @@ -3824,21 +3824,21 @@ if ('onhashchange' in window) { 4631 # setup 4632 # . clear-stream(_test-input-stream) 4633 # . . push args -4634 68/push _test-input-stream/imm32 +4634 68/push _test-input-stream/imm32 4635 # . . call 4636 e8/call clear-stream/disp32 4637 # . . discard args 4638 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4639 # . clear-stream(_test-output-stream) 4640 # . . push args -4641 68/push _test-output-stream/imm32 +4641 68/push _test-output-stream/imm32 4642 # . . call 4643 e8/call clear-stream/disp32 4644 # . . discard args 4645 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4646 # . clear-stream(_test-output-buffered-file+4) 4647 # . . push args -4648 b8/copy-to-EAX _test-output-buffered-file/imm32 +4648 b8/copy-to-EAX _test-output-buffered-file/imm32 4649 05/add-to-EAX 4/imm32 4650 50/push-EAX 4651 # . . call @@ -3849,15 +3849,15 @@ if ('onhashchange' in window) { 4656 # . write(_test-input-stream, "8b/copy 0/rm32 1/r32") 4657 # . . push args 4658 68/push "8b/copy 0/rm32 1/r32"/imm32 -4659 68/push _test-input-stream/imm32 +4659 68/push _test-input-stream/imm32 4660 # . . call 4661 e8/call write/disp32 4662 # . . discard args 4663 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4664 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4665 # . . push args -4666 68/push _test-output-buffered-file/imm32 -4667 68/push _test-input-stream/imm32 +4666 68/push _test-output-buffered-file/imm32 +4667 68/push _test-input-stream/imm32 4668 # . . call 4669 e8/call convert-instruction/disp32 4670 # . . discard args @@ -3865,7 +3865,7 @@ if ('onhashchange' in window) { 4672 # check output 4673 # . flush(_test-output-buffered-file) 4674 # . . push args -4675 68/push _test-output-buffered-file/imm32 +4675 68/push _test-output-buffered-file/imm32 4676 # . . call 4677 e8/call flush/disp32 4678 # . . discard args @@ -3875,7 +3875,7 @@ if ('onhashchange' in window) { 4707 # . . push args 4708 68/push "F - test-convert-instruction-emits-modrm-byte-with-missing-mod"/imm32 4709 68/push "8b 08 # 8b/copy 0/rm32 1/r32"/imm32 -4710 68/push _test-output-stream/imm32 +4710 68/push _test-output-stream/imm32 4711 # . . call 4712 e8/call check-stream-equal/disp32 4713 # . . discard args @@ -3893,21 +3893,21 @@ if ('onhashchange' in window) { 4725 # setup 4726 # . clear-stream(_test-input-stream) 4727 # . . push args -4728 68/push _test-input-stream/imm32 +4728 68/push _test-input-stream/imm32 4729 # . . call 4730 e8/call clear-stream/disp32 4731 # . . discard args 4732 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4733 # . clear-stream(_test-output-stream) 4734 # . . push args -4735 68/push _test-output-stream/imm32 +4735 68/push _test-output-stream/imm32 4736 # . . call 4737 e8/call clear-stream/disp32 4738 # . . discard args 4739 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4740 # . clear-stream(_test-output-buffered-file+4) 4741 # . . push args -4742 b8/copy-to-EAX _test-output-buffered-file/imm32 +4742 b8/copy-to-EAX _test-output-buffered-file/imm32 4743 05/add-to-EAX 4/imm32 4744 50/push-EAX 4745 # . . call @@ -3918,15 +3918,15 @@ if ('onhashchange' in window) { 4750 # . write(_test-input-stream, "8b/copy 0/mod 1/r32") 4751 # . . push args 4752 68/push "8b/copy 0/mod 1/r32"/imm32 -4753 68/push _test-input-stream/imm32 +4753 68/push _test-input-stream/imm32 4754 # . . call 4755 e8/call write/disp32 4756 # . . discard args 4757 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4758 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4759 # . . push args -4760 68/push _test-output-buffered-file/imm32 -4761 68/push _test-input-stream/imm32 +4760 68/push _test-output-buffered-file/imm32 +4761 68/push _test-input-stream/imm32 4762 # . . call 4763 e8/call convert-instruction/disp32 4764 # . . discard args @@ -3934,7 +3934,7 @@ if ('onhashchange' in window) { 4766 # check output 4767 # . flush(_test-output-buffered-file) 4768 # . . push args -4769 68/push _test-output-buffered-file/imm32 +4769 68/push _test-output-buffered-file/imm32 4770 # . . call 4771 e8/call flush/disp32 4772 # . . discard args @@ -3944,7 +3944,7 @@ if ('onhashchange' in window) { 4801 # . . push args 4802 68/push "F - test-convert-instruction-emits-modrm-byte-with-missing-rm32"/imm32 4803 68/push "8b 08 # 8b/copy 0/mod 1/r32"/imm32 -4804 68/push _test-output-stream/imm32 +4804 68/push _test-output-stream/imm32 4805 # . . call 4806 e8/call check-stream-equal/disp32 4807 # . . discard args @@ -3962,21 +3962,21 @@ if ('onhashchange' in window) { 4819 # setup 4820 # . clear-stream(_test-input-stream) 4821 # . . push args -4822 68/push _test-input-stream/imm32 +4822 68/push _test-input-stream/imm32 4823 # . . call 4824 e8/call clear-stream/disp32 4825 # . . discard args 4826 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4827 # . clear-stream(_test-output-stream) 4828 # . . push args -4829 68/push _test-output-stream/imm32 +4829 68/push _test-output-stream/imm32 4830 # . . call 4831 e8/call clear-stream/disp32 4832 # . . discard args 4833 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4834 # . clear-stream(_test-output-buffered-file+4) 4835 # . . push args -4836 b8/copy-to-EAX _test-output-buffered-file/imm32 +4836 b8/copy-to-EAX _test-output-buffered-file/imm32 4837 05/add-to-EAX 4/imm32 4838 50/push-EAX 4839 # . . call @@ -3987,15 +3987,15 @@ if ('onhashchange' in window) { 4844 # . write(_test-input-stream, "8b/copy 0/mod 0/rm32") 4845 # . . push args 4846 68/push "8b/copy 0/mod 0/rm32"/imm32 -4847 68/push _test-input-stream/imm32 +4847 68/push _test-input-stream/imm32 4848 # . . call 4849 e8/call write/disp32 4850 # . . discard args 4851 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4852 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4853 # . . push args -4854 68/push _test-output-buffered-file/imm32 -4855 68/push _test-input-stream/imm32 +4854 68/push _test-output-buffered-file/imm32 +4855 68/push _test-input-stream/imm32 4856 # . . call 4857 e8/call convert-instruction/disp32 4858 # . . discard args @@ -4003,7 +4003,7 @@ if ('onhashchange' in window) { 4860 # check output 4861 # . flush(_test-output-buffered-file) 4862 # . . push args -4863 68/push _test-output-buffered-file/imm32 +4863 68/push _test-output-buffered-file/imm32 4864 # . . call 4865 e8/call flush/disp32 4866 # . . discard args @@ -4013,7 +4013,7 @@ if ('onhashchange' in window) { 4895 # . . push args 4896 68/push "F - test-convert-instruction-emits-modrm-byte-with-missing-r32"/imm32 4897 68/push "8b 00 # 8b/copy 0/mod 0/rm32"/imm32 -4898 68/push _test-output-stream/imm32 +4898 68/push _test-output-stream/imm32 4899 # . . call 4900 e8/call check-stream-equal/disp32 4901 # . . discard args @@ -4031,21 +4031,21 @@ if ('onhashchange' in window) { 4913 # setup 4914 # . clear-stream(_test-input-stream) 4915 # . . push args -4916 68/push _test-input-stream/imm32 +4916 68/push _test-input-stream/imm32 4917 # . . call 4918 e8/call clear-stream/disp32 4919 # . . discard args 4920 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4921 # . clear-stream(_test-output-stream) 4922 # . . push args -4923 68/push _test-output-stream/imm32 +4923 68/push _test-output-stream/imm32 4924 # . . call 4925 e8/call clear-stream/disp32 4926 # . . discard args 4927 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 4928 # . clear-stream(_test-output-buffered-file+4) 4929 # . . push args -4930 b8/copy-to-EAX _test-output-buffered-file/imm32 +4930 b8/copy-to-EAX _test-output-buffered-file/imm32 4931 05/add-to-EAX 4/imm32 4932 50/push-EAX 4933 # . . call @@ -4056,15 +4056,15 @@ if ('onhashchange' in window) { 4938 # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index 0/scale") 4939 # . . push args 4940 68/push "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index 0/scale"/imm32 -4941 68/push _test-input-stream/imm32 +4941 68/push _test-input-stream/imm32 4942 # . . call 4943 e8/call write/disp32 4944 # . . discard args 4945 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 4946 # convert-instruction(_test-input-stream, _test-output-buffered-file) 4947 # . . push args -4948 68/push _test-output-buffered-file/imm32 -4949 68/push _test-input-stream/imm32 +4948 68/push _test-output-buffered-file/imm32 +4949 68/push _test-input-stream/imm32 4950 # . . call 4951 e8/call convert-instruction/disp32 4952 # . . discard args @@ -4072,7 +4072,7 @@ if ('onhashchange' in window) { 4954 # check output 4955 # . flush(_test-output-buffered-file) 4956 # . . push args -4957 68/push _test-output-buffered-file/imm32 +4957 68/push _test-output-buffered-file/imm32 4958 # . . call 4959 e8/call flush/disp32 4960 # . . discard args @@ -4082,7 +4082,7 @@ if ('onhashchange' in window) { 4989 # . . push args 4990 68/push "F - test-convert-instruction-emits-sib-byte"/imm32 4991 68/push "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 0/base 1/index 0/scale"/imm32 -4992 68/push _test-output-stream/imm32 +4992 68/push _test-output-stream/imm32 4993 # . . call 4994 e8/call check-stream-equal/disp32 4995 # . . discard args @@ -4100,21 +4100,21 @@ if ('onhashchange' in window) { 5007 # setup 5008 # . clear-stream(_test-input-stream) 5009 # . . push args -5010 68/push _test-input-stream/imm32 +5010 68/push _test-input-stream/imm32 5011 # . . call 5012 e8/call clear-stream/disp32 5013 # . . discard args 5014 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5015 # . clear-stream(_test-output-stream) 5016 # . . push args -5017 68/push _test-output-stream/imm32 +5017 68/push _test-output-stream/imm32 5018 # . . call 5019 e8/call clear-stream/disp32 5020 # . . discard args 5021 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5022 # . clear-stream(_test-output-buffered-file+4) 5023 # . . push args -5024 b8/copy-to-EAX _test-output-buffered-file/imm32 +5024 b8/copy-to-EAX _test-output-buffered-file/imm32 5025 05/add-to-EAX 4/imm32 5026 50/push-EAX 5027 # . . call @@ -4125,15 +4125,15 @@ if ('onhashchange' in window) { 5032 # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 1/index 0/scale") 5033 # . . push args 5034 68/push "8b/copy 0/mod 4/rm32 1/r32 1/index 0/scale"/imm32 -5035 68/push _test-input-stream/imm32 +5035 68/push _test-input-stream/imm32 5036 # . . call 5037 e8/call write/disp32 5038 # . . discard args 5039 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5040 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5041 # . . push args -5042 68/push _test-output-buffered-file/imm32 -5043 68/push _test-input-stream/imm32 +5042 68/push _test-output-buffered-file/imm32 +5043 68/push _test-input-stream/imm32 5044 # . . call 5045 e8/call convert-instruction/disp32 5046 # . . discard args @@ -4141,7 +4141,7 @@ if ('onhashchange' in window) { 5048 # check output 5049 # . flush(_test-output-buffered-file) 5050 # . . push args -5051 68/push _test-output-buffered-file/imm32 +5051 68/push _test-output-buffered-file/imm32 5052 # . . call 5053 e8/call flush/disp32 5054 # . . discard args @@ -4151,7 +4151,7 @@ if ('onhashchange' in window) { 5083 # . . push args 5084 68/push "F - test-convert-instruction-emits-sib-byte-with-missing-base"/imm32 5085 68/push "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 1/index 0/scale"/imm32 -5086 68/push _test-output-stream/imm32 +5086 68/push _test-output-stream/imm32 5087 # . . call 5088 e8/call check-stream-equal/disp32 5089 # . . discard args @@ -4169,21 +4169,21 @@ if ('onhashchange' in window) { 5101 # setup 5102 # . clear-stream(_test-input-stream) 5103 # . . push args -5104 68/push _test-input-stream/imm32 +5104 68/push _test-input-stream/imm32 5105 # . . call 5106 e8/call clear-stream/disp32 5107 # . . discard args 5108 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5109 # . clear-stream(_test-output-stream) 5110 # . . push args -5111 68/push _test-output-stream/imm32 +5111 68/push _test-output-stream/imm32 5112 # . . call 5113 e8/call clear-stream/disp32 5114 # . . discard args 5115 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5116 # . clear-stream(_test-output-buffered-file+4) 5117 # . . push args -5118 b8/copy-to-EAX _test-output-buffered-file/imm32 +5118 b8/copy-to-EAX _test-output-buffered-file/imm32 5119 05/add-to-EAX 4/imm32 5120 50/push-EAX 5121 # . . call @@ -4194,15 +4194,15 @@ if ('onhashchange' in window) { 5126 # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 0/base 0/scale") 5127 # . . push args 5128 68/push "8b/copy 0/mod 4/rm32 1/r32 0/base 0/scale"/imm32 -5129 68/push _test-input-stream/imm32 +5129 68/push _test-input-stream/imm32 5130 # . . call 5131 e8/call write/disp32 5132 # . . discard args 5133 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5134 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5135 # . . push args -5136 68/push _test-output-buffered-file/imm32 -5137 68/push _test-input-stream/imm32 +5136 68/push _test-output-buffered-file/imm32 +5137 68/push _test-input-stream/imm32 5138 # . . call 5139 e8/call convert-instruction/disp32 5140 # . . discard args @@ -4210,7 +4210,7 @@ if ('onhashchange' in window) { 5142 # check output 5143 # . flush(_test-output-buffered-file) 5144 # . . push args -5145 68/push _test-output-buffered-file/imm32 +5145 68/push _test-output-buffered-file/imm32 5146 # . . call 5147 e8/call flush/disp32 5148 # . . discard args @@ -4220,7 +4220,7 @@ if ('onhashchange' in window) { 5177 # . . push args 5178 68/push "F - test-convert-instruction-emits-sib-byte-with-missing-index"/imm32 5179 68/push "8b 0c 00 # 8b/copy 0/mod 4/rm32 1/r32 0/base 0/scale"/imm32 -5180 68/push _test-output-stream/imm32 +5180 68/push _test-output-stream/imm32 5181 # . . call 5182 e8/call check-stream-equal/disp32 5183 # . . discard args @@ -4238,21 +4238,21 @@ if ('onhashchange' in window) { 5195 # setup 5196 # . clear-stream(_test-input-stream) 5197 # . . push args -5198 68/push _test-input-stream/imm32 +5198 68/push _test-input-stream/imm32 5199 # . . call 5200 e8/call clear-stream/disp32 5201 # . . discard args 5202 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5203 # . clear-stream(_test-output-stream) 5204 # . . push args -5205 68/push _test-output-stream/imm32 +5205 68/push _test-output-stream/imm32 5206 # . . call 5207 e8/call clear-stream/disp32 5208 # . . discard args 5209 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5210 # . clear-stream(_test-output-buffered-file+4) 5211 # . . push args -5212 b8/copy-to-EAX _test-output-buffered-file/imm32 +5212 b8/copy-to-EAX _test-output-buffered-file/imm32 5213 05/add-to-EAX 4/imm32 5214 50/push-EAX 5215 # . . call @@ -4263,15 +4263,15 @@ if ('onhashchange' in window) { 5220 # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index") 5221 # . . push args 5222 68/push "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index"/imm32 -5223 68/push _test-input-stream/imm32 +5223 68/push _test-input-stream/imm32 5224 # . . call 5225 e8/call write/disp32 5226 # . . discard args 5227 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5228 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5229 # . . push args -5230 68/push _test-output-buffered-file/imm32 -5231 68/push _test-input-stream/imm32 +5230 68/push _test-output-buffered-file/imm32 +5231 68/push _test-input-stream/imm32 5232 # . . call 5233 e8/call convert-instruction/disp32 5234 # . . discard args @@ -4279,7 +4279,7 @@ if ('onhashchange' in window) { 5236 # check output 5237 # . flush(_test-output-buffered-file) 5238 # . . push args -5239 68/push _test-output-buffered-file/imm32 +5239 68/push _test-output-buffered-file/imm32 5240 # . . call 5241 e8/call flush/disp32 5242 # . . discard args @@ -4289,7 +4289,7 @@ if ('onhashchange' in window) { 5271 # . . push args 5272 68/push "F - test-convert-instruction-emits-sib-byte-with-missing-scale"/imm32 5273 68/push "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 0/base 1/index"/imm32 -5274 68/push _test-output-stream/imm32 +5274 68/push _test-output-stream/imm32 5275 # . . call 5276 e8/call check-stream-equal/disp32 5277 # . . discard args @@ -4307,21 +4307,21 @@ if ('onhashchange' in window) { 5289 # setup 5290 # . clear-stream(_test-input-stream) 5291 # . . push args -5292 68/push _test-input-stream/imm32 +5292 68/push _test-input-stream/imm32 5293 # . . call 5294 e8/call clear-stream/disp32 5295 # . . discard args 5296 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5297 # . clear-stream(_test-output-stream) 5298 # . . push args -5299 68/push _test-output-stream/imm32 +5299 68/push _test-output-stream/imm32 5300 # . . call 5301 e8/call clear-stream/disp32 5302 # . . discard args 5303 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5304 # . clear-stream(_test-output-buffered-file+4) 5305 # . . push args -5306 b8/copy-to-EAX _test-output-buffered-file/imm32 +5306 b8/copy-to-EAX _test-output-buffered-file/imm32 5307 05/add-to-EAX 4/imm32 5308 50/push-EAX 5309 # . . call @@ -4332,15 +4332,15 @@ if ('onhashchange' in window) { 5314 # . write(_test-input-stream, "e8/call 20/disp32") 5315 # . . push args 5316 68/push "e8/call 20/disp32"/imm32 -5317 68/push _test-input-stream/imm32 +5317 68/push _test-input-stream/imm32 5318 # . . call 5319 e8/call write/disp32 5320 # . . discard args 5321 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5322 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5323 # . . push args -5324 68/push _test-output-buffered-file/imm32 -5325 68/push _test-input-stream/imm32 +5324 68/push _test-output-buffered-file/imm32 +5325 68/push _test-input-stream/imm32 5326 # . . call 5327 e8/call convert-instruction/disp32 5328 # . . discard args @@ -4348,7 +4348,7 @@ if ('onhashchange' in window) { 5330 # check output 5331 # . flush(_test-output-buffered-file) 5332 # . . push args -5333 68/push _test-output-buffered-file/imm32 +5333 68/push _test-output-buffered-file/imm32 5334 # . . call 5335 e8/call flush/disp32 5336 # . . discard args @@ -4358,7 +4358,7 @@ if ('onhashchange' in window) { 5365 # . . push args 5366 68/push "F - test-convert-instruction-handles-disp32-operand"/imm32 5367 68/push "e8 20 00 00 00 # e8/call 20/disp32"/imm32 -5368 68/push _test-output-stream/imm32 +5368 68/push _test-output-stream/imm32 5369 # . . call 5370 e8/call check-stream-equal/disp32 5371 # . . discard args @@ -4376,21 +4376,21 @@ if ('onhashchange' in window) { 5383 # setup 5384 # . clear-stream(_test-input-stream) 5385 # . . push args -5386 68/push _test-input-stream/imm32 +5386 68/push _test-input-stream/imm32 5387 # . . call 5388 e8/call clear-stream/disp32 5389 # . . discard args 5390 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5391 # . clear-stream(_test-output-stream) 5392 # . . push args -5393 68/push _test-output-stream/imm32 +5393 68/push _test-output-stream/imm32 5394 # . . call 5395 e8/call clear-stream/disp32 5396 # . . discard args 5397 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5398 # . clear-stream(_test-output-buffered-file+4) 5399 # . . push args -5400 b8/copy-to-EAX _test-output-buffered-file/imm32 +5400 b8/copy-to-EAX _test-output-buffered-file/imm32 5401 05/add-to-EAX 4/imm32 5402 50/push-EAX 5403 # . . call @@ -4401,15 +4401,15 @@ if ('onhashchange' in window) { 5408 # . write(_test-input-stream, "e8/call 20/disp16") 5409 # . . push args 5410 68/push "e8/call 20/disp16"/imm32 # not a valid instruction -5411 68/push _test-input-stream/imm32 +5411 68/push _test-input-stream/imm32 5412 # . . call 5413 e8/call write/disp32 5414 # . . discard args 5415 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5416 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5417 # . . push args -5418 68/push _test-output-buffered-file/imm32 -5419 68/push _test-input-stream/imm32 +5418 68/push _test-output-buffered-file/imm32 +5419 68/push _test-input-stream/imm32 5420 # . . call 5421 e8/call convert-instruction/disp32 5422 # . . discard args @@ -4417,7 +4417,7 @@ if ('onhashchange' in window) { 5424 # check output 5425 # . flush(_test-output-buffered-file) 5426 # . . push args -5427 68/push _test-output-buffered-file/imm32 +5427 68/push _test-output-buffered-file/imm32 5428 # . . call 5429 e8/call flush/disp32 5430 # . . discard args @@ -4427,7 +4427,7 @@ if ('onhashchange' in window) { 5459 # . . push args 5460 68/push "F - test-convert-instruction-handles-disp16-operand"/imm32 5461 68/push "e8 20 00 # e8/call 20/disp16"/imm32 -5462 68/push _test-output-stream/imm32 +5462 68/push _test-output-stream/imm32 5463 # . . call 5464 e8/call check-stream-equal/disp32 5465 # . . discard args @@ -4445,21 +4445,21 @@ if ('onhashchange' in window) { 5477 # setup 5478 # . clear-stream(_test-input-stream) 5479 # . . push args -5480 68/push _test-input-stream/imm32 +5480 68/push _test-input-stream/imm32 5481 # . . call 5482 e8/call clear-stream/disp32 5483 # . . discard args 5484 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5485 # . clear-stream(_test-output-stream) 5486 # . . push args -5487 68/push _test-output-stream/imm32 +5487 68/push _test-output-stream/imm32 5488 # . . call 5489 e8/call clear-stream/disp32 5490 # . . discard args 5491 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5492 # . clear-stream(_test-output-buffered-file+4) 5493 # . . push args -5494 b8/copy-to-EAX _test-output-buffered-file/imm32 +5494 b8/copy-to-EAX _test-output-buffered-file/imm32 5495 05/add-to-EAX 4/imm32 5496 50/push-EAX 5497 # . . call @@ -4470,15 +4470,15 @@ if ('onhashchange' in window) { 5502 # . write(_test-input-stream, "eb/jump 20/disp8") 5503 # . . push args 5504 68/push "eb/jump 20/disp8"/imm32 -5505 68/push _test-input-stream/imm32 +5505 68/push _test-input-stream/imm32 5506 # . . call 5507 e8/call write/disp32 5508 # . . discard args 5509 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5510 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5511 # . . push args -5512 68/push _test-output-buffered-file/imm32 -5513 68/push _test-input-stream/imm32 +5512 68/push _test-output-buffered-file/imm32 +5513 68/push _test-input-stream/imm32 5514 # . . call 5515 e8/call convert-instruction/disp32 5516 # . . discard args @@ -4486,7 +4486,7 @@ if ('onhashchange' in window) { 5518 # check output 5519 # . flush(_test-output-buffered-file) 5520 # . . push args -5521 68/push _test-output-buffered-file/imm32 +5521 68/push _test-output-buffered-file/imm32 5522 # . . call 5523 e8/call flush/disp32 5524 # . . discard args @@ -4496,7 +4496,7 @@ if ('onhashchange' in window) { 5553 # . . push args 5554 68/push "F - test-convert-instruction-handles-disp8-operand"/imm32 5555 68/push "eb 20 # eb/jump 20/disp8"/imm32 -5556 68/push _test-output-stream/imm32 +5556 68/push _test-output-stream/imm32 5557 # . . call 5558 e8/call check-stream-equal/disp32 5559 # . . discard args @@ -4514,21 +4514,21 @@ if ('onhashchange' in window) { 5571 # setup 5572 # . clear-stream(_test-input-stream) 5573 # . . push args -5574 68/push _test-input-stream/imm32 +5574 68/push _test-input-stream/imm32 5575 # . . call 5576 e8/call clear-stream/disp32 5577 # . . discard args 5578 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5579 # . clear-stream(_test-output-stream) 5580 # . . push args -5581 68/push _test-output-stream/imm32 +5581 68/push _test-output-stream/imm32 5582 # . . call 5583 e8/call clear-stream/disp32 5584 # . . discard args 5585 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5586 # . clear-stream(_test-output-buffered-file+4) 5587 # . . push args -5588 b8/copy-to-EAX _test-output-buffered-file/imm32 +5588 b8/copy-to-EAX _test-output-buffered-file/imm32 5589 05/add-to-EAX 4/imm32 5590 50/push-EAX 5591 # . . call @@ -4539,15 +4539,15 @@ if ('onhashchange' in window) { 5596 # . write(_test-input-stream, "eb/jump xyz/disp8") 5597 # . . push args 5598 68/push "eb/jump xyz/disp8"/imm32 -5599 68/push _test-input-stream/imm32 +5599 68/push _test-input-stream/imm32 5600 # . . call 5601 e8/call write/disp32 5602 # . . discard args 5603 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5604 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5605 # . . push args -5606 68/push _test-output-buffered-file/imm32 -5607 68/push _test-input-stream/imm32 +5606 68/push _test-output-buffered-file/imm32 +5607 68/push _test-input-stream/imm32 5608 # . . call 5609 e8/call convert-instruction/disp32 5610 # . . discard args @@ -4555,7 +4555,7 @@ if ('onhashchange' in window) { 5612 # check output 5613 # . flush(_test-output-buffered-file) 5614 # . . push args -5615 68/push _test-output-buffered-file/imm32 +5615 68/push _test-output-buffered-file/imm32 5616 # . . call 5617 e8/call flush/disp32 5618 # . . discard args @@ -4565,7 +4565,7 @@ if ('onhashchange' in window) { 5647 # . . push args 5648 68/push "F - test-convert-instruction-handles-disp8-name"/imm32 5649 68/push "eb xyz/disp8 # eb/jump xyz/disp8"/imm32 -5650 68/push _test-output-stream/imm32 +5650 68/push _test-output-stream/imm32 5651 # . . call 5652 e8/call check-stream-equal/disp32 5653 # . . discard args @@ -4583,21 +4583,21 @@ if ('onhashchange' in window) { 5665 # setup 5666 # . clear-stream(_test-input-stream) 5667 # . . push args -5668 68/push _test-input-stream/imm32 +5668 68/push _test-input-stream/imm32 5669 # . . call 5670 e8/call clear-stream/disp32 5671 # . . discard args 5672 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5673 # . clear-stream(_test-output-stream) 5674 # . . push args -5675 68/push _test-output-stream/imm32 +5675 68/push _test-output-stream/imm32 5676 # . . call 5677 e8/call clear-stream/disp32 5678 # . . discard args 5679 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5680 # . clear-stream(_test-output-buffered-file+4) 5681 # . . push args -5682 b8/copy-to-EAX _test-output-buffered-file/imm32 +5682 b8/copy-to-EAX _test-output-buffered-file/imm32 5683 05/add-to-EAX 4/imm32 5684 50/push-EAX 5685 # . . call @@ -4608,15 +4608,15 @@ if ('onhashchange' in window) { 5690 # . write(_test-input-stream, "68/push 0x20/imm32") 5691 # . . push args 5692 68/push "68/push 0x20/imm32"/imm32 -5693 68/push _test-input-stream/imm32 +5693 68/push _test-input-stream/imm32 5694 # . . call 5695 e8/call write/disp32 5696 # . . discard args 5697 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5698 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5699 # . . push args -5700 68/push _test-output-buffered-file/imm32 -5701 68/push _test-input-stream/imm32 +5700 68/push _test-output-buffered-file/imm32 +5701 68/push _test-input-stream/imm32 5702 # . . call 5703 e8/call convert-instruction/disp32 5704 # . . discard args @@ -4624,7 +4624,7 @@ if ('onhashchange' in window) { 5706 # check output 5707 # . flush(_test-output-buffered-file) 5708 # . . push args -5709 68/push _test-output-buffered-file/imm32 +5709 68/push _test-output-buffered-file/imm32 5710 # . . call 5711 e8/call flush/disp32 5712 # . . discard args @@ -4634,7 +4634,7 @@ if ('onhashchange' in window) { 5741 # . . push args 5742 68/push "F - test-convert-instruction-handles-imm32-operand"/imm32 5743 68/push "68 20 00 00 00 # 68/push 0x20/imm32"/imm32 -5744 68/push _test-output-stream/imm32 +5744 68/push _test-output-stream/imm32 5745 # . . call 5746 e8/call check-stream-equal/disp32 5747 # . . discard args @@ -4653,21 +4653,21 @@ if ('onhashchange' in window) { 5760 # setup 5761 # . clear-stream(_test-input-stream) 5762 # . . push args -5763 68/push _test-input-stream/imm32 +5763 68/push _test-input-stream/imm32 5764 # . . call 5765 e8/call clear-stream/disp32 5766 # . . discard args 5767 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5768 # . clear-stream(_test-output-stream) 5769 # . . push args -5770 68/push _test-output-stream/imm32 +5770 68/push _test-output-stream/imm32 5771 # . . call 5772 e8/call clear-stream/disp32 5773 # . . discard args 5774 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5775 # . clear-stream(_test-output-buffered-file+4) 5776 # . . push args -5777 b8/copy-to-EAX _test-output-buffered-file/imm32 +5777 b8/copy-to-EAX _test-output-buffered-file/imm32 5778 05/add-to-EAX 4/imm32 5779 50/push-EAX 5780 # . . call @@ -4678,15 +4678,15 @@ if ('onhashchange' in window) { 5785 # . write(_test-input-stream, "68/push 0x20/imm16") 5786 # . . push args 5787 68/push "68/push 0x20/imm16"/imm32 # not a valid instruction -5788 68/push _test-input-stream/imm32 +5788 68/push _test-input-stream/imm32 5789 # . . call 5790 e8/call write/disp32 5791 # . . discard args 5792 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5793 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5794 # . . push args -5795 68/push _test-output-buffered-file/imm32 -5796 68/push _test-input-stream/imm32 +5795 68/push _test-output-buffered-file/imm32 +5796 68/push _test-input-stream/imm32 5797 # . . call 5798 e8/call convert-instruction/disp32 5799 # . . discard args @@ -4694,7 +4694,7 @@ if ('onhashchange' in window) { 5801 # check output 5802 # . flush(_test-output-buffered-file) 5803 # . . push args -5804 68/push _test-output-buffered-file/imm32 +5804 68/push _test-output-buffered-file/imm32 5805 # . . call 5806 e8/call flush/disp32 5807 # . . discard args @@ -4704,7 +4704,7 @@ if ('onhashchange' in window) { 5836 # . . push args 5837 68/push "F - test-convert-instruction-handles-imm16-operand"/imm32 5838 68/push "68 20 00 # 68/push 0x20/imm16"/imm32 -5839 68/push _test-output-stream/imm32 +5839 68/push _test-output-stream/imm32 5840 # . . call 5841 e8/call check-stream-equal/disp32 5842 # . . discard args @@ -4723,21 +4723,21 @@ if ('onhashchange' in window) { 5855 # setup 5856 # . clear-stream(_test-input-stream) 5857 # . . push args -5858 68/push _test-input-stream/imm32 +5858 68/push _test-input-stream/imm32 5859 # . . call 5860 e8/call clear-stream/disp32 5861 # . . discard args 5862 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5863 # . clear-stream(_test-output-stream) 5864 # . . push args -5865 68/push _test-output-stream/imm32 +5865 68/push _test-output-stream/imm32 5866 # . . call 5867 e8/call clear-stream/disp32 5868 # . . discard args 5869 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP 5870 # . clear-stream(_test-output-buffered-file+4) 5871 # . . push args -5872 b8/copy-to-EAX _test-output-buffered-file/imm32 +5872 b8/copy-to-EAX _test-output-buffered-file/imm32 5873 05/add-to-EAX 4/imm32 5874 50/push-EAX 5875 # . . call @@ -4748,15 +4748,15 @@ if ('onhashchange' in window) { 5880 # . write(_test-input-stream, "68/push 0x20/imm8") 5881 # . . push args 5882 68/push "68/push 0x20/imm8"/imm32 -5883 68/push _test-input-stream/imm32 +5883 68/push _test-input-stream/imm32 5884 # . . call 5885 e8/call write/disp32 5886 # . . discard args 5887 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5888 # convert-instruction(_test-input-stream, _test-output-buffered-file) 5889 # . . push args -5890 68/push _test-output-buffered-file/imm32 -5891 68/push _test-input-stream/imm32 +5890 68/push _test-output-buffered-file/imm32 +5891 68/push _test-input-stream/imm32 5892 # . . call 5893 e8/call convert-instruction/disp32 5894 # . . discard args @@ -4764,7 +4764,7 @@ if ('onhashchange' in window) { 5896 # check output 5897 # . flush(_test-output-buffered-file) 5898 # . . push args -5899 68/push _test-output-buffered-file/imm32 +5899 68/push _test-output-buffered-file/imm32 5900 # . . call 5901 e8/call flush/disp32 5902 # . . discard args @@ -4774,7 +4774,7 @@ if ('onhashchange' in window) { 5931 # . . push args 5932 68/push "F - test-convert-instruction-handles-imm8-operand"/imm32 5933 68/push "68 20 # 68/push 0x20/imm8"/imm32 -5934 68/push _test-output-stream/imm32 +5934 68/push _test-output-stream/imm32 5935 # . . call 5936 e8/call check-stream-equal/disp32 5937 # . . discard args diff --git a/html/apps/subx-common.subx.html b/html/apps/subx-common.subx.html index 780249d6..f7c7e257 100644 --- a/html/apps/subx-common.subx.html +++ b/html/apps/subx-common.subx.html @@ -14,18 +14,18 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.Folded { color: #080808; background-color: #949494; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.subxMinorFunction { color: #875f5f; } .LineNr { } +.subxS1Comment { color: #0000af; } +.Constant { color: #008787; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxTest { color: #5f8700; } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.subxMinorFunction { color: #875f5f; } +.Folded { color: #080808; background-color: #949494; } .subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -87,3041 +87,2028 @@ if ('onhashchange' in window) { 24 # . op subop mod rm32 base index scale r32 25 # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes 26 - 27 # - managing tables - 28 # SubX has rudimentary support for tables. - 29 # - 30 # Each table is a stream of rows. - 31 # - 32 # Each row consists of a 4-byte row (address to a string) and a variable-size - 33 # value. - 34 # - 35 # Accessing the table performs a linear scan for a key string, and always - 36 # requires passing in the row size. - 37 # - 38 # Table primitives: - 39 # get(stream, string, row-size) - 40 # aborts if not found - 41 # get-or-insert(stream, string, row-size) - 42 # inserts if not found - 43 # get-slice(stream, slice, row-size) - 44 # aborts if not found - 45 # leaky-get-or-insert-slice(stream, slice, row-size) - 46 # inserts if not found - 47 - 48 # 'table' is a stream of (key, value) rows - 49 # keys are always strings (addresses; size 4 bytes) - 50 # values may be any type, but rows (key+value) always occupy 'row-size' bytes - 51 # scan 'table' for a row with a key 'key' and return the address of the corresponding value - 52 # if no row is found, abort - 53 get: # table : (address stream {string, _}), key : (address string), row-size : int -> EAX : (address _) - 54 # pseudocode: - 55 # curr = table->data - 56 # max = &table->data[table->write] - 57 # while curr < max - 58 # if string-equal?(key, *curr) - 59 # return curr+4 - 60 # curr += row-size - 61 # abort - 62 # - 63 # . prolog - 64 55/push-EBP - 65 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 66 # . save registers - 67 51/push-ECX - 68 52/push-EDX - 69 56/push-ESI - 70 # ESI = table - 71 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 72 # curr/ECX = table->data - 73 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - 74 # max/EDX = table->data + table->write - 75 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 76 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX - 77 $get:search-loop: - 78 # if (curr >= max) abort - 79 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 80 73/jump-if-greater-or-equal-unsigned $get:abort/disp8 - 81 # if (string-equal?(key, *curr)) return curr+4 - 82 # . EAX = string-equal?(key, *curr) - 83 # . . push args - 84 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 85 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 27 # (re)compute the bounds of the next word in the line + 28 # return empty string on reaching end of file + 29 next-word: # line : (address stream byte), out : (address slice) + 30 # . prolog + 31 55/push-EBP + 32 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 33 # . save registers + 34 50/push-EAX + 35 51/push-ECX + 36 56/push-ESI + 37 57/push-EDI + 38 # ESI = line + 39 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI + 40 # EDI = out + 41 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI + 42 # skip-chars-matching(line, ' ') + 43 # . . push args + 44 68/push 0x20/imm32/space + 45 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 46 # . . call + 47 e8/call skip-chars-matching/disp32 + 48 # . . discard args + 49 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 50 $next-word:check0: + 51 # if (line->read >= line->write) clear out and return + 52 # . EAX = line->read + 53 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX + 54 # . if (EAX < line->write) goto next check + 55 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI + 56 7c/jump-if-lesser $next-word:check-for-comment/disp8 + 57 # . return out = {0, 0} + 58 c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI + 59 c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) + 60 eb/jump $next-word:end/disp8 + 61 $next-word:check-for-comment: + 62 # out->start = &line->data[line->read] + 63 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX + 64 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX + 65 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI + 66 # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return + 67 # . EAX = line->data[line->read] + 68 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX + 69 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL + 70 # . compare + 71 3d/compare-EAX-and 0x23/imm32/pound + 72 75/jump-if-not-equal $next-word:regular-word/disp8 + 73 $next-word:comment: + 74 # . out->end = &line->data[line->write] + 75 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX + 76 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX + 77 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) + 78 # . line->read = line->write + 79 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) + 80 # . return + 81 eb/jump $next-word:end/disp8 + 82 $next-word:regular-word: + 83 # otherwise skip-chars-not-matching-whitespace(line) # including trailing newline + 84 # . . push args + 85 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) 86 # . . call - 87 e8/call string-equal?/disp32 + 87 e8/call skip-chars-not-matching-whitespace/disp32 88 # . . discard args - 89 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 90 # . if (EAX != 0) return EAX = curr+4 - 91 3d/compare-EAX-and 0/imm32 - 92 74/jump-if-equal $get:mismatch/disp8 - 93 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - 94 eb/jump $get:end/disp8 - 95 $get:mismatch: - 96 # curr += row-size - 97 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - 98 # loop - 99 eb/jump $get:search-loop/disp8 - 100 $get:end: - 101 # . restore registers - 102 5e/pop-to-ESI - 103 5a/pop-to-EDX - 104 59/pop-to-ECX - 105 # . epilog - 106 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 107 5d/pop-to-EBP - 108 c3/return - 109 - 110 $get:abort: - 111 # . _write(2/stderr, error) - 112 # . . push args - 113 68/push "get: key not found: "/imm32 - 114 68/push 2/imm32/stderr - 115 # . . call - 116 e8/call _write/disp32 - 117 # . . discard args - 118 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 119 # . _write(2/stderr, key) - 120 # . . push args - 121 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 122 68/push 2/imm32/stderr - 123 # . . call - 124 e8/call _write/disp32 - 125 # . . discard args - 126 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 127 # . _write(2/stderr, "\n") - 128 # . . push args - 129 68/push "\n"/imm32 - 130 68/push 2/imm32/stderr - 131 # . . call - 132 e8/call _write/disp32 - 133 # . . discard args - 134 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 135 # . syscall(exit, 1) - 136 bb/copy-to-EBX 1/imm32 - 137 b8/copy-to-EAX 1/imm32/exit - 138 cd/syscall 0x80/imm8 - 139 # never gets here - 140 - 141 test-get: - 142 # . prolog - 143 55/push-EBP - 144 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 145 # - setup: create a table with a couple of keys - 146 # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 147 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 148 68/push 0x10/imm32/length - 149 68/push 0/imm32/read - 150 68/push 0/imm32/write - 151 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 152 # insert(table, "code", 8 bytes per row) - 153 # . . push args - 154 68/push 8/imm32/row-size - 155 68/push "code"/imm32 - 156 51/push-ECX - 157 # . . call - 158 e8/call get-or-insert/disp32 - 159 # . . discard args - 160 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 161 # insert(table, "data", 8 bytes per row) - 162 # . . push args - 163 68/push 8/imm32/row-size - 164 68/push "data"/imm32 - 165 51/push-ECX - 166 # . . call - 167 e8/call get-or-insert/disp32 - 168 # . . discard args - 169 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 170 $test-get:check1: - 171 # EAX = get(table, "code", 8 bytes per row) - 172 # . . push args - 173 68/push 8/imm32/row-size - 174 68/push "code"/imm32 - 175 51/push-ECX + 89 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 90 # out->end = &line->data[line->read] + 91 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX + 92 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX + 93 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) + 94 $next-word:end: + 95 # . restore registers + 96 5f/pop-to-EDI + 97 5e/pop-to-ESI + 98 59/pop-to-ECX + 99 58/pop-to-EAX + 100 # . epilog + 101 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 102 5d/pop-to-EBP + 103 c3/return + 104 + 105 test-next-word: + 106 # . prolog + 107 55/push-EBP + 108 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 109 # setup + 110 # . clear-stream(_test-stream) + 111 # . . push args + 112 68/push _test-stream/imm32 + 113 # . . call + 114 e8/call clear-stream/disp32 + 115 # . . discard args + 116 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 117 # var slice/ECX = {0, 0} + 118 68/push 0/imm32/end + 119 68/push 0/imm32/start + 120 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 121 # write(_test-stream, " ab") + 122 # . . push args + 123 68/push " ab"/imm32 + 124 68/push _test-stream/imm32 + 125 # . . call + 126 e8/call write/disp32 + 127 # . . discard args + 128 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 129 # next-word(_test-stream, slice) + 130 # . . push args + 131 51/push-ECX + 132 68/push _test-stream/imm32 + 133 # . . call + 134 e8/call next-word/disp32 + 135 # . . discard args + 136 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 137 # check-ints-equal(slice->start - _test-stream->data, 2, msg) + 138 # . check-ints-equal(slice->start - _test-stream, 14, msg) + 139 # . . push args + 140 68/push "F - test-next-word: start"/imm32 + 141 68/push 0xe/imm32 + 142 # . . push slice->start - _test-stream + 143 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX + 144 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX + 145 50/push-EAX + 146 # . . call + 147 e8/call check-ints-equal/disp32 + 148 # . . discard args + 149 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 150 # check-ints-equal(slice->end - _test-stream->data, 4, msg) + 151 # . check-ints-equal(slice->end - _test-stream, 16, msg) + 152 # . . push args + 153 68/push "F - test-next-word: end"/imm32 + 154 68/push 0x10/imm32 + 155 # . . push slice->end - _test-stream + 156 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX + 157 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX + 158 50/push-EAX + 159 # . . call + 160 e8/call check-ints-equal/disp32 + 161 # . . discard args + 162 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 163 # . epilog + 164 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 165 5d/pop-to-EBP + 166 c3/return + 167 + 168 test-next-word-returns-whole-comment: + 169 # . prolog + 170 55/push-EBP + 171 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 172 # setup + 173 # . clear-stream(_test-stream) + 174 # . . push args + 175 68/push _test-stream/imm32 176 # . . call - 177 e8/call get/disp32 + 177 e8/call clear-stream/disp32 178 # . . discard args - 179 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 180 # check-ints-equal(EAX - table->data, 4, msg) - 181 # . check-ints-equal(EAX - table, 16, msg) - 182 # . . push args - 183 68/push "F - test-get/0"/imm32 - 184 68/push 0x10/imm32 - 185 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 186 50/push-EAX - 187 # . . call - 188 e8/call check-ints-equal/disp32 - 189 # . . discard args - 190 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 191 $test-get:check2: - 192 # EAX = get(table, "data", 8 bytes per row) + 179 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 180 # var slice/ECX = {0, 0} + 181 68/push 0/imm32/end + 182 68/push 0/imm32/start + 183 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 184 # write(_test-stream, " # a") + 185 # . . push args + 186 68/push " # a"/imm32 + 187 68/push _test-stream/imm32 + 188 # . . call + 189 e8/call write/disp32 + 190 # . . discard args + 191 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 192 # next-word(_test-stream, slice) 193 # . . push args - 194 68/push 8/imm32/row-size - 195 68/push "data"/imm32 - 196 51/push-ECX - 197 # . . call - 198 e8/call get/disp32 - 199 # . . discard args - 200 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 201 # check-ints-equal(EAX - table->data, 12, msg) - 202 # . check-ints-equal(EAX - table, 24, msg) - 203 # . . push args - 204 68/push "F - test-get/1"/imm32 - 205 68/push 0x18/imm32 - 206 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 207 50/push-EAX - 208 # . . call - 209 e8/call check-ints-equal/disp32 - 210 # . . discard args - 211 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 212 $test-get:end: - 213 # . epilog - 214 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 215 5d/pop-to-EBP - 216 c3/return - 217 - 218 # 'table' is a stream of (key, value) rows - 219 # keys are always strings (addresses; size 4 bytes) - 220 # values may be any type, but rows (key+value) always occupy 'row-size' bytes - 221 # scan 'table' for a row with a key 'key' and return the address of the corresponding value - 222 # if no row is found, abort - 223 get-slice: # table : (address stream {string, _}), key : (address slice), row-size : int -> EAX : (address _) - 224 # pseudocode: - 225 # curr = table->data - 226 # max = &table->data[table->write] - 227 # while curr < max - 228 # if slice-equal?(key, *curr) - 229 # return curr+4 - 230 # curr += row-size - 231 # abort - 232 # - 233 # . prolog - 234 55/push-EBP - 235 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 236 # . save registers - 237 51/push-ECX - 238 52/push-EDX - 239 56/push-ESI - 240 # ESI = table - 241 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 242 # curr/ECX = table->data - 243 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - 244 # max/EDX = table->data + table->write - 245 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 246 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX - 247 $get-slice:search-loop: - 248 # if (curr >= max) abort - 249 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 250 73/jump-if-greater-or-equal-unsigned $get-slice:abort/disp8 - 251 # if (slice-equal?(key, *curr)) return curr+4 - 252 # . EAX = slice-equal?(key, *curr) - 253 # . . push args - 254 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 255 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 256 # . . call - 257 e8/call slice-equal?/disp32 - 258 # . . discard args - 259 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 260 # . if (EAX != 0) return EAX = curr+4 - 261 3d/compare-EAX-and 0/imm32 - 262 74/jump-if-equal $get-slice:mismatch/disp8 - 263 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - 264 eb/jump $get-slice:end/disp8 - 265 $get-slice:mismatch: - 266 # curr += row-size - 267 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - 268 # loop - 269 eb/jump $get-slice:search-loop/disp8 - 270 $get-slice:end: - 271 # . restore registers - 272 5e/pop-to-ESI - 273 5a/pop-to-EDX - 274 59/pop-to-ECX - 275 # . epilog - 276 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 277 5d/pop-to-EBP - 278 c3/return - 279 - 280 $get-slice:abort: - 281 # . _write(2/stderr, error) - 282 # . . push args - 283 68/push "get-slice: key not found: "/imm32 - 284 68/push 2/imm32/stderr - 285 # . . call - 286 e8/call _write/disp32 - 287 # . . discard args - 288 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 289 # . write-slice-buffered(Stderr, key) - 290 # . . push args - 291 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 292 68/push Stderr/imm32 - 293 # . . call - 294 e8/call write-slice-buffered/disp32 - 295 # . . discard args - 296 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 297 # . flush(Stderr) - 298 # . . push args - 299 68/push Stderr/imm32 - 300 # . . call - 301 e8/call flush/disp32 - 302 # . . discard args - 303 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 304 # . _write(2/stderr, "\n") - 305 # . . push args - 306 68/push "\n"/imm32 - 307 68/push 2/imm32/stderr - 308 # . . call - 309 e8/call _write/disp32 - 310 # . . discard args - 311 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 312 # . syscall(exit, 1) - 313 bb/copy-to-EBX 1/imm32 - 314 b8/copy-to-EAX 1/imm32/exit - 315 cd/syscall 0x80/imm8 - 316 # never gets here + 194 51/push-ECX + 195 68/push _test-stream/imm32 + 196 # . . call + 197 e8/call next-word/disp32 + 198 # . . discard args + 199 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 200 # check-ints-equal(slice->start - _test-stream->data, 2, msg) + 201 # . check-ints-equal(slice->start - _test-stream, 14, msg) + 202 # . . push args + 203 68/push "F - test-next-word-returns-whole-comment: start"/imm32 + 204 68/push 0xe/imm32 + 205 # . . push slice->start - _test-stream + 206 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX + 207 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX + 208 50/push-EAX + 209 # . . call + 210 e8/call check-ints-equal/disp32 + 211 # . . discard args + 212 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 213 # check-ints-equal(slice->end - _test-stream->data, 5, msg) + 214 # . check-ints-equal(slice->end - _test-stream, 17, msg) + 215 # . . push args + 216 68/push "F - test-next-word-returns-whole-comment: end"/imm32 + 217 68/push 0x11/imm32 + 218 # . . push slice->end - _test-stream + 219 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX + 220 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX + 221 50/push-EAX + 222 # . . call + 223 e8/call check-ints-equal/disp32 + 224 # . . discard args + 225 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 226 # . epilog + 227 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 228 5d/pop-to-EBP + 229 c3/return + 230 + 231 test-next-word-returns-empty-string-on-eof: + 232 # . prolog + 233 55/push-EBP + 234 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 235 # setup + 236 # . clear-stream(_test-stream) + 237 # . . push args + 238 68/push _test-stream/imm32 + 239 # . . call + 240 e8/call clear-stream/disp32 + 241 # . . discard args + 242 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 243 # var slice/ECX = {0, 0} + 244 68/push 0/imm32/end + 245 68/push 0/imm32/start + 246 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 247 # write nothing to _test-stream + 248 # next-word(_test-stream, slice) + 249 # . . push args + 250 51/push-ECX + 251 68/push _test-stream/imm32 + 252 # . . call + 253 e8/call next-word/disp32 + 254 # . . discard args + 255 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 256 # check-ints-equal(slice->end - slice->start, 0, msg) + 257 # . . push args + 258 68/push "F - test-next-word-returns-empty-string-on-eof"/imm32 + 259 68/push 0/imm32 + 260 # . . push slice->end - slice->start + 261 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX + 262 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX + 263 50/push-EAX + 264 # . . call + 265 e8/call check-ints-equal/disp32 + 266 # . . discard args + 267 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 268 # . epilog + 269 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 270 5d/pop-to-EBP + 271 c3/return + 272 + 273 # write an entire stream's contents to a buffered-file + 274 # ways to do this: + 275 # - construct a 'maximal slice' and pass it to write-slice-buffered + 276 # - flush the buffered-file and pass the stream directly to its fd (disabling buffering) + 277 # we'll go with the first way for now + 278 write-stream-data: # f : (address buffered-file), s : (address stream) -> <void> + 279 # . prolog + 280 55/push-EBP + 281 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 282 # . save registers + 283 50/push-EAX + 284 51/push-ECX + 285 56/push-ESI + 286 # ESI = s + 287 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI + 288 # var slice/ECX = {s->data, s->data + s->write} + 289 # . push s->data + s->write + 290 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX + 291 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX + 292 50/push-EAX + 293 # . push s->data + 294 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX + 295 50/push-EAX + 296 # . ECX = ESP + 297 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 298 # write-slice-buffered(f, slice) + 299 # . . push args + 300 51/push-ECX + 301 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 302 # . . call + 303 e8/call write-slice-buffered/disp32 + 304 # . . discard args + 305 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 306 $write-stream-data:end: + 307 # . restore locals + 308 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 309 # . restore registers + 310 5e/pop-to-ESI + 311 59/pop-to-ECX + 312 58/pop-to-EAX + 313 # . epilog + 314 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 315 5d/pop-to-EBP + 316 c3/return 317 - 318 test-get-slice: + 318 test-write-stream-data: 319 # . prolog 320 55/push-EBP 321 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 322 # - setup: create a table with a couple of keys - 323 # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 324 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 325 68/push 0x10/imm32/length - 326 68/push 0/imm32/read - 327 68/push 0/imm32/write - 328 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 329 # insert(table, "code", 8 bytes per row) - 330 # . . push args - 331 68/push 8/imm32/row-size - 332 68/push "code"/imm32 - 333 51/push-ECX - 334 # . . call - 335 e8/call get-or-insert/disp32 - 336 # . . discard args - 337 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 338 # insert(table, "data", 8 bytes per row) - 339 # . . push args - 340 68/push 8/imm32/row-size - 341 68/push "data"/imm32 - 342 51/push-ECX - 343 # . . call - 344 e8/call get-or-insert/disp32 - 345 # . . discard args - 346 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 347 $test-get-slice:check1: - 348 # (EAX..EDX) = "code" - 349 b8/copy-to-EAX "code"/imm32 - 350 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 351 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 352 05/add-to-EAX 4/imm32 - 353 # var slice/EDX = {EAX, EDX} - 354 52/push-EDX - 355 50/push-EAX - 356 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - 357 # EAX = get-slice(table, "code", 8 bytes per row) - 358 # . . push args - 359 68/push 8/imm32/row-size - 360 52/push-EDX - 361 51/push-ECX - 362 # . . call - 363 e8/call get-slice/disp32 - 364 # . . discard args - 365 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 366 # check-ints-equal(EAX - table->data, 4, msg) # first row's value slot returned - 367 # . check-ints-equal(EAX - table, 16, msg) - 368 # . . push args - 369 68/push "F - test-get-slice/0"/imm32 - 370 68/push 0x10/imm32 - 371 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 372 50/push-EAX - 373 # . . call - 374 e8/call check-ints-equal/disp32 - 375 # . . discard args - 376 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 377 $test-get-slice:check2: - 378 # (EAX..EDX) = "data" - 379 b8/copy-to-EAX "data"/imm32 - 380 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 381 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 382 05/add-to-EAX 4/imm32 - 383 # var slice/EDX = {EAX, EDX} - 384 52/push-EDX - 385 50/push-EAX - 386 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - 387 # EAX = get-slice(table, "data" slice, 8 bytes per row) - 388 # . . push args - 389 68/push 8/imm32/row-size - 390 52/push-EDX - 391 51/push-ECX - 392 # . . call - 393 e8/call get-slice/disp32 - 394 # . . discard args - 395 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 396 # check-ints-equal(EAX - table->data, 12, msg) - 397 # . check-ints-equal(EAX - table, 24, msg) - 398 # . . push args - 399 68/push "F - test-get-slice/1"/imm32 - 400 68/push 0x18/imm32 - 401 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 402 50/push-EAX - 403 # . . call - 404 e8/call check-ints-equal/disp32 - 405 # . . discard args - 406 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 407 $test-get-slice:end: - 408 # . epilog - 409 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 410 5d/pop-to-EBP - 411 c3/return - 412 - 413 # 'table' is a stream of (key, value) rows - 414 # keys are always strings (addresses; size 4 bytes) - 415 # values may be any type, but rows (key+value) always occupy 'row-size' bytes - 416 # scan 'table' for a row with a key 'key' and return the address of the corresponding value - 417 # if no row is found, save 'key' to the next available row - 418 # if there are no rows free, abort - 419 # return the address of the value - 420 # Beware: assume keys are immutable; they're inserted by reference - 421 # TODO: pass in an allocation descriptor - 422 get-or-insert: # table : (address stream {string, _}), key : (address string), row-size : int -> EAX : (address _) - 423 # pseudocode: - 424 # curr = table->data - 425 # max = &table->data[table->write] - 426 # while curr < max - 427 # if string-equal?(key, *curr) - 428 # return curr+4 - 429 # curr += row-size - 430 # if table->write >= table->length - 431 # abort - 432 # zero-out(max, row-size) - 433 # *max = key - 434 # table->write += row-size - 435 # return max+4 - 436 # - 437 # . prolog - 438 55/push-EBP - 439 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 440 # . save registers - 441 51/push-ECX - 442 52/push-EDX - 443 56/push-ESI - 444 # ESI = table - 445 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 446 # curr/ECX = table->data - 447 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - 448 # max/EDX = table->data + table->write - 449 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 450 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX - 451 $get-or-insert:search-loop: - 452 # if (curr >= max) break - 453 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 454 73/jump-if-greater-or-equal-unsigned $get-or-insert:not-found/disp8 - 455 # if (string-equal?(key, *curr)) return curr+4 - 456 # . EAX = string-equal?(key, *curr) - 457 # . . push args - 458 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 459 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 460 # . . call - 461 e8/call string-equal?/disp32 - 462 # . . discard args - 463 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 464 # . if (EAX != 0) return EAX = curr+4 - 465 3d/compare-EAX-and 0/imm32 - 466 74/jump-if-equal $get-or-insert:mismatch/disp8 - 467 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - 468 eb/jump $get-or-insert:end/disp8 - 469 $get-or-insert:mismatch: - 470 # curr += row-size - 471 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - 472 # loop - 473 eb/jump $get-or-insert:search-loop/disp8 - 474 $get-or-insert:not-found: - 475 # result/EAX = 0 - 476 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 477 # if (table->write >= table->length) abort - 478 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - 479 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # compare ECX with *(ESI+8) - 480 73/jump-if-greater-or-equal-unsigned $get-or-insert:abort/disp8 - 481 # zero-out(max, row-size) - 482 # . . push args - 483 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 484 52/push-EDX - 485 # . . call - 486 e8/call zero-out/disp32 - 487 # . . discard args - 488 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 489 # *max = key - 490 # . EAX = key - 491 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX - 492 # . *max = EAX - 493 89/copy 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to *EDX - 494 # table->write += row-size - 495 # . EAX = row-size - 496 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX - 497 # . table->write += EAX - 498 01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI - 499 # return max+4 - 500 # . EAX = max - 501 89/copy 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # copy EDX to EAX - 502 # . EAX += 4 - 503 05/add-to-EAX 4/imm32 - 504 $get-or-insert:end: - 505 # . restore registers - 506 5e/pop-to-ESI - 507 5a/pop-to-EDX - 508 59/pop-to-ECX - 509 # . epilog - 510 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 511 5d/pop-to-EBP - 512 c3/return - 513 - 514 $get-or-insert:abort: - 515 # . _write(2/stderr, error) - 516 # . . push args - 517 68/push "get-or-insert: table is full\n"/imm32 - 518 68/push 2/imm32/stderr - 519 # . . call - 520 e8/call _write/disp32 - 521 # . . discard args - 522 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 523 # . syscall(exit, 1) - 524 bb/copy-to-EBX 1/imm32 - 525 b8/copy-to-EAX 1/imm32/exit - 526 cd/syscall 0x80/imm8 - 527 # never gets here - 528 - 529 test-get-or-insert: - 530 # . prolog - 531 55/push-EBP - 532 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 533 # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 534 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 535 68/push 0x10/imm32/length - 536 68/push 0/imm32/read - 537 68/push 0/imm32/write - 538 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 539 $test-get-or-insert:first-call: - 540 # - start with an empty table, insert one key, verify that it was inserted - 541 # EAX = get-or-insert(table, "code", 8 bytes per row) - 542 # . . push args - 543 68/push 8/imm32/row-size - 544 68/push "code"/imm32 - 545 51/push-ECX - 546 # . . call - 547 e8/call get-or-insert/disp32 - 548 # . . discard args - 549 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 550 # check-ints-equal(EAX - table->data, 4, msg) # first row's value slot returned - 551 # . check-ints-equal(EAX - table, 16, msg) - 552 # . . push args - 553 68/push "F - test-get-or-insert/0"/imm32 - 554 68/push 0x10/imm32 - 555 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 556 50/push-EAX - 557 # . . call - 558 e8/call check-ints-equal/disp32 - 559 # . . discard args - 560 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 561 $test-get-or-insert:check2: - 562 # check-ints-equal(table->write, row-size = 8, msg) - 563 # . . push args - 564 68/push "F - test-get-or-insert/1"/imm32 - 565 68/push 8/imm32/row-size - 566 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 567 # . . call - 568 e8/call check-ints-equal/disp32 - 569 # . . discard args - 570 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 571 # check-string-equal(*table->data, "code", msg) - 572 # . . push args - 573 68/push "F - test-get-or-insert/2"/imm32 - 574 68/push "code"/imm32 - 575 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - 576 # . . call - 577 e8/call check-string-equal/disp32 - 578 # . . discard args - 579 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 580 $test-get-or-insert:second-call: - 581 # - insert the same key again, verify that it was reused - 582 # EAX = get-or-insert(table, "code", 8 bytes per row) - 583 # . . push args - 584 68/push 8/imm32/row-size - 585 68/push "code"/imm32 - 586 51/push-ECX - 587 # . . call - 588 e8/call get-or-insert/disp32 - 589 # . . discard args - 590 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 591 # check-ints-equal(EAX - table->data, 4, msg) - 592 # . check-ints-equal(EAX - table, 16, msg) - 593 # . . push args - 594 68/push "F - test-get-or-insert/3"/imm32 - 595 68/push 0x10/imm32 - 596 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 597 50/push-EAX - 598 # . . call - 599 e8/call check-ints-equal/disp32 - 600 # . . discard args - 601 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 602 # no new row inserted - 603 # . check-ints-equal(table->write, row-size = 8, msg) - 604 # . . push args - 605 68/push "F - test-get-or-insert/4"/imm32 - 606 68/push 8/imm32/row-size - 607 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 608 # . . call - 609 e8/call check-ints-equal/disp32 - 610 # . . discard args - 611 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 612 # check-string-equal(*table->data, "code", msg) - 613 # . . push args - 614 68/push "F - test-get-or-insert/5"/imm32 - 615 68/push "code"/imm32 - 616 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - 617 # . . call - 618 e8/call check-string-equal/disp32 - 619 # . . discard args - 620 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 621 $test-get-or-insert:third-call: - 622 # - insert a new key, verify that it was inserted - 623 # EAX = get-or-insert(table, "data", 8 bytes per row) - 624 # . . push args - 625 68/push 8/imm32/row-size - 626 68/push "data"/imm32 - 627 51/push-ECX - 628 # . . call - 629 e8/call get-or-insert/disp32 - 630 # . . discard args - 631 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 632 # table gets a new row - 633 # check-ints-equal(EAX - table->data, 12, msg) # second row's value slot returned - 634 # . check-ints-equal(EAX - table, 24, msg) - 635 # . . push args - 636 68/push "F - test-get-or-insert/6"/imm32 - 637 68/push 0x18/imm32 - 638 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 639 50/push-EAX - 640 # . . call - 641 e8/call check-ints-equal/disp32 - 642 # . . discard args - 643 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 644 # check-ints-equal(table->write, 2 rows = 16, msg) - 645 # . . push args - 646 68/push "F - test-get-or-insert/7"/imm32 - 647 68/push 0x10/imm32/two-rows - 648 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 649 # . . call - 650 e8/call check-ints-equal/disp32 - 651 # . . discard args - 652 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 653 # check-string-equal(*table->data+8, "data", msg) - 654 # check-string-equal(*(table+20), "data", msg) - 655 # . . push args - 656 68/push "F - test-get-or-insert/8"/imm32 - 657 68/push "data"/imm32 - 658 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0x14/disp8 . # push *(ECX+20) - 659 # . . call - 660 e8/call check-string-equal/disp32 - 661 # . . discard args - 662 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 663 $test-get-or-insert:end: - 664 # . epilog - 665 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 666 5d/pop-to-EBP - 667 c3/return - 668 - 669 # 'table' is a stream of (key, value) rows - 670 # keys are always strings (addresses; size 4 bytes) - 671 # values may be any type, but rows (key+value) always occupy 'row-size' bytes - 672 # scan 'table' for a row with a key 'key' and return the address of the corresponding value - 673 # if no row is found, save 'key' in the next available row - 674 # if there are no rows free, abort - 675 # WARNING: leaks memory - 676 # TODO: pass in an allocation descriptor - 677 leaky-get-or-insert-slice: # table : (address stream {string, _}), key : (address slice), row-size : int -> EAX : (address _) - 678 # pseudocode: - 679 # curr = table->data - 680 # max = &table->data[table->write] - 681 # while curr < max - 682 # if slice-equal?(key, *curr) - 683 # return curr+4 - 684 # curr += row-size - 685 # if table->write >= table->length - 686 # abort - 687 # zero-out(max, row-size) - 688 # *max = slice-to-string(Heap, key) - 689 # table->write += row-size - 690 # return max+4 - 691 # - 692 # . prolog - 693 55/push-EBP - 694 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 695 # . save registers - 696 51/push-ECX - 697 52/push-EDX - 698 56/push-ESI - 699 # ESI = table - 700 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 701 # curr/ECX = table->data - 702 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - 703 # max/EDX = table->data + table->write - 704 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 705 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX - 706 $leaky-get-or-insert-slice:search-loop: - 707 # if (curr >= max) break - 708 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 709 73/jump-if-greater-or-equal-unsigned $leaky-get-or-insert-slice:not-found/disp8 - 710 # if (slice-equal?(key, *curr)) return curr+4 - 711 # . EAX = slice-equal?(key, *curr) - 712 # . . push args - 713 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 714 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 715 # . . call - 716 e8/call slice-equal?/disp32 - 717 # . . discard args - 718 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 719 # . if (EAX != 0) return EAX = curr+4 - 720 3d/compare-EAX-and 0/imm32 - 721 74/jump-if-equal $leaky-get-or-insert-slice:mismatch/disp8 - 722 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - 723 eb/jump $leaky-get-or-insert-slice:end/disp8 - 724 $leaky-get-or-insert-slice:mismatch: - 725 # curr += row-size - 726 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - 727 # loop - 728 eb/jump $leaky-get-or-insert-slice:search-loop/disp8 - 729 $leaky-get-or-insert-slice:not-found: - 730 # result/EAX = 0 - 731 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 732 # if (table->write >= table->length) abort - 733 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - 734 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # compare ECX with *(ESI+8) - 735 7d/jump-if-greater-or-equal $leaky-get-or-insert-slice:abort/disp8 - 736 # zero-out(max, row-size) - 737 # . . push args - 738 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 739 52/push-EDX - 740 # . . call - 741 e8/call zero-out/disp32 - 742 # . . discard args - 743 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 744 # *max = slice-to-string(Heap, key) - 745 # . EAX = slice-to-string(Heap, key) - 746 # . . push args - 747 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 748 68/push Heap/imm32 - 749 # . . call - 750 e8/call slice-to-string/disp32 - 751 # . . discard args - 752 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 753 # . *max = EAX - 754 89/copy 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to *EDX - 755 # table->write += row-size - 756 # . EAX = row-size - 757 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX - 758 # . table->write += EAX - 759 01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI - 760 # return max+4 - 761 # . EAX = max - 762 89/copy 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # copy EDX to EAX - 763 # . EAX += 4 - 764 05/add-to-EAX 4/imm32 - 765 $leaky-get-or-insert-slice:end: - 766 # . restore registers - 767 5e/pop-to-ESI - 768 5a/pop-to-EDX - 769 59/pop-to-ECX - 770 # . epilog - 771 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 772 5d/pop-to-EBP - 773 c3/return - 774 - 775 $leaky-get-or-insert-slice:abort: - 776 # . _write(2/stderr, error) - 777 # . . push args - 778 68/push "leaky-get-or-insert-slice: table is full\n"/imm32 - 779 68/push 2/imm32/stderr + 322 # setup + 323 # . clear-stream(_test-output-stream) + 324 # . . push args + 325 68/push _test-output-stream/imm32 + 326 # . . call + 327 e8/call clear-stream/disp32 + 328 # . . discard args + 329 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 330 # . clear-stream(_test-output-buffered-file+4) + 331 # . . push args + 332 b8/copy-to-EAX _test-output-buffered-file/imm32 + 333 05/add-to-EAX 4/imm32 + 334 50/push-EAX + 335 # . . call + 336 e8/call clear-stream/disp32 + 337 # . . discard args + 338 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 339 # . clear-stream(_test-input-stream) + 340 # . . push args + 341 68/push _test-input-stream/imm32 + 342 # . . call + 343 e8/call clear-stream/disp32 + 344 # . . discard args + 345 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 346 # initialize input + 347 # . write(_test-input-stream, "abcd") + 348 # . . push args + 349 68/push "abcd"/imm32 + 350 68/push _test-input-stream/imm32 + 351 # . . call + 352 e8/call write/disp32 + 353 # . . discard args + 354 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 355 # write-stream-data(_test-output-buffered-file, _test-input-stream) + 356 # . . push args + 357 68/push _test-input-stream/imm32 + 358 68/push _test-output-buffered-file/imm32 + 359 # . . call + 360 e8/call write-stream-data/disp32 + 361 # . . discard args + 362 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 363 # check that the write happened as expected + 364 # . flush(_test-output-buffered-file) + 365 # . . push args + 366 68/push _test-output-buffered-file/imm32 + 367 # . . call + 368 e8/call flush/disp32 + 369 # . . discard args + 370 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 371 # . check-stream-equal(_test-output-stream, "abcd", msg) + 372 # . . push args + 373 68/push "F - test-write-stream-data"/imm32 + 374 68/push "abcd"/imm32 + 375 68/push _test-output-stream/imm32 + 376 # . . call + 377 e8/call check-stream-equal/disp32 + 378 # . . discard args + 379 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 380 # . epilog + 381 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 382 5d/pop-to-EBP + 383 c3/return + 384 + 385 has-metadata?: # word : (address slice), s : (address string) -> EAX : boolean + 386 # pseudocode: + 387 # var twig : &slice = next-token-from-slice(word->start, word->end, '/') # skip name + 388 # curr = twig->end + 389 # while true + 390 # twig = next-token-from-slice(curr, word->end, '/') + 391 # if (twig.empty()) break + 392 # if (slice-equal?(twig, s)) return true + 393 # curr = twig->end + 394 # return false + 395 # . prolog + 396 55/push-EBP + 397 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 398 # . save registers + 399 51/push-ECX + 400 52/push-EDX + 401 56/push-ESI + 402 57/push-EDI + 403 # ESI = word + 404 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI + 405 # EDX = word->end + 406 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 4/disp8 . # copy *(ESI+4) to EDX + 407 # var twig/EDI : (address slice) = {0, 0} + 408 68/push 0/imm32/end + 409 68/push 0/imm32/start + 410 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI + 411 # next-token-from-slice(word->start, word->end, '/', twig) + 412 # . . push args + 413 57/push-EDI + 414 68/push 0x2f/imm32/slash + 415 52/push-EDX + 416 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI + 417 # . . call + 418 e8/call next-token-from-slice/disp32 + 419 # . . discard args + 420 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP + 421 # curr/ECX = twig->end + 422 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX + 423 $has-metadata?:loop: + 424 # next-token-from-slice(curr, word->end, '/', twig) + 425 # . . push args + 426 57/push-EDI + 427 68/push 0x2f/imm32/slash + 428 52/push-EDX + 429 51/push-ECX + 430 # . . call + 431 e8/call next-token-from-slice/disp32 + 432 # . . discard args + 433 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP + 434 # if (slice-empty?(twig)) return false + 435 # . EAX = slice-empty?(twig) + 436 # . . push args + 437 57/push-EDI + 438 # . . call + 439 e8/call slice-empty?/disp32 + 440 # . . discard args + 441 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 442 # . if (EAX != 0) return false + 443 3d/compare-EAX-and 0/imm32 + 444 75/jump-if-not-equal $has-metadata?:false/disp8 + 445 # if (slice-equal?(twig, s)) return true + 446 # . EAX = slice-equal?(twig, s) + 447 # . . push args + 448 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 449 57/push-EDI + 450 # . . call + 451 e8/call slice-equal?/disp32 + 452 # . . discard args + 453 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 454 # . if (EAX != 0) return true + 455 3d/compare-EAX-and 0/imm32 + 456 75/jump-if-not-equal $has-metadata?:true/disp8 + 457 # curr = twig->end + 458 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX + 459 eb/jump $has-metadata?:loop/disp8 + 460 $has-metadata?:true: + 461 b8/copy-to-EAX 1/imm32/true + 462 eb/jump $has-metadata?:end/disp8 + 463 $has-metadata?:false: + 464 b8/copy-to-EAX 0/imm32/false + 465 $has-metadata?:end: + 466 # . reclaim locals + 467 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 468 # . restore registers + 469 5f/pop-to-EDI + 470 5e/pop-to-ESI + 471 5a/pop-to-EDX + 472 59/pop-to-ECX + 473 # . epilog + 474 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 475 5d/pop-to-EBP + 476 c3/return + 477 + 478 test-has-metadata-true: + 479 # . prolog + 480 55/push-EBP + 481 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 482 # (EAX..ECX) = "ab/imm32" + 483 b8/copy-to-EAX "ab/imm32"/imm32 + 484 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 485 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 486 05/add-to-EAX 4/imm32 + 487 # var in/ESI : (address slice) = {EAX, ECX} + 488 51/push-ECX + 489 50/push-EAX + 490 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + 491 # EAX = has-metadata?(ESI, "imm32") + 492 # . . push args + 493 68/push "imm32"/imm32 + 494 56/push-ESI + 495 # . . call + 496 e8/call has-metadata?/disp32 + 497 # . . discard args + 498 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 499 # check-ints-equal(EAX, 1, msg) + 500 # . . push args + 501 68/push "F - test-has-metadata-true"/imm32 + 502 68/push 1/imm32/true + 503 50/push-EAX + 504 # . . call + 505 e8/call check-ints-equal/disp32 + 506 # . . discard args + 507 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 508 # . epilog + 509 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 510 5d/pop-to-EBP + 511 c3/return + 512 + 513 test-has-metadata-false: + 514 # . prolog + 515 55/push-EBP + 516 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 517 # (EAX..ECX) = "ab/c" + 518 b8/copy-to-EAX "ab/c"/imm32 + 519 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 520 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 521 05/add-to-EAX 4/imm32 + 522 # var in/ESI : (address slice) = {EAX, ECX} + 523 51/push-ECX + 524 50/push-EAX + 525 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + 526 # EAX = has-metadata?(ESI, "d") + 527 # . . push args + 528 68/push "d"/imm32 + 529 56/push-ESI + 530 # . . call + 531 e8/call has-metadata?/disp32 + 532 # . . discard args + 533 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 534 # check-ints-equal(EAX, 0, msg) + 535 # . . push args + 536 68/push "F - test-has-metadata-false"/imm32 + 537 68/push 0/imm32/false + 538 50/push-EAX + 539 # . . call + 540 e8/call check-ints-equal/disp32 + 541 # . . discard args + 542 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 543 # . epilog + 544 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 545 5d/pop-to-EBP + 546 c3/return + 547 + 548 test-has-metadata-ignore-name: + 549 # . prolog + 550 55/push-EBP + 551 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 552 # (EAX..ECX) = "a/b" + 553 b8/copy-to-EAX "a/b"/imm32 + 554 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 555 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 556 05/add-to-EAX 4/imm32 + 557 # var in/ESI : (address slice) = {EAX, ECX} + 558 51/push-ECX + 559 50/push-EAX + 560 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + 561 # EAX = has-metadata?(ESI, "a") + 562 # . . push args + 563 68/push "a"/imm32 + 564 56/push-ESI + 565 # . . call + 566 e8/call has-metadata?/disp32 + 567 # . . discard args + 568 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 569 # check-ints-equal(EAX, 0, msg) + 570 # . . push args + 571 68/push "F - test-has-metadata-ignore-name"/imm32 + 572 68/push 0/imm32/false + 573 50/push-EAX + 574 # . . call + 575 e8/call check-ints-equal/disp32 + 576 # . . discard args + 577 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 578 # . epilog + 579 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 580 5d/pop-to-EBP + 581 c3/return + 582 + 583 test-has-metadata-multiple-true: + 584 # . prolog + 585 55/push-EBP + 586 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 587 # (EAX..ECX) = "a/b/c" + 588 b8/copy-to-EAX "a/b/c"/imm32 + 589 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 590 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 591 05/add-to-EAX 4/imm32 + 592 # var in/ESI : (address slice) = {EAX, ECX} + 593 51/push-ECX + 594 50/push-EAX + 595 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + 596 # EAX = has-metadata?(ESI, "c") + 597 # . . push args + 598 68/push "c"/imm32 + 599 56/push-ESI + 600 # . . call + 601 e8/call has-metadata?/disp32 + 602 # . . discard args + 603 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 604 # check-ints-equal(EAX, 1, msg) + 605 # . . push args + 606 68/push "F - test-has-metadata-multiple-true"/imm32 + 607 68/push 1/imm32/true + 608 50/push-EAX + 609 # . . call + 610 e8/call check-ints-equal/disp32 + 611 # . . discard args + 612 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 613 # . epilog + 614 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 615 5d/pop-to-EBP + 616 c3/return + 617 + 618 test-has-metadata-multiple-false: + 619 # . prolog + 620 55/push-EBP + 621 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 622 # (EAX..ECX) = "a/b/c" + 623 b8/copy-to-EAX "a/b/c"/imm32 + 624 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 625 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 626 05/add-to-EAX 4/imm32 + 627 # var in/ESI : (address slice) = {EAX, ECX} + 628 51/push-ECX + 629 50/push-EAX + 630 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + 631 # EAX = has-metadata?(ESI, "d") + 632 # . . push args + 633 68/push "d"/imm32 + 634 56/push-ESI + 635 # . . call + 636 e8/call has-metadata?/disp32 + 637 # . . discard args + 638 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 639 # check-ints-equal(EAX, 0, msg) + 640 # . . push args + 641 68/push "F - test-has-metadata-multiple-false"/imm32 + 642 68/push 0/imm32/false + 643 50/push-EAX + 644 # . . call + 645 e8/call check-ints-equal/disp32 + 646 # . . discard args + 647 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 648 # . epilog + 649 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 650 5d/pop-to-EBP + 651 c3/return + 652 + 653 # If datum of 'word' is not a valid name, it must be a hex int. Parse and print + 654 # it in 'width' bytes of hex, least significant first. + 655 # Otherwise just print the entire word including metadata. + 656 # Always print a trailing space. + 657 emit: # out : (address buffered-file), word : (address slice), width : int -> <void> + 658 # . prolog + 659 55/push-EBP + 660 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 661 # . save registers + 662 50/push-EAX + 663 56/push-ESI + 664 57/push-EDI + 665 # ESI = word + 666 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI + 667 # var name/EDI : (address slice) = {0, 0} + 668 68/push 0/imm32/end + 669 68/push 0/imm32/start + 670 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI + 671 # datum = next-token-from-slice(word->start, word->end, '/') + 672 # . . push args + 673 57/push-EDI + 674 68/push 0x2f/imm32/slash + 675 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) + 676 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI + 677 # . . call + 678 e8/call next-token-from-slice/disp32 + 679 # . . discard args + 680 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP + 681 # if (is-valid-name?(datum)) write-slice-buffered(out, word) and return + 682 # . EAX = is-valid-name?(name) + 683 # . . push args + 684 57/push-EDI + 685 # . . call + 686 e8/call is-valid-name?/disp32 + 687 # . . discard args + 688 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 689 # . if (EAX != 0) + 690 3d/compare-EAX-and 0/imm32 + 691 74/jump-if-equal $emit:hex-int/disp8 + 692 $emit:name: + 693 # . write-slice-buffered(out, word) + 694 # . . push args + 695 56/push-ESI + 696 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 697 # . . call + 698 e8/call write-slice-buffered/disp32 + 699 # . . discard args + 700 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 701 # . write-buffered(out, " ") + 702 # . . push args + 703 68/push " "/imm32 + 704 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 705 # . . call + 706 e8/call write-buffered/disp32 + 707 # . . discard args + 708 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 709 # . return + 710 eb/jump $emit:end/disp8 + 711 # otherwise emit-hex(out, parse-hex-int(datum), width) + 712 # (Weird shit can happen here if the datum of 'word' isn't either a valid + 713 # name or a hex number, but we're only going to be passing in real legal + 714 # programs. We just want to make sure that valid names aren't treated as + 715 # (valid) hex numbers.) + 716 $emit:hex-int: + 717 # . value/EAX = parse-hex-int(datum) + 718 # . . push args + 719 57/push-EDI + 720 # . . call + 721 e8/call parse-hex-int/disp32 + 722 # . . discard args + 723 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 724 # . emit-hex(out, value, width) + 725 # . . push args + 726 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + 727 50/push-EAX + 728 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 729 # . . call + 730 e8/call emit-hex/disp32 + 731 # . . discard args + 732 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 733 $emit:end: + 734 # . reclaim locals + 735 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 736 # . restore registers + 737 5f/pop-to-EDI + 738 5e/pop-to-ESI + 739 58/pop-to-EAX + 740 # . epilog + 741 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 742 5d/pop-to-EBP + 743 c3/return + 744 + 745 test-emit-number: + 746 # . prolog + 747 55/push-EBP + 748 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 749 # setup + 750 # . clear-stream(_test-output-stream) + 751 # . . push args + 752 68/push _test-output-stream/imm32 + 753 # . . call + 754 e8/call clear-stream/disp32 + 755 # . . discard args + 756 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 757 # . clear-stream(_test-output-buffered-file+4) + 758 # . . push args + 759 b8/copy-to-EAX _test-output-buffered-file/imm32 + 760 05/add-to-EAX 4/imm32 + 761 50/push-EAX + 762 # . . call + 763 e8/call clear-stream/disp32 + 764 # . . discard args + 765 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 766 # (EAX..ECX) = "30" + 767 b8/copy-to-EAX "30"/imm32 + 768 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 769 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 770 05/add-to-EAX 4/imm32 + 771 # var slice/ECX = {EAX, ECX} + 772 51/push-ECX + 773 50/push-EAX + 774 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 775 # emit(_test-output-buffered-file, slice, 1) + 776 # . . push args + 777 68/push 1/imm32 + 778 51/push-ECX + 779 68/push _test-output-buffered-file/imm32 780 # . . call - 781 e8/call _write/disp32 + 781 e8/call emit/disp32 782 # . . discard args - 783 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 784 # . syscall(exit, 1) - 785 bb/copy-to-EBX 1/imm32 - 786 b8/copy-to-EAX 1/imm32/exit - 787 cd/syscall 0x80/imm8 - 788 # never gets here - 789 - 790 test-leaky-get-or-insert-slice: - 791 # . prolog - 792 55/push-EBP - 793 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 794 # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 795 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 796 68/push 0x10/imm32/length - 797 68/push 0/imm32/read - 798 68/push 0/imm32/write - 799 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 800 # (EAX..EDX) = "code" - 801 b8/copy-to-EAX "code"/imm32 - 802 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 803 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 804 05/add-to-EAX 4/imm32 - 805 # var slice/EDX = {EAX, EDX} - 806 52/push-EDX - 807 50/push-EAX - 808 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - 809 $test-leaky-get-or-insert-slice:first-call: - 810 # - start with an empty table, insert one key, verify that it was inserted - 811 # EAX = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row) + 783 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 784 # flush(_test-output-buffered-file) + 785 # . . push args + 786 68/push _test-output-buffered-file/imm32 + 787 # . . call + 788 e8/call flush/disp32 + 789 # . . discard args + 790 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 791 # check-stream-equal(_test-output-stream, "30 ", msg) + 792 # . . push args + 793 68/push "F - test-emit-number/1"/imm32 + 794 68/push "30 "/imm32 + 795 68/push _test-output-stream/imm32 + 796 # . . call + 797 e8/call check-stream-equal/disp32 + 798 # . . discard args + 799 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 800 # . epilog + 801 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 802 5d/pop-to-EBP + 803 c3/return + 804 + 805 test-emit-negative-number: + 806 # test support for sign-extending negative numbers + 807 # . prolog + 808 55/push-EBP + 809 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 810 # setup + 811 # . clear-stream(_test-output-stream) 812 # . . push args - 813 68/push 8/imm32/row-size - 814 52/push-EDX - 815 51/push-ECX - 816 # . . call - 817 e8/call leaky-get-or-insert-slice/disp32 - 818 # . . discard args - 819 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 820 # check-ints-equal(EAX - table->data, 4, msg) # first row's value slot returned - 821 # . check-ints-equal(EAX - table, 16, msg) - 822 # . . push args - 823 68/push "F - test-leaky-get-or-insert-slice/0"/imm32 - 824 68/push 0x10/imm32 - 825 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 826 50/push-EAX - 827 # . . call - 828 e8/call check-ints-equal/disp32 - 829 # . . discard args - 830 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 831 $test-leaky-get-or-insert-slice:check2: - 832 # check-ints-equal(table->write, row-size = 8, msg) - 833 # . . push args - 834 68/push "F - test-leaky-get-or-insert-slice/1"/imm32 - 835 68/push 8/imm32/row-size - 836 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 837 # . . call - 838 e8/call check-ints-equal/disp32 - 839 # . . discard args - 840 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 841 # check-string-equal(*table->data, "code", msg) - 842 # . . push args - 843 68/push "F - test-leaky-get-or-insert-slice/2"/imm32 - 844 68/push "code"/imm32 - 845 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - 846 # . . call - 847 e8/call check-string-equal/disp32 - 848 # . . discard args - 849 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 850 $test-leaky-get-or-insert-slice:second-call: - 851 # - insert the same key again, verify that it was reused - 852 # EAX = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row) + 813 68/push _test-output-stream/imm32 + 814 # . . call + 815 e8/call clear-stream/disp32 + 816 # . . discard args + 817 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 818 # . clear-stream(_test-output-buffered-file+4) + 819 # . . push args + 820 b8/copy-to-EAX _test-output-buffered-file/imm32 + 821 05/add-to-EAX 4/imm32 + 822 50/push-EAX + 823 # . . call + 824 e8/call clear-stream/disp32 + 825 # . . discard args + 826 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 827 # (EAX..ECX) = "-2" + 828 b8/copy-to-EAX "-2"/imm32 + 829 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 830 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 831 05/add-to-EAX 4/imm32 + 832 # var slice/ECX = {EAX, ECX} + 833 51/push-ECX + 834 50/push-EAX + 835 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 836 # emit(_test-output-buffered-file, slice, 2) + 837 # . . push args + 838 68/push 2/imm32 + 839 51/push-ECX + 840 68/push _test-output-buffered-file/imm32 + 841 # . . call + 842 e8/call emit/disp32 + 843 # . . discard args + 844 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 845 # flush(_test-output-buffered-file) + 846 # . . push args + 847 68/push _test-output-buffered-file/imm32 + 848 # . . call + 849 e8/call flush/disp32 + 850 # . . discard args + 851 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 852 # check-stream-equal(_test-output-stream, "fe ff ", msg) 853 # . . push args - 854 68/push 8/imm32/row-size - 855 52/push-EDX - 856 51/push-ECX + 854 68/push "F - test-emit-number/1"/imm32 + 855 68/push "fe ff "/imm32 + 856 68/push _test-output-stream/imm32 857 # . . call - 858 e8/call leaky-get-or-insert-slice/disp32 + 858 e8/call check-stream-equal/disp32 859 # . . discard args 860 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 861 # check-ints-equal(EAX - table->data, 4, msg) - 862 # . check-ints-equal(EAX - table, 16, msg) - 863 # . . push args - 864 68/push "F - test-leaky-get-or-insert-slice/3"/imm32 - 865 68/push 0x10/imm32 - 866 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 867 50/push-EAX - 868 # . . call - 869 e8/call check-ints-equal/disp32 - 870 # . . discard args - 871 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 872 # no new row inserted - 873 # . check-ints-equal(table->write, row-size = 8, msg) - 874 # . . push args - 875 68/push "F - test-leaky-get-or-insert-slice/4"/imm32 - 876 68/push 8/imm32/row-size - 877 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 878 # . . call - 879 e8/call check-ints-equal/disp32 - 880 # . . discard args - 881 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 882 # check-string-equal(*table->data, "code", msg) - 883 # . . push args - 884 68/push "F - test-leaky-get-or-insert-slice/5"/imm32 - 885 68/push "code"/imm32 - 886 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - 887 # . . call - 888 e8/call check-string-equal/disp32 - 889 # . . discard args - 890 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 891 $test-leaky-get-or-insert-slice:third-call: - 892 # - insert a new key, verify that it was inserted - 893 # (EAX..EDX) = "data" - 894 b8/copy-to-EAX "data"/imm32 - 895 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 896 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 897 05/add-to-EAX 4/imm32 - 898 # var slice/EDX = {EAX, EDX} - 899 52/push-EDX - 900 50/push-EAX - 901 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - 902 # EAX = leaky-get-or-insert-slice(table, "data" slice, 8 bytes per row) - 903 # . . push args - 904 68/push 8/imm32/row-size - 905 52/push-EDX - 906 51/push-ECX - 907 # . . call - 908 e8/call leaky-get-or-insert-slice/disp32 - 909 # . . discard args - 910 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 911 # table gets a new row - 912 # check-ints-equal(EAX - table->data, 12, msg) # second row's value slot returned - 913 # . check-ints-equal(EAX - table, 24, msg) + 861 # . epilog + 862 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 863 5d/pop-to-EBP + 864 c3/return + 865 + 866 test-emit-number-with-metadata: + 867 # . prolog + 868 55/push-EBP + 869 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 870 # setup + 871 # . clear-stream(_test-output-stream) + 872 # . . push args + 873 68/push _test-output-stream/imm32 + 874 # . . call + 875 e8/call clear-stream/disp32 + 876 # . . discard args + 877 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 878 # . clear-stream(_test-output-buffered-file+4) + 879 # . . push args + 880 b8/copy-to-EAX _test-output-buffered-file/imm32 + 881 05/add-to-EAX 4/imm32 + 882 50/push-EAX + 883 # . . call + 884 e8/call clear-stream/disp32 + 885 # . . discard args + 886 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 887 # (EAX..ECX) = "-2/foo" + 888 b8/copy-to-EAX "-2/foo"/imm32 + 889 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 890 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 891 05/add-to-EAX 4/imm32 + 892 # var slice/ECX = {EAX, ECX} + 893 51/push-ECX + 894 50/push-EAX + 895 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 896 # emit(_test-output-buffered-file, slice, 2) + 897 # . . push args + 898 68/push 2/imm32 + 899 51/push-ECX + 900 68/push _test-output-buffered-file/imm32 + 901 # . . call + 902 e8/call emit/disp32 + 903 # . . discard args + 904 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 905 # flush(_test-output-buffered-file) + 906 # . . push args + 907 68/push _test-output-buffered-file/imm32 + 908 # . . call + 909 e8/call flush/disp32 + 910 # . . discard args + 911 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 912 # the '/foo' will have no impact on the output + 913 # check-stream-equal(_test-output-stream, "fe ff ", msg) 914 # . . push args - 915 68/push "F - test-leaky-get-or-insert-slice/6"/imm32 - 916 68/push 0x18/imm32 - 917 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 918 50/push-EAX - 919 # . . call - 920 e8/call check-ints-equal/disp32 - 921 # . . discard args - 922 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 923 # check-ints-equal(table->write, 2 rows = 16, msg) - 924 # . . push args - 925 68/push "F - test-leaky-get-or-insert-slice/7"/imm32 - 926 68/push 0x10/imm32/two-rows - 927 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - 928 # . . call - 929 e8/call check-ints-equal/disp32 - 930 # . . discard args - 931 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 932 # check-string-equal(*table->data+8, "data", msg) - 933 # check-string-equal(*(table+20), "data", msg) - 934 # . . push args - 935 68/push "F - test-leaky-get-or-insert-slice/8"/imm32 - 936 68/push "data"/imm32 - 937 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0x14/disp8 . # push *(ECX+20) - 938 # . . call - 939 e8/call check-string-equal/disp32 - 940 # . . discard args - 941 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 942 $test-leaky-get-or-insert-slice:end: - 943 # . epilog - 944 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 945 5d/pop-to-EBP - 946 c3/return - 947 - 948 # (re)compute the bounds of the next word in the line - 949 # return empty string on reaching end of file - 950 next-word: # line : (address stream byte), out : (address slice) - 951 # . prolog - 952 55/push-EBP - 953 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 954 # . save registers + 915 68/push "F - test-emit-number-with-metadata"/imm32 + 916 68/push "fe ff "/imm32 + 917 68/push _test-output-stream/imm32 + 918 # . . call + 919 e8/call check-stream-equal/disp32 + 920 # . . discard args + 921 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 922 # . epilog + 923 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 924 5d/pop-to-EBP + 925 c3/return + 926 + 927 test-emit-non-number: + 928 # . prolog + 929 55/push-EBP + 930 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 931 # setup + 932 # . clear-stream(_test-output-stream) + 933 # . . push args + 934 68/push _test-output-stream/imm32 + 935 # . . call + 936 e8/call clear-stream/disp32 + 937 # . . discard args + 938 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 939 # . clear-stream(_test-output-buffered-file+4) + 940 # . . push args + 941 b8/copy-to-EAX _test-output-buffered-file/imm32 + 942 05/add-to-EAX 4/imm32 + 943 50/push-EAX + 944 # . . call + 945 e8/call clear-stream/disp32 + 946 # . . discard args + 947 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 948 # (EAX..ECX) = "xyz" + 949 b8/copy-to-EAX "xyz"/imm32 + 950 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 951 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 952 05/add-to-EAX 4/imm32 + 953 # var slice/ECX = {EAX, ECX} + 954 51/push-ECX 955 50/push-EAX - 956 51/push-ECX - 957 56/push-ESI - 958 57/push-EDI - 959 # ESI = line - 960 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 961 # EDI = out - 962 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI - 963 # skip-chars-matching(line, ' ') - 964 # . . push args - 965 68/push 0x20/imm32/space - 966 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 967 # . . call - 968 e8/call skip-chars-matching/disp32 - 969 # . . discard args - 970 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 971 $next-word:check0: - 972 # if (line->read >= line->write) clear out and return - 973 # . EAX = line->read - 974 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - 975 # . if (EAX < line->write) goto next check - 976 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI - 977 7c/jump-if-lesser $next-word:check-for-comment/disp8 - 978 # . return out = {0, 0} - 979 c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI - 980 c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) - 981 eb/jump $next-word:end/disp8 - 982 $next-word:check-for-comment: - 983 # out->start = &line->data[line->read] - 984 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX - 985 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX - 986 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI - 987 # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return - 988 # . EAX = line->data[line->read] - 989 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 990 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL - 991 # . compare - 992 3d/compare-EAX-and 0x23/imm32/pound - 993 75/jump-if-not-equal $next-word:regular-word/disp8 - 994 $next-word:comment: - 995 # . out->end = &line->data[line->write] - 996 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX - 997 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX - 998 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) - 999 # . line->read = line->write -1000 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) -1001 # . return -1002 eb/jump $next-word:end/disp8 -1003 $next-word:regular-word: -1004 # otherwise skip-chars-not-matching-whitespace(line) # including trailing newline -1005 # . . push args -1006 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1007 # . . call -1008 e8/call skip-chars-not-matching-whitespace/disp32 -1009 # . . discard args -1010 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1011 # out->end = &line->data[line->read] -1012 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX -1013 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX -1014 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) -1015 $next-word:end: -1016 # . restore registers -1017 5f/pop-to-EDI -1018 5e/pop-to-ESI -1019 59/pop-to-ECX -1020 58/pop-to-EAX -1021 # . epilog -1022 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1023 5d/pop-to-EBP -1024 c3/return -1025 -1026 test-next-word: -1027 # . prolog -1028 55/push-EBP -1029 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1030 # setup -1031 # . clear-stream(_test-stream) -1032 # . . push args -1033 68/push _test-stream/imm32 -1034 # . . call -1035 e8/call clear-stream/disp32 -1036 # . . discard args -1037 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1038 # var slice/ECX = {0, 0} -1039 68/push 0/imm32/end -1040 68/push 0/imm32/start -1041 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1042 # write(_test-stream, " ab") -1043 # . . push args -1044 68/push " ab"/imm32 -1045 68/push _test-stream/imm32 -1046 # . . call -1047 e8/call write/disp32 -1048 # . . discard args -1049 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1050 # next-word(_test-stream, slice) -1051 # . . push args -1052 51/push-ECX -1053 68/push _test-stream/imm32 -1054 # . . call -1055 e8/call next-word/disp32 -1056 # . . discard args -1057 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1058 # check-ints-equal(slice->start - _test-stream->data, 2, msg) -1059 # . check-ints-equal(slice->start - _test-stream, 14, msg) + 956 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 957 # emit(_test-output-buffered-file, slice, 2) + 958 # . . push args + 959 68/push 2/imm32 + 960 51/push-ECX + 961 68/push _test-output-buffered-file/imm32 + 962 # . . call + 963 e8/call emit/disp32 + 964 # . . discard args + 965 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 966 # flush(_test-output-buffered-file) + 967 # . . push args + 968 68/push _test-output-buffered-file/imm32 + 969 # . . call + 970 e8/call flush/disp32 + 971 # . . discard args + 972 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 973 # check-stream-equal(_test-output-stream, "xyz", msg) + 974 # . . push args + 975 68/push "F - test-emit-non-number"/imm32 + 976 68/push "xyz "/imm32 + 977 68/push _test-output-stream/imm32 + 978 # . . call + 979 e8/call check-stream-equal/disp32 + 980 # . . discard args + 981 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 982 # . epilog + 983 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 984 5d/pop-to-EBP + 985 c3/return + 986 + 987 test-emit-non-number-with-metadata: + 988 # . prolog + 989 55/push-EBP + 990 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 991 # setup + 992 # . clear-stream(_test-output-stream) + 993 # . . push args + 994 68/push _test-output-stream/imm32 + 995 # . . call + 996 e8/call clear-stream/disp32 + 997 # . . discard args + 998 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 999 # . clear-stream(_test-output-buffered-file+4) +1000 # . . push args +1001 b8/copy-to-EAX _test-output-buffered-file/imm32 +1002 05/add-to-EAX 4/imm32 +1003 50/push-EAX +1004 # . . call +1005 e8/call clear-stream/disp32 +1006 # . . discard args +1007 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1008 # (EAX..ECX) = "xyz/" +1009 b8/copy-to-EAX "xyz/"/imm32 +1010 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1011 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1012 05/add-to-EAX 4/imm32 +1013 # var slice/ECX = {EAX, ECX} +1014 51/push-ECX +1015 50/push-EAX +1016 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1017 # emit(_test-output-buffered-file, slice, 2) +1018 # . . push args +1019 68/push 2/imm32 +1020 51/push-ECX +1021 68/push _test-output-buffered-file/imm32 +1022 # . . call +1023 e8/call emit/disp32 +1024 # . . discard args +1025 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1026 # flush(_test-output-buffered-file) +1027 # . . push args +1028 68/push _test-output-buffered-file/imm32 +1029 # . . call +1030 e8/call flush/disp32 +1031 # . . discard args +1032 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1033 # check-stream-equal(_test-output-stream, "xyz/", msg) +1034 # . . push args +1035 68/push "F - test-emit-non-number-with-metadata"/imm32 +1036 68/push "xyz/ "/imm32 +1037 68/push _test-output-stream/imm32 +1038 # . . call +1039 e8/call check-stream-equal/disp32 +1040 # . . discard args +1041 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1042 # . epilog +1043 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1044 5d/pop-to-EBP +1045 c3/return +1046 +1047 test-emit-non-number-with-all-hex-digits-and-metadata: +1048 # . prolog +1049 55/push-EBP +1050 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1051 # setup +1052 # . clear-stream(_test-output-stream) +1053 # . . push args +1054 68/push _test-output-stream/imm32 +1055 # . . call +1056 e8/call clear-stream/disp32 +1057 # . . discard args +1058 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1059 # . clear-stream(_test-output-buffered-file+4) 1060 # . . push args -1061 68/push "F - test-next-word: start"/imm32 -1062 68/push 0xe/imm32 -1063 # . . push slice->start - _test-stream -1064 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -1065 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1066 50/push-EAX -1067 # . . call -1068 e8/call check-ints-equal/disp32 -1069 # . . discard args -1070 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1071 # check-ints-equal(slice->end - _test-stream->data, 4, msg) -1072 # . check-ints-equal(slice->end - _test-stream, 16, msg) -1073 # . . push args -1074 68/push "F - test-next-word: end"/imm32 -1075 68/push 0x10/imm32 -1076 # . . push slice->end - _test-stream -1077 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1078 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1079 50/push-EAX -1080 # . . call -1081 e8/call check-ints-equal/disp32 -1082 # . . discard args -1083 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1084 # . epilog -1085 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1086 5d/pop-to-EBP -1087 c3/return -1088 -1089 test-next-word-returns-whole-comment: -1090 # . prolog -1091 55/push-EBP -1092 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1093 # setup -1094 # . clear-stream(_test-stream) -1095 # . . push args -1096 68/push _test-stream/imm32 -1097 # . . call -1098 e8/call clear-stream/disp32 -1099 # . . discard args -1100 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1101 # var slice/ECX = {0, 0} -1102 68/push 0/imm32/end -1103 68/push 0/imm32/start -1104 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1105 # write(_test-stream, " # a") -1106 # . . push args -1107 68/push " # a"/imm32 -1108 68/push _test-stream/imm32 -1109 # . . call -1110 e8/call write/disp32 -1111 # . . discard args -1112 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1113 # next-word(_test-stream, slice) -1114 # . . push args -1115 51/push-ECX -1116 68/push _test-stream/imm32 -1117 # . . call -1118 e8/call next-word/disp32 -1119 # . . discard args -1120 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1121 # check-ints-equal(slice->start - _test-stream->data, 2, msg) -1122 # . check-ints-equal(slice->start - _test-stream, 14, msg) -1123 # . . push args -1124 68/push "F - test-next-word-returns-whole-comment: start"/imm32 -1125 68/push 0xe/imm32 -1126 # . . push slice->start - _test-stream -1127 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -1128 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1129 50/push-EAX -1130 # . . call -1131 e8/call check-ints-equal/disp32 -1132 # . . discard args -1133 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1134 # check-ints-equal(slice->end - _test-stream->data, 5, msg) -1135 # . check-ints-equal(slice->end - _test-stream, 17, msg) -1136 # . . push args -1137 68/push "F - test-next-word-returns-whole-comment: end"/imm32 -1138 68/push 0x11/imm32 -1139 # . . push slice->end - _test-stream -1140 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1141 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -1142 50/push-EAX -1143 # . . call -1144 e8/call check-ints-equal/disp32 -1145 # . . discard args -1146 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1147 # . epilog -1148 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1149 5d/pop-to-EBP -1150 c3/return -1151 -1152 test-next-word-returns-empty-string-on-eof: -1153 # . prolog -1154 55/push-EBP -1155 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1156 # setup -1157 # . clear-stream(_test-stream) -1158 # . . push args -1159 68/push _test-stream/imm32 -1160 # . . call -1161 e8/call clear-stream/disp32 -1162 # . . discard args -1163 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1164 # var slice/ECX = {0, 0} -1165 68/push 0/imm32/end -1166 68/push 0/imm32/start -1167 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1168 # write nothing to _test-stream -1169 # next-word(_test-stream, slice) -1170 # . . push args -1171 51/push-ECX -1172 68/push _test-stream/imm32 -1173 # . . call -1174 e8/call next-word/disp32 -1175 # . . discard args -1176 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1177 # check-ints-equal(slice->end - slice->start, 0, msg) -1178 # . . push args -1179 68/push "F - test-next-word-returns-empty-string-on-eof"/imm32 -1180 68/push 0/imm32 -1181 # . . push slice->end - slice->start -1182 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -1183 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX -1184 50/push-EAX -1185 # . . call -1186 e8/call check-ints-equal/disp32 -1187 # . . discard args -1188 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1189 # . epilog -1190 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1191 5d/pop-to-EBP -1192 c3/return -1193 -1194 # write an entire stream's contents to a buffered-file -1195 # ways to do this: -1196 # - construct a 'maximal slice' and pass it to write-slice-buffered -1197 # - flush the buffered-file and pass the stream directly to its fd (disabling buffering) -1198 # we'll go with the first way for now -1199 write-stream-data: # f : (address buffered-file), s : (address stream) -> <void> -1200 # . prolog -1201 55/push-EBP -1202 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1203 # . save registers -1204 50/push-EAX +1061 b8/copy-to-EAX _test-output-buffered-file/imm32 +1062 05/add-to-EAX 4/imm32 +1063 50/push-EAX +1064 # . . call +1065 e8/call clear-stream/disp32 +1066 # . . discard args +1067 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1068 # (EAX..ECX) = "abcd/xyz" +1069 b8/copy-to-EAX "abcd/xyz"/imm32 +1070 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1071 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1072 05/add-to-EAX 4/imm32 +1073 # var slice/ECX = {EAX, ECX} +1074 51/push-ECX +1075 50/push-EAX +1076 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1077 # emit(_test-output-buffered-file, slice, 2) +1078 # . . push args +1079 68/push 2/imm32 +1080 51/push-ECX +1081 68/push _test-output-buffered-file/imm32 +1082 # . . call +1083 e8/call emit/disp32 +1084 # . . discard args +1085 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1086 # flush(_test-output-buffered-file) +1087 # . . push args +1088 68/push _test-output-buffered-file/imm32 +1089 # . . call +1090 e8/call flush/disp32 +1091 # . . discard args +1092 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1093 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1119 # check-stream-equal(_test-output-stream, "abcd/xyz") +1120 # . . push args +1121 68/push "F - test-emit-non-number-with-all-hex-digits"/imm32 +1122 68/push "abcd/xyz "/imm32 +1123 68/push _test-output-stream/imm32 +1124 # . . call +1125 e8/call check-stream-equal/disp32 +1126 # . . discard args +1127 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1128 # . epilog +1129 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1130 5d/pop-to-EBP +1131 c3/return +1132 +1133 # conditions for 'valid' names that are not at risk of looking like hex numbers +1134 # keep in sync with the rules in labels.cc +1135 #: - if it starts with a digit, it's treated as a number. If it can't be +1136 #: parsed as hex it will raise an error. +1137 #: - if it starts with '-' it's treated as a number. +1138 #: - if it starts with '0x' it's treated as a number. (redundant) +1139 #: - if it's two characters long, it can't be a name. Either it's a hex +1140 #: byte, or it raises an error. +1141 is-valid-name?: # in : (address slice) -> EAX : boolean +1142 # . prolog +1143 55/push-EBP +1144 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1145 # . save registers +1146 51/push-ECX +1147 56/push-ESI +1148 # ESI = in +1149 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +1150 # start/ECX = in->start +1151 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX +1152 # end/EAX = in->end +1153 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX +1154 $is-valid-name?:check0: +1155 # if (start >= end) return false +1156 39/compare 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # compare ECX with EAX +1157 73/jump-if-greater-or-equal-unsigned $is-valid-name?:false/disp8 +1158 $is-valid-name?:check1: +1159 # EAX -= ECX +1160 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX +1161 # if (EAX == 2) return false +1162 3d/compare-EAX-and 2/imm32 +1163 74/jump-if-equal $is-valid-name?:false/disp8 +1164 $is-valid-name?:check2: +1165 # c/EAX = *ECX +1166 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +1167 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL +1168 # if (c == "-") return false +1169 3d/compare-EAX-and 2d/imm32/- +1170 74/jump-if-equal $is-valid-name?:false/disp8 +1171 $is-valid-name?:check3a: +1172 # if (c < "0") return true +1173 3d/compare-EAX-with 30/imm32/0 +1174 7c/jump-if-lesser $is-valid-name?:true/disp8 +1175 $is-valid-name?:check3b: +1176 # if (c > "9") return true +1177 3d/compare-EAX-with 39/imm32/9 +1178 7f/jump-if-greater $is-valid-name?:true/disp8 +1179 $is-valid-name?:false: +1180 # return false +1181 b8/copy-to-EAX 0/imm32/false +1182 eb/jump $is-valid-name?:end/disp8 +1183 $is-valid-name?:true: +1184 # return true +1185 b8/copy-to-EAX 1/imm32/true +1186 $is-valid-name?:end: +1187 # . restore registers +1188 5e/pop-to-ESI +1189 59/pop-to-ECX +1190 # . epilog +1191 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1192 5d/pop-to-EBP +1193 c3/return +1194 +1195 test-is-valid-name-digit-prefix: +1196 # . prolog +1197 55/push-EBP +1198 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1199 # (EAX..ECX) = "34" +1200 b8/copy-to-EAX "34"/imm32 +1201 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1202 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1203 05/add-to-EAX 4/imm32 +1204 # var slice/ECX = {EAX, ECX} 1205 51/push-ECX -1206 56/push-ESI -1207 # ESI = s -1208 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI -1209 # var slice/ECX = {s->data, s->data + s->write} -1210 # . push s->data + s->write -1211 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX -1212 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX -1213 50/push-EAX -1214 # . push s->data -1215 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX -1216 50/push-EAX -1217 # . ECX = ESP -1218 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1219 # write-slice-buffered(f, slice) -1220 # . . push args -1221 51/push-ECX -1222 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1223 # . . call -1224 e8/call write-slice-buffered/disp32 -1225 # . . discard args -1226 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1227 $write-stream-data:end: -1228 # . restore locals -1229 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1230 # . restore registers -1231 5e/pop-to-ESI -1232 59/pop-to-ECX -1233 58/pop-to-EAX -1234 # . epilog -1235 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1236 5d/pop-to-EBP -1237 c3/return -1238 -1239 test-write-stream-data: -1240 # . prolog -1241 55/push-EBP -1242 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1243 # setup -1244 # . clear-stream(_test-output-stream) -1245 # . . push args -1246 68/push _test-output-stream/imm32 -1247 # . . call -1248 e8/call clear-stream/disp32 -1249 # . . discard args -1250 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1251 # . clear-stream(_test-output-buffered-file+4) -1252 # . . push args -1253 b8/copy-to-EAX _test-output-buffered-file/imm32 -1254 05/add-to-EAX 4/imm32 -1255 50/push-EAX -1256 # . . call -1257 e8/call clear-stream/disp32 -1258 # . . discard args -1259 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1260 # . clear-stream(_test-input-stream) -1261 # . . push args -1262 68/push _test-input-stream/imm32 -1263 # . . call -1264 e8/call clear-stream/disp32 -1265 # . . discard args -1266 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1267 # initialize input -1268 # . write(_test-input-stream, "abcd") -1269 # . . push args -1270 68/push "abcd"/imm32 -1271 68/push _test-input-stream/imm32 -1272 # . . call -1273 e8/call write/disp32 -1274 # . . discard args -1275 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1276 # write-stream-data(_test-output-buffered-file, _test-input-stream) +1206 50/push-EAX +1207 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1208 # EAX = is-valid-name?(slice) +1209 # . . push args +1210 51/push-ECX +1211 # . . call +1212 e8/call is-valid-name?/disp32 +1213 # . . discard args +1214 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1215 # check-ints-equal(EAX, 0, msg) +1216 # . . push args +1217 68/push "F - test-is-valid-name-digit-prefix"/imm32 +1218 68/push 0/imm32/false +1219 50/push-EAX +1220 # . . call +1221 e8/call check-ints-equal/disp32 +1222 # . . discard args +1223 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1224 # . epilog +1225 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1226 5d/pop-to-EBP +1227 c3/return +1228 +1229 test-is-valid-name-negative-prefix: +1230 # . prolog +1231 55/push-EBP +1232 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1233 # (EAX..ECX) = "-0x34" +1234 b8/copy-to-EAX "-0x34"/imm32 +1235 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1236 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1237 05/add-to-EAX 4/imm32 +1238 # var slice/ECX = {EAX, ECX} +1239 51/push-ECX +1240 50/push-EAX +1241 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1242 # EAX = is-valid-name?(slice) +1243 # . . push args +1244 51/push-ECX +1245 # . . call +1246 e8/call is-valid-name?/disp32 +1247 # . . discard args +1248 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1249 # check-ints-equal(EAX, 0, msg) +1250 # . . push args +1251 68/push "F - test-is-valid-name-negative-prefix"/imm32 +1252 68/push 0/imm32/false +1253 50/push-EAX +1254 # . . call +1255 e8/call check-ints-equal/disp32 +1256 # . . discard args +1257 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1258 # . epilog +1259 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1260 5d/pop-to-EBP +1261 c3/return +1262 +1263 test-is-valid-name-0x-prefix: +1264 # . prolog +1265 55/push-EBP +1266 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1267 # (EAX..ECX) = "0x34" +1268 b8/copy-to-EAX "0x34"/imm32 +1269 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1270 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1271 05/add-to-EAX 4/imm32 +1272 # var slice/ECX = {EAX, ECX} +1273 51/push-ECX +1274 50/push-EAX +1275 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1276 # EAX = is-valid-name?(slice) 1277 # . . push args -1278 68/push _test-input-stream/imm32 -1279 68/push _test-output-buffered-file/imm32 -1280 # . . call -1281 e8/call write-stream-data/disp32 -1282 # . . discard args -1283 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1284 # check that the write happened as expected -1285 # . flush(_test-output-buffered-file) -1286 # . . push args -1287 68/push _test-output-buffered-file/imm32 +1278 51/push-ECX +1279 # . . call +1280 e8/call is-valid-name?/disp32 +1281 # . . discard args +1282 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1283 # check-ints-equal(EAX, 0, msg) +1284 # . . push args +1285 68/push "F - test-is-valid-name-0x-prefix"/imm32 +1286 68/push 0/imm32/false +1287 50/push-EAX 1288 # . . call -1289 e8/call flush/disp32 +1289 e8/call check-ints-equal/disp32 1290 # . . discard args -1291 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1292 # . check-stream-equal(_test-output-stream, "abcd", msg) -1293 # . . push args -1294 68/push "F - test-write-stream-data"/imm32 -1295 68/push "abcd"/imm32 -1296 68/push _test-output-stream/imm32 -1297 # . . call -1298 e8/call check-stream-equal/disp32 -1299 # . . discard args -1300 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1301 # . epilog -1302 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1303 5d/pop-to-EBP -1304 c3/return -1305 -1306 has-metadata?: # word : (address slice), s : (address string) -> EAX : boolean -1307 # pseudocode: -1308 # var twig : &slice = next-token-from-slice(word->start, word->end, '/') # skip name -1309 # curr = twig->end -1310 # while true -1311 # twig = next-token-from-slice(curr, word->end, '/') -1312 # if (twig.empty()) break -1313 # if (slice-equal?(twig, s)) return true -1314 # curr = twig->end -1315 # return false -1316 # . prolog -1317 55/push-EBP -1318 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1319 # . save registers -1320 51/push-ECX -1321 52/push-EDX -1322 56/push-ESI -1323 57/push-EDI -1324 # ESI = word -1325 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -1326 # EDX = word->end -1327 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 4/disp8 . # copy *(ESI+4) to EDX -1328 # var twig/EDI : (address slice) = {0, 0} -1329 68/push 0/imm32/end -1330 68/push 0/imm32/start -1331 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI -1332 # next-token-from-slice(word->start, word->end, '/', twig) -1333 # . . push args -1334 57/push-EDI -1335 68/push 0x2f/imm32/slash -1336 52/push-EDX -1337 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI -1338 # . . call -1339 e8/call next-token-from-slice/disp32 -1340 # . . discard args -1341 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -1342 # curr/ECX = twig->end -1343 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX -1344 $has-metadata?:loop: -1345 # next-token-from-slice(curr, word->end, '/', twig) -1346 # . . push args -1347 57/push-EDI -1348 68/push 0x2f/imm32/slash -1349 52/push-EDX -1350 51/push-ECX -1351 # . . call -1352 e8/call next-token-from-slice/disp32 -1353 # . . discard args -1354 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -1355 # if (slice-empty?(twig)) return false -1356 # . EAX = slice-empty?(twig) -1357 # . . push args -1358 57/push-EDI -1359 # . . call -1360 e8/call slice-empty?/disp32 -1361 # . . discard args -1362 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1363 # . if (EAX != 0) return false -1364 3d/compare-EAX-and 0/imm32 -1365 75/jump-if-not-equal $has-metadata?:false/disp8 -1366 # if (slice-equal?(twig, s)) return true -1367 # . EAX = slice-equal?(twig, s) -1368 # . . push args -1369 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -1370 57/push-EDI -1371 # . . call -1372 e8/call slice-equal?/disp32 -1373 # . . discard args -1374 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1375 # . if (EAX != 0) return true -1376 3d/compare-EAX-and 0/imm32 -1377 75/jump-if-not-equal $has-metadata?:true/disp8 -1378 # curr = twig->end -1379 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX -1380 eb/jump $has-metadata?:loop/disp8 -1381 $has-metadata?:true: -1382 b8/copy-to-EAX 1/imm32/true -1383 eb/jump $has-metadata?:end/disp8 -1384 $has-metadata?:false: -1385 b8/copy-to-EAX 0/imm32/false -1386 $has-metadata?:end: -1387 # . reclaim locals -1388 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1389 # . restore registers -1390 5f/pop-to-EDI -1391 5e/pop-to-ESI -1392 5a/pop-to-EDX -1393 59/pop-to-ECX +1291 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1292 # . epilog +1293 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1294 5d/pop-to-EBP +1295 c3/return +1296 +1297 test-is-valid-name-starts-with-pre-digit: +1298 # . prolog +1299 55/push-EBP +1300 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1301 # (EAX..ECX) = "/03" +1302 b8/copy-to-EAX "/03"/imm32 +1303 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1304 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1305 05/add-to-EAX 4/imm32 +1306 # var slice/ECX = {EAX, ECX} +1307 51/push-ECX +1308 50/push-EAX +1309 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1310 # EAX = is-valid-name?(slice) +1311 # . . push args +1312 51/push-ECX +1313 # . . call +1314 e8/call is-valid-name?/disp32 +1315 # . . discard args +1316 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1317 # check-ints-equal(EAX, 1, msg) +1318 # . . push args +1319 68/push "F - test-is-valid-name-starts-with-pre-digit"/imm32 +1320 68/push 1/imm32/true +1321 50/push-EAX +1322 # . . call +1323 e8/call check-ints-equal/disp32 +1324 # . . discard args +1325 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1326 # . epilog +1327 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1328 5d/pop-to-EBP +1329 c3/return +1330 +1331 test-is-valid-name-starts-with-post-digit: +1332 # . prolog +1333 55/push-EBP +1334 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1335 # (EAX..ECX) = "q34" +1336 b8/copy-to-EAX "q34"/imm32 +1337 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1338 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1339 05/add-to-EAX 4/imm32 +1340 # var slice/ECX = {EAX, ECX} +1341 51/push-ECX +1342 50/push-EAX +1343 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1344 # EAX = is-valid-name?(slice) +1345 # . . push args +1346 51/push-ECX +1347 # . . call +1348 e8/call is-valid-name?/disp32 +1349 # . . discard args +1350 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1351 # check-ints-equal(EAX, 1, msg) +1352 # . . push args +1353 68/push "F - test-is-valid-name-starts-with-post-digit"/imm32 +1354 68/push 1/imm32/true +1355 50/push-EAX +1356 # . . call +1357 e8/call check-ints-equal/disp32 +1358 # . . discard args +1359 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1360 # . epilog +1361 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1362 5d/pop-to-EBP +1363 c3/return +1364 +1365 test-is-valid-name-starts-with-digit: +1366 # . prolog +1367 55/push-EBP +1368 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1369 # (EAX..ECX) = "0x34" +1370 b8/copy-to-EAX "0x34"/imm32 +1371 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1372 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1373 05/add-to-EAX 4/imm32 +1374 # var slice/ECX = {EAX, ECX} +1375 51/push-ECX +1376 50/push-EAX +1377 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1378 # EAX = is-valid-name?(slice) +1379 # . . push args +1380 51/push-ECX +1381 # . . call +1382 e8/call is-valid-name?/disp32 +1383 # . . discard args +1384 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1385 # check-ints-equal(EAX, 0, msg) +1386 # . . push args +1387 68/push "F - test-is-valid-name-starts-with-digit"/imm32 +1388 68/push 0/imm32/false +1389 50/push-EAX +1390 # . . call +1391 e8/call check-ints-equal/disp32 +1392 # . . discard args +1393 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 1394 # . epilog 1395 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 1396 5d/pop-to-EBP 1397 c3/return 1398 -1399 test-has-metadata-true: -1400 # . prolog -1401 55/push-EBP -1402 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1403 # (EAX..ECX) = "ab/imm32" -1404 b8/copy-to-EAX "ab/imm32"/imm32 -1405 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1406 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1407 05/add-to-EAX 4/imm32 -1408 # var in/ESI : (address slice) = {EAX, ECX} -1409 51/push-ECX -1410 50/push-EAX -1411 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI -1412 # EAX = has-metadata?(ESI, "imm32") -1413 # . . push args -1414 68/push "imm32"/imm32 -1415 56/push-ESI -1416 # . . call -1417 e8/call has-metadata?/disp32 -1418 # . . discard args -1419 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1420 # check-ints-equal(EAX, 1, msg) -1421 # . . push args -1422 68/push "F - test-has-metadata-true"/imm32 -1423 68/push 1/imm32/true -1424 50/push-EAX -1425 # . . call -1426 e8/call check-ints-equal/disp32 -1427 # . . discard args -1428 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1429 # . epilog -1430 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1431 5d/pop-to-EBP -1432 c3/return -1433 -1434 test-has-metadata-false: -1435 # . prolog -1436 55/push-EBP -1437 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1438 # (EAX..ECX) = "ab/c" -1439 b8/copy-to-EAX "ab/c"/imm32 -1440 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1441 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1442 05/add-to-EAX 4/imm32 -1443 # var in/ESI : (address slice) = {EAX, ECX} -1444 51/push-ECX -1445 50/push-EAX -1446 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI -1447 # EAX = has-metadata?(ESI, "d") -1448 # . . push args -1449 68/push "d"/imm32 -1450 56/push-ESI -1451 # . . call -1452 e8/call has-metadata?/disp32 -1453 # . . discard args -1454 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1455 # check-ints-equal(EAX, 0, msg) -1456 # . . push args -1457 68/push "F - test-has-metadata-false"/imm32 -1458 68/push 0/imm32/false -1459 50/push-EAX -1460 # . . call -1461 e8/call check-ints-equal/disp32 -1462 # . . discard args -1463 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1464 # . epilog -1465 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1466 5d/pop-to-EBP -1467 c3/return -1468 -1469 test-has-metadata-ignore-name: -1470 # . prolog -1471 55/push-EBP -1472 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1473 # (EAX..ECX) = "a/b" -1474 b8/copy-to-EAX "a/b"/imm32 -1475 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1476 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1477 05/add-to-EAX 4/imm32 -1478 # var in/ESI : (address slice) = {EAX, ECX} -1479 51/push-ECX -1480 50/push-EAX -1481 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI -1482 # EAX = has-metadata?(ESI, "a") -1483 # . . push args -1484 68/push "a"/imm32 -1485 56/push-ESI +1399 # print 'n' in hex in 'width' bytes in lower-endian order, with a space after every byte +1400 emit-hex: # out : (address buffered-file), n : int, width : int -> <void> +1401 # . prolog +1402 55/push-EBP +1403 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1404 # . save registers +1405 50/push-EAX +1406 51/push-ECX +1407 52/push-EDX +1408 53/push-EBX +1409 57/push-EDI +1410 # EDI = out +1411 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI +1412 # EBX = n +1413 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX +1414 # EDX = width +1415 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX +1416 # var curr/ECX = 0 +1417 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX +1418 $emit-hex:loop: +1419 # if (curr >= width) break +1420 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX +1421 7d/jump-if-greater-or-equal $emit-hex:end/disp8 +1422 # print-byte-buffered(out, EBX) +1423 # . . push args +1424 53/push-EBX +1425 57/push-EDI +1426 # . . call +1427 e8/call print-byte-buffered/disp32 +1428 # . . discard args +1429 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1430 # write-byte-buffered(out, ' ') +1431 # . . push args +1432 68/push 0x20/imm32/space +1433 57/push-EDI +1434 # . . call +1435 e8/call write-byte-buffered/disp32 +1436 # . . discard args +1437 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1438 # EBX = EBX >> 8 +1439 c1/shift 5/subop/logic-right 3/mod/direct 3/rm32/EBX . . . . . 8/imm8 # shift EBX right by 8 bits, while padding zeroes +1440 $emit-hex:continue: +1441 # ++curr +1442 41/increment-ECX +1443 eb/jump $emit-hex:loop/disp8 +1444 $emit-hex:end: +1445 # . restore registers +1446 5f/pop-to-EDI +1447 5b/pop-to-EBX +1448 5a/pop-to-EDX +1449 59/pop-to-ECX +1450 58/pop-to-EAX +1451 # . epilog +1452 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1453 5d/pop-to-EBP +1454 c3/return +1455 +1456 test-emit-hex-single-byte: +1457 # setup +1458 # . clear-stream(_test-output-stream) +1459 # . . push args +1460 68/push _test-output-stream/imm32 +1461 # . . call +1462 e8/call clear-stream/disp32 +1463 # . . discard args +1464 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1465 # . clear-stream(_test-output-buffered-file+4) +1466 # . . push args +1467 b8/copy-to-EAX _test-output-buffered-file/imm32 +1468 05/add-to-EAX 4/imm32 +1469 50/push-EAX +1470 # . . call +1471 e8/call clear-stream/disp32 +1472 # . . discard args +1473 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1474 # emit-hex(_test-output-buffered-file, 0xab, 1) +1475 # . . push args +1476 68/push 1/imm32 +1477 68/push 0xab/imm32 +1478 68/push _test-output-buffered-file/imm32 +1479 # . . call +1480 e8/call emit-hex/disp32 +1481 # . . discard args +1482 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1483 # flush(_test-output-buffered-file) +1484 # . . push args +1485 68/push _test-output-buffered-file/imm32 1486 # . . call -1487 e8/call has-metadata?/disp32 +1487 e8/call flush/disp32 1488 # . . discard args -1489 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1490 # check-ints-equal(EAX, 0, msg) +1489 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1490 # check-ints-equal(*_test-output-stream->data, 'ab ', msg) 1491 # . . push args -1492 68/push "F - test-has-metadata-ignore-name"/imm32 -1493 68/push 0/imm32/false -1494 50/push-EAX -1495 # . . call -1496 e8/call check-ints-equal/disp32 -1497 # . . discard args -1498 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1499 # . epilog -1500 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1501 5d/pop-to-EBP +1492 68/push "F - test-emit-hex-single-byte"/imm32 +1493 68/push 0x206261/imm32 +1494 # . . push *_test-output-stream->data +1495 b8/copy-to-EAX _test-output-stream/imm32 +1496 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) +1497 # . . call +1498 e8/call check-ints-equal/disp32 +1499 # . . discard args +1500 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1501 # . end 1502 c3/return 1503 -1504 test-has-metadata-multiple-true: -1505 # . prolog -1506 55/push-EBP -1507 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1508 # (EAX..ECX) = "a/b/c" -1509 b8/copy-to-EAX "a/b/c"/imm32 -1510 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1511 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1512 05/add-to-EAX 4/imm32 -1513 # var in/ESI : (address slice) = {EAX, ECX} -1514 51/push-ECX -1515 50/push-EAX -1516 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI -1517 # EAX = has-metadata?(ESI, "c") -1518 # . . push args -1519 68/push "c"/imm32 -1520 56/push-ESI -1521 # . . call -1522 e8/call has-metadata?/disp32 -1523 # . . discard args -1524 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1525 # check-ints-equal(EAX, 1, msg) -1526 # . . push args -1527 68/push "F - test-has-metadata-multiple-true"/imm32 -1528 68/push 1/imm32/true -1529 50/push-EAX -1530 # . . call -1531 e8/call check-ints-equal/disp32 -1532 # . . discard args -1533 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1534 # . epilog -1535 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1536 5d/pop-to-EBP -1537 c3/return -1538 -1539 test-has-metadata-multiple-false: -1540 # . prolog -1541 55/push-EBP -1542 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1543 # (EAX..ECX) = "a/b/c" -1544 b8/copy-to-EAX "a/b/c"/imm32 -1545 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1546 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1547 05/add-to-EAX 4/imm32 -1548 # var in/ESI : (address slice) = {EAX, ECX} -1549 51/push-ECX -1550 50/push-EAX -1551 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI -1552 # EAX = has-metadata?(ESI, "d") +1504 test-emit-hex-multiple-byte: +1505 # setup +1506 # . clear-stream(_test-output-stream) +1507 # . . push args +1508 68/push _test-output-stream/imm32 +1509 # . . call +1510 e8/call clear-stream/disp32 +1511 # . . discard args +1512 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1513 # . clear-stream(_test-output-buffered-file+4) +1514 # . . push args +1515 b8/copy-to-EAX _test-output-buffered-file/imm32 +1516 05/add-to-EAX 4/imm32 +1517 50/push-EAX +1518 # . . call +1519 e8/call clear-stream/disp32 +1520 # . . discard args +1521 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1522 # emit-hex(_test-output-buffered-file, 0x1234, 2) +1523 # . . push args +1524 68/push 2/imm32 +1525 68/push 0x1234/imm32 +1526 68/push _test-output-buffered-file/imm32 +1527 # . . call +1528 e8/call emit-hex/disp32 +1529 # . . discard args +1530 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1531 # flush(_test-output-buffered-file) +1532 # . . push args +1533 68/push _test-output-buffered-file/imm32 +1534 # . . call +1535 e8/call flush/disp32 +1536 # . . discard args +1537 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1538 # check-stream-equal(_test-output-stream, "34 12 ", msg) +1539 # . . push args +1540 68/push "F - test-emit-hex-multiple-byte/1"/imm32 +1541 68/push "34 12 "/imm32 +1542 68/push _test-output-stream/imm32 +1543 # . . call +1544 e8/call check-stream-equal/disp32 +1545 # . . discard args +1546 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1547 # . end +1548 c3/return +1549 +1550 test-emit-hex-zero-pad: +1551 # setup +1552 # . clear-stream(_test-output-stream) 1553 # . . push args -1554 68/push "d"/imm32 -1555 56/push-ESI -1556 # . . call -1557 e8/call has-metadata?/disp32 -1558 # . . discard args -1559 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1560 # check-ints-equal(EAX, 0, msg) -1561 # . . push args -1562 68/push "F - test-has-metadata-multiple-false"/imm32 -1563 68/push 0/imm32/false -1564 50/push-EAX -1565 # . . call -1566 e8/call check-ints-equal/disp32 -1567 # . . discard args -1568 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1569 # . epilog -1570 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1571 5d/pop-to-EBP -1572 c3/return -1573 -1574 # If datum of 'word' is not a valid name, it must be a hex int. Parse and print -1575 # it in 'width' bytes of hex, least significant first. -1576 # Otherwise just print the entire word including metadata. -1577 # Always print a trailing space. -1578 emit: # out : (address buffered-file), word : (address slice), width : int -> <void> -1579 # . prolog -1580 55/push-EBP -1581 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1582 # . save registers -1583 50/push-EAX -1584 56/push-ESI -1585 57/push-EDI -1586 # ESI = word -1587 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI -1588 # var name/EDI : (address slice) = {0, 0} -1589 68/push 0/imm32/end -1590 68/push 0/imm32/start -1591 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI -1592 # datum = next-token-from-slice(word->start, word->end, '/') -1593 # . . push args -1594 57/push-EDI -1595 68/push 0x2f/imm32/slash -1596 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) -1597 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI -1598 # . . call -1599 e8/call next-token-from-slice/disp32 -1600 # . . discard args -1601 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -1602 # if (is-valid-name?(datum)) write-slice-buffered(out, word) and return -1603 # . EAX = is-valid-name?(name) -1604 # . . push args -1605 57/push-EDI -1606 # . . call -1607 e8/call is-valid-name?/disp32 -1608 # . . discard args -1609 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1610 # . if (EAX != 0) -1611 3d/compare-EAX-and 0/imm32 -1612 74/jump-if-equal $emit:hex-int/disp8 -1613 $emit:name: -1614 # . write-slice-buffered(out, word) +1554 68/push _test-output-stream/imm32 +1555 # . . call +1556 e8/call clear-stream/disp32 +1557 # . . discard args +1558 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1559 # . clear-stream(_test-output-buffered-file+4) +1560 # . . push args +1561 b8/copy-to-EAX _test-output-buffered-file/imm32 +1562 05/add-to-EAX 4/imm32 +1563 50/push-EAX +1564 # . . call +1565 e8/call clear-stream/disp32 +1566 # . . discard args +1567 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1568 # emit-hex(_test-output-buffered-file, 0xab, 2) +1569 # . . push args +1570 68/push 2/imm32 +1571 68/push 0xab/imm32 +1572 68/push _test-output-buffered-file/imm32 +1573 # . . call +1574 e8/call emit-hex/disp32 +1575 # . . discard args +1576 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1577 # flush(_test-output-buffered-file) +1578 # . . push args +1579 68/push _test-output-buffered-file/imm32 +1580 # . . call +1581 e8/call flush/disp32 +1582 # . . discard args +1583 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1584 # check(_test-output-stream->data == 'ab 00 ') +1585 # . . push args +1586 68/push "F - test-emit-hex-zero-pad/1"/imm32 +1587 68/push "ab 00 "/imm32 +1588 68/push _test-output-stream/imm32 +1589 # . . call +1590 e8/call check-stream-equal/disp32 +1591 # . . discard args +1592 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1593 # . end +1594 c3/return +1595 +1596 test-emit-hex-negative: +1597 # setup +1598 # . clear-stream(_test-output-stream) +1599 # . . push args +1600 68/push _test-output-stream/imm32 +1601 # . . call +1602 e8/call clear-stream/disp32 +1603 # . . discard args +1604 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1605 # . clear-stream(_test-output-buffered-file+4) +1606 # . . push args +1607 b8/copy-to-EAX _test-output-buffered-file/imm32 +1608 05/add-to-EAX 4/imm32 +1609 50/push-EAX +1610 # . . call +1611 e8/call clear-stream/disp32 +1612 # . . discard args +1613 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1614 # emit-hex(_test-output-buffered-file, -1, 2) 1615 # . . push args -1616 56/push-ESI -1617 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1618 # . . call -1619 e8/call write-slice-buffered/disp32 -1620 # . . discard args -1621 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1622 # . write-buffered(out, " ") -1623 # . . push args -1624 68/push " "/imm32 -1625 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1616 68/push 2/imm32 +1617 68/push -1/imm32 +1618 68/push _test-output-buffered-file/imm32 +1619 # . . call +1620 e8/call emit-hex/disp32 +1621 # . . discard args +1622 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1623 # flush(_test-output-buffered-file) +1624 # . . push args +1625 68/push _test-output-buffered-file/imm32 1626 # . . call -1627 e8/call write-buffered/disp32 +1627 e8/call flush/disp32 1628 # . . discard args -1629 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1630 # . return -1631 eb/jump $emit:end/disp8 -1632 # otherwise emit-hex(out, parse-hex-int(datum), width) -1633 # (Weird shit can happen here if the datum of 'word' isn't either a valid -1634 # name or a hex number, but we're only going to be passing in real legal -1635 # programs. We just want to make sure that valid names aren't treated as -1636 # (valid) hex numbers.) -1637 $emit:hex-int: -1638 # . value/EAX = parse-hex-int(datum) -1639 # . . push args -1640 57/push-EDI -1641 # . . call -1642 e8/call parse-hex-int/disp32 -1643 # . . discard args -1644 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1645 # . emit-hex(out, value, width) -1646 # . . push args -1647 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +1629 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1630 # check-stream-equal(_test-output-stream == "ff ff ") +1631 # . . push args +1632 68/push "F - test-emit-hex-negative/1"/imm32 +1633 68/push "ff ff "/imm32 +1634 68/push _test-output-stream/imm32 +1635 # . . call +1636 e8/call check-stream-equal/disp32 +1637 # . . discard args +1638 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1639 # . end +1640 c3/return +1641 +1642 # print 'arr' in hex with a space after every byte +1643 emit-hex-array: # out : (address buffered-file), arr : (address array byte) -> <void> +1644 # . prolog +1645 55/push-EBP +1646 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1647 # . save registers 1648 50/push-EAX -1649 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1650 # . . call -1651 e8/call emit-hex/disp32 -1652 # . . discard args -1653 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1654 $emit:end: -1655 # . reclaim locals -1656 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1657 # . restore registers -1658 5f/pop-to-EDI -1659 5e/pop-to-ESI -1660 58/pop-to-EAX -1661 # . epilog -1662 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1663 5d/pop-to-EBP -1664 c3/return -1665 -1666 test-emit-number: -1667 # . prolog -1668 55/push-EBP -1669 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1670 # setup -1671 # . clear-stream(_test-output-stream) -1672 # . . push args -1673 68/push _test-output-stream/imm32 -1674 # . . call -1675 e8/call clear-stream/disp32 -1676 # . . discard args -1677 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1678 # . clear-stream(_test-output-buffered-file+4) -1679 # . . push args -1680 b8/copy-to-EAX _test-output-buffered-file/imm32 -1681 05/add-to-EAX 4/imm32 -1682 50/push-EAX -1683 # . . call -1684 e8/call clear-stream/disp32 -1685 # . . discard args -1686 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1687 # (EAX..ECX) = "30" -1688 b8/copy-to-EAX "30"/imm32 -1689 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1690 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1691 05/add-to-EAX 4/imm32 -1692 # var slice/ECX = {EAX, ECX} -1693 51/push-ECX -1694 50/push-EAX -1695 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1696 # emit(_test-output-buffered-file, slice, 1) +1649 51/push-ECX +1650 52/push-EDX +1651 57/push-EDI +1652 # EDI = out +1653 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI +1654 # EDX = arr # <== 0xbdffffe4 +1655 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX +1656 # curr/ECX = arr->data +1657 8d/copy-address 1/mod/*+disp8 2/rm32/EDX . . . 1/r32/ECX 4/disp8 . # copy EDX+4 to ECX +1658 # max/EDX = arr->data + arr->length +1659 8b/copy 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX +1660 01/add 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # add ECX to EDX +1661 # EAX = 0 +1662 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +1663 $emit-hex-array:loop: +1664 # if (curr >= width) break +1665 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX +1666 73/jump-if-greater-or-equal-unsigned $emit-hex-array:end/disp8 +1667 # emit-hex(out, *curr, width=1) +1668 # . . push args +1669 68/push 1/imm32/width +1670 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL +1671 50/push-EAX +1672 57/push-EDI +1673 # . . call +1674 e8/call emit-hex/disp32 +1675 # . . discard args +1676 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1677 # ++curr +1678 41/increment-ECX +1679 eb/jump $emit-hex-array:loop/disp8 +1680 $emit-hex-array:end: +1681 # . restore registers +1682 5f/pop-to-EDI +1683 5a/pop-to-EDX +1684 59/pop-to-ECX +1685 58/pop-to-EAX +1686 # . epilog +1687 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1688 5d/pop-to-EBP +1689 c3/return +1690 +1691 test-emit-hex-array: +1692 # . prolog +1693 55/push-EBP +1694 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1695 # setup +1696 # . clear-stream(_test-output-stream) 1697 # . . push args -1698 68/push 1/imm32 -1699 51/push-ECX -1700 68/push _test-output-buffered-file/imm32 -1701 # . . call -1702 e8/call emit/disp32 -1703 # . . discard args -1704 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1705 # flush(_test-output-buffered-file) -1706 # . . push args -1707 68/push _test-output-buffered-file/imm32 +1698 68/push _test-output-stream/imm32 +1699 # . . call +1700 e8/call clear-stream/disp32 +1701 # . . discard args +1702 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1703 # . clear-stream(_test-output-buffered-file+4) +1704 # . . push args +1705 b8/copy-to-EAX _test-output-buffered-file/imm32 +1706 05/add-to-EAX 4/imm32 +1707 50/push-EAX 1708 # . . call -1709 e8/call flush/disp32 +1709 e8/call clear-stream/disp32 1710 # . . discard args 1711 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1712 # check-stream-equal(_test-output-stream, "30 ", msg) -1713 # . . push args -1714 68/push "F - test-emit-number/1"/imm32 -1715 68/push "30 "/imm32 -1716 68/push _test-output-stream/imm32 -1717 # . . call -1718 e8/call check-stream-equal/disp32 -1719 # . . discard args -1720 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1721 # . epilog -1722 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1723 5d/pop-to-EBP -1724 c3/return -1725 -1726 test-emit-negative-number: -1727 # test support for sign-extending negative numbers -1728 # . prolog -1729 55/push-EBP -1730 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1731 # setup -1732 # . clear-stream(_test-output-stream) -1733 # . . push args -1734 68/push _test-output-stream/imm32 -1735 # . . call -1736 e8/call clear-stream/disp32 -1737 # . . discard args -1738 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1739 # . clear-stream(_test-output-buffered-file+4) -1740 # . . push args -1741 b8/copy-to-EAX _test-output-buffered-file/imm32 -1742 05/add-to-EAX 4/imm32 -1743 50/push-EAX -1744 # . . call -1745 e8/call clear-stream/disp32 -1746 # . . discard args -1747 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1748 # (EAX..ECX) = "-2" -1749 b8/copy-to-EAX "-2"/imm32 -1750 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1751 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1752 05/add-to-EAX 4/imm32 -1753 # var slice/ECX = {EAX, ECX} -1754 51/push-ECX -1755 50/push-EAX -1756 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1757 # emit(_test-output-buffered-file, slice, 2) -1758 # . . push args -1759 68/push 2/imm32 -1760 51/push-ECX -1761 68/push _test-output-buffered-file/imm32 -1762 # . . call -1763 e8/call emit/disp32 -1764 # . . discard args -1765 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1766 # flush(_test-output-buffered-file) -1767 # . . push args -1768 68/push _test-output-buffered-file/imm32 +1712 # var arr/ECX (address array byte) = [01, 02, 03] +1713 68/push 0x00030201/imm32 # bytes 01 02 03 +1714 68/push 3/imm32/length +1715 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1716 # emit-hex-array(_test-output-buffered-file, arr) +1717 # . . push args +1718 51/push-ECX +1719 68/push _test-output-buffered-file/imm32 +1720 # . . call +1721 e8/call emit-hex-array/disp32 +1722 # . . discard args +1723 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1724 # . flush(_test-output-buffered-file) +1725 # . . push args +1726 68/push _test-output-buffered-file/imm32 +1727 # . . call +1728 e8/call flush/disp32 +1729 # . . discard args +1730 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1731 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +1764 # check-next-stream-line-equal(_test-output-stream, "01 02 03 ", msg) +1765 # . . push args +1766 68/push "F - test-emit-hex-array"/imm32 +1767 68/push "01 02 03 "/imm32 +1768 68/push _test-output-stream/imm32 1769 # . . call -1770 e8/call flush/disp32 +1770 e8/call check-next-stream-line-equal/disp32 1771 # . . discard args -1772 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1773 # check-stream-equal(_test-output-stream, "fe ff ", msg) -1774 # . . push args -1775 68/push "F - test-emit-number/1"/imm32 -1776 68/push "fe ff "/imm32 -1777 68/push _test-output-stream/imm32 -1778 # . . call -1779 e8/call check-stream-equal/disp32 -1780 # . . discard args -1781 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1782 # . epilog -1783 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1784 5d/pop-to-EBP -1785 c3/return -1786 -1787 test-emit-number-with-metadata: -1788 # . prolog -1789 55/push-EBP -1790 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1791 # setup -1792 # . clear-stream(_test-output-stream) -1793 # . . push args -1794 68/push _test-output-stream/imm32 -1795 # . . call -1796 e8/call clear-stream/disp32 -1797 # . . discard args -1798 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1799 # . clear-stream(_test-output-buffered-file+4) -1800 # . . push args -1801 b8/copy-to-EAX _test-output-buffered-file/imm32 -1802 05/add-to-EAX 4/imm32 -1803 50/push-EAX -1804 # . . call -1805 e8/call clear-stream/disp32 -1806 # . . discard args -1807 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1808 # (EAX..ECX) = "-2/foo" -1809 b8/copy-to-EAX "-2/foo"/imm32 -1810 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1811 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1812 05/add-to-EAX 4/imm32 -1813 # var slice/ECX = {EAX, ECX} -1814 51/push-ECX -1815 50/push-EAX -1816 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1817 # emit(_test-output-buffered-file, slice, 2) -1818 # . . push args -1819 68/push 2/imm32 -1820 51/push-ECX -1821 68/push _test-output-buffered-file/imm32 -1822 # . . call -1823 e8/call emit/disp32 -1824 # . . discard args -1825 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1826 # flush(_test-output-buffered-file) -1827 # . . push args -1828 68/push _test-output-buffered-file/imm32 -1829 # . . call -1830 e8/call flush/disp32 -1831 # . . discard args -1832 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1833 # the '/foo' will have no impact on the output -1834 # check-stream-equal(_test-output-stream, "fe ff ", msg) +1772 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1773 # . epilog +1774 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1775 5d/pop-to-EBP +1776 c3/return +1777 +1778 compute-width: # word : (address array byte) -> EAX : int +1779 # . prolog +1780 55/push-EBP +1781 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1782 # . save registers +1783 51/push-ECX +1784 # EAX = word +1785 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to ECX +1786 # ECX = word + word->length +1787 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +1788 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +1789 # EAX = word->data +1790 05/add-to-EAX 4/imm32 +1791 # var in/ECX : (address slice) = {EAX, ECX} +1792 51/push-ECX +1793 50/push-EAX +1794 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1795 # return compute-width-of-slice(ECX) +1796 # . . push args +1797 51/push-ECX +1798 # . . call +1799 e8/call compute-width-of-slice/disp32 +1800 # . . discard args +1801 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1802 $compute-width:end: +1803 # . reclaim locals +1804 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1805 # . restore registers +1806 59/pop-to-ECX +1807 # . epilog +1808 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1809 5d/pop-to-EBP +1810 c3/return +1811 +1812 compute-width-of-slice: # s : (address slice) -> EAX : int +1813 # . prolog +1814 55/push-EBP +1815 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1816 # . save registers +1817 51/push-ECX +1818 # ECX = s +1819 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX +1820 # if (has-metadata?(word, "imm32")) return 4 +1821 # . EAX = has-metadata?(word, "imm32") +1822 # . . push args +1823 68/push "imm32"/imm32 +1824 51/push-ECX +1825 # . . call +1826 e8/call has-metadata?/disp32 +1827 # . . discard args +1828 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1829 # . if (EAX != 0) return 4 +1830 3d/compare-EAX-and 0/imm32 +1831 b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now +1832 75/jump-if-not-equal $compute-width-of-slice:end/disp8 +1833 # if (has-metadata?(word, "disp32")) return 4 +1834 # . EAX = has-metadata?(word, "disp32") 1835 # . . push args -1836 68/push "F - test-emit-number-with-metadata"/imm32 -1837 68/push "fe ff "/imm32 -1838 68/push _test-output-stream/imm32 -1839 # . . call -1840 e8/call check-stream-equal/disp32 -1841 # . . discard args -1842 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1843 # . epilog -1844 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1845 5d/pop-to-EBP -1846 c3/return -1847 -1848 test-emit-non-number: -1849 # . prolog -1850 55/push-EBP -1851 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1852 # setup -1853 # . clear-stream(_test-output-stream) -1854 # . . push args -1855 68/push _test-output-stream/imm32 -1856 # . . call -1857 e8/call clear-stream/disp32 -1858 # . . discard args -1859 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1860 # . clear-stream(_test-output-buffered-file+4) +1836 68/push "disp32"/imm32 +1837 51/push-ECX +1838 # . . call +1839 e8/call has-metadata?/disp32 +1840 # . . discard args +1841 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1842 # . if (EAX != 0) return 4 +1843 3d/compare-EAX-and 0/imm32 +1844 b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now +1845 75/jump-if-not-equal $compute-width-of-slice:end/disp8 +1846 # if (has-metadata?(word, "imm16")) return 2 +1847 # . EAX = has-metadata?(word, "imm16") +1848 # . . push args +1849 68/push "imm16"/imm32 +1850 51/push-ECX +1851 # . . call +1852 e8/call has-metadata?/disp32 +1853 # . . discard args +1854 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1855 # . if (EAX != 0) return 2 +1856 3d/compare-EAX-and 0/imm32 +1857 b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now +1858 75/jump-if-not-equal $compute-width-of-slice:end/disp8 +1859 # if (has-metadata?(word, "disp16")) return 2 +1860 # . EAX = has-metadata?(word, "disp16") 1861 # . . push args -1862 b8/copy-to-EAX _test-output-buffered-file/imm32 -1863 05/add-to-EAX 4/imm32 -1864 50/push-EAX -1865 # . . call -1866 e8/call clear-stream/disp32 -1867 # . . discard args -1868 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1869 # (EAX..ECX) = "xyz" -1870 b8/copy-to-EAX "xyz"/imm32 -1871 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1872 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1873 05/add-to-EAX 4/imm32 -1874 # var slice/ECX = {EAX, ECX} -1875 51/push-ECX -1876 50/push-EAX -1877 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1878 # emit(_test-output-buffered-file, slice, 2) -1879 # . . push args -1880 68/push 2/imm32 -1881 51/push-ECX -1882 68/push _test-output-buffered-file/imm32 -1883 # . . call -1884 e8/call emit/disp32 -1885 # . . discard args -1886 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1887 # flush(_test-output-buffered-file) +1862 68/push "disp16"/imm32 +1863 51/push-ECX +1864 # . . call +1865 e8/call has-metadata?/disp32 +1866 # . . discard args +1867 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1868 # . if (EAX != 0) return 2 +1869 3d/compare-EAX-and 0/imm32 +1870 b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now +1871 75/jump-if-not-equal $compute-width-of-slice:end/disp8 +1872 # otherwise return 1 +1873 b8/copy-to-EAX 1/imm32 +1874 $compute-width-of-slice:end: +1875 # . restore registers +1876 59/pop-to-ECX +1877 # . epilog +1878 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1879 5d/pop-to-EBP +1880 c3/return +1881 +1882 test-compute-width: +1883 # . prolog +1884 55/push-EBP +1885 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1886 $test-compute-width:imm8: +1887 # EAX = compute-width("0x2/imm8") 1888 # . . push args -1889 68/push _test-output-buffered-file/imm32 +1889 68/push "0x2/imm8"/imm32 1890 # . . call -1891 e8/call flush/disp32 +1891 e8/call compute-width/disp32 1892 # . . discard args 1893 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1894 # check-stream-equal(_test-output-stream, "xyz", msg) +1894 # check-ints-equal(EAX, 1, msg) 1895 # . . push args -1896 68/push "F - test-emit-non-number"/imm32 -1897 68/push "xyz "/imm32 -1898 68/push _test-output-stream/imm32 +1896 68/push "F - test-compute-width: 0x2/imm8"/imm32 +1897 50/push-EAX +1898 68/push 1/imm32 1899 # . . call -1900 e8/call check-stream-equal/disp32 +1900 e8/call check-ints-equal/disp32 1901 # . . discard args 1902 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1903 # . epilog -1904 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1905 5d/pop-to-EBP -1906 c3/return -1907 -1908 test-emit-non-number-with-metadata: -1909 # . prolog -1910 55/push-EBP -1911 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1912 # setup -1913 # . clear-stream(_test-output-stream) -1914 # . . push args -1915 68/push _test-output-stream/imm32 +1903 $test-compute-width:imm16: +1904 # EAX = compute-width("4/imm16") +1905 # . . push args +1906 68/push "4/imm16"/imm32 +1907 # . . call +1908 e8/call compute-width/disp32 +1909 # . . discard args +1910 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1911 # check-ints-equal(EAX, 2, msg) +1912 # . . push args +1913 68/push "F - test-compute-width: 4/imm16"/imm32 +1914 50/push-EAX +1915 68/push 2/imm32 1916 # . . call -1917 e8/call clear-stream/disp32 +1917 e8/call check-ints-equal/disp32 1918 # . . discard args -1919 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1920 # . clear-stream(_test-output-buffered-file+4) -1921 # . . push args -1922 b8/copy-to-EAX _test-output-buffered-file/imm32 -1923 05/add-to-EAX 4/imm32 -1924 50/push-EAX -1925 # . . call -1926 e8/call clear-stream/disp32 -1927 # . . discard args -1928 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1929 # (EAX..ECX) = "xyz/" -1930 b8/copy-to-EAX "xyz/"/imm32 -1931 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1932 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1933 05/add-to-EAX 4/imm32 -1934 # var slice/ECX = {EAX, ECX} -1935 51/push-ECX -1936 50/push-EAX -1937 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1938 # emit(_test-output-buffered-file, slice, 2) +1919 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1920 $test-compute-width:imm32: +1921 # EAX = compute-width("4/imm32") +1922 # . . push args +1923 68/push "4/imm32"/imm32 +1924 # . . call +1925 e8/call compute-width/disp32 +1926 # . . discard args +1927 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1928 # check-ints-equal(EAX, 4, msg) +1929 # . . push args +1930 68/push "F - test-compute-width: 4/imm32"/imm32 +1931 50/push-EAX +1932 68/push 4/imm32 +1933 # . . call +1934 e8/call check-ints-equal/disp32 +1935 # . . discard args +1936 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1937 $test-compute-width:disp8: +1938 # EAX = compute-width("foo/disp8") 1939 # . . push args -1940 68/push 2/imm32 -1941 51/push-ECX -1942 68/push _test-output-buffered-file/imm32 -1943 # . . call -1944 e8/call emit/disp32 -1945 # . . discard args -1946 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1947 # flush(_test-output-buffered-file) -1948 # . . push args -1949 68/push _test-output-buffered-file/imm32 +1940 68/push "foo/disp8"/imm32 +1941 # . . call +1942 e8/call compute-width/disp32 +1943 # . . discard args +1944 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1945 # check-ints-equal(EAX, 1, msg) +1946 # . . push args +1947 68/push "F - test-compute-width: foo/disp8"/imm32 +1948 50/push-EAX +1949 68/push 1/imm32 1950 # . . call -1951 e8/call flush/disp32 +1951 e8/call check-ints-equal/disp32 1952 # . . discard args -1953 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1954 # check-stream-equal(_test-output-stream, "xyz/", msg) -1955 # . . push args -1956 68/push "F - test-emit-non-number-with-metadata"/imm32 -1957 68/push "xyz/ "/imm32 -1958 68/push _test-output-stream/imm32 -1959 # . . call -1960 e8/call check-stream-equal/disp32 -1961 # . . discard args -1962 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1963 # . epilog -1964 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1965 5d/pop-to-EBP -1966 c3/return -1967 -1968 test-emit-non-number-with-all-hex-digits-and-metadata: -1969 # . prolog -1970 55/push-EBP -1971 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1972 # setup -1973 # . clear-stream(_test-output-stream) -1974 # . . push args -1975 68/push _test-output-stream/imm32 -1976 # . . call -1977 e8/call clear-stream/disp32 -1978 # . . discard args -1979 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1980 # . clear-stream(_test-output-buffered-file+4) -1981 # . . push args -1982 b8/copy-to-EAX _test-output-buffered-file/imm32 -1983 05/add-to-EAX 4/imm32 -1984 50/push-EAX -1985 # . . call -1986 e8/call clear-stream/disp32 -1987 # . . discard args -1988 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1989 # (EAX..ECX) = "abcd/xyz" -1990 b8/copy-to-EAX "abcd/xyz"/imm32 -1991 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -1992 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -1993 05/add-to-EAX 4/imm32 -1994 # var slice/ECX = {EAX, ECX} -1995 51/push-ECX -1996 50/push-EAX -1997 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1998 # emit(_test-output-buffered-file, slice, 2) -1999 # . . push args -2000 68/push 2/imm32 -2001 51/push-ECX -2002 68/push _test-output-buffered-file/imm32 -2003 # . . call -2004 e8/call emit/disp32 -2005 # . . discard args -2006 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2007 # flush(_test-output-buffered-file) -2008 # . . push args -2009 68/push _test-output-buffered-file/imm32 -2010 # . . call -2011 e8/call flush/disp32 -2012 # . . discard args -2013 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2014 +-- 26 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -2040 # check-stream-equal(_test-output-stream, "abcd/xyz") -2041 # . . push args -2042 68/push "F - test-emit-non-number-with-all-hex-digits"/imm32 -2043 68/push "abcd/xyz "/imm32 -2044 68/push _test-output-stream/imm32 -2045 # . . call -2046 e8/call check-stream-equal/disp32 -2047 # . . discard args -2048 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2049 # . epilog -2050 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2051 5d/pop-to-EBP -2052 c3/return -2053 -2054 # conditions for 'valid' names that are not at risk of looking like hex numbers -2055 # keep in sync with the rules in labels.cc -2056 #: - if it starts with a digit, it's treated as a number. If it can't be -2057 #: parsed as hex it will raise an error. -2058 #: - if it starts with '-' it's treated as a number. -2059 #: - if it starts with '0x' it's treated as a number. (redundant) -2060 #: - if it's two characters long, it can't be a name. Either it's a hex -2061 #: byte, or it raises an error. -2062 is-valid-name?: # in : (address slice) -> EAX : boolean -2063 # . prolog -2064 55/push-EBP -2065 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2066 # . save registers -2067 51/push-ECX -2068 56/push-ESI -2069 # ESI = in -2070 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -2071 # start/ECX = in->start -2072 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX -2073 # end/EAX = in->end -2074 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX -2075 $is-valid-name?:check0: -2076 # if (start >= end) return false -2077 39/compare 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # compare ECX with EAX -2078 73/jump-if-greater-or-equal-unsigned $is-valid-name?:false/disp8 -2079 $is-valid-name?:check1: -2080 # EAX -= ECX -2081 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX -2082 # if (EAX == 2) return false -2083 3d/compare-EAX-and 2/imm32 -2084 74/jump-if-equal $is-valid-name?:false/disp8 -2085 $is-valid-name?:check2: -2086 # c/EAX = *ECX -2087 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -2088 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL -2089 # if (c == "-") return false -2090 3d/compare-EAX-and 2d/imm32/- -2091 74/jump-if-equal $is-valid-name?:false/disp8 -2092 $is-valid-name?:check3a: -2093 # if (c < "0") return true -2094 3d/compare-EAX-with 30/imm32/0 -2095 7c/jump-if-lesser $is-valid-name?:true/disp8 -2096 $is-valid-name?:check3b: -2097 # if (c > "9") return true -2098 3d/compare-EAX-with 39/imm32/9 -2099 7f/jump-if-greater $is-valid-name?:true/disp8 -2100 $is-valid-name?:false: -2101 # return false -2102 b8/copy-to-EAX 0/imm32/false -2103 eb/jump $is-valid-name?:end/disp8 -2104 $is-valid-name?:true: -2105 # return true -2106 b8/copy-to-EAX 1/imm32/true -2107 $is-valid-name?:end: -2108 # . restore registers -2109 5e/pop-to-ESI -2110 59/pop-to-ECX -2111 # . epilog -2112 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2113 5d/pop-to-EBP -2114 c3/return -2115 -2116 test-is-valid-name-digit-prefix: -2117 # . prolog -2118 55/push-EBP -2119 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2120 # (EAX..ECX) = "34" -2121 b8/copy-to-EAX "34"/imm32 -2122 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2123 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2124 05/add-to-EAX 4/imm32 -2125 # var slice/ECX = {EAX, ECX} -2126 51/push-ECX -2127 50/push-EAX -2128 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2129 # EAX = is-valid-name?(slice) -2130 # . . push args -2131 51/push-ECX -2132 # . . call -2133 e8/call is-valid-name?/disp32 -2134 # . . discard args -2135 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2136 # check-ints-equal(EAX, 0, msg) -2137 # . . push args -2138 68/push "F - test-is-valid-name-digit-prefix"/imm32 -2139 68/push 0/imm32/false -2140 50/push-EAX -2141 # . . call -2142 e8/call check-ints-equal/disp32 -2143 # . . discard args -2144 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2145 # . epilog -2146 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2147 5d/pop-to-EBP -2148 c3/return -2149 -2150 test-is-valid-name-negative-prefix: -2151 # . prolog -2152 55/push-EBP -2153 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2154 # (EAX..ECX) = "-0x34" -2155 b8/copy-to-EAX "-0x34"/imm32 -2156 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2157 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2158 05/add-to-EAX 4/imm32 -2159 # var slice/ECX = {EAX, ECX} -2160 51/push-ECX -2161 50/push-EAX -2162 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2163 # EAX = is-valid-name?(slice) -2164 # . . push args -2165 51/push-ECX -2166 # . . call -2167 e8/call is-valid-name?/disp32 -2168 # . . discard args -2169 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2170 # check-ints-equal(EAX, 0, msg) -2171 # . . push args -2172 68/push "F - test-is-valid-name-negative-prefix"/imm32 -2173 68/push 0/imm32/false -2174 50/push-EAX -2175 # . . call -2176 e8/call check-ints-equal/disp32 -2177 # . . discard args -2178 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2179 # . epilog -2180 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2181 5d/pop-to-EBP -2182 c3/return -2183 -2184 test-is-valid-name-0x-prefix: -2185 # . prolog -2186 55/push-EBP -2187 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2188 # (EAX..ECX) = "0x34" -2189 b8/copy-to-EAX "0x34"/imm32 -2190 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2191 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2192 05/add-to-EAX 4/imm32 -2193 # var slice/ECX = {EAX, ECX} -2194 51/push-ECX -2195 50/push-EAX -2196 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2197 # EAX = is-valid-name?(slice) -2198 # . . push args -2199 51/push-ECX -2200 # . . call -2201 e8/call is-valid-name?/disp32 -2202 # . . discard args -2203 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2204 # check-ints-equal(EAX, 0, msg) -2205 # . . push args -2206 68/push "F - test-is-valid-name-0x-prefix"/imm32 -2207 68/push 0/imm32/false -2208 50/push-EAX -2209 # . . call -2210 e8/call check-ints-equal/disp32 -2211 # . . discard args -2212 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2213 # . epilog -2214 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2215 5d/pop-to-EBP -2216 c3/return -2217 -2218 test-is-valid-name-starts-with-pre-digit: -2219 # . prolog -2220 55/push-EBP -2221 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2222 # (EAX..ECX) = "/03" -2223 b8/copy-to-EAX "/03"/imm32 -2224 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2225 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2226 05/add-to-EAX 4/imm32 -2227 # var slice/ECX = {EAX, ECX} -2228 51/push-ECX -2229 50/push-EAX -2230 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2231 # EAX = is-valid-name?(slice) -2232 # . . push args -2233 51/push-ECX -2234 # . . call -2235 e8/call is-valid-name?/disp32 -2236 # . . discard args -2237 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2238 # check-ints-equal(EAX, 1, msg) -2239 # . . push args -2240 68/push "F - test-is-valid-name-starts-with-pre-digit"/imm32 -2241 68/push 1/imm32/true -2242 50/push-EAX -2243 # . . call -2244 e8/call check-ints-equal/disp32 -2245 # . . discard args -2246 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2247 # . epilog -2248 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2249 5d/pop-to-EBP -2250 c3/return -2251 -2252 test-is-valid-name-starts-with-post-digit: -2253 # . prolog -2254 55/push-EBP -2255 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2256 # (EAX..ECX) = "q34" -2257 b8/copy-to-EAX "q34"/imm32 -2258 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2259 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2260 05/add-to-EAX 4/imm32 -2261 # var slice/ECX = {EAX, ECX} -2262 51/push-ECX -2263 50/push-EAX -2264 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2265 # EAX = is-valid-name?(slice) -2266 # . . push args -2267 51/push-ECX -2268 # . . call -2269 e8/call is-valid-name?/disp32 -2270 # . . discard args -2271 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2272 # check-ints-equal(EAX, 1, msg) -2273 # . . push args -2274 68/push "F - test-is-valid-name-starts-with-post-digit"/imm32 -2275 68/push 1/imm32/true -2276 50/push-EAX -2277 # . . call -2278 e8/call check-ints-equal/disp32 -2279 # . . discard args -2280 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2281 # . epilog -2282 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2283 5d/pop-to-EBP -2284 c3/return -2285 -2286 test-is-valid-name-starts-with-digit: -2287 # . prolog -2288 55/push-EBP -2289 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2290 # (EAX..ECX) = "0x34" -2291 b8/copy-to-EAX "0x34"/imm32 -2292 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2293 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2294 05/add-to-EAX 4/imm32 -2295 # var slice/ECX = {EAX, ECX} -2296 51/push-ECX -2297 50/push-EAX -2298 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2299 # EAX = is-valid-name?(slice) -2300 # . . push args -2301 51/push-ECX -2302 # . . call -2303 e8/call is-valid-name?/disp32 -2304 # . . discard args -2305 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2306 # check-ints-equal(EAX, 0, msg) -2307 # . . push args -2308 68/push "F - test-is-valid-name-starts-with-digit"/imm32 -2309 68/push 0/imm32/false -2310 50/push-EAX -2311 # . . call -2312 e8/call check-ints-equal/disp32 -2313 # . . discard args -2314 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2315 # . epilog -2316 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2317 5d/pop-to-EBP -2318 c3/return -2319 -2320 # print 'n' in hex in 'width' bytes in lower-endian order, with a space after every byte -2321 emit-hex: # out : (address buffered-file), n : int, width : int -> <void> -2322 # . prolog -2323 55/push-EBP -2324 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2325 # . save registers -2326 50/push-EAX -2327 51/push-ECX -2328 52/push-EDX -2329 53/push-EBX -2330 57/push-EDI -2331 # EDI = out -2332 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI -2333 # EBX = n -2334 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX -2335 # EDX = width -2336 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX -2337 # var curr/ECX = 0 -2338 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX -2339 $emit-hex:loop: -2340 # if (curr >= width) break -2341 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX -2342 7d/jump-if-greater-or-equal $emit-hex:end/disp8 -2343 # print-byte-buffered(out, EBX) -2344 # . . push args -2345 53/push-EBX -2346 57/push-EDI -2347 # . . call -2348 e8/call print-byte-buffered/disp32 -2349 # . . discard args -2350 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2351 # write-byte-buffered(out, ' ') -2352 # . . push args -2353 68/push 0x20/imm32/space -2354 57/push-EDI -2355 # . . call -2356 e8/call write-byte-buffered/disp32 -2357 # . . discard args -2358 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2359 # EBX = EBX >> 8 -2360 c1/shift 5/subop/logic-right 3/mod/direct 3/rm32/EBX . . . . . 8/imm8 # shift EBX right by 8 bits, while padding zeroes -2361 $emit-hex:continue: -2362 # ++curr -2363 41/increment-ECX -2364 eb/jump $emit-hex:loop/disp8 -2365 $emit-hex:end: -2366 # . restore registers -2367 5f/pop-to-EDI -2368 5b/pop-to-EBX -2369 5a/pop-to-EDX -2370 59/pop-to-ECX -2371 58/pop-to-EAX -2372 # . epilog -2373 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2374 5d/pop-to-EBP -2375 c3/return -2376 -2377 test-emit-hex-single-byte: -2378 # setup -2379 # . clear-stream(_test-output-stream) -2380 # . . push args -2381 68/push _test-output-stream/imm32 -2382 # . . call -2383 e8/call clear-stream/disp32 -2384 # . . discard args -2385 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2386 # . clear-stream(_test-output-buffered-file+4) -2387 # . . push args -2388 b8/copy-to-EAX _test-output-buffered-file/imm32 -2389 05/add-to-EAX 4/imm32 -2390 50/push-EAX -2391 # . . call -2392 e8/call clear-stream/disp32 -2393 # . . discard args -2394 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2395 # emit-hex(_test-output-buffered-file, 0xab, 1) -2396 # . . push args -2397 68/push 1/imm32 -2398 68/push 0xab/imm32 -2399 68/push _test-output-buffered-file/imm32 -2400 # . . call -2401 e8/call emit-hex/disp32 -2402 # . . discard args -2403 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2404 # flush(_test-output-buffered-file) -2405 # . . push args -2406 68/push _test-output-buffered-file/imm32 -2407 # . . call -2408 e8/call flush/disp32 -2409 # . . discard args -2410 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2411 # check-ints-equal(*_test-output-stream->data, 'ab ', msg) -2412 # . . push args -2413 68/push "F - test-emit-hex-single-byte"/imm32 -2414 68/push 0x206261/imm32 -2415 # . . push *_test-output-stream->data -2416 b8/copy-to-EAX _test-output-stream/imm32 -2417 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) -2418 # . . call -2419 e8/call check-ints-equal/disp32 -2420 # . . discard args -2421 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2422 # . end -2423 c3/return -2424 -2425 test-emit-hex-multiple-byte: -2426 # setup -2427 # . clear-stream(_test-output-stream) -2428 # . . push args -2429 68/push _test-output-stream/imm32 -2430 # . . call -2431 e8/call clear-stream/disp32 -2432 # . . discard args -2433 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2434 # . clear-stream(_test-output-buffered-file+4) -2435 # . . push args -2436 b8/copy-to-EAX _test-output-buffered-file/imm32 -2437 05/add-to-EAX 4/imm32 -2438 50/push-EAX -2439 # . . call -2440 e8/call clear-stream/disp32 -2441 # . . discard args -2442 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2443 # emit-hex(_test-output-buffered-file, 0x1234, 2) -2444 # . . push args -2445 68/push 2/imm32 -2446 68/push 0x1234/imm32 -2447 68/push _test-output-buffered-file/imm32 -2448 # . . call -2449 e8/call emit-hex/disp32 -2450 # . . discard args -2451 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2452 # flush(_test-output-buffered-file) -2453 # . . push args -2454 68/push _test-output-buffered-file/imm32 -2455 # . . call -2456 e8/call flush/disp32 -2457 # . . discard args -2458 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2459 # check-stream-equal(_test-output-stream, "34 12 ", msg) -2460 # . . push args -2461 68/push "F - test-emit-hex-multiple-byte/1"/imm32 -2462 68/push "34 12 "/imm32 -2463 68/push _test-output-stream/imm32 -2464 # . . call -2465 e8/call check-stream-equal/disp32 -2466 # . . discard args -2467 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2468 # . end -2469 c3/return -2470 -2471 test-emit-hex-zero-pad: -2472 # setup -2473 # . clear-stream(_test-output-stream) -2474 # . . push args -2475 68/push _test-output-stream/imm32 -2476 # . . call -2477 e8/call clear-stream/disp32 -2478 # . . discard args -2479 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2480 # . clear-stream(_test-output-buffered-file+4) -2481 # . . push args -2482 b8/copy-to-EAX _test-output-buffered-file/imm32 -2483 05/add-to-EAX 4/imm32 -2484 50/push-EAX -2485 # . . call -2486 e8/call clear-stream/disp32 -2487 # . . discard args -2488 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2489 # emit-hex(_test-output-buffered-file, 0xab, 2) -2490 # . . push args -2491 68/push 2/imm32 -2492 68/push 0xab/imm32 -2493 68/push _test-output-buffered-file/imm32 -2494 # . . call -2495 e8/call emit-hex/disp32 -2496 # . . discard args -2497 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2498 # flush(_test-output-buffered-file) -2499 # . . push args -2500 68/push _test-output-buffered-file/imm32 -2501 # . . call -2502 e8/call flush/disp32 -2503 # . . discard args -2504 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2505 # check(_test-output-stream->data == 'ab 00 ') -2506 # . . push args -2507 68/push "F - test-emit-hex-zero-pad/1"/imm32 -2508 68/push "ab 00 "/imm32 -2509 68/push _test-output-stream/imm32 -2510 # . . call -2511 e8/call check-stream-equal/disp32 -2512 # . . discard args -2513 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2514 # . end -2515 c3/return -2516 -2517 test-emit-hex-negative: -2518 # setup -2519 # . clear-stream(_test-output-stream) -2520 # . . push args -2521 68/push _test-output-stream/imm32 -2522 # . . call -2523 e8/call clear-stream/disp32 -2524 # . . discard args -2525 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2526 # . clear-stream(_test-output-buffered-file+4) -2527 # . . push args -2528 b8/copy-to-EAX _test-output-buffered-file/imm32 -2529 05/add-to-EAX 4/imm32 -2530 50/push-EAX -2531 # . . call -2532 e8/call clear-stream/disp32 -2533 # . . discard args -2534 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2535 # emit-hex(_test-output-buffered-file, -1, 2) -2536 # . . push args -2537 68/push 2/imm32 -2538 68/push -1/imm32 -2539 68/push _test-output-buffered-file/imm32 -2540 # . . call -2541 e8/call emit-hex/disp32 -2542 # . . discard args -2543 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2544 # flush(_test-output-buffered-file) -2545 # . . push args -2546 68/push _test-output-buffered-file/imm32 -2547 # . . call -2548 e8/call flush/disp32 -2549 # . . discard args -2550 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2551 # check-stream-equal(_test-output-stream == "ff ff ") -2552 # . . push args -2553 68/push "F - test-emit-hex-negative/1"/imm32 -2554 68/push "ff ff "/imm32 -2555 68/push _test-output-stream/imm32 -2556 # . . call -2557 e8/call check-stream-equal/disp32 -2558 # . . discard args -2559 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2560 # . end -2561 c3/return -2562 -2563 # print 'arr' in hex with a space after every byte -2564 emit-hex-array: # out : (address buffered-file), arr : (address array byte) -> <void> -2565 # . prolog -2566 55/push-EBP -2567 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2568 # . save registers -2569 50/push-EAX -2570 51/push-ECX -2571 52/push-EDX -2572 57/push-EDI -2573 # EDI = out -2574 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI -2575 # EDX = arr # <== 0xbdffffe4 -2576 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX -2577 # curr/ECX = arr->data -2578 8d/copy-address 1/mod/*+disp8 2/rm32/EDX . . . 1/r32/ECX 4/disp8 . # copy EDX+4 to ECX -2579 # max/EDX = arr->data + arr->length -2580 8b/copy 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX -2581 01/add 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # add ECX to EDX -2582 # EAX = 0 -2583 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -2584 $emit-hex-array:loop: -2585 # if (curr >= width) break -2586 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX -2587 73/jump-if-greater-or-equal-unsigned $emit-hex-array:end/disp8 -2588 # emit-hex(out, *curr, width=1) -2589 # . . push args -2590 68/push 1/imm32/width -2591 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL -2592 50/push-EAX -2593 57/push-EDI -2594 # . . call -2595 e8/call emit-hex/disp32 -2596 # . . discard args -2597 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2598 # ++curr -2599 41/increment-ECX -2600 eb/jump $emit-hex-array:loop/disp8 -2601 $emit-hex-array:end: -2602 # . restore registers -2603 5f/pop-to-EDI -2604 5a/pop-to-EDX -2605 59/pop-to-ECX -2606 58/pop-to-EAX -2607 # . epilog -2608 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2609 5d/pop-to-EBP -2610 c3/return -2611 -2612 test-emit-hex-array: -2613 # . prolog -2614 55/push-EBP -2615 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2616 # setup -2617 # . clear-stream(_test-output-stream) -2618 # . . push args -2619 68/push _test-output-stream/imm32 -2620 # . . call -2621 e8/call clear-stream/disp32 -2622 # . . discard args -2623 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2624 # . clear-stream(_test-output-buffered-file+4) -2625 # . . push args -2626 b8/copy-to-EAX _test-output-buffered-file/imm32 -2627 05/add-to-EAX 4/imm32 -2628 50/push-EAX -2629 # . . call -2630 e8/call clear-stream/disp32 -2631 # . . discard args -2632 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2633 # var arr/ECX (address array byte) = [01, 02, 03] -2634 68/push 0x00030201/imm32 # bytes 01 02 03 -2635 68/push 3/imm32/length -2636 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2637 # emit-hex-array(_test-output-buffered-file, arr) -2638 # . . push args -2639 51/push-ECX -2640 68/push _test-output-buffered-file/imm32 -2641 # . . call -2642 e8/call emit-hex-array/disp32 -2643 # . . discard args -2644 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2645 # . flush(_test-output-buffered-file) -2646 # . . push args -2647 68/push _test-output-buffered-file/imm32 -2648 # . . call -2649 e8/call flush/disp32 -2650 # . . discard args -2651 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2652 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -2685 # check-next-stream-line-equal(_test-output-stream, "01 02 03 ", msg) -2686 # . . push args -2687 68/push "F - test-emit-hex-array"/imm32 -2688 68/push "01 02 03 "/imm32 -2689 68/push _test-output-stream/imm32 -2690 # . . call -2691 e8/call check-next-stream-line-equal/disp32 -2692 # . . discard args -2693 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2694 # . epilog -2695 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2696 5d/pop-to-EBP -2697 c3/return -2698 -2699 compute-width: # word : (address array byte) -> EAX : int -2700 # . prolog -2701 55/push-EBP -2702 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2703 # . save registers -2704 51/push-ECX -2705 # EAX = word -2706 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to ECX -2707 # ECX = word + word->length -2708 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2709 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2710 # EAX = word->data -2711 05/add-to-EAX 4/imm32 -2712 # var in/ECX : (address slice) = {EAX, ECX} -2713 51/push-ECX -2714 50/push-EAX -2715 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2716 # return compute-width-of-slice(ECX) -2717 # . . push args -2718 51/push-ECX -2719 # . . call -2720 e8/call compute-width-of-slice/disp32 -2721 # . . discard args -2722 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2723 $compute-width:end: -2724 # . reclaim locals -2725 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2726 # . restore registers -2727 59/pop-to-ECX -2728 # . epilog -2729 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2730 5d/pop-to-EBP -2731 c3/return -2732 -2733 compute-width-of-slice: # s : (address slice) -> EAX : int -2734 # . prolog -2735 55/push-EBP -2736 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2737 # . save registers -2738 51/push-ECX -2739 # ECX = s -2740 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX -2741 # if (has-metadata?(word, "imm32")) return 4 -2742 # . EAX = has-metadata?(word, "imm32") -2743 # . . push args -2744 68/push "imm32"/imm32 -2745 51/push-ECX -2746 # . . call -2747 e8/call has-metadata?/disp32 -2748 # . . discard args -2749 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2750 # . if (EAX != 0) return 4 -2751 3d/compare-EAX-and 0/imm32 -2752 b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now -2753 75/jump-if-not-equal $compute-width-of-slice:end/disp8 -2754 # if (has-metadata?(word, "disp32")) return 4 -2755 # . EAX = has-metadata?(word, "disp32") -2756 # . . push args -2757 68/push "disp32"/imm32 -2758 51/push-ECX -2759 # . . call -2760 e8/call has-metadata?/disp32 -2761 # . . discard args -2762 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2763 # . if (EAX != 0) return 4 -2764 3d/compare-EAX-and 0/imm32 -2765 b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now -2766 75/jump-if-not-equal $compute-width-of-slice:end/disp8 -2767 # if (has-metadata?(word, "imm16")) return 2 -2768 # . EAX = has-metadata?(word, "imm16") -2769 # . . push args -2770 68/push "imm16"/imm32 -2771 51/push-ECX -2772 # . . call -2773 e8/call has-metadata?/disp32 -2774 # . . discard args -2775 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2776 # . if (EAX != 0) return 2 -2777 3d/compare-EAX-and 0/imm32 -2778 b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now -2779 75/jump-if-not-equal $compute-width-of-slice:end/disp8 -2780 # if (has-metadata?(word, "disp16")) return 2 -2781 # . EAX = has-metadata?(word, "disp16") -2782 # . . push args -2783 68/push "disp16"/imm32 -2784 51/push-ECX -2785 # . . call -2786 e8/call has-metadata?/disp32 -2787 # . . discard args -2788 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2789 # . if (EAX != 0) return 2 -2790 3d/compare-EAX-and 0/imm32 -2791 b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now -2792 75/jump-if-not-equal $compute-width-of-slice:end/disp8 -2793 # otherwise return 1 -2794 b8/copy-to-EAX 1/imm32 -2795 $compute-width-of-slice:end: -2796 # . restore registers -2797 59/pop-to-ECX -2798 # . epilog -2799 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2800 5d/pop-to-EBP -2801 c3/return -2802 -2803 test-compute-width: -2804 # . prolog -2805 55/push-EBP -2806 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2807 $test-compute-width:imm8: -2808 # EAX = compute-width("0x2/imm8") -2809 # . . push args -2810 68/push "0x2/imm8"/imm32 -2811 # . . call -2812 e8/call compute-width/disp32 -2813 # . . discard args -2814 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2815 # check-ints-equal(EAX, 1, msg) -2816 # . . push args -2817 68/push "F - test-compute-width: 0x2/imm8"/imm32 -2818 50/push-EAX -2819 68/push 1/imm32 -2820 # . . call -2821 e8/call check-ints-equal/disp32 -2822 # . . discard args -2823 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2824 $test-compute-width:imm16: -2825 # EAX = compute-width("4/imm16") -2826 # . . push args -2827 68/push "4/imm16"/imm32 -2828 # . . call -2829 e8/call compute-width/disp32 -2830 # . . discard args -2831 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2832 # check-ints-equal(EAX, 2, msg) -2833 # . . push args -2834 68/push "F - test-compute-width: 4/imm16"/imm32 -2835 50/push-EAX -2836 68/push 2/imm32 -2837 # . . call -2838 e8/call check-ints-equal/disp32 -2839 # . . discard args -2840 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2841 $test-compute-width:imm32: -2842 # EAX = compute-width("4/imm32") -2843 # . . push args -2844 68/push "4/imm32"/imm32 -2845 # . . call -2846 e8/call compute-width/disp32 -2847 # . . discard args -2848 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2849 # check-ints-equal(EAX, 4, msg) -2850 # . . push args -2851 68/push "F - test-compute-width: 4/imm32"/imm32 -2852 50/push-EAX -2853 68/push 4/imm32 -2854 # . . call -2855 e8/call check-ints-equal/disp32 -2856 # . . discard args -2857 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2858 $test-compute-width:disp8: -2859 # EAX = compute-width("foo/disp8") -2860 # . . push args -2861 68/push "foo/disp8"/imm32 -2862 # . . call -2863 e8/call compute-width/disp32 -2864 # . . discard args -2865 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2866 # check-ints-equal(EAX, 1, msg) -2867 # . . push args -2868 68/push "F - test-compute-width: foo/disp8"/imm32 -2869 50/push-EAX -2870 68/push 1/imm32 -2871 # . . call -2872 e8/call check-ints-equal/disp32 -2873 # . . discard args -2874 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2875 $test-compute-width:disp16: -2876 # EAX = compute-width("foo/disp16") -2877 # . . push args -2878 68/push "foo/disp16"/imm32 -2879 # . . call -2880 e8/call compute-width/disp32 -2881 # . . discard args -2882 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2883 # check-ints-equal(EAX, 2, msg) -2884 # . . push args -2885 68/push "F - test-compute-width: foo/disp16"/imm32 -2886 50/push-EAX -2887 68/push 2/imm32 -2888 # . . call -2889 e8/call check-ints-equal/disp32 -2890 # . . discard args -2891 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2892 $test-compute-width:disp32: -2893 # EAX = compute-width("foo/disp32") -2894 # . . push args -2895 68/push "foo/disp32"/imm32 -2896 # . . call -2897 e8/call compute-width/disp32 -2898 # . . discard args -2899 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2900 # check-ints-equal(EAX, 4, msg) -2901 # . . push args -2902 68/push "F - test-compute-width: foo/disp32"/imm32 -2903 50/push-EAX -2904 68/push 4/imm32 -2905 # . . call -2906 e8/call check-ints-equal/disp32 -2907 # . . discard args -2908 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2909 $test-compute-width:no-metadata: -2910 # EAX = compute-width("45") -2911 # . . push args -2912 68/push "45"/imm32 -2913 # . . call -2914 e8/call compute-width/disp32 -2915 # . . discard args -2916 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2917 # check-ints-equal(EAX, 1, msg) -2918 # . . push args -2919 68/push "F - test-compute-width: 45 (no metadata)"/imm32 -2920 50/push-EAX -2921 68/push 1/imm32 -2922 # . . call -2923 e8/call check-ints-equal/disp32 -2924 # . . discard args -2925 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2926 # . epilog -2927 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2928 5d/pop-to-EBP -2929 c3/return -2930 -2931 is-label?: # word : (address slice) -> EAX : boolean -2932 # . prolog -2933 55/push-EBP -2934 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2935 # . save registers -2936 51/push-ECX -2937 # ECX = word -2938 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX -2939 # ECX = word->end -2940 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 1/r32/ECX 4/disp8 . # copy *(ECX+4) to ECX -2941 # return *(word->end - 1) == ':' -2942 # . EAX = 0 -2943 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -2944 # . EAX = *((char *) word->end - 1) -2945 8a/copy-byte 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/AL -1/disp8 . # copy byte at *(ECX-1) to AL -2946 # . return (EAX == ':') -2947 3d/compare-EAX-and 0x3a/imm32/colon -2948 b8/copy-to-EAX 1/imm32/true -2949 74/jump-if-equal $is-label?:end/disp8 -2950 b8/copy-to-EAX 0/imm32/false -2951 $is-label?:end: -2952 # . restore registers -2953 59/pop-to-ECX -2954 # . epilog -2955 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2956 5d/pop-to-EBP -2957 c3/return -2958 -2959 test-is-label?: -2960 # . prolog -2961 55/push-EBP -2962 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2963 $test-is-label?:true: -2964 # (EAX..ECX) = "AAA:" -2965 b8/copy-to-EAX "AAA:"/imm32 -2966 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2967 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2968 05/add-to-EAX 4/imm32 -2969 # var slice/ECX = {EAX, ECX} -2970 51/push-ECX -2971 50/push-EAX -2972 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2973 # is-label?(slice/ECX) -2974 # . . push args -2975 51/push-ECX -2976 # . . call -2977 e8/call is-label?/disp32 -2978 # . . discard args -2979 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2980 # check-ints-equal(EAX, 1, msg) -2981 # . . push args -2982 68/push "F - test-is-label?:true"/imm32 -2983 68/push 1/imm32 -2984 50/push-EAX -2985 # . . call -2986 e8/call check-ints-equal/disp32 -2987 # . . discard args -2988 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2989 $test-is-label?:false: -2990 # (EAX..ECX) = "AAA" -2991 b8/copy-to-EAX "AAA"/imm32 -2992 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -2993 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -2994 05/add-to-EAX 4/imm32 -2995 # var slice/ECX = {EAX, ECX} -2996 51/push-ECX -2997 50/push-EAX -2998 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2999 # is-label?(slice/ECX) -3000 # . . push args -3001 51/push-ECX -3002 # . . call -3003 e8/call is-label?/disp32 -3004 # . . discard args -3005 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3006 # check-ints-equal(EAX, 0, msg) -3007 # . . push args -3008 68/push "F - test-is-label?:false"/imm32 -3009 68/push 0/imm32 -3010 50/push-EAX -3011 # . . call -3012 e8/call check-ints-equal/disp32 -3013 # . . discard args -3014 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3015 # . epilog -3016 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3017 5d/pop-to-EBP -3018 c3/return -3019 -3020 == data -3021 -3022 _test-input-stream: -3023 # current write index -3024 0/imm32 -3025 # current read index -3026 0/imm32 -3027 # length -3028 0x100/imm32 # 256 bytes -3029 # data (16 lines x 16 bytes/line) -3030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3031 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3032 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3033 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3034 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3035 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3036 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3037 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3038 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3039 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3041 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3042 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3043 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3044 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3045 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3046 -3047 # a test buffered file for _test-input-stream -3048 _test-input-buffered-file: -3049 # file descriptor or (address stream) -3050 _test-input-stream/imm32 -3051 # current write index -3052 0/imm32 -3053 # current read index -3054 0/imm32 -3055 # length -3056 6/imm32 -3057 # data -3058 00 00 00 00 00 00 # 6 bytes -3059 -3060 _test-output-stream: -3061 # current write index -3062 0/imm32 -3063 # current read index -3064 0/imm32 -3065 # length -3066 0x200/imm32 # 512 bytes -3067 # data (32 lines x 16 bytes/line) -3068 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3069 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3071 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3072 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3073 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3074 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3075 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3076 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3077 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3078 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3079 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3081 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3082 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3083 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3084 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3085 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3086 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3087 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3088 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3089 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3091 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3092 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3093 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3094 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3095 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3096 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3097 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3098 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3099 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -3100 -3101 # a test buffered file for _test-output-stream -3102 _test-output-buffered-file: -3103 # file descriptor or (address stream) -3104 _test-output-stream/imm32 -3105 # current write index -3106 0/imm32 -3107 # current read index -3108 0/imm32 -3109 # length -3110 6/imm32 -3111 # data -3112 00 00 00 00 00 00 # 6 bytes -3113 -3114 _test-data-segment: -3115 64/d 61/a 74/t 61/a -3116 _test-data-segment-end: -3117 -3118 # . . vim:nowrap:textwidth=0 +1953 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1954 $test-compute-width:disp16: +1955 # EAX = compute-width("foo/disp16") +1956 # . . push args +1957 68/push "foo/disp16"/imm32 +1958 # . . call +1959 e8/call compute-width/disp32 +1960 # . . discard args +1961 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1962 # check-ints-equal(EAX, 2, msg) +1963 # . . push args +1964 68/push "F - test-compute-width: foo/disp16"/imm32 +1965 50/push-EAX +1966 68/push 2/imm32 +1967 # . . call +1968 e8/call check-ints-equal/disp32 +1969 # . . discard args +1970 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1971 $test-compute-width:disp32: +1972 # EAX = compute-width("foo/disp32") +1973 # . . push args +1974 68/push "foo/disp32"/imm32 +1975 # . . call +1976 e8/call compute-width/disp32 +1977 # . . discard args +1978 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1979 # check-ints-equal(EAX, 4, msg) +1980 # . . push args +1981 68/push "F - test-compute-width: foo/disp32"/imm32 +1982 50/push-EAX +1983 68/push 4/imm32 +1984 # . . call +1985 e8/call check-ints-equal/disp32 +1986 # . . discard args +1987 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1988 $test-compute-width:no-metadata: +1989 # EAX = compute-width("45") +1990 # . . push args +1991 68/push "45"/imm32 +1992 # . . call +1993 e8/call compute-width/disp32 +1994 # . . discard args +1995 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1996 # check-ints-equal(EAX, 1, msg) +1997 # . . push args +1998 68/push "F - test-compute-width: 45 (no metadata)"/imm32 +1999 50/push-EAX +2000 68/push 1/imm32 +2001 # . . call +2002 e8/call check-ints-equal/disp32 +2003 # . . discard args +2004 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2005 # . epilog +2006 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2007 5d/pop-to-EBP +2008 c3/return +2009 +2010 is-label?: # word : (address slice) -> EAX : boolean +2011 # . prolog +2012 55/push-EBP +2013 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2014 # . save registers +2015 51/push-ECX +2016 # ECX = word +2017 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX +2018 # ECX = word->end +2019 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 1/r32/ECX 4/disp8 . # copy *(ECX+4) to ECX +2020 # return *(word->end - 1) == ':' +2021 # . EAX = 0 +2022 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +2023 # . EAX = *((char *) word->end - 1) +2024 8a/copy-byte 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/AL -1/disp8 . # copy byte at *(ECX-1) to AL +2025 # . return (EAX == ':') +2026 3d/compare-EAX-and 0x3a/imm32/colon +2027 b8/copy-to-EAX 1/imm32/true +2028 74/jump-if-equal $is-label?:end/disp8 +2029 b8/copy-to-EAX 0/imm32/false +2030 $is-label?:end: +2031 # . restore registers +2032 59/pop-to-ECX +2033 # . epilog +2034 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2035 5d/pop-to-EBP +2036 c3/return +2037 +2038 test-is-label?: +2039 # . prolog +2040 55/push-EBP +2041 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2042 $test-is-label?:true: +2043 # (EAX..ECX) = "AAA:" +2044 b8/copy-to-EAX "AAA:"/imm32 +2045 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2046 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2047 05/add-to-EAX 4/imm32 +2048 # var slice/ECX = {EAX, ECX} +2049 51/push-ECX +2050 50/push-EAX +2051 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2052 # is-label?(slice/ECX) +2053 # . . push args +2054 51/push-ECX +2055 # . . call +2056 e8/call is-label?/disp32 +2057 # . . discard args +2058 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2059 # check-ints-equal(EAX, 1, msg) +2060 # . . push args +2061 68/push "F - test-is-label?:true"/imm32 +2062 68/push 1/imm32 +2063 50/push-EAX +2064 # . . call +2065 e8/call check-ints-equal/disp32 +2066 # . . discard args +2067 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2068 $test-is-label?:false: +2069 # (EAX..ECX) = "AAA" +2070 b8/copy-to-EAX "AAA"/imm32 +2071 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +2072 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +2073 05/add-to-EAX 4/imm32 +2074 # var slice/ECX = {EAX, ECX} +2075 51/push-ECX +2076 50/push-EAX +2077 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2078 # is-label?(slice/ECX) +2079 # . . push args +2080 51/push-ECX +2081 # . . call +2082 e8/call is-label?/disp32 +2083 # . . discard args +2084 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2085 # check-ints-equal(EAX, 0, msg) +2086 # . . push args +2087 68/push "F - test-is-label?:false"/imm32 +2088 68/push 0/imm32 +2089 50/push-EAX +2090 # . . call +2091 e8/call check-ints-equal/disp32 +2092 # . . discard args +2093 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2094 # . epilog +2095 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2096 5d/pop-to-EBP +2097 c3/return +2098 +2099 == data +2100 +2101 _test-data-segment: +2102 64/d 61/a 74/t 61/a +2103 _test-data-segment-end: +2104 +2105 # . . vim:nowrap:textwidth=0 diff --git a/html/apps/survey.subx.html b/html/apps/survey.subx.html index de10a1e0..2c549f7f 100644 --- a/html/apps/survey.subx.html +++ b/html/apps/survey.subx.html @@ -14,18 +14,18 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } -.subxTest { color: #5f8700; } +.subxS1Comment { color: #0000af; } +.CommentedCode { color: #8a8a8a; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Folded { color: #080808; background-color: #949494; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxTest { color: #5f8700; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> @@ -124,707 +124,707 @@ if ('onhashchange' in window) { 61 # run tests if necessary, convert stdin if not 62 # . prolog 63 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 64 # initialize heap - 65 # - if argc > 1 and argv[1] == "test", then return run_tests() - 66 # . argc > 1 - 67 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP - 68 7e/jump-if-lesser-or-equal $run-main/disp8 - 69 # . argv[1] == "test" - 70 # . . push args - 71 68/push "test"/imm32 - 72 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 73 # . . call - 74 e8/call kernel-string-equal?/disp32 - 75 # . . discard args - 76 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 77 # . check result - 78 3d/compare-EAX-and 1/imm32 - 79 75/jump-if-not-equal $run-main/disp8 - 80 # . run-tests() - 81 e8/call run-tests/disp32 - 82 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 83 eb/jump $main:end/disp8 - 84 $run-main: - 85 # - otherwise convert stdin - 86 # convert(Stdin, Stdout) - 87 # . . push args - 88 68/push Stdout/imm32 - 89 68/push Stdin/imm32 - 90 # . . call - 91 e8/call convert/disp32 - 92 # . . discard args - 93 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 94 #? # . write-stream(2/stderr, Trace-stream) - 95 #? # . . push args - 96 #? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - 97 #? 68/push 2/imm32/stderr - 98 #? # . . call - 99 #? e8/call write-stream/disp32 - 100 #? # . . discard args - 101 #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 102 # . syscall(exit, 0) - 103 bb/copy-to-EBX 0/imm32 - 104 $main:end: - 105 b8/copy-to-EAX 1/imm32/exit - 106 cd/syscall 0x80/imm8 - 107 - 108 # data structures: - 109 # segment-info: {address, file-offset, size} (12 bytes) - 110 # segments: (address stream {string, segment-info}) (16 bytes per row) - 111 # label-info: {segment-name, segment-offset, address} (12 bytes) - 112 # labels: (address stream {string, label-info}) (16 bytes per row) - 113 # these are all inefficient; use sequential scans for lookups - 114 - 115 convert: # infile : (address buffered-file), out : (address buffered-file) -> <void> - 116 # pseudocode - 117 # var in : (address stream byte) = stream(4096) - 118 # slurp(infile, in) - 119 # var segments = new-stream(10 rows, 16 bytes each) - 120 # var labels = new-stream(Max-labels rows, 16 bytes each) - 121 # compute-offsets(in, segments, labels) - 122 # compute-addresses(segments, labels) - 123 # rewind-stream(in) - 124 # emit-output(in, out, segments, labels) - 125 # - 126 # . prolog - 127 55/push-EBP - 128 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 129 # . save registers - 130 51/push-ECX - 131 52/push-EDX - 132 56/push-ESI - 133 # var segments/ECX = stream(10 * 16) - 134 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP - 135 68/push 0xa0/imm32/length - 136 68/push 0/imm32/read - 137 68/push 0/imm32/write - 138 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 139 # var labels/EDX = stream(Max-labels * 16) - 140 # . data - 141 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/ESP Max-labels/disp32 # subtract *Max-labels from ESP - 142 # . length - 143 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Max-labels/disp32 # push *Max-labels - 144 # . read - 145 68/push 0/imm32/read - 146 # . write - 147 68/push 0/imm32/write - 148 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - 149 # var in/ESI = stream(Input-size * 1) - 150 # . data - 151 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/ESP Input-size/disp32 # subtract *Input-size from ESP - 152 # . length - 153 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Input-size/disp32 # push *Input-size - 154 # . read - 155 68/push 0/imm32/read - 156 # . write - 157 68/push 0/imm32/write - 158 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - 159 +-- 47 lines: #? # dump labels->write -------------------------------------------------------------------------------------------------------------------- - 206 +-- 9 lines: #? # write(2/stderr, "slurp in\n") --------------------------------------------------------------------------------------------------------- - 215 # slurp(infile, in) - 216 # . . push args - 217 56/push-ESI - 218 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 219 # . . call - 220 e8/call slurp/disp32 - 221 # . . discard args - 222 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 223 +-- 46 lines: #? # dump labels->write -------------------------------------------------------------------------------------------------------------------- - 269 +-- 33 lines: #? # dump in ------------------------------------------------------------------------------------------------------------------------------- - 302 +-- 9 lines: #? # write(2/stderr, "compute-offsets\n") -------------------------------------------------------------------------------------------------- - 311 # compute-offsets(in, segments, labels) - 312 # . . push args - 313 52/push-EDX - 314 51/push-ECX - 315 56/push-ESI - 316 # . . call - 317 e8/call compute-offsets/disp32 - 318 # . . discard args - 319 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 320 +-- 9 lines: #? # write(2/stderr, "compute-addresses\n") ------------------------------------------------------------------------------------------------ - 329 # compute-addresses(segments, labels) - 330 # . . push args - 331 52/push-EDX - 332 51/push-ECX - 333 # . . call - 334 e8/call compute-addresses/disp32 - 335 # . . discard args - 336 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x8/imm32 # add to ESP - 337 # rewind-stream(in) - 338 # . . push args - 339 56/push-ESI - 340 # . . call - 341 e8/call rewind-stream/disp32 - 342 # . . discard args - 343 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 344 +-- 9 lines: #? # write(2/stderr, "emit-output\n") ------------------------------------------------------------------------------------------------------ - 353 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- - 379 +-- 46 lines: #? # dump labels->write -------------------------------------------------------------------------------------------------------------------- - 425 # emit-output(in, out, segments, labels) - 426 # . . push args - 427 52/push-EDX - 428 51/push-ECX - 429 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 430 56/push-ESI - 431 # . . call - 432 e8/call emit-output/disp32 - 433 # . . discard args - 434 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - 435 # flush(out) - 436 # . . push args - 437 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 438 # . . call - 439 e8/call flush/disp32 - 440 # . . discard args - 441 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 442 $convert:end: - 443 # . reclaim locals - 444 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x30a0/imm32 # add to ESP - 445 # . restore registers - 446 5e/pop-to-ESI - 447 5a/pop-to-EDX - 448 59/pop-to-ECX - 449 # . epilog - 450 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 451 5d/pop-to-EBP - 452 c3/return - 453 - 454 test-convert-computes-addresses: - 455 # input: - 456 # == code 0x1 - 457 # Entry: - 458 # ab x/imm32 - 459 # == data 0x1000 - 460 # x: - 461 # 01 - 462 # - 463 # trace contains (in any order): - 464 # label x is at address 0x1079 - 465 # segment code starts at address 0x74 - 466 # segment code has size 5 - 467 # segment data starts at address 0x1079 - 468 # - 469 # . prolog - 470 55/push-EBP - 471 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 472 # setup - 473 # . clear-stream(_test-input-stream) - 474 # . . push args - 475 68/push _test-input-stream/imm32 - 476 # . . call - 477 e8/call clear-stream/disp32 - 478 # . . discard args - 479 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 480 # . clear-stream(_test-input-buffered-file+4) - 481 # . . push args - 482 b8/copy-to-EAX _test-input-buffered-file/imm32 - 483 05/add-to-EAX 4/imm32 - 484 50/push-EAX - 485 # . . call - 486 e8/call clear-stream/disp32 - 487 # . . discard args - 488 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 489 # . clear-stream(_test-output-stream) - 490 # . . push args - 491 68/push _test-output-stream/imm32 - 492 # . . call - 493 e8/call clear-stream/disp32 - 494 # . . discard args - 495 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 496 # . clear-stream(_test-output-buffered-file+4) - 497 # . . push args - 498 b8/copy-to-EAX _test-output-buffered-file/imm32 - 499 05/add-to-EAX 4/imm32 - 500 50/push-EAX - 501 # . . call - 502 e8/call clear-stream/disp32 - 503 # . . discard args - 504 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 505 # initialize input - 506 # . write(_test-input-stream, "== code 0x1\n") - 507 # . . push args - 508 68/push "== code 0x1\n"/imm32 - 509 68/push _test-input-stream/imm32 - 510 # . . call - 511 e8/call write/disp32 - 512 # . . discard args - 513 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 514 # . write(_test-input-stream, "Entry:\n") - 515 # . . push args - 516 68/push "Entry:\n"/imm32 - 517 68/push _test-input-stream/imm32 - 518 # . . call - 519 e8/call write/disp32 - 520 # . . discard args - 521 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 522 # . write(_test-input-stream, "ab x/imm32\n") - 523 # . . push args - 524 68/push "ab x/imm32\n"/imm32 - 525 68/push _test-input-stream/imm32 - 526 # . . call - 527 e8/call write/disp32 - 528 # . . discard args - 529 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 530 # . write(_test-input-stream, "== data 0x1000\n") - 531 # . . push args - 532 68/push "== data 0x1000\n"/imm32 - 533 68/push _test-input-stream/imm32 - 534 # . . call - 535 e8/call write/disp32 - 536 # . . discard args - 537 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 538 # . write(_test-input-stream, "x:\n") - 539 # . . push args - 540 68/push "x:\n"/imm32 - 541 68/push _test-input-stream/imm32 - 542 # . . call - 543 e8/call write/disp32 - 544 # . . discard args - 545 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 546 # . write(_test-input-stream, "01\n") - 547 # . . push args - 548 68/push "01\n"/imm32 - 549 68/push _test-input-stream/imm32 - 550 # . . call - 551 e8/call write/disp32 - 552 # . . discard args - 553 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 554 # convert(_test-input-buffered-file, _test-output-buffered-file) - 555 # . . push args - 556 68/push _test-output-buffered-file/imm32 - 557 68/push _test-input-buffered-file/imm32 - 558 # . . call - 559 e8/call convert/disp32 - 560 # . . discard args - 561 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 562 # check trace - 563 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- - 589 # . check-trace-contains("label 'x' is at address 0x00001079.", msg) - 590 # . . push args - 591 68/push "F - test-convert-computes-addresses/0"/imm32 - 592 68/push "label 'x' is at address 0x00001079."/imm32 - 593 # . . call - 594 e8/call check-trace-contains/disp32 - 595 # . . discard args - 596 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 597 # . check-trace-contains("segment 'code' starts at address 0x00000074.", msg) - 598 # . . push args - 599 68/push "F - test-convert-computes-addresses/1"/imm32 - 600 68/push "segment 'code' starts at address 0x00000074."/imm32 - 601 # . . call - 602 e8/call check-trace-contains/disp32 - 603 # . . discard args - 604 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 605 # . check-trace-contains("segment 'code' has size 0x00000005.", msg) - 606 # . . push args - 607 68/push "F - test-convert-computes-addresses/2"/imm32 - 608 68/push "segment 'code' has size 0x00000005."/imm32 - 609 # . . call - 610 e8/call check-trace-contains/disp32 - 611 # . . discard args - 612 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 613 # . check-trace-contains("segment 'data' starts at address 0x00001079.", msg) - 614 # . . push args - 615 68/push "F - test-convert-computes-addresses/3"/imm32 - 616 68/push "segment 'data' starts at address 0x00001079."/imm32 - 617 # . . call - 618 e8/call check-trace-contains/disp32 - 619 # . . discard args - 620 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 621 # . epilog - 622 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 623 5d/pop-to-EBP - 624 c3/return - 625 - 626 # global scratch space for compute-offsets in the data segment - 627 == data - 628 - 629 compute-offsets:file-offset: # int - 630 0/imm32 - 631 compute-offsets:segment-offset: # int - 632 0/imm32 - 633 compute-offsets:word-slice: - 634 0/imm32/start - 635 0/imm32/end - 636 compute-offsets:segment-tmp: # slice - 637 0/imm32/start - 638 0/imm32/end - 639 - 640 == code - 641 - 642 compute-offsets: # in : (address stream), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) - 643 # skeleton: - 644 # for lines in 'in' - 645 # for words in line - 646 # switch word - 647 # case 1 - 648 # case 2 - 649 # ... - 650 # default - 651 # - 652 # pseudocode: - 653 # curr-segment-name : (address string) = 0 - 654 # var line = new-stream(512, 1) - 655 # while true # line loop - 656 # clear-stream(line) - 657 # read-line(in, line) - 658 # if (line->write == 0) break # end of file - 659 # while true # word loop - 660 # word-slice = next-word(line) - 661 # if slice-empty?(word-slice) # end of line - 662 # break - 663 # else if slice-starts-with?(word-slice, "#") # comment - 664 # break # end of line - 665 # else if slice-equal?(word-slice, "==") - 666 # if curr-segment-name != 0 - 667 # seg = get-or-insert(segments, curr-segment-name) - 668 # seg->size = *file-offset - seg->file-offset - 669 # trace("segment '", curr-segment-name, "' has size ", seg->size) - 670 # segment-tmp = next-word(line) - 671 # curr-segment-name = slice-to-string(segment-tmp) - 672 # if empty?(curr-segment-name) - 673 # abort - 674 # segment-tmp = next-word(line) - 675 # if slice-empty?(segment-tmp) - 676 # abort - 677 # seg = get-or-insert(segments, curr-segment-name) - 678 # seg->starting-address = parse-hex-int(segment-tmp) - 679 # seg->file-offset = *file-offset - 680 # trace("segment '", curr-segment-name, "' is at file offset ", seg->file-offset) - 681 # segment-offset = 0 - 682 # break (next line) - 683 # else if is-label?(word-slice) - 684 # strip trailing ':' from word-slice - 685 # x : (address label-info) = get-or-insert(labels, name) - 686 # x->segment-name = curr-segment-name - 687 # trace("label '", word-slice, "' is in segment '", curr-segment-name, "'.") - 688 # x->segment-offset = segment-offset - 689 # trace("label '", word-slice, "' is at segment offset ", segment-offset, ".") - 690 # # labels occupy no space, so no need to increment offsets - 691 # else - 692 # width = compute-width-of-slice(word-slice) - 693 # *segment-offset += width - 694 # *file-offset += width - 695 # - 696 # . prolog - 697 55/push-EBP - 698 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 699 # . save registers - 700 50/push-EAX - 701 51/push-ECX - 702 52/push-EDX - 703 53/push-EBX - 704 56/push-ESI - 705 57/push-EDI - 706 # curr-segment-name/ESI = 0 - 707 31/xor 3/mod/direct 6/rm32/ESI . . . 6/r32/ESI . . # clear ESI - 708 # file-offset = 0 - 709 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:file-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice - 710 # segment-offset = 0 - 711 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice - 712 # line/ECX = new-stream(512, 1) - 713 # . EAX = new-stream(512, 1) - 714 # . . push args - 715 68/push 1/imm32 - 716 68/push 0x200/imm32 - 717 68/push Heap/imm32 - 718 # . . call - 719 e8/call new-stream/disp32 - 720 # . . discard args - 721 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 722 # . line/ECX = EAX - 723 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX - 724 $compute-offsets:line-loop: - 725 # clear-stream(line/ECX) - 726 51/push-ECX - 727 e8/call clear-stream/disp32 - 728 # . discard args - 729 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 730 # read-line(in, line/ECX) - 731 51/push-ECX - 732 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 733 e8/call read-line/disp32 - 734 # . discard args - 735 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 736 # if (line->write == 0) break - 737 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 738 3d/compare-EAX-and 0/imm32 - 739 0f 84/jump-if-equal $compute-offsets:break-line-loop/disp32 - 740 +-- 33 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- - 773 $compute-offsets:word-loop: - 774 # EDX = word-slice - 775 ba/copy-to-EDX compute-offsets:word-slice/imm32 - 776 # next-word(line/ECX, word-slice/EDX) - 777 52/push-EDX - 778 51/push-ECX - 779 e8/call next-word/disp32 - 780 # . discard args - 781 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 782 +-- 80 lines: #? # dump word-slice and maybe curr-segment-name ------------------------------------------------------------------------------------------- - 862 $compute-offsets:case-empty: - 863 # if slice-empty?(word/EDX) break - 864 # . EAX = slice-empty?(word/EDX) - 865 52/push-EDX - 866 e8/call slice-empty?/disp32 - 867 # . . discard args - 868 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 869 # . if (EAX != 0) break - 870 3d/compare-EAX-and 0/imm32 - 871 0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32 - 872 $compute-offsets:case-comment: - 873 # if slice-starts-with?(word-slice, "#") continue - 874 68/push "#"/imm32 - 875 52/push-EDX - 876 e8/call slice-starts-with?/disp32 - 877 # . . discard args - 878 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 879 # . if (EAX != 0) break - 880 3d/compare-EAX-and 0/imm32 - 881 0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32 - 882 $compute-offsets:case-segment-header: - 883 # if (!slice-equal?(word-slice/EDX, "==")) goto next case - 884 # . EAX = slice-equal?(word-slice/EDX, "==") - 885 68/push "=="/imm32 - 886 52/push-EDX - 887 e8/call slice-equal?/disp32 - 888 # . . discard args - 889 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 890 # . if (EAX == 0) goto next case - 891 3d/compare-EAX-and 0/imm32 - 892 0f 84/jump-if-equal $compute-offsets:case-label/disp32 - 893 # if (curr-segment-name == 0) goto construct-next-segment - 894 81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI - 895 74/jump-if-equal $compute-offsets:construct-next-segment/disp8 - 896 # seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16) - 897 # . . push args - 898 68/push 0x10/imm32/row-size - 899 56/push-ESI - 900 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 901 # . . call - 902 e8/call get-or-insert/disp32 - 903 # . . discard args - 904 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 905 # seg->size = file-offset - seg->file-offset - 906 # . save ECX - 907 51/push-ECX - 908 # . EBX = *file-offset - 909 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX - 910 # . ECX = seg->file-offset - 911 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX - 912 # . EBX -= ECX - 913 29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX - 914 # . seg->size = EBX - 915 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8) - 916 # . restore ECX - 917 59/pop-to-ECX - 918 # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".") - 919 # . . push args - 920 68/push "."/imm32 - 921 53/push-EBX - 922 68/push "' has size "/imm32 - 923 56/push-ESI - 924 68/push "segment '"/imm32 - 925 # . . call - 926 e8/call trace-sssns/disp32 - 927 # . . discard args - 928 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - 929 $compute-offsets:construct-next-segment: - 930 # next-word(line/ECX, segment-tmp) - 931 68/push compute-offsets:segment-tmp/imm32 - 932 51/push-ECX - 933 e8/call next-word/disp32 - 934 # . discard args - 935 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 936 +-- 47 lines: #? # dump curr-segment-name if not null (clobbering EAX) ----------------------------------------------------------------------------------- - 983 $compute-offsets:update-curr-segment-name: - 984 # curr-segment-name = slice-to-string(segment-tmp) - 985 # . EAX = slice-to-string(Heap, segment-tmp) - 986 # . . push args - 987 68/push compute-offsets:segment-tmp/imm32 - 988 68/push Heap/imm32 - 989 # . . call - 990 e8/call slice-to-string/disp32 - 991 # . . discard args - 992 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 993 # . curr-segment-name = EAX - 994 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI - 995 # if empty?(curr-segment-name) abort - 996 # . if (EAX == 0) abort - 997 3d/compare-EAX-and 0/imm32 - 998 0f 84/jump-if-equal $compute-offsets:abort/disp32 - 999 # next-word(line/ECX, segment-tmp) -1000 68/push compute-offsets:segment-tmp/imm32 -1001 51/push-ECX -1002 e8/call next-word/disp32 -1003 # . discard args -1004 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1005 # if slice-empty?(segment-tmp) abort -1006 # . EAX = slice-empty?(segment-tmp) -1007 68/push compute-offsets:segment-tmp/imm32 -1008 e8/call slice-empty?/disp32 -1009 # . . discard args -1010 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1011 # . if (EAX != 0) abort -1012 3d/compare-EAX-and 0/imm32 -1013 0f 85/jump-if-not-equal $compute-offsets:abort/disp32 -1014 # seg/EBX = get-or-insert(segments, curr-segment-name, row-size=16) -1015 # . . push args -1016 68/push 0x10/imm32/row-size -1017 56/push-ESI -1018 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -1019 # . . call -1020 e8/call get-or-insert/disp32 -1021 # . . discard args -1022 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1023 # . EBX = EAX -1024 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX -1025 # seg->address = parse-hex-int(segment-tmp) -1026 # . EAX = parse-hex-int(segment-tmp) -1027 68/push compute-offsets:segment-tmp/imm32 -1028 e8/call parse-hex-int/disp32 -1029 # . . discard args -1030 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1031 # . seg->address = EAX -1032 89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX -1033 # seg->file-offset = *file-offset -1034 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # copy *file-offset to EAX -1035 89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4) -1036 # trace-sssns("segment '", curr-segment-name, "' is at file offset ", seg->file-offset, "") -1037 # . . push args -1038 68/push "."/imm32 -1039 50/push-EAX -1040 68/push "' is at file offset "/imm32 -1041 56/push-ESI -1042 68/push "segment '"/imm32 -1043 # . . call -1044 e8/call trace-sssns/disp32 -1045 # . . discard args -1046 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1047 # segment-offset = 0 -1048 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *segment-offset -1049 # break -1050 e9/jump $compute-offsets:line-loop/disp32 -1051 $compute-offsets:case-label: -1052 # if (!is-label?(word-slice/EDX)) goto next case -1053 # . EAX = is-label?(word-slice/EDX) -1054 # . . push args -1055 52/push-EDX -1056 # . . call -1057 e8/call is-label?/disp32 -1058 # . . discard args -1059 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1060 # . if (EAX == 0) goto next case -1061 3d/compare-EAX-and 0/imm32 -1062 74/jump-if-equal $compute-offsets:case-default/disp8 -1063 # strip trailing ':' from word-slice -1064 ff 1/subop/decrement 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # decrement *(EDX+4) -1065 # x/EAX = leaky-get-or-insert-slice(labels, word-slice, row-size=16) -1066 # . . push args -1067 68/push 0x10/imm32/row-size -1068 52/push-EDX -1069 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -1070 # . . call -1071 e8/call leaky-get-or-insert-slice/disp32 -1072 # . . discard args -1073 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1074 $compute-offsets:save-label-offset: -1075 # x->segment-name = curr-segment-name -1076 89/copy 0/mod/indirect 0/rm32/EAX . . . 6/r32/ESI . . # copy ESI to *EAX -1077 # trace-slsss("label '" word-slice/EDX "' is in segment '" current-segment-name "'.") -1078 # . . push args -1079 68/push "'."/imm32 -1080 56/push-ESI -1081 68/push "' is in segment '"/imm32 -1082 52/push-EDX -1083 68/push "label '"/imm32 -1084 # . . call -1085 e8/call trace-slsss/disp32 -1086 # . . discard args -1087 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1088 # x->segment-offset = segment-offset -1089 # . EBX = segment-offset -1090 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:segment-offset/disp32 # copy *segment-offset to EBX -1091 # . x->segment-offset = EBX -1092 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 4/disp8 . # copy EBX to *(EAX+4) -1093 # trace-slsns("label '" word-slice/EDX "' is at segment offset " *segment-offset/EAX ".") -1094 # . . EAX = file-offset -1095 b8/copy-to-EAX compute-offsets:segment-offset/imm32 -1096 # . . EAX = *file-offset/EAX -1097 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX -1098 # . . push args -1099 68/push "."/imm32 -1100 50/push-EAX -1101 68/push "' is at segment offset "/imm32 -1102 52/push-EDX -1103 68/push "label '"/imm32 -1104 # . . call -1105 e8/call trace-slsns/disp32 -1106 # . . discard args -1107 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1108 # continue -1109 e9/jump $compute-offsets:word-loop/disp32 -1110 $compute-offsets:case-default: -1111 # width/EAX = compute-width-of-slice(word-slice) -1112 # . . push args -1113 52/push-EDX -1114 # . . call -1115 e8/call compute-width-of-slice/disp32 -1116 # . . discard args -1117 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -1118 # segment-offset += width -1119 01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:segment-offset/disp32 # add EAX to *segment-offset -1120 # file-offset += width -1121 01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # add EAX to *file-offset -1122 +-- 47 lines: #? # dump segment-offset ------------------------------------------------------------------------------------------------------------------- -1169 e9/jump $compute-offsets:word-loop/disp32 -1170 $compute-offsets:break-line-loop: -1171 # seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16) -1172 # . . push args -1173 68/push 0x10/imm32/row-size -1174 56/push-ESI -1175 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -1176 # . . call -1177 e8/call get-or-insert/disp32 -1178 # . . discard args -1179 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1180 # seg->size = file-offset - seg->file-offset -1181 # . save ECX -1182 51/push-ECX -1183 # . EBX = *file-offset -1184 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX -1185 # . ECX = seg->file-offset -1186 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX -1187 # . EBX -= ECX -1188 29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX -1189 # . seg->size = EBX -1190 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8) -1191 # . restore ECX -1192 59/pop-to-ECX -1193 # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".") -1194 # . trace-sssns("segment '", curr-segment-name, "' has size ", EBX, ".") -1195 # . . push args -1196 68/push "."/imm32 -1197 53/push-EBX -1198 68/push "' has size "/imm32 -1199 56/push-ESI -1200 68/push "segment '"/imm32 -1201 # . . call -1202 e8/call trace-sssns/disp32 -1203 # . . discard args -1204 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1205 $compute-offsets:end: -1206 # . reclaim locals -1207 # . restore registers -1208 5f/pop-to-EDI -1209 5e/pop-to-ESI -1210 5b/pop-to-EBX -1211 5a/pop-to-EDX -1212 59/pop-to-ECX -1213 58/pop-to-EAX -1214 # . epilog -1215 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1216 5d/pop-to-EBP -1217 c3/return + 64 # - if argc > 1 and argv[1] == "test", then return run_tests() + 65 # . argc > 1 + 66 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP + 67 7e/jump-if-lesser-or-equal $run-main/disp8 + 68 # . argv[1] == "test" + 69 # . . push args + 70 68/push "test"/imm32 + 71 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 72 # . . call + 73 e8/call kernel-string-equal?/disp32 + 74 # . . discard args + 75 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 76 # . check result + 77 3d/compare-EAX-and 1/imm32 + 78 75/jump-if-not-equal $run-main/disp8 + 79 # . run-tests() + 80 e8/call run-tests/disp32 + 81 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 82 eb/jump $main:end/disp8 + 83 $run-main: + 84 # - otherwise convert stdin + 85 # convert(Stdin, Stdout) + 86 # . . push args + 87 68/push Stdout/imm32 + 88 68/push Stdin/imm32 + 89 # . . call + 90 e8/call convert/disp32 + 91 # . . discard args + 92 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 93 #? # . write-stream(2/stderr, Trace-stream) + 94 #? # . . push args + 95 #? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream + 96 #? 68/push 2/imm32/stderr + 97 #? # . . call + 98 #? e8/call write-stream/disp32 + 99 #? # . . discard args + 100 #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 101 # . syscall(exit, 0) + 102 bb/copy-to-EBX 0/imm32 + 103 $main:end: + 104 b8/copy-to-EAX 1/imm32/exit + 105 cd/syscall 0x80/imm8 + 106 + 107 # data structures: + 108 # segment-info: {address, file-offset, size} (12 bytes) + 109 # segments: (address stream {string, segment-info}) (16 bytes per row) + 110 # label-info: {segment-name, segment-offset, address} (12 bytes) + 111 # labels: (address stream {string, label-info}) (16 bytes per row) + 112 # these are all inefficient; use sequential scans for lookups + 113 + 114 convert: # infile : (address buffered-file), out : (address buffered-file) -> <void> + 115 # pseudocode + 116 # var in : (address stream byte) = stream(4096) + 117 # slurp(infile, in) + 118 # var segments = new-stream(10 rows, 16 bytes each) + 119 # var labels = new-stream(Max-labels rows, 16 bytes each) + 120 # compute-offsets(in, segments, labels) + 121 # compute-addresses(segments, labels) + 122 # rewind-stream(in) + 123 # emit-output(in, out, segments, labels) + 124 # + 125 # . prolog + 126 55/push-EBP + 127 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 128 # . save registers + 129 51/push-ECX + 130 52/push-EDX + 131 56/push-ESI + 132 # var segments/ECX = stream(10 * 16) + 133 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP + 134 68/push 0xa0/imm32/length + 135 68/push 0/imm32/read + 136 68/push 0/imm32/write + 137 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 138 # var labels/EDX = stream(Max-labels * 16) + 139 # . data + 140 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/ESP Max-labels/disp32 # subtract *Max-labels from ESP + 141 # . length + 142 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Max-labels/disp32 # push *Max-labels + 143 # . read + 144 68/push 0/imm32/read + 145 # . write + 146 68/push 0/imm32/write + 147 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX + 148 # var in/ESI = stream(Input-size * 1) + 149 # . data + 150 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/ESP Input-size/disp32 # subtract *Input-size from ESP + 151 # . length + 152 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Input-size/disp32 # push *Input-size + 153 # . read + 154 68/push 0/imm32/read + 155 # . write + 156 68/push 0/imm32/write + 157 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + 158 +-- 47 lines: #? # dump labels->write -------------------------------------------------------------------------------------------------------------------- + 205 +-- 9 lines: #? # write(2/stderr, "slurp in\n") --------------------------------------------------------------------------------------------------------- + 214 # slurp(infile, in) + 215 # . . push args + 216 56/push-ESI + 217 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 218 # . . call + 219 e8/call slurp/disp32 + 220 # . . discard args + 221 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 222 +-- 46 lines: #? # dump labels->write -------------------------------------------------------------------------------------------------------------------- + 268 +-- 33 lines: #? # dump in ------------------------------------------------------------------------------------------------------------------------------- + 301 +-- 9 lines: #? # write(2/stderr, "compute-offsets\n") -------------------------------------------------------------------------------------------------- + 310 # compute-offsets(in, segments, labels) + 311 # . . push args + 312 52/push-EDX + 313 51/push-ECX + 314 56/push-ESI + 315 # . . call + 316 e8/call compute-offsets/disp32 + 317 # . . discard args + 318 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 319 +-- 9 lines: #? # write(2/stderr, "compute-addresses\n") ------------------------------------------------------------------------------------------------ + 328 # compute-addresses(segments, labels) + 329 # . . push args + 330 52/push-EDX + 331 51/push-ECX + 332 # . . call + 333 e8/call compute-addresses/disp32 + 334 # . . discard args + 335 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x8/imm32 # add to ESP + 336 # rewind-stream(in) + 337 # . . push args + 338 56/push-ESI + 339 # . . call + 340 e8/call rewind-stream/disp32 + 341 # . . discard args + 342 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 343 +-- 9 lines: #? # write(2/stderr, "emit-output\n") ------------------------------------------------------------------------------------------------------ + 352 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- + 378 +-- 46 lines: #? # dump labels->write -------------------------------------------------------------------------------------------------------------------- + 424 # emit-output(in, out, segments, labels) + 425 # . . push args + 426 52/push-EDX + 427 51/push-ECX + 428 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 429 56/push-ESI + 430 # . . call + 431 e8/call emit-output/disp32 + 432 # . . discard args + 433 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP + 434 # flush(out) + 435 # . . push args + 436 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 437 # . . call + 438 e8/call flush/disp32 + 439 # . . discard args + 440 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 441 $convert:end: + 442 # . reclaim locals + 443 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x30a0/imm32 # add to ESP + 444 # . restore registers + 445 5e/pop-to-ESI + 446 5a/pop-to-EDX + 447 59/pop-to-ECX + 448 # . epilog + 449 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 450 5d/pop-to-EBP + 451 c3/return + 452 + 453 test-convert-computes-addresses: + 454 # input: + 455 # == code 0x1 + 456 # Entry: + 457 # ab x/imm32 + 458 # == data 0x1000 + 459 # x: + 460 # 01 + 461 # + 462 # trace contains (in any order): + 463 # label x is at address 0x1079 + 464 # segment code starts at address 0x74 + 465 # segment code has size 5 + 466 # segment data starts at address 0x1079 + 467 # + 468 # . prolog + 469 55/push-EBP + 470 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 471 # setup + 472 # . clear-stream(_test-input-stream) + 473 # . . push args + 474 68/push _test-input-stream/imm32 + 475 # . . call + 476 e8/call clear-stream/disp32 + 477 # . . discard args + 478 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 479 # . clear-stream(_test-input-buffered-file+4) + 480 # . . push args + 481 b8/copy-to-EAX _test-input-buffered-file/imm32 + 482 05/add-to-EAX 4/imm32 + 483 50/push-EAX + 484 # . . call + 485 e8/call clear-stream/disp32 + 486 # . . discard args + 487 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 488 # . clear-stream(_test-output-stream) + 489 # . . push args + 490 68/push _test-output-stream/imm32 + 491 # . . call + 492 e8/call clear-stream/disp32 + 493 # . . discard args + 494 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 495 # . clear-stream(_test-output-buffered-file+4) + 496 # . . push args + 497 b8/copy-to-EAX _test-output-buffered-file/imm32 + 498 05/add-to-EAX 4/imm32 + 499 50/push-EAX + 500 # . . call + 501 e8/call clear-stream/disp32 + 502 # . . discard args + 503 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 504 # initialize input + 505 # . write(_test-input-stream, "== code 0x1\n") + 506 # . . push args + 507 68/push "== code 0x1\n"/imm32 + 508 68/push _test-input-stream/imm32 + 509 # . . call + 510 e8/call write/disp32 + 511 # . . discard args + 512 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 513 # . write(_test-input-stream, "Entry:\n") + 514 # . . push args + 515 68/push "Entry:\n"/imm32 + 516 68/push _test-input-stream/imm32 + 517 # . . call + 518 e8/call write/disp32 + 519 # . . discard args + 520 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 521 # . write(_test-input-stream, "ab x/imm32\n") + 522 # . . push args + 523 68/push "ab x/imm32\n"/imm32 + 524 68/push _test-input-stream/imm32 + 525 # . . call + 526 e8/call write/disp32 + 527 # . . discard args + 528 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 529 # . write(_test-input-stream, "== data 0x1000\n") + 530 # . . push args + 531 68/push "== data 0x1000\n"/imm32 + 532 68/push _test-input-stream/imm32 + 533 # . . call + 534 e8/call write/disp32 + 535 # . . discard args + 536 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 537 # . write(_test-input-stream, "x:\n") + 538 # . . push args + 539 68/push "x:\n"/imm32 + 540 68/push _test-input-stream/imm32 + 541 # . . call + 542 e8/call write/disp32 + 543 # . . discard args + 544 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 545 # . write(_test-input-stream, "01\n") + 546 # . . push args + 547 68/push "01\n"/imm32 + 548 68/push _test-input-stream/imm32 + 549 # . . call + 550 e8/call write/disp32 + 551 # . . discard args + 552 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 553 # convert(_test-input-buffered-file, _test-output-buffered-file) + 554 # . . push args + 555 68/push _test-output-buffered-file/imm32 + 556 68/push _test-input-buffered-file/imm32 + 557 # . . call + 558 e8/call convert/disp32 + 559 # . . discard args + 560 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 561 # check trace + 562 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- + 588 # . check-trace-contains("label 'x' is at address 0x00001079.", msg) + 589 # . . push args + 590 68/push "F - test-convert-computes-addresses/0"/imm32 + 591 68/push "label 'x' is at address 0x00001079."/imm32 + 592 # . . call + 593 e8/call check-trace-contains/disp32 + 594 # . . discard args + 595 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 596 # . check-trace-contains("segment 'code' starts at address 0x00000074.", msg) + 597 # . . push args + 598 68/push "F - test-convert-computes-addresses/1"/imm32 + 599 68/push "segment 'code' starts at address 0x00000074."/imm32 + 600 # . . call + 601 e8/call check-trace-contains/disp32 + 602 # . . discard args + 603 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 604 # . check-trace-contains("segment 'code' has size 0x00000005.", msg) + 605 # . . push args + 606 68/push "F - test-convert-computes-addresses/2"/imm32 + 607 68/push "segment 'code' has size 0x00000005."/imm32 + 608 # . . call + 609 e8/call check-trace-contains/disp32 + 610 # . . discard args + 611 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 612 # . check-trace-contains("segment 'data' starts at address 0x00001079.", msg) + 613 # . . push args + 614 68/push "F - test-convert-computes-addresses/3"/imm32 + 615 68/push "segment 'data' starts at address 0x00001079."/imm32 + 616 # . . call + 617 e8/call check-trace-contains/disp32 + 618 # . . discard args + 619 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 620 # . epilog + 621 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 622 5d/pop-to-EBP + 623 c3/return + 624 + 625 # global scratch space for compute-offsets in the data segment + 626 == data + 627 + 628 compute-offsets:file-offset: # int + 629 0/imm32 + 630 compute-offsets:segment-offset: # int + 631 0/imm32 + 632 compute-offsets:word-slice: + 633 0/imm32/start + 634 0/imm32/end + 635 compute-offsets:segment-tmp: # slice + 636 0/imm32/start + 637 0/imm32/end + 638 + 639 == code + 640 + 641 compute-offsets: # in : (address stream), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) + 642 # skeleton: + 643 # for lines in 'in' + 644 # for words in line + 645 # switch word + 646 # case 1 + 647 # case 2 + 648 # ... + 649 # default + 650 # + 651 # pseudocode: + 652 # curr-segment-name : (address string) = 0 + 653 # var line = new-stream(512, 1) + 654 # while true # line loop + 655 # clear-stream(line) + 656 # read-line(in, line) + 657 # if (line->write == 0) break # end of file + 658 # while true # word loop + 659 # word-slice = next-word(line) + 660 # if slice-empty?(word-slice) # end of line + 661 # break + 662 # else if slice-starts-with?(word-slice, "#") # comment + 663 # break # end of line + 664 # else if slice-equal?(word-slice, "==") + 665 # if curr-segment-name != 0 + 666 # seg = get-or-insert(segments, curr-segment-name) + 667 # seg->size = *file-offset - seg->file-offset + 668 # trace("segment '", curr-segment-name, "' has size ", seg->size) + 669 # segment-tmp = next-word(line) + 670 # curr-segment-name = slice-to-string(segment-tmp) + 671 # if empty?(curr-segment-name) + 672 # abort + 673 # segment-tmp = next-word(line) + 674 # if slice-empty?(segment-tmp) + 675 # abort + 676 # seg = get-or-insert(segments, curr-segment-name) + 677 # seg->starting-address = parse-hex-int(segment-tmp) + 678 # seg->file-offset = *file-offset + 679 # trace("segment '", curr-segment-name, "' is at file offset ", seg->file-offset) + 680 # segment-offset = 0 + 681 # break (next line) + 682 # else if is-label?(word-slice) + 683 # strip trailing ':' from word-slice + 684 # x : (address label-info) = get-or-insert(labels, name) + 685 # x->segment-name = curr-segment-name + 686 # trace("label '", word-slice, "' is in segment '", curr-segment-name, "'.") + 687 # x->segment-offset = segment-offset + 688 # trace("label '", word-slice, "' is at segment offset ", segment-offset, ".") + 689 # # labels occupy no space, so no need to increment offsets + 690 # else + 691 # width = compute-width-of-slice(word-slice) + 692 # *segment-offset += width + 693 # *file-offset += width + 694 # + 695 # . prolog + 696 55/push-EBP + 697 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 698 # . save registers + 699 50/push-EAX + 700 51/push-ECX + 701 52/push-EDX + 702 53/push-EBX + 703 56/push-ESI + 704 57/push-EDI + 705 # curr-segment-name/ESI = 0 + 706 31/xor 3/mod/direct 6/rm32/ESI . . . 6/r32/ESI . . # clear ESI + 707 # file-offset = 0 + 708 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:file-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice + 709 # segment-offset = 0 + 710 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice + 711 # line/ECX = new-stream(512, 1) + 712 # . EAX = new-stream(512, 1) + 713 # . . push args + 714 68/push 1/imm32 + 715 68/push 0x200/imm32 + 716 68/push Heap/imm32 + 717 # . . call + 718 e8/call new-stream/disp32 + 719 # . . discard args + 720 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 721 # . line/ECX = EAX + 722 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX + 723 $compute-offsets:line-loop: + 724 # clear-stream(line/ECX) + 725 51/push-ECX + 726 e8/call clear-stream/disp32 + 727 # . discard args + 728 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 729 # read-line(in, line/ECX) + 730 51/push-ECX + 731 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 732 e8/call read-line/disp32 + 733 # . discard args + 734 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 735 # if (line->write == 0) break + 736 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX + 737 3d/compare-EAX-and 0/imm32 + 738 0f 84/jump-if-equal $compute-offsets:break-line-loop/disp32 + 739 +-- 33 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- + 772 $compute-offsets:word-loop: + 773 # EDX = word-slice + 774 ba/copy-to-EDX compute-offsets:word-slice/imm32 + 775 # next-word(line/ECX, word-slice/EDX) + 776 52/push-EDX + 777 51/push-ECX + 778 e8/call next-word/disp32 + 779 # . discard args + 780 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 781 +-- 80 lines: #? # dump word-slice and maybe curr-segment-name ------------------------------------------------------------------------------------------- + 861 $compute-offsets:case-empty: + 862 # if slice-empty?(word/EDX) break + 863 # . EAX = slice-empty?(word/EDX) + 864 52/push-EDX + 865 e8/call slice-empty?/disp32 + 866 # . . discard args + 867 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 868 # . if (EAX != 0) break + 869 3d/compare-EAX-and 0/imm32 + 870 0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32 + 871 $compute-offsets:case-comment: + 872 # if slice-starts-with?(word-slice, "#") continue + 873 68/push "#"/imm32 + 874 52/push-EDX + 875 e8/call slice-starts-with?/disp32 + 876 # . . discard args + 877 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 878 # . if (EAX != 0) break + 879 3d/compare-EAX-and 0/imm32 + 880 0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32 + 881 $compute-offsets:case-segment-header: + 882 # if (!slice-equal?(word-slice/EDX, "==")) goto next case + 883 # . EAX = slice-equal?(word-slice/EDX, "==") + 884 68/push "=="/imm32 + 885 52/push-EDX + 886 e8/call slice-equal?/disp32 + 887 # . . discard args + 888 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 889 # . if (EAX == 0) goto next case + 890 3d/compare-EAX-and 0/imm32 + 891 0f 84/jump-if-equal $compute-offsets:case-label/disp32 + 892 # if (curr-segment-name == 0) goto construct-next-segment + 893 81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI + 894 74/jump-if-equal $compute-offsets:construct-next-segment/disp8 + 895 # seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16) + 896 # . . push args + 897 68/push 0x10/imm32/row-size + 898 56/push-ESI + 899 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 900 # . . call + 901 e8/call get-or-insert/disp32 + 902 # . . discard args + 903 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 904 # seg->size = file-offset - seg->file-offset + 905 # . save ECX + 906 51/push-ECX + 907 # . EBX = *file-offset + 908 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX + 909 # . ECX = seg->file-offset + 910 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX + 911 # . EBX -= ECX + 912 29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX + 913 # . seg->size = EBX + 914 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8) + 915 # . restore ECX + 916 59/pop-to-ECX + 917 # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".") + 918 # . . push args + 919 68/push "."/imm32 + 920 53/push-EBX + 921 68/push "' has size "/imm32 + 922 56/push-ESI + 923 68/push "segment '"/imm32 + 924 # . . call + 925 e8/call trace-sssns/disp32 + 926 # . . discard args + 927 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP + 928 $compute-offsets:construct-next-segment: + 929 # next-word(line/ECX, segment-tmp) + 930 68/push compute-offsets:segment-tmp/imm32 + 931 51/push-ECX + 932 e8/call next-word/disp32 + 933 # . discard args + 934 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 935 +-- 47 lines: #? # dump curr-segment-name if not null (clobbering EAX) ----------------------------------------------------------------------------------- + 982 $compute-offsets:update-curr-segment-name: + 983 # curr-segment-name = slice-to-string(segment-tmp) + 984 # . EAX = slice-to-string(Heap, segment-tmp) + 985 # . . push args + 986 68/push compute-offsets:segment-tmp/imm32 + 987 68/push Heap/imm32 + 988 # . . call + 989 e8/call slice-to-string/disp32 + 990 # . . discard args + 991 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 992 # . curr-segment-name = EAX + 993 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI + 994 # if empty?(curr-segment-name) abort + 995 # . if (EAX == 0) abort + 996 3d/compare-EAX-and 0/imm32 + 997 0f 84/jump-if-equal $compute-offsets:abort/disp32 + 998 # next-word(line/ECX, segment-tmp) + 999 68/push compute-offsets:segment-tmp/imm32 +1000 51/push-ECX +1001 e8/call next-word/disp32 +1002 # . discard args +1003 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1004 # if slice-empty?(segment-tmp) abort +1005 # . EAX = slice-empty?(segment-tmp) +1006 68/push compute-offsets:segment-tmp/imm32 +1007 e8/call slice-empty?/disp32 +1008 # . . discard args +1009 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1010 # . if (EAX != 0) abort +1011 3d/compare-EAX-and 0/imm32 +1012 0f 85/jump-if-not-equal $compute-offsets:abort/disp32 +1013 # seg/EBX = get-or-insert(segments, curr-segment-name, row-size=16) +1014 # . . push args +1015 68/push 0x10/imm32/row-size +1016 56/push-ESI +1017 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +1018 # . . call +1019 e8/call get-or-insert/disp32 +1020 # . . discard args +1021 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1022 # . EBX = EAX +1023 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX +1024 # seg->address = parse-hex-int(segment-tmp) +1025 # . EAX = parse-hex-int(segment-tmp) +1026 68/push compute-offsets:segment-tmp/imm32 +1027 e8/call parse-hex-int/disp32 +1028 # . . discard args +1029 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1030 # . seg->address = EAX +1031 89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX +1032 # seg->file-offset = *file-offset +1033 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # copy *file-offset to EAX +1034 89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4) +1035 # trace-sssns("segment '", curr-segment-name, "' is at file offset ", seg->file-offset, "") +1036 # . . push args +1037 68/push "."/imm32 +1038 50/push-EAX +1039 68/push "' is at file offset "/imm32 +1040 56/push-ESI +1041 68/push "segment '"/imm32 +1042 # . . call +1043 e8/call trace-sssns/disp32 +1044 # . . discard args +1045 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1046 # segment-offset = 0 +1047 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *segment-offset +1048 # break +1049 e9/jump $compute-offsets:line-loop/disp32 +1050 $compute-offsets:case-label: +1051 # if (!is-label?(word-slice/EDX)) goto next case +1052 # . EAX = is-label?(word-slice/EDX) +1053 # . . push args +1054 52/push-EDX +1055 # . . call +1056 e8/call is-label?/disp32 +1057 # . . discard args +1058 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1059 # . if (EAX == 0) goto next case +1060 3d/compare-EAX-and 0/imm32 +1061 74/jump-if-equal $compute-offsets:case-default/disp8 +1062 # strip trailing ':' from word-slice +1063 ff 1/subop/decrement 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # decrement *(EDX+4) +1064 # x/EAX = leaky-get-or-insert-slice(labels, word-slice, row-size=16) +1065 # . . push args +1066 68/push 0x10/imm32/row-size +1067 52/push-EDX +1068 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +1069 # . . call +1070 e8/call leaky-get-or-insert-slice/disp32 +1071 # . . discard args +1072 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1073 $compute-offsets:save-label-offset: +1074 # x->segment-name = curr-segment-name +1075 89/copy 0/mod/indirect 0/rm32/EAX . . . 6/r32/ESI . . # copy ESI to *EAX +1076 # trace-slsss("label '" word-slice/EDX "' is in segment '" current-segment-name "'.") +1077 # . . push args +1078 68/push "'."/imm32 +1079 56/push-ESI +1080 68/push "' is in segment '"/imm32 +1081 52/push-EDX +1082 68/push "label '"/imm32 +1083 # . . call +1084 e8/call trace-slsss/disp32 +1085 # . . discard args +1086 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1087 # x->segment-offset = segment-offset +1088 # . EBX = segment-offset +1089 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:segment-offset/disp32 # copy *segment-offset to EBX +1090 # . x->segment-offset = EBX +1091 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 4/disp8 . # copy EBX to *(EAX+4) +1092 # trace-slsns("label '" word-slice/EDX "' is at segment offset " *segment-offset/EAX ".") +1093 # . . EAX = file-offset +1094 b8/copy-to-EAX compute-offsets:segment-offset/imm32 +1095 # . . EAX = *file-offset/EAX +1096 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX +1097 # . . push args +1098 68/push "."/imm32 +1099 50/push-EAX +1100 68/push "' is at segment offset "/imm32 +1101 52/push-EDX +1102 68/push "label '"/imm32 +1103 # . . call +1104 e8/call trace-slsns/disp32 +1105 # . . discard args +1106 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1107 # continue +1108 e9/jump $compute-offsets:word-loop/disp32 +1109 $compute-offsets:case-default: +1110 # width/EAX = compute-width-of-slice(word-slice) +1111 # . . push args +1112 52/push-EDX +1113 # . . call +1114 e8/call compute-width-of-slice/disp32 +1115 # . . discard args +1116 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +1117 # segment-offset += width +1118 01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:segment-offset/disp32 # add EAX to *segment-offset +1119 # file-offset += width +1120 01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # add EAX to *file-offset +1121 +-- 47 lines: #? # dump segment-offset ------------------------------------------------------------------------------------------------------------------- +1168 e9/jump $compute-offsets:word-loop/disp32 +1169 $compute-offsets:break-line-loop: +1170 # seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16) +1171 # . . push args +1172 68/push 0x10/imm32/row-size +1173 56/push-ESI +1174 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +1175 # . . call +1176 e8/call get-or-insert/disp32 +1177 # . . discard args +1178 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1179 # seg->size = file-offset - seg->file-offset +1180 # . save ECX +1181 51/push-ECX +1182 # . EBX = *file-offset +1183 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX +1184 # . ECX = seg->file-offset +1185 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX +1186 # . EBX -= ECX +1187 29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX +1188 # . seg->size = EBX +1189 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8) +1190 # . restore ECX +1191 59/pop-to-ECX +1192 # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".") +1193 # . trace-sssns("segment '", curr-segment-name, "' has size ", EBX, ".") +1194 # . . push args +1195 68/push "."/imm32 +1196 53/push-EBX +1197 68/push "' has size "/imm32 +1198 56/push-ESI +1199 68/push "segment '"/imm32 +1200 # . . call +1201 e8/call trace-sssns/disp32 +1202 # . . discard args +1203 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1204 $compute-offsets:end: +1205 # . reclaim locals +1206 # . restore registers +1207 5f/pop-to-EDI +1208 5e/pop-to-ESI +1209 5b/pop-to-EBX +1210 5a/pop-to-EDX +1211 59/pop-to-ECX +1212 58/pop-to-EAX +1213 # . epilog +1214 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1215 5d/pop-to-EBP +1216 c3/return +1217 1218 $compute-offsets:abort: 1219 # . _write(2/stderr, error) 1220 # . . push args @@ -863,7 +863,7 @@ if ('onhashchange' in window) { 1253 # setup 1254 # . clear-stream(_test-input-stream) 1255 # . . push args -1256 68/push _test-input-stream/imm32 +1256 68/push _test-input-stream/imm32 1257 # . . call 1258 e8/call clear-stream/disp32 1259 # . . discard args @@ -884,7 +884,7 @@ if ('onhashchange' in window) { 1274 # . write(_test-input-stream, "== code 0x1\n") 1275 # . . push args 1276 68/push "== code 0x1\n"/imm32 -1277 68/push _test-input-stream/imm32 +1277 68/push _test-input-stream/imm32 1278 # . . call 1279 e8/call write/disp32 1280 # . . discard args @@ -892,7 +892,7 @@ if ('onhashchange' in window) { 1282 # . write(_test-input-stream, "ab x/imm32 # skip comment\n") 1283 # . . push args 1284 68/push "ab x/imm32 # skip comment\n"/imm32 -1285 68/push _test-input-stream/imm32 +1285 68/push _test-input-stream/imm32 1286 # . . call 1287 e8/call write/disp32 1288 # . . discard args @@ -900,7 +900,7 @@ if ('onhashchange' in window) { 1290 # . write(_test-input-stream, "== data 0x1000\n") 1291 # . . push args 1292 68/push "== data 0x1000\n"/imm32 -1293 68/push _test-input-stream/imm32 +1293 68/push _test-input-stream/imm32 1294 # . . call 1295 e8/call write/disp32 1296 # . . discard args @@ -908,7 +908,7 @@ if ('onhashchange' in window) { 1298 # . write(_test-input-stream, "00\n") 1299 # . . push args 1300 68/push "00\n"/imm32 -1301 68/push _test-input-stream/imm32 +1301 68/push _test-input-stream/imm32 1302 # . . call 1303 e8/call write/disp32 1304 # . . discard args @@ -916,7 +916,7 @@ if ('onhashchange' in window) { 1306 # . write(_test-input-stream, "x:\n") 1307 # . . push args 1308 68/push "x:\n"/imm32 -1309 68/push _test-input-stream/imm32 +1309 68/push _test-input-stream/imm32 1310 # . . call 1311 e8/call write/disp32 1312 # . . discard args @@ -924,7 +924,7 @@ if ('onhashchange' in window) { 1314 # . write(_test-input-stream, "34\n") 1315 # . . push args 1316 68/push "34\n"/imm32 -1317 68/push _test-input-stream/imm32 +1317 68/push _test-input-stream/imm32 1318 # . . call 1319 e8/call write/disp32 1320 # . . discard args @@ -933,9 +933,9 @@ if ('onhashchange' in window) { 1323 # . . push args 1324 52/push-EDX 1325 51/push-ECX -1326 68/push _test-input-stream/imm32 +1326 68/push _test-input-stream/imm32 1327 # . . call -1328 e8/call compute-offsets/disp32 +1328 e8/call compute-offsets/disp32 1329 # . . discard args 1330 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP 1331 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- @@ -1020,7 +1020,7 @@ if ('onhashchange' in window) { 1435 # while true 1436 # if (lrow >= max) break 1437 # seg-name : (address string) = lrow->segment-name -1438 # label-seg : (address segment-info) = get(segments, seg-name, row-size=16) +1438 # label-seg : (address segment-info) = get(segments, seg-name) 1439 # lrow->address = label-seg->address + lrow->segment-offset 1440 # trace-sssns("label " lrow->key " is at address " lrow->address) 1441 # lrow += 16 # row-size @@ -1076,7 +1076,7 @@ if ('onhashchange' in window) { 1491 ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX 1492 68/push "segment '"/imm32 1493 # . . call -1494 e8/call trace-sssns/disp32 +1494 e8/call trace-sssns/disp32 1495 # . . discard args 1496 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP 1497 # srow += 16 # size of row @@ -1099,2633 +1099,2636 @@ if ('onhashchange' in window) { 1564 # seg-name/EDX = lrow->segment-name 1565 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 2/r32/EDX 4/disp8 . # copy *EAX to EDX 1566 +-- 26 lines: #? # dump seg-name ------------------------------------------------------------------------------------------------------------------------- -1592 # label-seg/EDX : (address segment-info) = get(segments, seg-name, row-size=16) +1592 # label-seg/EDX : (address segment-info) = get(segments, seg-name, row-size=16, "segment table") 1593 # . save EAX 1594 50/push-EAX 1595 # . EAX = get(segments, seg-name, row-size=16) 1596 # . . push args -1597 68/push 0x10/imm32/row-size -1598 52/push-EDX -1599 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1600 # . . call -1601 e8/call get/disp32 -1602 # . . discard args -1603 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1604 # . EDX = EAX -1605 89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX -1606 # . restore EAX -1607 58/pop-to-EAX -1608 # EBX = label-seg->address -1609 8b/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy *EDX to EBX -1610 # EBX += lrow->segment-offset -1611 03/add 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # add *(EAX+8) to EBX -1612 # lrow->address = EBX -1613 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 0xc/disp8 . # copy EBX to *(EAX+12) -1614 # trace-sssns("label " lrow->key " is at address " lrow->address ".") -1615 # . . push args -1616 68/push "."/imm32 -1617 53/push-EBX -1618 68/push "' is at address "/imm32 -1619 ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX -1620 68/push "label '"/imm32 -1621 # . . call -1622 e8/call trace-sssns/disp32 -1623 # . . discard args -1624 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1625 # lrow += 16 # size of row -1626 05/add-to-EAX 0x10/imm32 -1627 e9/jump $compute-addresses:label-loop/disp32 -1628 $compute-addresses:end: -1629 # . restore registers -1630 5f/pop-to-EDI -1631 5e/pop-to-ESI -1632 5b/pop-to-EBX -1633 5a/pop-to-EDX -1634 59/pop-to-ECX -1635 58/pop-to-EAX -1636 # . epilog -1637 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1638 5d/pop-to-EBP -1639 c3/return -1640 -1641 test-compute-addresses: -1642 # input: -1643 # segments: -1644 # - 'a': {0x1000, 0, 5} -1645 # - 'b': {0x2018, 5, 1} -1646 # - 'c': {0x5444, 6, 12} -1647 # labels: -1648 # - 'l1': {'a', 3, 0} -1649 # - 'l2': {'b', 0, 0} -1650 # -1651 # trace contains in any order (comments in parens): -1652 # segment 'a' starts at address 0x00001094. (0x34 + 0x20 for each segment) -1653 # segment 'b' starts at address 0x00002099. (0x018 discarded) -1654 # segment 'c' starts at address 0x0000509a. (0x444 discarded) -1655 # label 'l1' is at address 0x00001097. (0x1094 + segment-offset 3) -1656 # label 'l2' is at address 0x00002099. (0x2099 + segment-offset 0) -1657 # -1658 # . prolog -1659 55/push-EBP -1660 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1661 # setup -1662 # . var segments/ECX = stream(10 * 16) -1663 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP -1664 68/push 0xa0/imm32/length -1665 68/push 0/imm32/read -1666 68/push 0/imm32/write -1667 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1668 # . var labels/EDX = stream(512 * 16) -1669 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP -1670 68/push 0x2000/imm32/length -1671 68/push 0/imm32/read -1672 68/push 0/imm32/write -1673 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -1674 # . stream-add4(segments, "a", 0x1000, 0, 5) -1675 68/push 5/imm32/segment-size -1676 68/push 0/imm32/file-offset -1677 68/push 0x1000/imm32/start-address -1678 68/push "a"/imm32/segment-name -1679 51/push-ECX -1680 # . . call -1681 e8/call stream-add4/disp32 -1682 # . . discard args -1683 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1684 # . stream-add4(segments, "b", 0x2018, 5, 1) -1685 68/push 1/imm32/segment-size -1686 68/push 5/imm32/file-offset -1687 68/push 0x2018/imm32/start-address -1688 68/push "b"/imm32/segment-name -1689 51/push-ECX -1690 # . . call -1691 e8/call stream-add4/disp32 -1692 # . . discard args -1693 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1694 # . stream-add4(segments, "c", 0x5444, 6, 12) -1695 68/push 0xc/imm32/segment-size -1696 68/push 6/imm32/file-offset -1697 68/push 0x5444/imm32/start-address -1698 68/push "c"/imm32/segment-name -1699 51/push-ECX -1700 # . . call -1701 e8/call stream-add4/disp32 -1702 # . . discard args -1703 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1704 # . stream-add4(labels, "l1", "a", 3, 0) -1705 68/push 0/imm32/label-address -1706 68/push 3/imm32/segment-offset -1707 68/push "a"/imm32/segment-name -1708 68/push "l1"/imm32/label-name -1709 52/push-EDX -1710 # . . call -1711 e8/call stream-add4/disp32 -1712 # . . discard args -1713 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1714 # . stream-add4(labels, "l2", "b", 0, 0) -1715 68/push 0/imm32/label-address -1716 68/push 0/imm32/segment-offset -1717 68/push "b"/imm32/segment-name -1718 68/push "l2"/imm32/label-name -1719 52/push-EDX -1720 # . . call -1721 e8/call stream-add4/disp32 -1722 # . . discard args -1723 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1724 # component under test -1725 # . compute-addresses(segments, labels) -1726 # . . push args -1727 52/push-EDX -1728 51/push-ECX -1729 # . . call -1730 e8/call compute-addresses/disp32 -1731 # . . discard args -1732 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1733 # checks -1734 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- -1760 # . check-trace-contains("segment 'a' starts at address 0x00001094.", msg) -1761 # . . push args -1762 68/push "F - test-compute-addresses/0"/imm32 -1763 68/push "segment 'a' starts at address 0x00001094."/imm32 -1764 # . . call -1765 e8/call check-trace-contains/disp32 -1766 # . . discard args -1767 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1768 # . check-trace-contains("segment 'b' starts at address 0x00002099.", msg) -1769 # . . push args -1770 68/push "F - test-compute-addresses/1"/imm32 -1771 68/push "segment 'b' starts at address 0x00002099."/imm32 -1772 # . . call -1773 e8/call check-trace-contains/disp32 -1774 # . . discard args -1775 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1776 # . check-trace-contains("segment 'c' starts at address 0x0000509a.", msg) -1777 # . . push args -1778 68/push "F - test-compute-addresses/2"/imm32 -1779 68/push "segment 'c' starts at address 0x0000509a."/imm32 -1780 # . . call -1781 e8/call check-trace-contains/disp32 -1782 # . . discard args -1783 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1784 # . check-trace-contains("label 'l1' is at address 0x00001097.", msg) -1785 # . . push args -1786 68/push "F - test-compute-addresses/3"/imm32 -1787 68/push "label 'l1' is at address 0x00001097."/imm32 -1788 # . . call -1789 e8/call check-trace-contains/disp32 -1790 # . . discard args -1791 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1792 # . check-trace-contains("label 'l2' is at address 0x00002099.", msg) -1793 # . . push args -1794 68/push "F - test-compute-addresses/4"/imm32 -1795 68/push "label 'l2' is at address 0x00002099."/imm32 -1796 # . . call -1797 e8/call check-trace-contains/disp32 -1798 # . . discard args -1799 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1800 # . check-ints-equal(labels->write, 0x20, msg) -1801 # . . push args -1802 68/push "F - test-compute-addresses/maintains-labels-write-index"/imm32 -1803 68/push 0x20/imm32/2-entries -1804 ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX -1805 # . . call -1806 e8/call check-ints-equal/disp32 -1807 # . . discard args -1808 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1809 # . epilog -1810 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1811 5d/pop-to-EBP -1812 c3/return -1813 -1814 test-compute-addresses-large-segments: -1815 # input: -1816 # segments: -1817 # - 'a': {0x1000, 0, 0x5604} -1818 # - 'b': {0x2018, 0x5604, 1} -1819 # labels: -1820 # - 'l1': {'a', 3, 0} -1821 # -1822 # trace contains in any order (comments in parens): -1823 # segment 'a' starts at address 0x00001074. (0x34 + 0x20 for each segment) -1824 # segment 'b' starts at address 0x00002678. (0x018 discarded; last 3 nibbles from 0x1074 + 0x5604) -1825 # label 'l1' is at address 0x00001077. (0x1074 + segment-offset 3) -1826 # -1827 # . prolog -1828 55/push-EBP -1829 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1830 # setup -1831 # . var segments/ECX = stream(10 * 16) -1832 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP -1833 68/push 0xa0/imm32/length -1834 68/push 0/imm32/read -1835 68/push 0/imm32/write -1836 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -1837 # . var labels/EDX = stream(512 * 16) -1838 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP -1839 68/push 0x2000/imm32/length -1840 68/push 0/imm32/read -1841 68/push 0/imm32/write -1842 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -1843 # . stream-add4(segments, "a", 0x1000, 0, 0x5604) -1844 68/push 0x5604/imm32/segment-size -1845 68/push 0/imm32/file-offset -1846 68/push 0x1000/imm32/start-address -1847 68/push "a"/imm32/segment-name -1848 51/push-ECX -1849 # . . call -1850 e8/call stream-add4/disp32 -1851 # . . discard args -1852 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1853 # . stream-add4(segments, "b", 0x2018, 0x5604, 1) -1854 68/push 1/imm32/segment-size -1855 68/push 0x5604/imm32/file-offset -1856 68/push 0x2018/imm32/start-address -1857 68/push "b"/imm32/segment-name -1858 51/push-ECX -1859 # . . call -1860 e8/call stream-add4/disp32 -1861 # . . discard args -1862 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1863 # . stream-add4(labels, "l1", "a", 3, 0) -1864 68/push 0/imm32/label-address -1865 68/push 3/imm32/segment-offset -1866 68/push "a"/imm32/segment-name -1867 68/push "l1"/imm32/label-name -1868 52/push-EDX -1869 # . . call -1870 e8/call stream-add4/disp32 -1871 # . . discard args -1872 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -1873 # component under test -1874 # . compute-addresses(segments, labels) -1875 # . . push args -1876 52/push-EDX -1877 51/push-ECX -1878 # . . call -1879 e8/call compute-addresses/disp32 -1880 # . . discard args -1881 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1882 # checks -1883 # . check-trace-contains("segment 'a' starts at address 0x00001074.", msg) -1884 # . . push args -1885 68/push "F - test-compute-addresses-large-segments/0"/imm32 -1886 68/push "segment 'a' starts at address 0x00001074."/imm32 -1887 # . . call -1888 e8/call check-trace-contains/disp32 -1889 # . . discard args -1890 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1891 # . check-trace-contains("segment 'b' starts at address 0x00002678.", msg) -1892 # . . push args -1893 68/push "F - test-compute-addresses-large-segments/1"/imm32 -1894 68/push "segment 'b' starts at address 0x00002678."/imm32 -1895 # . . call -1896 e8/call check-trace-contains/disp32 -1897 # . . discard args -1898 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1899 # . check-trace-contains("label 'l1' is at address 0x00001077.", msg) -1900 # . . push args -1901 68/push "F - test-compute-addresses-large-segments/3"/imm32 -1902 68/push "label 'l1' is at address 0x00001077."/imm32 -1903 # . . call -1904 e8/call check-trace-contains/disp32 -1905 # . . discard args -1906 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -1907 # . epilog -1908 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1909 5d/pop-to-EBP -1910 c3/return -1911 -1912 emit-output: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) -1913 # pseudocode: -1914 # emit-headers(out, segments, labels) -1915 # emit-segments(in, out, segments, labels) -1916 # -1917 # . prolog -1918 55/push-EBP -1919 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -1920 +-- 9 lines: #? # write(2/stderr, "emit-headers\n") ----------------------------------------------------------------------------------------------------- -1929 # emit-headers(out, segments, labels) -1930 # . . push args -1931 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -1932 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -1933 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -1934 # . . call -1935 e8/call emit-headers/disp32 -1936 # . . discard args -1937 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -1938 +-- 9 lines: #? # write(2/stderr, "emit-segments\n") ---------------------------------------------------------------------------------------------------- -1947 # emit-segments(in, out, segments, labels) -1948 # . . push args -1949 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -1950 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -1951 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -1952 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -1953 # . . call -1954 e8/call emit-segments/disp32 -1955 # . . discard args -1956 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -1957 $emit-output:end: -1958 # . epilog -1959 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -1960 5d/pop-to-EBP -1961 c3/return -1962 -1963 emit-segments: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) -1964 # pseudocode: -1965 # var offset-of-next-instruction = 0 -1966 # var line = new-stream(512, 1) -1967 # line-loop: -1968 # while true -1969 # clear-stream(line) -1970 # read-line(in, line) -1971 # if (line->write == 0) break # end of file -1972 # offset-of-next-instruction += num-bytes(line) -1973 # while true -1974 # var word-slice = next-word(line) -1975 # if slice-empty?(word-slice) # end of line -1976 # break -1977 # if slice-starts-with?(word-slice, "#") # comment -1978 # break -1979 # if is-label?(word-slice) # no need for label declarations anymore -1980 # goto line-loop # don't insert empty lines -1981 # if slice-equal?(word-slice, "==") # no need for segment header lines -1982 # goto line-loop # don't insert empty lines -1983 # if length(word-slice) == 2 -1984 # write-slice-buffered(out, word-slice) -1985 # write-buffered(out, " ") -1986 # continue -1987 # datum = next-token-from-slice(word-slice->start, word-slice->end, "/") -1988 # info = get-slice(labels, datum) -1989 # if !string-equal?(info->segment-name, "code") -1990 # if has-metadata?(word-slice, "disp8") -1991 # abort -1992 # if has-metadata?(word-slice, "imm8") -1993 # abort -1994 # emit(out, info->address, 4) # global variables always translate to absolute addresses -1995 # # code segment cases -1996 # else if has-metadata?(word-slice, "imm8") -1997 # abort # label should never go to imm8 -1998 # else if has-metadata?(word-slice, "imm32") -1999 # emit(out, info->address, 4) -2000 # else if has-metadata?(word-slice, "disp8") -2001 # value = info->offset - offset-of-next-instruction -2002 # emit(out, value, 1) -2003 # else if has-metadata?(word-slice, "disp32") -2004 # value = info->offset - offset-of-next-instruction -2005 # emit(out, value, 4) -2006 # else -2007 # abort -2008 # write-buffered(out, "\n") -2009 # -2010 # registers: -2011 # line: ECX -2012 # word-slice: EDX -2013 # offset-of-next-instruction: EBX -2014 # datum: EDI -2015 # info: ESI (inner loop only) -2016 # temporaries: EAX, ESI (outer loop) -2017 # -2018 # . prolog -2019 55/push-EBP -2020 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2021 # . save registers -2022 50/push-EAX -2023 51/push-ECX -2024 52/push-EDX -2025 53/push-EBX -2026 56/push-ESI -2027 57/push-EDI -2028 # var line/ECX : (address stream byte) = stream(512) -2029 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP -2030 68/push 0x200/imm32/length -2031 68/push 0/imm32/read -2032 68/push 0/imm32/write -2033 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2034 # var word-slice/EDX = {0, 0} -2035 68/push 0/imm32/end -2036 68/push 0/imm32/start -2037 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -2038 # var datum/EDI = {0, 0} -2039 68/push 0/imm32/end -2040 68/push 0/imm32/start -2041 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI -2042 # offset-of-next-instruction/EBX = 0 -2043 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX -2044 $emit-segments:line-loop: -2045 # clear-stream(line) -2046 # . . push args -2047 51/push-ECX -2048 # . . call -2049 e8/call clear-stream/disp32 -2050 # . . discard args -2051 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2052 # read-line(in, line) -2053 # . . push args -2054 51/push-ECX -2055 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -2056 # . . call -2057 e8/call read-line/disp32 -2058 # . . discard args -2059 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2060 +-- 33 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- -2093 $emit-segments:check-for-end-of-input: -2094 # if (line->write == 0) break -2095 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX -2096 0f 84/jump-if-equal $emit-segments:end/disp32 -2097 # offset-of-next-instruction += num-bytes(line) -2098 # . EAX = num-bytes(line) -2099 # . . push args -2100 51/push-ECX -2101 # . . call -2102 e8/call num-bytes/disp32 -2103 # . . discard args -2104 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2105 # . EBX += EAX -2106 01/add 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # add EAX to EBX -2107 $emit-segments:word-loop: -2108 # next-word(line, word-slice) -2109 # . . push args -2110 52/push-EDX -2111 51/push-ECX -2112 # . . call -2113 e8/call next-word/disp32 -2114 # . . discard args -2115 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2116 +-- 33 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- -2149 $emit-segments:check-for-end-of-line: -2150 # if (slice-empty?(word-slice)) break -2151 # . EAX = slice-empty?(word-slice) -2152 # . . push args -2153 52/push-EDX -2154 # . . call -2155 e8/call slice-empty?/disp32 -2156 # . . discard args -2157 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2158 # . if (EAX != 0) break -2159 3d/compare-EAX-and 0/imm32 -2160 0f 85/jump-if-not-equal $emit-segments:next-line/disp32 -2161 $emit-segments:check-for-comment: -2162 # if (slice-starts-with?(word-slice, "#")) break -2163 # . start/ESI = word-slice->start -2164 8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *EDX to ESI -2165 # . c/EAX = *start -2166 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -2167 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL -2168 # . if (EAX == '#') break -2169 3d/compare-EAX-and 0x23/imm32/hash -2170 0f 84/jump-if-equal $emit-segments:next-line/disp32 -2171 $emit-segments:check-for-label: -2172 # if is-label?(word-slice) break -2173 # . EAX = is-label?(word-slice) -2174 # . . push args -2175 52/push-EDX -2176 # . . call -2177 e8/call is-label?/disp32 -2178 # . . discard args -2179 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2180 # . if (EAX != 0) break -2181 3d/compare-EAX-and 0/imm32 -2182 0f 85/jump-if-not-equal $emit-segments:line-loop/disp32 -2183 $emit-segments:check-for-segment-header: -2184 # if (slice-equal?(word-slice, "==")) break -2185 # . EAX = slice-equal?(word-slice, "==") -2186 # . . push args -2187 68/push "=="/imm32 -2188 52/push-EDX -2189 # . . call -2190 e8/call slice-equal?/disp32 -2191 # . . discard args -2192 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2193 # . if (EAX != 0) break -2194 3d/compare-EAX-and 0/imm32 -2195 0f 85/jump-if-not-equal $emit-segments:line-loop/disp32 -2196 $emit-segments:2-character: -2197 # if (length(word-slice) != 2) goto next check -2198 # . EAX = length(word-slice) -2199 8b/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy *(EDX+4) to EAX -2200 2b/subtract 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # subtract *EDX from EAX -2201 # . if (EAX != 2) goto next check -2202 3d/compare-EAX-and 2/imm32 -2203 75/jump-if-not-equal $emit-segments:check-metadata/disp8 -2204 # write-slice-buffered(out, word-slice) -2205 # . . push args -2206 52/push-EDX -2207 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -2208 # . . call -2209 e8/call write-slice-buffered/disp32 -2210 # . . discard args -2211 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2212 # write-buffered(out, " ") -2213 # . . push args -2214 68/push " "/imm32 -2215 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -2216 # . . call -2217 e8/call write-buffered/disp32 -2218 # . . discard args -2219 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2220 # continue -2221 e9/jump $emit-segments:word-loop/disp32 -2222 $emit-segments:check-metadata: -2223 # - if we get here, 'word-slice' must be a label to be looked up -2224 # datum/EDI = next-token-from-slice(word-slice->start, word-slice->end, "/") -2225 # . . push args -2226 57/push-EDI -2227 68/push 0x2f/imm32/slash -2228 ff 6/subop/push 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # push *(EDX+4) -2229 ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX -2230 # . . call -2231 e8/call next-token-from-slice/disp32 -2232 # . . discard args -2233 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -2234 +-- 33 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- -2267 # info/ESI = get-slice(labels, datum, row-size=16) -2268 # . EAX = get-slice(labels, datum, row-size=16) -2269 # . . push args -2270 68/push 0x10/imm32/row-size -2271 57/push-EDI -2272 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -2273 # . . call -2274 e8/call get-slice/disp32 -2275 # . . discard args -2276 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2277 # . ESI = EAX -2278 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI -2279 $emit-segments:check-global-variable: -2280 +-- 26 lines: #? # dump info->segment-name --------------------------------------------------------------------------------------------------------------- -2306 # if string-equal?(info->segment-name, "code") goto code label checks -2307 # . EAX = string-equal?(info->segment-name, "code") -2308 # . . push args -2309 68/push "code"/imm32 -2310 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI -2311 # . . call -2312 e8/call string-equal?/disp32 -2313 # . . discard args -2314 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2315 # . if (EAX != 0) goto code label checks -2316 3d/compare-EAX-and 0/imm32 -2317 0f 85/jump-if-not-equal $emit-segments:check-code-label-for-imm8/disp32 -2318 $emit-segments:check-global-variable-for-disp8: -2319 # if has-metadata?(word-slice, "disp8") abort -2320 # . EAX = has-metadata?(word-slice, "disp8") -2321 # . . push args -2322 68/push "disp8"/imm32 -2323 52/push-EDX -2324 # . . call -2325 e8/call has-metadata?/disp32 -2326 # . . discard args -2327 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2328 # . if (EAX != 0) abort -2329 3d/compare-EAX-and 0/imm32 -2330 0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32 -2331 $emit-segments:check-global-variable-for-imm8: -2332 # if has-metadata?(word-slice, "imm8") abort -2333 # . EAX = has-metadata?(word-slice, "imm8") -2334 # . . push args -2335 68/push "imm8"/imm32 -2336 52/push-EDX -2337 # . . call -2338 e8/call has-metadata?/disp32 -2339 # . . discard args -2340 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2341 # . if (EAX != 0) abort -2342 3d/compare-EAX-and 0/imm32 -2343 0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32 -2344 $emit-segments:emit-global-variable: -2345 # emit-hex(out, info->address, 4) -2346 # . . push args -2347 68/push 4/imm32 -2348 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8) -2349 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -2350 # . . call -2351 e8/call emit-hex/disp32 -2352 # . . discard args -2353 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2354 # continue -2355 e9/jump $emit-segments:word-loop/disp32 -2356 $emit-segments:check-code-label-for-imm8: -2357 # if (has-metadata?(word-slice, "imm8")) abort -2358 # . EAX = has-metadata?(EDX, "imm8") -2359 # . . push args -2360 68/push "imm8"/imm32 -2361 52/push-EDX -2362 # . . call -2363 e8/call has-metadata?/disp32 -2364 # . . discard args -2365 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2366 # . if (EAX != 0) abort -2367 3d/compare-EAX-and 0/imm32 -2368 0f 85/jump-if-not-equal $emit-segments:imm8-abort/disp32 -2369 $emit-segments:check-code-label-for-imm32: -2370 # if (!has-metadata?(word-slice, "imm32")) goto next check -2371 # . EAX = has-metadata?(EDX, "imm32") -2372 # . . push args -2373 68/push "imm32"/imm32 -2374 52/push-EDX -2375 # . . call -2376 e8/call has-metadata?/disp32 -2377 # . . discard args -2378 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2379 # . if (EAX == 0) goto next check -2380 3d/compare-EAX-and 0/imm32 -2381 74/jump-if-equal $emit-segments:check-code-label-for-disp8/disp8 -2382 +-- 33 lines: #? # dump info->address -------------------------------------------------------------------------------------------------------------------- -2415 $emit-segments:emit-code-label-imm32: -2416 # emit-hex(out, info->address, 4) -2417 # . . push args -2418 68/push 4/imm32 -2419 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8) -2420 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -2421 # . . call -2422 e8/call emit-hex/disp32 -2423 # . . discard args -2424 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2425 # continue -2426 e9/jump $emit-segments:word-loop/disp32 -2427 $emit-segments:check-code-label-for-disp8: -2428 # if (!has-metadata?(word-slice, "disp8")) goto next check -2429 # . EAX = has-metadata?(EDX, "disp8") -2430 # . . push args -2431 68/push "disp8"/imm32 -2432 52/push-EDX -2433 # . . call -2434 e8/call has-metadata?/disp32 -2435 # . . discard args -2436 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2437 # . if (EAX == 0) goto next check -2438 3d/compare-EAX-and 0/imm32 -2439 74/jump-if-equal $emit-segments:check-code-label-for-disp32/disp8 -2440 $emit-segments:emit-code-label-disp8: -2441 # emit-hex(out, info->offset - offset-of-next-instruction, 1) -2442 # . . push args -2443 68/push 1/imm32 -2444 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX -2445 29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX -2446 50/push-EAX -2447 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -2448 # . . call -2449 e8/call emit-hex/disp32 -2450 # . . discard args -2451 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2452 # continue -2453 e9/jump $emit-segments:word-loop/disp32 -2454 $emit-segments:check-code-label-for-disp32: -2455 # if (!has-metadata?(word-slice, "disp32")) abort -2456 # . EAX = has-metadata?(EDX, "disp32") -2457 # . . push args -2458 68/push "disp32"/imm32 -2459 52/push-EDX -2460 # . . call -2461 e8/call has-metadata?/disp32 -2462 # . . discard args -2463 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2464 # . if (EAX == 0) abort -2465 3d/compare-EAX-and 0/imm32 -2466 0f 84/jump-if-equal $emit-segments:abort/disp32 -2467 $emit-segments:emit-code-label-disp32: -2468 # emit-hex(out, info->offset - offset-of-next-instruction, 4) -2469 # . . push args -2470 68/push 4/imm32 -2471 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX -2472 29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX -2473 50/push-EAX -2474 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -2475 # . . call -2476 e8/call emit-hex/disp32 -2477 # . . discard args -2478 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2479 # continue -2480 e9/jump $emit-segments:word-loop/disp32 -2481 $emit-segments:next-line: -2482 # write-buffered(out, "\n") -2483 # . . push args -2484 68/push Newline/imm32 -2485 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -2486 # . . call -2487 e8/call write-buffered/disp32 -2488 # . . discard args -2489 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2490 # loop -2491 e9/jump $emit-segments:line-loop/disp32 -2492 $emit-segments:end: -2493 # . reclaim locals -2494 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x21c/imm32 # add to ESP -2495 # . restore registers -2496 5f/pop-to-EDI -2497 5e/pop-to-ESI -2498 5b/pop-to-EBX -2499 5a/pop-to-EDX -2500 59/pop-to-ECX -2501 58/pop-to-EAX -2502 # . epilog -2503 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2504 5d/pop-to-EBP -2505 c3/return -2506 -2507 $emit-segments:global-variable-abort: -2508 # . _write(2/stderr, error) -2509 # . . push args -2510 68/push "emit-segments: must refer to global variables with /disp32 or /imm32"/imm32 -2511 68/push 2/imm32/stderr -2512 # . . call -2513 e8/call _write/disp32 -2514 # . . discard args -2515 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2516 # . syscall(exit, 1) -2517 bb/copy-to-EBX 1/imm32 -2518 b8/copy-to-EAX 1/imm32/exit -2519 cd/syscall 0x80/imm8 -2520 # never gets here -2521 -2522 $emit-segments:imm8-abort: -2523 # . _write(2/stderr, error) -2524 # . . push args -2525 68/push "emit-segments: cannot refer to code labels with /imm8"/imm32 -2526 68/push 2/imm32/stderr -2527 # . . call -2528 e8/call _write/disp32 -2529 # . . discard args -2530 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2531 # . syscall(exit, 1) -2532 bb/copy-to-EBX 1/imm32 -2533 b8/copy-to-EAX 1/imm32/exit -2534 cd/syscall 0x80/imm8 -2535 # never gets here -2536 -2537 $emit-segments:abort: -2538 # print(stderr, "missing metadata in " word-slice) -2539 # . _write(2/stderr, "missing metadata in word ") -2540 # . . push args -2541 68/push "emit-segments: missing metadata in "/imm32 -2542 68/push 2/imm32/stderr -2543 # . . call -2544 e8/call _write/disp32 -2545 # . . discard args -2546 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2547 # . write-slice-buffered(Stderr, word-slice) -2548 # . . push args -2549 52/push-EDX -2550 68/push Stderr/imm32 -2551 # . . call -2552 e8/call write-slice-buffered/disp32 -2553 # . . discard args -2554 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2555 # . flush(Stderr) -2556 # . . push args -2557 68/push Stderr/imm32 -2558 # . . call -2559 e8/call flush/disp32 -2560 # . . discard args -2561 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2562 # . syscall(exit, 1) -2563 bb/copy-to-EBX 1/imm32 -2564 b8/copy-to-EAX 1/imm32/exit -2565 cd/syscall 0x80/imm8 -2566 # never gets here -2567 -2568 test-emit-segments-global-variable: -2569 # global variables always convert to absolute addresses, regardless of metadata -2570 # -2571 # input: -2572 # in: -2573 # == code 0x1000 -2574 # ab cd ef gh -2575 # ij x/disp32 -2576 # == data 0x2000 -2577 # 00 -2578 # x: -2579 # 34 -2580 # segments: -2581 # - 'code': {0x1074, 0, 9} -2582 # - 'data': {0x2079, 5, 2} -2583 # labels: -2584 # - 'x': {'data', 1, 0x207a} -2585 # -2586 # output: -2587 # ab cd ef gh -2588 # ij 7a 20 00 00 -2589 # 00 -2590 # 34 -2591 # -2592 # . prolog -2593 55/push-EBP -2594 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2595 # setup -2596 # . clear-stream(_test-input-stream) -2597 # . . push args -2598 68/push _test-input-stream/imm32 -2599 # . . call -2600 e8/call clear-stream/disp32 -2601 # . . discard args -2602 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2603 # . clear-stream(_test-output-stream) -2604 # . . push args -2605 68/push _test-output-stream/imm32 -2606 # . . call -2607 e8/call clear-stream/disp32 -2608 # . . discard args -2609 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2610 # . clear-stream(_test-output-buffered-file+4) -2611 # . . push args -2612 b8/copy-to-EAX _test-output-buffered-file/imm32 -2613 05/add-to-EAX 4/imm32 -2614 50/push-EAX -2615 # . . call -2616 e8/call clear-stream/disp32 -2617 # . . discard args -2618 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2619 # . var segments/ECX = stream(10 * 16) -2620 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP -2621 68/push 0xa0/imm32/length -2622 68/push 0/imm32/read -2623 68/push 0/imm32/write -2624 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2625 # . var labels/EDX = stream(512 * 16) -2626 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP -2627 68/push 0x2000/imm32/length -2628 68/push 0/imm32/read -2629 68/push 0/imm32/write -2630 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -2631 # initialize input -2632 # . write(_test-input-stream, "== code 0x1000\n") -2633 # . . push args -2634 68/push "== code 0x1000\n"/imm32 -2635 68/push _test-input-stream/imm32 -2636 # . . call -2637 e8/call write/disp32 -2638 # . . discard args -2639 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2640 # . write(_test-input-stream, "ab cd ef gh\n") -2641 # . . push args -2642 68/push "ab cd ef gh\n"/imm32 -2643 68/push _test-input-stream/imm32 -2644 # . . call -2645 e8/call write/disp32 -2646 # . . discard args -2647 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2648 # . write(_test-input-stream, "ij x/disp32\n") -2649 # . . push args -2650 68/push "ij x/disp32\n"/imm32 -2651 68/push _test-input-stream/imm32 -2652 # . . call -2653 e8/call write/disp32 -2654 # . . discard args -2655 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2656 # . write(_test-input-stream, "== data 0x2000\n") -2657 # . . push args -2658 68/push "== data 0x2000\n"/imm32 -2659 68/push _test-input-stream/imm32 -2660 # . . call -2661 e8/call write/disp32 -2662 # . . discard args -2663 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2664 # . write(_test-input-stream, "00\n") -2665 # . . push args -2666 68/push "00\n"/imm32 -2667 68/push _test-input-stream/imm32 -2668 # . . call -2669 e8/call write/disp32 -2670 # . . discard args -2671 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2672 # . write(_test-input-stream, "x:\n") -2673 # . . push args -2674 68/push "x:\n"/imm32 -2675 68/push _test-input-stream/imm32 -2676 # . . call -2677 e8/call write/disp32 -2678 # . . discard args -2679 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2680 # . write(_test-input-stream, "34\n") -2681 # . . push args -2682 68/push "34\n"/imm32 -2683 68/push _test-input-stream/imm32 -2684 # . . call -2685 e8/call write/disp32 -2686 # . . discard args -2687 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2688 # . stream-add4(segments, "code", 0x1074, 0, 9) -2689 68/push 9/imm32/segment-size -2690 68/push 0/imm32/file-offset -2691 68/push 0x1074/imm32/start-address -2692 68/push "code"/imm32/segment-name -2693 51/push-ECX -2694 # . . call -2695 e8/call stream-add4/disp32 -2696 # . . discard args -2697 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -2698 # . stream-add4(segments, "data", 0x2079, 5, 2) -2699 68/push 1/imm32/segment-size -2700 68/push 5/imm32/file-offset -2701 68/push 0x2079/imm32/start-address -2702 68/push "data"/imm32/segment-name -2703 51/push-ECX -2704 # . . call -2705 e8/call stream-add4/disp32 -2706 # . . discard args -2707 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -2708 # . stream-add4(labels, "x", "data", 1, 0x207a) -2709 68/push 0x207a/imm32/label-address -2710 68/push 1/imm32/segment-offset -2711 68/push "data"/imm32/segment-name -2712 68/push "x"/imm32/label-name -2713 52/push-EDX -2714 # . . call -2715 e8/call stream-add4/disp32 -2716 # . . discard args -2717 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -2718 # component under test -2719 # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) -2720 # . . push args -2721 52/push-EDX -2722 51/push-ECX -2723 68/push _test-output-buffered-file/imm32 -2724 68/push _test-input-stream/imm32 -2725 # . . call -2726 e8/call emit-segments/disp32 -2727 # . . discard args -2728 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -2729 # checks -2730 # . flush(_test-output-buffered-file) -2731 # . . push args -2732 68/push _test-output-buffered-file/imm32 -2733 # . . call -2734 e8/call flush/disp32 -2735 # . . discard args -2736 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2737 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -2770 # . check-next-stream-line-equal(_test-output-stream, "ab cd ef gh ", msg) -2771 # . . push args -2772 68/push "F - test-emit-segments-global-variable/0"/imm32 -2773 68/push "ab cd ef gh "/imm32 -2774 68/push _test-output-stream/imm32 -2775 # . . call -2776 e8/call check-next-stream-line-equal/disp32 -2777 # . . discard args -2778 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2779 # . check-next-stream-line-equal(_test-output-stream, "ij 7a 20 00 00 ", msg) -2780 # . . push args -2781 68/push "F - test-emit-segments-global-variable/1"/imm32 -2782 68/push "ij 7a 20 00 00 "/imm32 -2783 68/push _test-output-stream/imm32 -2784 # . . call -2785 e8/call check-next-stream-line-equal/disp32 -2786 # . . discard args -2787 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2788 # . check-next-stream-line-equal(_test-output-stream, "00 ", msg) -2789 # . . push args -2790 68/push "F - test-emit-segments-global-variable/2"/imm32 -2791 68/push "00 "/imm32 -2792 68/push _test-output-stream/imm32 -2793 # . . call -2794 e8/call check-next-stream-line-equal/disp32 -2795 # . . discard args -2796 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2797 # . check-next-stream-line-equal(_test-output-stream, "34 ", msg) -2798 # . . push args -2799 68/push "F - test-emit-segments-global-variable/3"/imm32 -2800 68/push "34 "/imm32 -2801 68/push _test-output-stream/imm32 -2802 # . . call -2803 e8/call check-next-stream-line-equal/disp32 -2804 # . . discard args -2805 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2806 # . epilog -2807 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -2808 5d/pop-to-EBP -2809 c3/return -2810 -2811 test-emit-segments-code-label: -2812 # labels usually convert to displacements -2813 # -2814 # input: -2815 # in: -2816 # == code 0x1000 -2817 # ab cd -2818 # l1: -2819 # ef gh -2820 # ij l1/disp32 -2821 # segments: -2822 # - 'code': {0x1054, 0, 9} -2823 # labels: -2824 # - 'l1': {'code', 2, 0x1056} -2825 # -2826 # output: -2827 # ab cd -2828 # ef gh -2829 # ij f9 ff ff ff # -7 -2830 # -2831 # . prolog -2832 55/push-EBP -2833 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -2834 # setup -2835 # . clear-stream(_test-input-stream) -2836 # . . push args -2837 68/push _test-input-stream/imm32 -2838 # . . call -2839 e8/call clear-stream/disp32 -2840 # . . discard args -2841 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2842 # . clear-stream(_test-output-stream) -2843 # . . push args -2844 68/push _test-output-stream/imm32 -2845 # . . call -2846 e8/call clear-stream/disp32 -2847 # . . discard args -2848 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2849 # . clear-stream(_test-output-buffered-file+4) -2850 # . . push args -2851 b8/copy-to-EAX _test-output-buffered-file/imm32 -2852 05/add-to-EAX 4/imm32 -2853 50/push-EAX -2854 # . . call -2855 e8/call clear-stream/disp32 -2856 # . . discard args -2857 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2858 # . var segments/ECX = stream(10 * 16) -2859 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP -2860 68/push 0xa0/imm32/length -2861 68/push 0/imm32/read -2862 68/push 0/imm32/write -2863 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -2864 # . var labels/EDX = stream(512 * 16) -2865 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP -2866 68/push 0x2000/imm32/length -2867 68/push 0/imm32/read -2868 68/push 0/imm32/write -2869 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -2870 # initialize input -2871 # . write(_test-input-stream, "== code 0x1000\n") -2872 # . . push args -2873 68/push "== code 0x1000\n"/imm32 -2874 68/push _test-input-stream/imm32 -2875 # . . call -2876 e8/call write/disp32 -2877 # . . discard args -2878 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2879 # . write(_test-input-stream, "ab cd\n") -2880 # . . push args -2881 68/push "ab cd\n"/imm32 -2882 68/push _test-input-stream/imm32 -2883 # . . call -2884 e8/call write/disp32 -2885 # . . discard args -2886 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2887 # . write(_test-input-stream, "l1:\n") -2888 # . . push args -2889 68/push "l1:\n"/imm32 -2890 68/push _test-input-stream/imm32 -2891 # . . call -2892 e8/call write/disp32 -2893 # . . discard args -2894 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2895 # . write(_test-input-stream, " ef gh\n") -2896 # . . push args -2897 68/push " ef gh\n"/imm32 -2898 68/push _test-input-stream/imm32 -2899 # . . call -2900 e8/call write/disp32 -2901 # . . discard args -2902 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2903 # . write(_test-input-stream, " ij l1/disp32\n") -2904 # . . push args -2905 68/push " ij l1/disp32\n"/imm32 -2906 68/push _test-input-stream/imm32 -2907 # . . call -2908 e8/call write/disp32 -2909 # . . discard args -2910 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -2911 # . stream-add4(segments, "code", 0x1054, 0, 9) -2912 68/push 9/imm32/segment-size -2913 68/push 0/imm32/file-offset -2914 68/push 0x1054/imm32/start-address -2915 68/push "code"/imm32/segment-name -2916 51/push-ECX -2917 # . . call -2918 e8/call stream-add4/disp32 -2919 # . . discard args -2920 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -2921 # . stream-add4(labels, "l1", "code", 2, 0x1056) -2922 68/push 0x1056/imm32/label-address -2923 68/push 2/imm32/segment-offset -2924 68/push "code"/imm32/segment-name -2925 68/push "l1"/imm32/label-name -2926 52/push-EDX -2927 # . . call -2928 e8/call stream-add4/disp32 -2929 # . . discard args -2930 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -2931 # component under test -2932 # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) -2933 # . . push args -2934 52/push-EDX -2935 51/push-ECX -2936 68/push _test-output-buffered-file/imm32 -2937 68/push _test-input-stream/imm32 -2938 # . . call -2939 e8/call emit-segments/disp32 -2940 # . . discard args -2941 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -2942 # checks -2943 # . flush(_test-output-buffered-file) -2944 # . . push args -2945 68/push _test-output-buffered-file/imm32 -2946 # . . call -2947 e8/call flush/disp32 -2948 # . . discard args -2949 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -2950 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -2983 # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg) -2984 # . . push args -2985 68/push "F - test-emit-segments-code-label/0"/imm32 -2986 68/push "ab cd "/imm32 -2987 68/push _test-output-stream/imm32 -2988 # . . call -2989 e8/call check-next-stream-line-equal/disp32 -2990 # . . discard args -2991 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -2992 # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg) -2993 # . . push args -2994 68/push "F - test-emit-segments-code-label/1"/imm32 -2995 68/push "ef gh "/imm32 -2996 68/push _test-output-stream/imm32 -2997 # . . call -2998 e8/call check-next-stream-line-equal/disp32 -2999 # . . discard args -3000 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3001 # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg) -3002 # . . push args -3003 68/push "F - test-emit-segments-code-label/2"/imm32 -3004 68/push "ij f9 ff ff ff "/imm32 -3005 68/push _test-output-stream/imm32 -3006 # . . call -3007 e8/call check-next-stream-line-equal/disp32 -3008 # . . discard args -3009 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3010 # . epilog -3011 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3012 5d/pop-to-EBP -3013 c3/return -3014 -3015 test-emit-segments-code-label-absolute: -3016 # labels can also convert to absolute addresses -3017 # -3018 # input: -3019 # in: -3020 # == code 0x1000 -3021 # ab cd -3022 # l1: -3023 # ef gh -3024 # ij l1/imm32 -3025 # segments: -3026 # - 'code': {0x1054, 0, 9} -3027 # labels: -3028 # - 'l1': {'code', 2, 0x1056} -3029 # -3030 # output: -3031 # ab cd -3032 # ef gh -3033 # ij 56 10 00 00 -3034 # -3035 # . prolog -3036 55/push-EBP -3037 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3038 # setup -3039 # . clear-stream(_test-input-stream) -3040 # . . push args -3041 68/push _test-input-stream/imm32 -3042 # . . call -3043 e8/call clear-stream/disp32 -3044 # . . discard args -3045 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3046 # . clear-stream(_test-output-stream) -3047 # . . push args -3048 68/push _test-output-stream/imm32 -3049 # . . call -3050 e8/call clear-stream/disp32 -3051 # . . discard args -3052 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3053 # . clear-stream(_test-output-buffered-file+4) -3054 # . . push args -3055 b8/copy-to-EAX _test-output-buffered-file/imm32 -3056 05/add-to-EAX 4/imm32 -3057 50/push-EAX -3058 # . . call -3059 e8/call clear-stream/disp32 -3060 # . . discard args -3061 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3062 # . var segments/ECX = stream(10 * 16) -3063 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP -3064 68/push 0xa0/imm32/length -3065 68/push 0/imm32/read -3066 68/push 0/imm32/write -3067 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -3068 # . var labels/EDX = stream(512 * 16) -3069 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP -3070 68/push 0x2000/imm32/length -3071 68/push 0/imm32/read -3072 68/push 0/imm32/write -3073 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -3074 # initialize input -3075 # . write(_test-input-stream, "== code 0x1000\n") -3076 # . . push args -3077 68/push "== code 0x1000\n"/imm32 -3078 68/push _test-input-stream/imm32 -3079 # . . call -3080 e8/call write/disp32 -3081 # . . discard args -3082 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3083 # . write(_test-input-stream, "ab cd\n") -3084 # . . push args -3085 68/push "ab cd\n"/imm32 -3086 68/push _test-input-stream/imm32 -3087 # . . call -3088 e8/call write/disp32 -3089 # . . discard args -3090 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3091 # . write(_test-input-stream, "l1:\n") -3092 # . . push args -3093 68/push "l1:\n"/imm32 -3094 68/push _test-input-stream/imm32 -3095 # . . call -3096 e8/call write/disp32 -3097 # . . discard args -3098 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3099 # . write(_test-input-stream, " ef gh\n") -3100 # . . push args -3101 68/push " ef gh\n"/imm32 -3102 68/push _test-input-stream/imm32 -3103 # . . call -3104 e8/call write/disp32 -3105 # . . discard args -3106 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3107 # . write(_test-input-stream, " ij l1/imm32\n") -3108 # . . push args -3109 68/push " ij l1/imm32\n"/imm32 -3110 68/push _test-input-stream/imm32 -3111 # . . call -3112 e8/call write/disp32 -3113 # . . discard args -3114 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3115 # . stream-add4(segments, "code", 0x1054, 0, 9) -3116 68/push 9/imm32/segment-size -3117 68/push 0/imm32/file-offset -3118 68/push 0x1054/imm32/start-address -3119 68/push "code"/imm32/segment-name -3120 51/push-ECX -3121 # . . call -3122 e8/call stream-add4/disp32 -3123 # . . discard args -3124 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -3125 # . stream-add4(labels, "l1", "code", 2, 0x1056) -3126 68/push 0x1056/imm32/label-address -3127 68/push 2/imm32/segment-offset -3128 68/push "code"/imm32/segment-name -3129 68/push "l1"/imm32/label-name -3130 52/push-EDX -3131 # . . call -3132 e8/call stream-add4/disp32 -3133 # . . discard args -3134 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -3135 # component under test -3136 # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) -3137 # . . push args -3138 52/push-EDX -3139 51/push-ECX -3140 68/push _test-output-buffered-file/imm32 -3141 68/push _test-input-stream/imm32 -3142 # . . call -3143 e8/call emit-segments/disp32 -3144 # . . discard args -3145 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -3146 # checks -3147 # . flush(_test-output-buffered-file) -3148 # . . push args -3149 68/push _test-output-buffered-file/imm32 -3150 # . . call -3151 e8/call flush/disp32 -3152 # . . discard args -3153 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3154 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- -3187 # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg) -3188 # . . push args -3189 68/push "F - test-emit-segments-code-label-absolute/0"/imm32 -3190 68/push "ab cd "/imm32 -3191 68/push _test-output-stream/imm32 -3192 # . . call -3193 e8/call check-next-stream-line-equal/disp32 -3194 # . . discard args -3195 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3196 # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg) -3197 # . . push args -3198 68/push "F - test-emit-segments-code-label-absolute/1"/imm32 -3199 68/push "ef gh "/imm32 -3200 68/push _test-output-stream/imm32 -3201 # . . call -3202 e8/call check-next-stream-line-equal/disp32 -3203 # . . discard args -3204 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3205 # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg) -3206 # . . push args -3207 68/push "F - test-emit-segments-code-label-absolute/2"/imm32 -3208 68/push "ij 56 10 00 00 "/imm32 -3209 68/push _test-output-stream/imm32 -3210 # . . call -3211 e8/call check-next-stream-line-equal/disp32 -3212 # . . discard args -3213 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3214 # . epilog -3215 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3216 5d/pop-to-EBP -3217 c3/return -3218 -3219 emit-headers: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) -3220 # pseudocode: -3221 # emit-elf-header(out, segments, labels) -3222 # curr-segment = segments->data -3223 # max = segments->data + segments->write -3224 # while true -3225 # if (curr-segment >= max) break -3226 # emit-elf-program-header-entry(out, curr-segment) -3227 # curr-segment += 16 # size of a row -3228 # -3229 # . prolog -3230 55/push-EBP -3231 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3232 # . save registers -3233 50/push-EAX -3234 51/push-ECX -3235 +-- 9 lines: #? # write(2/stderr, "emit-elf-header\n") -------------------------------------------------------------------------------------------------- -3244 # emit-elf-header(out, segments, labels) -3245 # . . push args -3246 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -3247 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -3248 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3249 # . . call -3250 e8/call emit-elf-header/disp32 -3251 # . . discard args -3252 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3253 # EAX = segments -3254 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX -3255 # ECX = segments->write -3256 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -3257 # curr-segment/EAX = segments->data -3258 8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 0xc/disp8 . # copy EAX+12 to EAX -3259 # max/ECX = segments->data + segments->write -3260 01/add 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to ECX -3261 $emit-headers:loop: -3262 # if (curr-segment >= max) break -3263 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX -3264 0f 83/jump-if-greater-or-equal-unsigned $emit-headers:end/disp32 -3265 +-- 69 lines: #? # dump curr-segment->name --------------------------------------------------------------------------------------------------------------- -3334 +-- 9 lines: #? # write(2/stderr, "emit-segment-header\n") ---------------------------------------------------------------------------------------------- -3343 # emit-elf-program-header-entry(out, curr-segment) -3344 # . . push args -3345 50/push-EAX -3346 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3347 # . . call -3348 e8/call emit-elf-program-header-entry/disp32 -3349 # . . discard args -3350 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3351 # curr-segment += 16 # size of a row -3352 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0x10/imm32 # add to EAX -3353 e9/jump $emit-headers:loop/disp32 -3354 $emit-headers:end: -3355 # . restore registers -3356 59/pop-to-ECX -3357 58/pop-to-EAX -3358 # . epilog -3359 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3360 5d/pop-to-EBP -3361 c3/return -3362 -3363 emit-elf-header: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) -3364 # pseudocode -3365 # *Elf_e_entry = get(labels, "Entry")->address -3366 # *Elf_e_phnum = segments->write / 16 # size of a row -3367 # emit-hex-array(out, Elf_header) -3368 # write-buffered(out, "\n") -3369 # -3370 # . prolog -3371 55/push-EBP -3372 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3373 # . save registers -3374 50/push-EAX -3375 51/push-ECX -3376 52/push-EDX # just because we need to call idiv -3377 # *Elf_e_entry = get(labels, "Entry")->address -3378 # . EAX = labels -3379 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX -3380 # . label-info/EAX = get(labels, "Entry", row-size=16) -3381 # . . push args -3382 68/push 0x10/imm32/row-size -3383 68/push "Entry"/imm32 -3384 50/push-EAX -3385 # . . call -3386 e8/call get/disp32 -3387 # . . discard args -3388 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -3389 # . EAX = label-info->address -3390 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 8/disp8 . # copy *(EAX+8) to EAX -3391 # . *Elf_e_entry = EAX -3392 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_entry/disp32 # copy EAX to *Elf_e_entry -3393 # *Elf_e_phnum = segments->write / 0x10 -3394 # . EAX = segments -3395 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX -3396 # . len/EAX = segments->write -3397 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX -3398 # . EAX = len / 0x10 (destroying EDX) -3399 b9/copy-to-ECX 0x10/imm32 -3400 31/xor 3/mod/direct 2/rm32/EDX . . . 2/r32/EDX . . # clear EDX -3401 f7 7/subop/idiv 3/mod/direct 1/rm32/ECX . . . . . . # divide EDX:EAX by ECX, storing quotient in EAX and remainder in EDX -3402 # . *Elf_e_phnum = EAX -3403 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_phnum/disp32 # copy EAX to *Elf_e_phnum -3404 # emit-hex-array(out, Elf_header) -3405 # . . push args -3406 68/push Elf_header/imm32 -3407 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3408 # . . call -3409 e8/call emit-hex-array/disp32 -3410 # . . discard args -3411 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3412 # write-buffered(out, "\n") -3413 # . . push args -3414 68/push "\n"/imm32 -3415 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3416 # . . call -3417 e8/call write-buffered/disp32 -3418 # . . discard args -3419 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3420 $emit-elf-header:end: -3421 # . restore registers -3422 5a/pop-to-EDX -3423 59/pop-to-ECX -3424 58/pop-to-EAX -3425 # . epilog -3426 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3427 5d/pop-to-EBP -3428 c3/return -3429 -3430 emit-elf-program-header-entry: # out : (address buffered-file), curr-segment : (address {string, segment-info}) -3431 # pseudocode: -3432 # *Elf_p_offset = curr-segment->file-offset -3433 # *Elf_p_vaddr = curr-segment->address -3434 # *Elf_p_paddr = curr-segment->address -3435 # *Elf_p_filesz = curr-segment->size -3436 # *Elf_p_memsz = curr-segment->size -3437 # if curr-segment->name == "code" -3438 # *Elf_p_flags = 5 # r-x -3439 # else -3440 # *Elf_p_flags = 6 # rw- -3441 # emit-hex-array(out, Elf_program_header_entry) -3442 # write-buffered(out, "\n") -3443 # -3444 # . prolog -3445 55/push-EBP -3446 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3447 # . save registers -3448 50/push-EAX -3449 56/push-ESI -3450 # ESI = curr-segment -3451 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI -3452 # *Elf_p_offset = curr-segment->file-offset -3453 # . EAX = curr-segment->file-offset -3454 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 8/disp8 . # copy *(ESI+8) to EAX -3455 # . *Elf_p_offset = EAX -3456 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_offset/disp32 # copy EAX to *Elf_p_offset -3457 # *Elf_p_vaddr = curr-segment->address -3458 # . EAX = curr-segment->address -3459 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX -3460 # . *Elf_p_vaddr = EAX -3461 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_vaddr/disp32 # copy EAX to *Elf_p_vaddr -3462 # *Elf_p_paddr = curr-segment->address -3463 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_paddr/disp32 # copy EAX to *Elf_p_paddr -3464 # *Elf_p_filesz = curr-segment->size -3465 # . EAX = curr-segment->size -3466 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy *(ESI+12) to EAX -3467 # . *Elf_p_filesz = EAX -3468 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_filesz/disp32 # copy EAX to *Elf_p_filesz -3469 # *Elf_p_memsz = curr-segment->size -3470 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_memsz/disp32 # copy EAX to *Elf_p_memsz -3471 # if (!string-equal?(curr-segment->name, "code") goto next check -3472 # . EAX = curr-segment->name -3473 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX -3474 # . EAX = string-equal?(curr-segment->name, "code") -3475 # . . push args -3476 68/push "code"/imm32 -3477 50/push-EAX -3478 # . . call -3479 e8/call string-equal?/disp32 -3480 # . . discard args -3481 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3482 # . if (EAX == 0) goto next check -3483 3d/compare-EAX-and 0/imm32 -3484 74/jump-if-equal $emit-elf-program-header-entry:data/disp8 -3485 # *Elf_p_flags = r-x -3486 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 5/imm32 # copy to *Elf_p_flags -3487 eb/jump $emit-elf-program-header-entry:really-emit/disp8 -3488 $emit-elf-program-header-entry:data: -3489 # otherwise *Elf_p_flags = rw- -3490 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 6/imm32 # copy to *Elf_p_flags -3491 $emit-elf-program-header-entry:really-emit: -3492 # emit-hex-array(out, Elf_program_header_entry) -3493 # . . push args -3494 68/push Elf_program_header_entry/imm32 -3495 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3496 # . . call -3497 e8/call emit-hex-array/disp32 -3498 # . . discard args -3499 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3500 # write-buffered(out, "\n") -3501 # . . push args -3502 68/push "\n"/imm32 -3503 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3504 # . . call -3505 e8/call write-buffered/disp32 -3506 # . . discard args -3507 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3508 $emit-elf-program-header-entry:end: -3509 # . restore registers -3510 5e/pop-to-ESI -3511 58/pop-to-EAX -3512 # . epilog -3513 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3514 5d/pop-to-EBP -3515 c3/return -3516 -3517 # - some helpers for tests -3518 -3519 stream-add4: # in : (address stream byte), key : address, val1 : address, val2 : address, val3 : address -3520 # . prolog -3521 55/push-EBP -3522 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3523 # . save registers -3524 50/push-EAX -3525 51/push-ECX -3526 52/push-EDX -3527 56/push-ESI -3528 # ESI = in -3529 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -3530 # curr/EAX = in->data + in->write -3531 # . EAX = in->write -3532 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX -3533 # . EAX = ESI+EAX+12 -3534 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX -3535 # max/EDX = in->data + in->length -3536 # . EDX = in->length -3537 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 8/disp8 . # copy *(ESI+8) to EDX -3538 # . EDX = ESI+EDX+12 -3539 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ESI+EDX+12 to EDX -3540 # if (curr >= max) abort -3541 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX -3542 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 -3543 # *curr = key -3544 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX -3545 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX -3546 # curr += 4 -3547 05/add-to-EAX 4/imm32 -3548 # if (curr >= max) abort -3549 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX -3550 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 -3551 # *curr = val1 -3552 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX -3553 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX -3554 # curr += 4 -3555 05/add-to-EAX 4/imm32 -3556 # if (curr >= max) abort -3557 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX -3558 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 -3559 # *curr = val2 -3560 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x14/disp8 . # copy *(EBP+20) to ECX -3561 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX -3562 # curr += 4 -3563 05/add-to-EAX 4/imm32 -3564 # if (curr >= max) abort -3565 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX -3566 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 -3567 # *curr = val3 -3568 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x18/disp8 . # copy *(EBP+24) to ECX -3569 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX -3570 # in->write += 16 -3571 81 0/subop/add 0/mod/indirect 6/rm32/ESI . . . . . 0x10/imm32 # add to *ESI -3572 $stream-add4:end: -3573 # . restore registers -3574 5e/pop-to-ESI -3575 5a/pop-to-EDX -3576 59/pop-to-ECX -3577 58/pop-to-EAX -3578 # . epilog -3579 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3580 5d/pop-to-EBP -3581 c3/return -3582 -3583 $stream-add4:abort: -3584 # . _write(2/stderr, error) -3585 # . . push args -3586 68/push "overflow in stream-add4\n"/imm32 -3587 68/push 2/imm32/stderr -3588 # . . call -3589 e8/call _write/disp32 -3590 # . . discard args -3591 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3592 # . syscall(exit, 1) -3593 bb/copy-to-EBX 1/imm32 -3594 b8/copy-to-EAX 1/imm32/exit -3595 cd/syscall 0x80/imm8 -3596 # never gets here -3597 -3598 # some variants of 'trace' that take multiple arguments in different combinations of types: -3599 # n: int -3600 # c: character [4-bytes, will eventually be UTF-8] -3601 # s: (address string) -3602 # l: (address slice) -3603 # one gotcha: 's5' must not be empty -3604 -3605 trace-sssns: # s1 : (address string), s2 : (address string), s3 : (address string), n4 : int, s5 : (address string) -3606 # . prolog -3607 55/push-EBP -3608 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3609 # write(*Trace-stream, s1) -3610 # . . push args -3611 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3612 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3613 # . . call -3614 e8/call write/disp32 -3615 # . . discard args -3616 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3617 # write(*Trace-stream, s2) -3618 # . . push args -3619 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -3620 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3621 # . . call -3622 e8/call write/disp32 -3623 # . . discard args -3624 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3625 # write(*Trace-stream, s3) -3626 # . . push args -3627 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -3628 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3629 # . . call -3630 e8/call write/disp32 -3631 # . . discard args -3632 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3633 # print-int32(*Trace-stream, n4) -3634 # . . push args -3635 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -3636 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3637 # . . call -3638 e8/call print-int32/disp32 -3639 # . . discard args -3640 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3641 # trace(s5) # implicitly adds a newline and finalizes the trace line -3642 # . . push args -3643 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) -3644 # . . call -3645 e8/call trace/disp32 -3646 # . . discard args -3647 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3648 $trace-sssns:end: -3649 # . epilog -3650 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3651 5d/pop-to-EBP -3652 c3/return -3653 -3654 test-trace-sssns: -3655 # . prolog -3656 55/push-EBP -3657 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3658 # setup -3659 # . *Trace-stream->write = 0 -3660 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX -3661 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX -3662 # trace-sssns("A" "b" "c " 3 " e") -3663 # . . push args -3664 68/push " e"/imm32 -3665 68/push 3/imm32 -3666 68/push "c "/imm32 -3667 68/push "b"/imm32 -3668 68/push "A"/imm32 -3669 # . . call -3670 e8/call trace-sssns/disp32 -3671 # . . discard args -3672 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -3673 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- -3699 # check-trace-contains("Abc 0x00000003 e") -3700 # . . push args -3701 68/push "F - test-trace-sssns"/imm32 -3702 68/push "Abc 0x00000003 e"/imm32 -3703 # . . call -3704 e8/call check-trace-contains/disp32 -3705 # . . discard args -3706 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3707 # . epilog -3708 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3709 5d/pop-to-EBP -3710 c3/return -3711 -3712 trace-snsns: # s1 : (address string), n2 : int, s3 : (address string), n4 : int, s5 : (address string) -3713 # . prolog -3714 55/push-EBP -3715 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3716 # write(*Trace-stream, s1) -3717 # . . push args -3718 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3719 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3720 # . . call -3721 e8/call write/disp32 -3722 # . . discard args -3723 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3724 # print-int32(*Trace-stream, n2) -3725 # . . push args -3726 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -3727 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3728 # . . call -3729 e8/call print-int32/disp32 -3730 # . . discard args -3731 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3732 # write(*Trace-stream, s3) -3733 # . . push args -3734 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -3735 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3736 # . . call -3737 e8/call write/disp32 -3738 # . . discard args -3739 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3740 # print-int32(*Trace-stream, n4) -3741 # . . push args -3742 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -3743 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3744 # . . call -3745 e8/call print-int32/disp32 -3746 # . . discard args -3747 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3748 # trace(s5) # implicitly adds a newline and finalizes the trace line -3749 # . . push args -3750 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) -3751 # . . call -3752 e8/call trace/disp32 -3753 # . . discard args -3754 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3755 $trace-snsns:end: -3756 # . epilog -3757 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3758 5d/pop-to-EBP -3759 c3/return -3760 -3761 test-trace-snsns: -3762 # . prolog -3763 55/push-EBP -3764 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3765 # setup -3766 # . *Trace-stream->write = 0 -3767 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX -3768 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX -3769 # trace-snsns("A " 2 " c " 3 " e") -3770 # . . push args -3771 68/push " e"/imm32 -3772 68/push 3/imm32 -3773 68/push " c "/imm32 -3774 68/push 2/imm32 -3775 68/push "A "/imm32 -3776 # . . call -3777 e8/call trace-snsns/disp32 -3778 # . . discard args -3779 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -3780 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- -3806 # check-trace-contains("Abc 0x00000003 e") -3807 # . . push args -3808 68/push "F - test-trace-snsns"/imm32 -3809 68/push "A 0x00000002 c 0x00000003 e"/imm32 -3810 # . . call -3811 e8/call check-trace-contains/disp32 -3812 # . . discard args -3813 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3814 # . epilog -3815 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3816 5d/pop-to-EBP -3817 c3/return -3818 -3819 trace-slsls: # s1 : (address string), l2 : (address slice), s3 : (address string), l4 : (address slice), s5 : (address string) -3820 # . prolog -3821 55/push-EBP -3822 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3823 # write(*Trace-stream, s1) -3824 # . . push args -3825 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3826 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3827 # . . call -3828 e8/call write/disp32 -3829 # . . discard args -3830 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3831 # write-slice(*Trace-stream, l2) -3832 # . . push args -3833 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -3834 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3835 # . . call -3836 e8/call write-slice/disp32 -3837 # . . discard args -3838 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3839 # write(*Trace-stream, s3) -3840 # . . push args -3841 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -3842 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3843 # . . call -3844 e8/call write/disp32 -3845 # . . discard args -3846 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3847 # write-slice(*Trace-stream, l4) -3848 # . . push args -3849 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -3850 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3851 # . . call -3852 e8/call write-slice/disp32 -3853 # . . discard args -3854 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3855 # trace(s5) # implicitly adds a newline and finalizes the trace line -3856 # . . push args -3857 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) -3858 # . . call -3859 e8/call trace/disp32 -3860 # . . discard args -3861 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3862 $trace-slsls:end: -3863 # . epilog -3864 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3865 5d/pop-to-EBP -3866 c3/return -3867 -3868 test-trace-slsls: -3869 # . prolog -3870 55/push-EBP -3871 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3872 # setup -3873 # . *Trace-stream->write = 0 -3874 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX -3875 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX -3876 # (EAX..ECX) = "b" -3877 b8/copy-to-EAX "b"/imm32 -3878 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -3879 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -3880 05/add-to-EAX 4/imm32 -3881 # var b/EBX : (address slice) = {EAX, ECX} -3882 51/push-ECX -3883 50/push-EAX -3884 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX -3885 # (EAX..ECX) = "d" -3886 b8/copy-to-EAX "d"/imm32 -3887 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -3888 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -3889 05/add-to-EAX 4/imm32 -3890 # var d/EDX : (address slice) = {EAX, ECX} -3891 51/push-ECX -3892 50/push-EAX -3893 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -3894 # trace-slsls("A" b "c" d "e") -3895 # . . push args -3896 68/push "e"/imm32 -3897 52/push-EDX -3898 68/push "c"/imm32 -3899 53/push-EBX -3900 68/push "A"/imm32 -3901 # . . call -3902 e8/call trace-slsls/disp32 -3903 # . . discard args -3904 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -3905 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- -3931 # check-trace-contains("Abcde") -3932 # . . push args -3933 68/push "F - test-trace-slsls"/imm32 -3934 68/push "Abcde"/imm32 -3935 # . . call -3936 e8/call check-trace-contains/disp32 -3937 # . . discard args -3938 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3939 # . epilog -3940 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3941 5d/pop-to-EBP -3942 c3/return -3943 -3944 trace-slsns: # s1 : (address string), l2 : (address slice), s3 : (address string), n4 : int, s5 : (address string) -3945 # . prolog -3946 55/push-EBP -3947 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3948 # write(*Trace-stream, s1) -3949 # . . push args -3950 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -3951 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3952 # . . call -3953 e8/call write/disp32 -3954 # . . discard args -3955 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3956 # write-slice(*Trace-stream, l2) -3957 # . . push args -3958 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -3959 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3960 # . . call -3961 e8/call write-slice/disp32 -3962 # . . discard args -3963 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3964 # write(*Trace-stream, s3) -3965 # . . push args -3966 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -3967 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3968 # . . call -3969 e8/call write/disp32 -3970 # . . discard args -3971 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3972 # print-int32(*Trace-stream, n4) -3973 # . . push args -3974 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -3975 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -3976 # . . call -3977 e8/call print-int32/disp32 -3978 # . . discard args -3979 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -3980 # trace(s5) # implicitly adds a newline and finalizes the trace line -3981 # . . push args -3982 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) -3983 # . . call -3984 e8/call trace/disp32 -3985 # . . discard args -3986 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -3987 $trace-slsns:end: -3988 # . epilog -3989 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -3990 5d/pop-to-EBP -3991 c3/return -3992 -3993 test-trace-slsns: -3994 # . prolog -3995 55/push-EBP -3996 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -3997 # setup -3998 # . *Trace-stream->write = 0 -3999 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX -4000 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX -4001 # (EAX..ECX) = "b" -4002 b8/copy-to-EAX "b"/imm32 -4003 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -4004 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -4005 05/add-to-EAX 4/imm32 -4006 # var b/EBX : (address slice) = {EAX, ECX} -4007 51/push-ECX -4008 50/push-EAX -4009 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX -4010 # trace-slsls("A" b "c " 3 " e") -4011 # . . push args -4012 68/push " e"/imm32 -4013 68/push 3/imm32 -4014 68/push "c "/imm32 -4015 53/push-EBX -4016 68/push "A"/imm32 -4017 # . . call -4018 e8/call trace-slsns/disp32 -4019 # . . discard args -4020 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -4021 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- -4047 # check-trace-contains("Abc 0x00000003 e") -4048 # . . push args -4049 68/push "F - test-trace-slsls"/imm32 -4050 68/push "Abc 0x00000003 e"/imm32 -4051 # . . call -4052 e8/call check-trace-contains/disp32 -4053 # . . discard args -4054 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4055 # . epilog -4056 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4057 5d/pop-to-EBP -4058 c3/return -4059 -4060 trace-slsss: # s1 : (address string), l2 : (address slice), s3 : (address string), s4 : (address string), s5 : (address string) -4061 # . prolog -4062 55/push-EBP -4063 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4064 # write(*Trace-stream, s1) -4065 # . . push args -4066 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -4067 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -4068 # . . call -4069 e8/call write/disp32 -4070 # . . discard args -4071 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4072 # write-slice(*Trace-stream, l2) -4073 # . . push args -4074 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) -4075 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -4076 # . . call -4077 e8/call write-slice/disp32 -4078 # . . discard args -4079 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4080 # write(*Trace-stream, s3) -4081 # . . push args -4082 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) -4083 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -4084 # . . call -4085 e8/call write/disp32 -4086 # . . discard args -4087 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4088 # write(*Trace-stream, s4) -4089 # . . push args -4090 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) -4091 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -4092 # . . call -4093 e8/call write/disp32 -4094 # . . discard args -4095 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4096 # trace(s5) # implicitly adds a newline and finalizes the trace line -4097 # . . push args -4098 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) -4099 # . . call -4100 e8/call trace/disp32 -4101 # . . discard args -4102 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4103 $trace-slsss:end: -4104 # . epilog -4105 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4106 5d/pop-to-EBP -4107 c3/return -4108 -4109 test-trace-slsss: -4110 # . prolog -4111 55/push-EBP -4112 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4113 # setup -4114 # . *Trace-stream->write = 0 -4115 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX -4116 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX -4117 # (EAX..ECX) = "b" -4118 b8/copy-to-EAX "b"/imm32 -4119 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -4120 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX -4121 05/add-to-EAX 4/imm32 -4122 # var b/EBX : (address slice) = {EAX, ECX} -4123 51/push-ECX -4124 50/push-EAX -4125 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX -4126 # trace-slsss("A" b "c" "d" "e") -4127 # . . push args -4128 68/push "e"/imm32 -4129 68/push "d"/imm32 -4130 68/push "c"/imm32 -4131 53/push-EBX -4132 68/push "A"/imm32 -4133 # . . call -4134 e8/call trace-slsss/disp32 -4135 # . . discard args -4136 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -4137 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- -4163 # check-trace-contains("Abcde") -4164 # . . push args -4165 68/push "F - test-trace-slsss"/imm32 -4166 68/push "Abcde"/imm32 -4167 # . . call -4168 e8/call check-trace-contains/disp32 -4169 # . . discard args -4170 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4171 # . epilog -4172 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4173 5d/pop-to-EBP -4174 c3/return -4175 -4176 num-bytes: # line : (address stream) -> EAX : int -4177 # pseudocode: -4178 # result = 0 -4179 # while true -4180 # var word-slice = next-word(line) -4181 # if slice-empty?(word-slice) # end of line -4182 # break -4183 # if slice-starts-with?(word-slice, "#") # comment -4184 # break -4185 # if is-label?(word-slice) # no need for label declarations anymore -4186 # break -4187 # if slice-equal?(word-slice, "==") -4188 # break # no need for segment header lines -4189 # result += compute-width(word-slice) -4190 # return result -4191 # -4192 # . prolog -4193 55/push-EBP -4194 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4195 # . save registers -4196 51/push-ECX -4197 52/push-EDX -4198 53/push-EBX -4199 # var result/EAX = 0 -4200 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -4201 # var word-slice/ECX = {0, 0} -4202 68/push 0/imm32/end -4203 68/push 0/imm32/start -4204 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -4205 +-- 26 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- -4231 # . rewind-stream(line) -4232 # . . push args -4233 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -4234 # . . call -4235 e8/call rewind-stream/disp32 -4236 # . . discard args -4237 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4238 $num-bytes:loop: -4239 # next-word(line, word-slice) -4240 # . . push args -4241 51/push-ECX -4242 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -4243 # . . call -4244 e8/call next-word/disp32 -4245 # . . discard args -4246 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4247 +-- 46 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- -4293 $num-bytes:check0: -4294 # if (slice-empty?(word-slice)) break -4295 # . save result -4296 50/push-EAX -4297 # . EAX = slice-empty?(word-slice) -4298 # . . push args -4299 51/push-ECX -4300 # . . call -4301 e8/call slice-empty?/disp32 -4302 # . . discard args -4303 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4304 # . if (EAX != 0) break -4305 3d/compare-EAX-and 0/imm32 -4306 # . restore result now that ZF is set -4307 58/pop-to-EAX -4308 75/jump-if-not-equal $num-bytes:end/disp8 -4309 $num-bytes:check-for-comment: -4310 # if (slice-starts-with?(word-slice, "#")) break -4311 # . start/EDX = word-slice->start -4312 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX -4313 # . c/EBX = *start -4314 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX -4315 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 3/r32/BL . . # copy byte at *EDX to BL -4316 # . if (EBX == '#') break -4317 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x23/imm32/hash # compare EBX -4318 74/jump-if-equal $num-bytes:end/disp8 -4319 $num-bytes:check-for-label: -4320 # if (slice-ends-with?(word-slice, ":")) break -4321 # . end/EDX = word-slice->end -4322 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX -4323 # . c/EBX = *(end-1) -4324 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX -4325 8a/copy-byte 1/mod/*+disp8 2/rm32/EDX . . . 3/r32/BL -1/disp8 . # copy byte at *ECX to BL -4326 # . if (EBX == ':') break -4327 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x3a/imm32/colon # compare EBX -4328 74/jump-if-equal $num-bytes:end/disp8 -4329 $num-bytes:check-for-segment-header: -4330 # if (slice-equal?(word-slice, "==")) break -4331 # . push result -4332 50/push-EAX -4333 # . EAX = slice-equal?(word-slice, "==") -4334 # . . push args -4335 68/push "=="/imm32 -4336 51/push-ECX -4337 # . . call -4338 e8/call slice-equal?/disp32 -4339 # . . discard args -4340 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4341 # . if (EAX != 0) break -4342 3d/compare-EAX-and 0/imm32 -4343 # . restore result now that ZF is set -4344 58/pop-to-EAX -4345 75/jump-if-not-equal $num-bytes:end/disp8 -4346 $num-bytes:loop-body: -4347 # result += compute-width-of-slice(word-slice) -4348 # . copy result to EDX -4349 89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX -4350 # . EAX = compute-width-of-slice(word-slice) -4351 # . . push args -4352 51/push-ECX -4353 # . . call -4354 e8/call compute-width-of-slice/disp32 -4355 # . . discard args -4356 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4357 # . EAX += result -4358 01/add 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # add EDX to EAX -4359 e9/jump $num-bytes:loop/disp32 -4360 $num-bytes:end: -4361 # . rewind-stream(line) -4362 # . . push args -4363 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -4364 # . . call -4365 e8/call rewind-stream/disp32 -4366 # . . discard args -4367 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4368 # . reclaim locals -4369 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4370 # . restore registers -4371 5b/pop-to-EBX -4372 5a/pop-to-EDX -4373 59/pop-to-ECX -4374 # . epilog -4375 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4376 5d/pop-to-EBP -4377 c3/return -4378 -4379 test-num-bytes-handles-empty-string: -4380 # if a line starts with '#', return 0 -4381 # . prolog -4382 55/push-EBP -4383 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4384 # setup -4385 # . clear-stream(_test-input-stream) -4386 # . . push args -4387 68/push _test-input-stream/imm32 -4388 # . . call -4389 e8/call clear-stream/disp32 -4390 # . . discard args -4391 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4392 # . clear-stream(_test-output-stream) -4393 # . . push args -4394 68/push _test-output-stream/imm32 -4395 # . . call -4396 e8/call clear-stream/disp32 -4397 # . . discard args -4398 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4399 # no contents in input -4400 # EAX = num-bytes(_test-input-stream) -4401 # . . push args -4402 68/push _test-input-stream/imm32 -4403 # . . call -4404 e8/call num-bytes/disp32 -4405 # . . discard args -4406 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4407 # check-ints-equal(EAX, 0, msg) -4408 # . . push args -4409 68/push "F - test-num-bytes-handles-empty-string"/imm32 -4410 68/push 0/imm32/true -4411 50/push-EAX -4412 # . . call -4413 e8/call check-ints-equal/disp32 -4414 # . . discard args -4415 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -4416 # . epilog -4417 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4418 5d/pop-to-EBP -4419 c3/return -4420 -4421 test-num-bytes-ignores-comments: -4422 # if a line starts with '#', return 0 -4423 # . prolog -4424 55/push-EBP -4425 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4426 # setup -4427 # . clear-stream(_test-input-stream) -4428 # . . push args -4429 68/push _test-input-stream/imm32 -4430 # . . call -4431 e8/call clear-stream/disp32 -4432 # . . discard args -4433 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4434 # . clear-stream(_test-output-stream) -4435 # . . push args -4436 68/push _test-output-stream/imm32 -4437 # . . call -4438 e8/call clear-stream/disp32 -4439 # . . discard args -4440 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4441 # initialize input -4442 # . write(_test-input-stream, "# abcd") -4443 # . . push args -4444 68/push "# abcd"/imm32 -4445 68/push _test-input-stream/imm32 -4446 # . . call -4447 e8/call write/disp32 -4448 # . . discard args -4449 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4450 # EAX = num-bytes(_test-input-stream) -4451 # . . push args -4452 68/push _test-input-stream/imm32 -4453 # . . call -4454 e8/call num-bytes/disp32 -4455 # . . discard args -4456 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4457 # check-ints-equal(EAX, 0, msg) -4458 # . . push args -4459 68/push "F - test-num-bytes-ignores-comments"/imm32 -4460 68/push 0/imm32/true -4461 50/push-EAX -4462 # . . call -4463 e8/call check-ints-equal/disp32 -4464 # . . discard args -4465 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -4466 # . epilog -4467 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4468 5d/pop-to-EBP -4469 c3/return -4470 -4471 test-num-bytes-ignores-labels: -4472 # if the first word ends with ':', return 0 -4473 # . prolog -4474 55/push-EBP -4475 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4476 # setup -4477 # . clear-stream(_test-input-stream) -4478 # . . push args -4479 68/push _test-input-stream/imm32 -4480 # . . call -4481 e8/call clear-stream/disp32 -4482 # . . discard args -4483 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4484 # . clear-stream(_test-output-stream) -4485 # . . push args -4486 68/push _test-output-stream/imm32 -4487 # . . call -4488 e8/call clear-stream/disp32 -4489 # . . discard args -4490 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4491 # initialize input -4492 # . write(_test-input-stream, "ab: # cd") -4493 # . . push args -4494 68/push "ab: # cd"/imm32 -4495 68/push _test-input-stream/imm32 -4496 # . . call -4497 e8/call write/disp32 -4498 # . . discard args -4499 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4500 # EAX = num-bytes(_test-input-stream) -4501 # . . push args -4502 68/push _test-input-stream/imm32 -4503 # . . call -4504 e8/call num-bytes/disp32 -4505 # . . discard args -4506 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4507 # check-ints-equal(EAX, 0, msg) -4508 # . . push args -4509 68/push "F - test-num-bytes-ignores-labels"/imm32 -4510 68/push 0/imm32/true -4511 50/push-EAX -4512 # . . call -4513 e8/call check-ints-equal/disp32 -4514 # . . discard args -4515 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -4516 # . epilog -4517 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4518 5d/pop-to-EBP -4519 c3/return -4520 -4521 test-num-bytes-ignores-segment-headers: -4522 # if the first word is '==', return 0 -4523 # . prolog -4524 55/push-EBP -4525 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4526 # setup -4527 # . clear-stream(_test-input-stream) -4528 # . . push args -4529 68/push _test-input-stream/imm32 -4530 # . . call -4531 e8/call clear-stream/disp32 -4532 # . . discard args -4533 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4534 # . clear-stream(_test-output-stream) -4535 # . . push args -4536 68/push _test-output-stream/imm32 -4537 # . . call -4538 e8/call clear-stream/disp32 -4539 # . . discard args -4540 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4541 # initialize input -4542 # . write(_test-input-stream, "== ab cd") -4543 # . . push args -4544 68/push "== ab cd"/imm32 -4545 68/push _test-input-stream/imm32 -4546 # . . call -4547 e8/call write/disp32 -4548 # . . discard args -4549 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4550 # EAX = num-bytes(_test-input-stream) -4551 # . . push args -4552 68/push _test-input-stream/imm32 -4553 # . . call -4554 e8/call num-bytes/disp32 -4555 # . . discard args -4556 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4557 # check-ints-equal(EAX, 0, msg) -4558 # . . push args -4559 68/push "F - test-num-bytes-ignores-segment-headers"/imm32 -4560 68/push 0/imm32/true -4561 50/push-EAX -4562 # . . call -4563 e8/call check-ints-equal/disp32 -4564 # . . discard args -4565 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -4566 # . epilog -4567 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4568 5d/pop-to-EBP -4569 c3/return -4570 -4571 test-num-bytes-counts-words-by-default: -4572 # without metadata, count words -4573 # . prolog -4574 55/push-EBP -4575 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4576 # setup -4577 # . clear-stream(_test-input-stream) -4578 # . . push args -4579 68/push _test-input-stream/imm32 -4580 # . . call -4581 e8/call clear-stream/disp32 -4582 # . . discard args -4583 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4584 # . clear-stream(_test-output-stream) -4585 # . . push args -4586 68/push _test-output-stream/imm32 -4587 # . . call -4588 e8/call clear-stream/disp32 -4589 # . . discard args -4590 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4591 # initialize input -4592 # . write(_test-input-stream, "ab cd ef") -4593 # . . push args -4594 68/push "ab cd ef"/imm32 -4595 68/push _test-input-stream/imm32 -4596 # . . call -4597 e8/call write/disp32 -4598 # . . discard args -4599 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4600 # EAX = num-bytes(_test-input-stream) -4601 # . . push args -4602 68/push _test-input-stream/imm32 -4603 # . . call -4604 e8/call num-bytes/disp32 -4605 # . . discard args -4606 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4607 # check-ints-equal(EAX, 3, msg) -4608 # . . push args -4609 68/push "F - test-num-bytes-counts-words-by-default"/imm32 -4610 68/push 3/imm32/true -4611 50/push-EAX -4612 # . . call -4613 e8/call check-ints-equal/disp32 -4614 # . . discard args -4615 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -4616 # . epilog -4617 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4618 5d/pop-to-EBP -4619 c3/return -4620 -4621 test-num-bytes-ignores-trailing-comment: -4622 # trailing comments appropriately ignored -4623 # . prolog -4624 55/push-EBP -4625 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4626 # setup -4627 # . clear-stream(_test-input-stream) -4628 # . . push args -4629 68/push _test-input-stream/imm32 -4630 # . . call -4631 e8/call clear-stream/disp32 -4632 # . . discard args -4633 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4634 # . clear-stream(_test-output-stream) -4635 # . . push args -4636 68/push _test-output-stream/imm32 -4637 # . . call -4638 e8/call clear-stream/disp32 -4639 # . . discard args -4640 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4641 # initialize input -4642 # . write(_test-input-stream, "ab cd # ef") -4643 # . . push args -4644 68/push "ab cd # ef"/imm32 -4645 68/push _test-input-stream/imm32 -4646 # . . call -4647 e8/call write/disp32 -4648 # . . discard args -4649 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4650 # EAX = num-bytes(_test-input-stream) -4651 # . . push args -4652 68/push _test-input-stream/imm32 -4653 # . . call -4654 e8/call num-bytes/disp32 -4655 # . . discard args -4656 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4657 # check-ints-equal(EAX, 2, msg) -4658 # . . push args -4659 68/push "F - test-num-bytes-ignores-trailing-comment"/imm32 -4660 68/push 2/imm32/true -4661 50/push-EAX -4662 # . . call -4663 e8/call check-ints-equal/disp32 -4664 # . . discard args -4665 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -4666 # . epilog -4667 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4668 5d/pop-to-EBP -4669 c3/return -4670 -4671 test-num-bytes-handles-imm32: -4672 # if a word has the /imm32 metadata, count it as 4 bytes -4673 # . prolog -4674 55/push-EBP -4675 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -4676 # setup -4677 # . clear-stream(_test-input-stream) -4678 # . . push args -4679 68/push _test-input-stream/imm32 -4680 # . . call -4681 e8/call clear-stream/disp32 -4682 # . . discard args -4683 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4684 # . clear-stream(_test-output-stream) -4685 # . . push args -4686 68/push _test-output-stream/imm32 -4687 # . . call -4688 e8/call clear-stream/disp32 -4689 # . . discard args -4690 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4691 # initialize input -4692 # . write(_test-input-stream, "ab cd/imm32 ef") -4693 # . . push args -4694 68/push "ab cd/imm32 ef"/imm32 -4695 68/push _test-input-stream/imm32 -4696 # . . call -4697 e8/call write/disp32 -4698 # . . discard args -4699 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -4700 # EAX = num-bytes(_test-input-stream) -4701 # . . push args -4702 68/push _test-input-stream/imm32 -4703 # . . call -4704 e8/call num-bytes/disp32 -4705 # . . discard args -4706 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -4707 # check-ints-equal(EAX, 6, msg) -4708 # . . push args -4709 68/push "F - test-num-bytes-handles-imm32"/imm32 -4710 68/push 6/imm32/true -4711 50/push-EAX -4712 # . . call -4713 e8/call check-ints-equal/disp32 -4714 # . . discard args -4715 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -4716 # . epilog -4717 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -4718 5d/pop-to-EBP -4719 c3/return -4720 -4721 == data -4722 -4723 # This block of bytes gets copied to the start of the output ELF file, with -4724 # some fields filled in. -4725 # http://www.sco.com/developers/gabi/latest/ch4.eheader.html -4726 Elf_header: -4727 # - length -4728 0x34/imm32 -4729 # - data -4730 $e_ident: -4731 7f 45/E 4c/L 46/F -4732 01/32-bit 01/little-endian 01/file-version 00/no-os-extensions -4733 00 00 00 00 00 00 00 00 # 8 bytes of padding -4734 $e_type: -4735 02 00 -4736 $e_machine: -4737 03 00 -4738 $e_version: -4739 1/imm32 -4740 Elf_e_entry: -4741 0x09000000/imm32 # approximate default; must be updated -4742 $e_phoff: -4743 0x34/imm32 # offset for the 'program header table' containing segment headers -4744 $e_shoff: -4745 0/imm32 # no sections -4746 $e_flags: -4747 0/imm32 # unused -4748 $e_ehsize: -4749 0x34 00 -4750 $e_phentsize: -4751 0x20 00 -4752 Elf_e_phnum: -4753 00 00 # number of segments; must be updated -4754 $e_shentsize: -4755 00 00 # no sections -4756 $e_shnum: -4757 00 00 -4758 $e_shstrndx: -4759 00 00 -4760 -4761 # This block of bytes gets copied after the Elf_header once for each segment. -4762 # Some fields need filling in each time. -4763 # https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-83432/index.html -4764 Elf_program_header_entry: -4765 # - length -4766 0x20/imm32 -4767 # - data -4768 $p_type: -4769 1/imm32/PT_LOAD -4770 Elf_p_offset: -4771 0/imm32 # byte offset in the file at which a segment begins; must be updated -4772 Elf_p_vaddr: -4773 0/imm32 # starting address to store the segment at before running the program -4774 Elf_p_paddr: -4775 0/imm32 # should have same value as Elf_p_vaddr -4776 Elf_p_filesz: -4777 0/imm32 -4778 Elf_p_memsz: -4779 0/imm32 # should have same value as Elf_p_filesz -4780 Elf_p_flags: -4781 6/imm32/rw- # read/write/execute permissions for the segment; must be updated for the code segment -4782 $p_align: -4783 # we hold this constant; changing it will require adjusting the way we -4784 # compute the starting address for each segment -4785 0x1000/imm32 -4786 -4787 # . . vim:nowrap:textwidth=0 +1597 68/push "segment table"/imm32 +1598 68/push 0x10/imm32/row-size +1599 52/push-EDX +1600 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1601 # . . call +1602 e8/call get/disp32 +1603 # . . discard args +1604 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +1605 # . EDX = EAX +1606 89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX +1607 # . restore EAX +1608 58/pop-to-EAX +1609 # EBX = label-seg->address +1610 8b/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy *EDX to EBX +1611 # EBX += lrow->segment-offset +1612 03/add 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # add *(EAX+8) to EBX +1613 # lrow->address = EBX +1614 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 0xc/disp8 . # copy EBX to *(EAX+12) +1615 # trace-sssns("label " lrow->key " is at address " lrow->address ".") +1616 # . . push args +1617 68/push "."/imm32 +1618 53/push-EBX +1619 68/push "' is at address "/imm32 +1620 ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX +1621 68/push "label '"/imm32 +1622 # . . call +1623 e8/call trace-sssns/disp32 +1624 # . . discard args +1625 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1626 # lrow += 16 # size of row +1627 05/add-to-EAX 0x10/imm32 +1628 e9/jump $compute-addresses:label-loop/disp32 +1629 $compute-addresses:end: +1630 # . restore registers +1631 5f/pop-to-EDI +1632 5e/pop-to-ESI +1633 5b/pop-to-EBX +1634 5a/pop-to-EDX +1635 59/pop-to-ECX +1636 58/pop-to-EAX +1637 # . epilog +1638 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1639 5d/pop-to-EBP +1640 c3/return +1641 +1642 test-compute-addresses: +1643 # input: +1644 # segments: +1645 # - 'a': {0x1000, 0, 5} +1646 # - 'b': {0x2018, 5, 1} +1647 # - 'c': {0x5444, 6, 12} +1648 # labels: +1649 # - 'l1': {'a', 3, 0} +1650 # - 'l2': {'b', 0, 0} +1651 # +1652 # trace contains in any order (comments in parens): +1653 # segment 'a' starts at address 0x00001094. (0x34 + 0x20 for each segment) +1654 # segment 'b' starts at address 0x00002099. (0x018 discarded) +1655 # segment 'c' starts at address 0x0000509a. (0x444 discarded) +1656 # label 'l1' is at address 0x00001097. (0x1094 + segment-offset 3) +1657 # label 'l2' is at address 0x00002099. (0x2099 + segment-offset 0) +1658 # +1659 # . prolog +1660 55/push-EBP +1661 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1662 # setup +1663 # . var segments/ECX = stream(10 * 16) +1664 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP +1665 68/push 0xa0/imm32/length +1666 68/push 0/imm32/read +1667 68/push 0/imm32/write +1668 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1669 # . var labels/EDX = stream(512 * 16) +1670 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP +1671 68/push 0x2000/imm32/length +1672 68/push 0/imm32/read +1673 68/push 0/imm32/write +1674 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX +1675 # . stream-add4(segments, "a", 0x1000, 0, 5) +1676 68/push 5/imm32/segment-size +1677 68/push 0/imm32/file-offset +1678 68/push 0x1000/imm32/start-address +1679 68/push "a"/imm32/segment-name +1680 51/push-ECX +1681 # . . call +1682 e8/call stream-add4/disp32 +1683 # . . discard args +1684 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1685 # . stream-add4(segments, "b", 0x2018, 5, 1) +1686 68/push 1/imm32/segment-size +1687 68/push 5/imm32/file-offset +1688 68/push 0x2018/imm32/start-address +1689 68/push "b"/imm32/segment-name +1690 51/push-ECX +1691 # . . call +1692 e8/call stream-add4/disp32 +1693 # . . discard args +1694 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1695 # . stream-add4(segments, "c", 0x5444, 6, 12) +1696 68/push 0xc/imm32/segment-size +1697 68/push 6/imm32/file-offset +1698 68/push 0x5444/imm32/start-address +1699 68/push "c"/imm32/segment-name +1700 51/push-ECX +1701 # . . call +1702 e8/call stream-add4/disp32 +1703 # . . discard args +1704 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1705 # . stream-add4(labels, "l1", "a", 3, 0) +1706 68/push 0/imm32/label-address +1707 68/push 3/imm32/segment-offset +1708 68/push "a"/imm32/segment-name +1709 68/push "l1"/imm32/label-name +1710 52/push-EDX +1711 # . . call +1712 e8/call stream-add4/disp32 +1713 # . . discard args +1714 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1715 # . stream-add4(labels, "l2", "b", 0, 0) +1716 68/push 0/imm32/label-address +1717 68/push 0/imm32/segment-offset +1718 68/push "b"/imm32/segment-name +1719 68/push "l2"/imm32/label-name +1720 52/push-EDX +1721 # . . call +1722 e8/call stream-add4/disp32 +1723 # . . discard args +1724 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1725 # component under test +1726 # . compute-addresses(segments, labels) +1727 # . . push args +1728 52/push-EDX +1729 51/push-ECX +1730 # . . call +1731 e8/call compute-addresses/disp32 +1732 # . . discard args +1733 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1734 # checks +1735 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- +1761 # . check-trace-contains("segment 'a' starts at address 0x00001094.", msg) +1762 # . . push args +1763 68/push "F - test-compute-addresses/0"/imm32 +1764 68/push "segment 'a' starts at address 0x00001094."/imm32 +1765 # . . call +1766 e8/call check-trace-contains/disp32 +1767 # . . discard args +1768 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1769 # . check-trace-contains("segment 'b' starts at address 0x00002099.", msg) +1770 # . . push args +1771 68/push "F - test-compute-addresses/1"/imm32 +1772 68/push "segment 'b' starts at address 0x00002099."/imm32 +1773 # . . call +1774 e8/call check-trace-contains/disp32 +1775 # . . discard args +1776 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1777 # . check-trace-contains("segment 'c' starts at address 0x0000509a.", msg) +1778 # . . push args +1779 68/push "F - test-compute-addresses/2"/imm32 +1780 68/push "segment 'c' starts at address 0x0000509a."/imm32 +1781 # . . call +1782 e8/call check-trace-contains/disp32 +1783 # . . discard args +1784 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1785 # . check-trace-contains("label 'l1' is at address 0x00001097.", msg) +1786 # . . push args +1787 68/push "F - test-compute-addresses/3"/imm32 +1788 68/push "label 'l1' is at address 0x00001097."/imm32 +1789 # . . call +1790 e8/call check-trace-contains/disp32 +1791 # . . discard args +1792 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1793 # . check-trace-contains("label 'l2' is at address 0x00002099.", msg) +1794 # . . push args +1795 68/push "F - test-compute-addresses/4"/imm32 +1796 68/push "label 'l2' is at address 0x00002099."/imm32 +1797 # . . call +1798 e8/call check-trace-contains/disp32 +1799 # . . discard args +1800 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1801 # . check-ints-equal(labels->write, 0x20, msg) +1802 # . . push args +1803 68/push "F - test-compute-addresses/maintains-labels-write-index"/imm32 +1804 68/push 0x20/imm32/2-entries +1805 ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX +1806 # . . call +1807 e8/call check-ints-equal/disp32 +1808 # . . discard args +1809 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1810 # . epilog +1811 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1812 5d/pop-to-EBP +1813 c3/return +1814 +1815 test-compute-addresses-large-segments: +1816 # input: +1817 # segments: +1818 # - 'a': {0x1000, 0, 0x5604} +1819 # - 'b': {0x2018, 0x5604, 1} +1820 # labels: +1821 # - 'l1': {'a', 3, 0} +1822 # +1823 # trace contains in any order (comments in parens): +1824 # segment 'a' starts at address 0x00001074. (0x34 + 0x20 for each segment) +1825 # segment 'b' starts at address 0x00002678. (0x018 discarded; last 3 nibbles from 0x1074 + 0x5604) +1826 # label 'l1' is at address 0x00001077. (0x1074 + segment-offset 3) +1827 # +1828 # . prolog +1829 55/push-EBP +1830 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1831 # setup +1832 # . var segments/ECX = stream(10 * 16) +1833 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP +1834 68/push 0xa0/imm32/length +1835 68/push 0/imm32/read +1836 68/push 0/imm32/write +1837 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +1838 # . var labels/EDX = stream(512 * 16) +1839 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP +1840 68/push 0x2000/imm32/length +1841 68/push 0/imm32/read +1842 68/push 0/imm32/write +1843 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX +1844 # . stream-add4(segments, "a", 0x1000, 0, 0x5604) +1845 68/push 0x5604/imm32/segment-size +1846 68/push 0/imm32/file-offset +1847 68/push 0x1000/imm32/start-address +1848 68/push "a"/imm32/segment-name +1849 51/push-ECX +1850 # . . call +1851 e8/call stream-add4/disp32 +1852 # . . discard args +1853 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1854 # . stream-add4(segments, "b", 0x2018, 0x5604, 1) +1855 68/push 1/imm32/segment-size +1856 68/push 0x5604/imm32/file-offset +1857 68/push 0x2018/imm32/start-address +1858 68/push "b"/imm32/segment-name +1859 51/push-ECX +1860 # . . call +1861 e8/call stream-add4/disp32 +1862 # . . discard args +1863 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1864 # . stream-add4(labels, "l1", "a", 3, 0) +1865 68/push 0/imm32/label-address +1866 68/push 3/imm32/segment-offset +1867 68/push "a"/imm32/segment-name +1868 68/push "l1"/imm32/label-name +1869 52/push-EDX +1870 # . . call +1871 e8/call stream-add4/disp32 +1872 # . . discard args +1873 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +1874 # component under test +1875 # . compute-addresses(segments, labels) +1876 # . . push args +1877 52/push-EDX +1878 51/push-ECX +1879 # . . call +1880 e8/call compute-addresses/disp32 +1881 # . . discard args +1882 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1883 # checks +1884 # . check-trace-contains("segment 'a' starts at address 0x00001074.", msg) +1885 # . . push args +1886 68/push "F - test-compute-addresses-large-segments/0"/imm32 +1887 68/push "segment 'a' starts at address 0x00001074."/imm32 +1888 # . . call +1889 e8/call check-trace-contains/disp32 +1890 # . . discard args +1891 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1892 # . check-trace-contains("segment 'b' starts at address 0x00002678.", msg) +1893 # . . push args +1894 68/push "F - test-compute-addresses-large-segments/1"/imm32 +1895 68/push "segment 'b' starts at address 0x00002678."/imm32 +1896 # . . call +1897 e8/call check-trace-contains/disp32 +1898 # . . discard args +1899 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1900 # . check-trace-contains("label 'l1' is at address 0x00001077.", msg) +1901 # . . push args +1902 68/push "F - test-compute-addresses-large-segments/3"/imm32 +1903 68/push "label 'l1' is at address 0x00001077."/imm32 +1904 # . . call +1905 e8/call check-trace-contains/disp32 +1906 # . . discard args +1907 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +1908 # . epilog +1909 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1910 5d/pop-to-EBP +1911 c3/return +1912 +1913 emit-output: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) +1914 # pseudocode: +1915 # emit-headers(out, segments, labels) +1916 # emit-segments(in, out, segments, labels) +1917 # +1918 # . prolog +1919 55/push-EBP +1920 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +1921 +-- 9 lines: #? # write(2/stderr, "emit-headers\n") ----------------------------------------------------------------------------------------------------- +1930 # emit-headers(out, segments, labels) +1931 # . . push args +1932 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +1933 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +1934 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +1935 # . . call +1936 e8/call emit-headers/disp32 +1937 # . . discard args +1938 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +1939 +-- 9 lines: #? # write(2/stderr, "emit-segments\n") ---------------------------------------------------------------------------------------------------- +1948 # emit-segments(in, out, segments, labels) +1949 # . . push args +1950 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +1951 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +1952 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +1953 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +1954 # . . call +1955 e8/call emit-segments/disp32 +1956 # . . discard args +1957 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +1958 $emit-output:end: +1959 # . epilog +1960 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +1961 5d/pop-to-EBP +1962 c3/return +1963 +1964 emit-segments: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) +1965 # pseudocode: +1966 # var offset-of-next-instruction = 0 +1967 # var line = new-stream(512, 1) +1968 # line-loop: +1969 # while true +1970 # clear-stream(line) +1971 # read-line(in, line) +1972 # if (line->write == 0) break # end of file +1973 # offset-of-next-instruction += num-bytes(line) +1974 # while true +1975 # var word-slice = next-word(line) +1976 # if slice-empty?(word-slice) # end of line +1977 # break +1978 # if slice-starts-with?(word-slice, "#") # comment +1979 # break +1980 # if is-label?(word-slice) # no need for label declarations anymore +1981 # goto line-loop # don't insert empty lines +1982 # if slice-equal?(word-slice, "==") # no need for segment header lines +1983 # goto line-loop # don't insert empty lines +1984 # if length(word-slice) == 2 +1985 # write-slice-buffered(out, word-slice) +1986 # write-buffered(out, " ") +1987 # continue +1988 # datum = next-token-from-slice(word-slice->start, word-slice->end, "/") +1989 # info = get-slice(labels, datum) +1990 # if !string-equal?(info->segment-name, "code") +1991 # if has-metadata?(word-slice, "disp8") +1992 # abort +1993 # if has-metadata?(word-slice, "imm8") +1994 # abort +1995 # emit(out, info->address, 4) # global variables always translate to absolute addresses +1996 # # code segment cases +1997 # else if has-metadata?(word-slice, "imm8") +1998 # abort # label should never go to imm8 +1999 # else if has-metadata?(word-slice, "imm32") +2000 # emit(out, info->address, 4) +2001 # else if has-metadata?(word-slice, "disp8") +2002 # value = info->offset - offset-of-next-instruction +2003 # emit(out, value, 1) +2004 # else if has-metadata?(word-slice, "disp32") +2005 # value = info->offset - offset-of-next-instruction +2006 # emit(out, value, 4) +2007 # else +2008 # abort +2009 # write-buffered(out, "\n") +2010 # +2011 # registers: +2012 # line: ECX +2013 # word-slice: EDX +2014 # offset-of-next-instruction: EBX +2015 # datum: EDI +2016 # info: ESI (inner loop only) +2017 # temporaries: EAX, ESI (outer loop) +2018 # +2019 # . prolog +2020 55/push-EBP +2021 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2022 # . save registers +2023 50/push-EAX +2024 51/push-ECX +2025 52/push-EDX +2026 53/push-EBX +2027 56/push-ESI +2028 57/push-EDI +2029 # var line/ECX : (address stream byte) = stream(512) +2030 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP +2031 68/push 0x200/imm32/length +2032 68/push 0/imm32/read +2033 68/push 0/imm32/write +2034 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2035 # var word-slice/EDX = {0, 0} +2036 68/push 0/imm32/end +2037 68/push 0/imm32/start +2038 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX +2039 # var datum/EDI = {0, 0} +2040 68/push 0/imm32/end +2041 68/push 0/imm32/start +2042 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI +2043 # offset-of-next-instruction/EBX = 0 +2044 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +2045 $emit-segments:line-loop: +2046 # clear-stream(line) +2047 # . . push args +2048 51/push-ECX +2049 # . . call +2050 e8/call clear-stream/disp32 +2051 # . . discard args +2052 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2053 # read-line(in, line) +2054 # . . push args +2055 51/push-ECX +2056 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +2057 # . . call +2058 e8/call read-line/disp32 +2059 # . . discard args +2060 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2061 +-- 33 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- +2094 $emit-segments:check-for-end-of-input: +2095 # if (line->write == 0) break +2096 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX +2097 0f 84/jump-if-equal $emit-segments:end/disp32 +2098 # offset-of-next-instruction += num-bytes(line) +2099 # . EAX = num-bytes(line) +2100 # . . push args +2101 51/push-ECX +2102 # . . call +2103 e8/call num-bytes/disp32 +2104 # . . discard args +2105 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2106 # . EBX += EAX +2107 01/add 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # add EAX to EBX +2108 $emit-segments:word-loop: +2109 # next-word(line, word-slice) +2110 # . . push args +2111 52/push-EDX +2112 51/push-ECX +2113 # . . call +2114 e8/call next-word/disp32 +2115 # . . discard args +2116 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2117 +-- 33 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- +2150 $emit-segments:check-for-end-of-line: +2151 # if (slice-empty?(word-slice)) break +2152 # . EAX = slice-empty?(word-slice) +2153 # . . push args +2154 52/push-EDX +2155 # . . call +2156 e8/call slice-empty?/disp32 +2157 # . . discard args +2158 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2159 # . if (EAX != 0) break +2160 3d/compare-EAX-and 0/imm32 +2161 0f 85/jump-if-not-equal $emit-segments:next-line/disp32 +2162 $emit-segments:check-for-comment: +2163 # if (slice-starts-with?(word-slice, "#")) break +2164 # . start/ESI = word-slice->start +2165 8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *EDX to ESI +2166 # . c/EAX = *start +2167 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +2168 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL +2169 # . if (EAX == '#') break +2170 3d/compare-EAX-and 0x23/imm32/hash +2171 0f 84/jump-if-equal $emit-segments:next-line/disp32 +2172 $emit-segments:check-for-label: +2173 # if is-label?(word-slice) break +2174 # . EAX = is-label?(word-slice) +2175 # . . push args +2176 52/push-EDX +2177 # . . call +2178 e8/call is-label?/disp32 +2179 # . . discard args +2180 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2181 # . if (EAX != 0) break +2182 3d/compare-EAX-and 0/imm32 +2183 0f 85/jump-if-not-equal $emit-segments:line-loop/disp32 +2184 $emit-segments:check-for-segment-header: +2185 # if (slice-equal?(word-slice, "==")) break +2186 # . EAX = slice-equal?(word-slice, "==") +2187 # . . push args +2188 68/push "=="/imm32 +2189 52/push-EDX +2190 # . . call +2191 e8/call slice-equal?/disp32 +2192 # . . discard args +2193 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2194 # . if (EAX != 0) break +2195 3d/compare-EAX-and 0/imm32 +2196 0f 85/jump-if-not-equal $emit-segments:line-loop/disp32 +2197 $emit-segments:2-character: +2198 # if (length(word-slice) != 2) goto next check +2199 # . EAX = length(word-slice) +2200 8b/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy *(EDX+4) to EAX +2201 2b/subtract 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # subtract *EDX from EAX +2202 # . if (EAX != 2) goto next check +2203 3d/compare-EAX-and 2/imm32 +2204 75/jump-if-not-equal $emit-segments:check-metadata/disp8 +2205 # write-slice-buffered(out, word-slice) +2206 # . . push args +2207 52/push-EDX +2208 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +2209 # . . call +2210 e8/call write-slice-buffered/disp32 +2211 # . . discard args +2212 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2213 # write-buffered(out, " ") +2214 # . . push args +2215 68/push " "/imm32 +2216 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +2217 # . . call +2218 e8/call write-buffered/disp32 +2219 # . . discard args +2220 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2221 # continue +2222 e9/jump $emit-segments:word-loop/disp32 +2223 $emit-segments:check-metadata: +2224 # - if we get here, 'word-slice' must be a label to be looked up +2225 # datum/EDI = next-token-from-slice(word-slice->start, word-slice->end, "/") +2226 # . . push args +2227 57/push-EDI +2228 68/push 0x2f/imm32/slash +2229 ff 6/subop/push 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # push *(EDX+4) +2230 ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX +2231 # . . call +2232 e8/call next-token-from-slice/disp32 +2233 # . . discard args +2234 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +2235 +-- 33 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- +2268 # info/ESI = get-slice(labels, datum, row-size=16, "label table") +2269 # . EAX = get-slice(labels, datum, row-size=16, "label table") +2270 # . . push args +2271 68/push "label table"/imm32 +2272 68/push 0x10/imm32/row-size +2273 57/push-EDI +2274 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +2275 # . . call +2276 e8/call get-slice/disp32 +2277 # . . discard args +2278 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +2279 # . ESI = EAX +2280 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI +2281 $emit-segments:check-global-variable: +2282 +-- 26 lines: #? # dump info->segment-name --------------------------------------------------------------------------------------------------------------- +2308 # if string-equal?(info->segment-name, "code") goto code label checks +2309 # . EAX = string-equal?(info->segment-name, "code") +2310 # . . push args +2311 68/push "code"/imm32 +2312 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI +2313 # . . call +2314 e8/call string-equal?/disp32 +2315 # . . discard args +2316 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2317 # . if (EAX != 0) goto code label checks +2318 3d/compare-EAX-and 0/imm32 +2319 0f 85/jump-if-not-equal $emit-segments:check-code-label-for-imm8/disp32 +2320 $emit-segments:check-global-variable-for-disp8: +2321 # if has-metadata?(word-slice, "disp8") abort +2322 # . EAX = has-metadata?(word-slice, "disp8") +2323 # . . push args +2324 68/push "disp8"/imm32 +2325 52/push-EDX +2326 # . . call +2327 e8/call has-metadata?/disp32 +2328 # . . discard args +2329 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2330 # . if (EAX != 0) abort +2331 3d/compare-EAX-and 0/imm32 +2332 0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32 +2333 $emit-segments:check-global-variable-for-imm8: +2334 # if has-metadata?(word-slice, "imm8") abort +2335 # . EAX = has-metadata?(word-slice, "imm8") +2336 # . . push args +2337 68/push "imm8"/imm32 +2338 52/push-EDX +2339 # . . call +2340 e8/call has-metadata?/disp32 +2341 # . . discard args +2342 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2343 # . if (EAX != 0) abort +2344 3d/compare-EAX-and 0/imm32 +2345 0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32 +2346 $emit-segments:emit-global-variable: +2347 # emit-hex(out, info->address, 4) +2348 # . . push args +2349 68/push 4/imm32 +2350 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8) +2351 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +2352 # . . call +2353 e8/call emit-hex/disp32 +2354 # . . discard args +2355 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2356 # continue +2357 e9/jump $emit-segments:word-loop/disp32 +2358 $emit-segments:check-code-label-for-imm8: +2359 # if (has-metadata?(word-slice, "imm8")) abort +2360 # . EAX = has-metadata?(EDX, "imm8") +2361 # . . push args +2362 68/push "imm8"/imm32 +2363 52/push-EDX +2364 # . . call +2365 e8/call has-metadata?/disp32 +2366 # . . discard args +2367 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2368 # . if (EAX != 0) abort +2369 3d/compare-EAX-and 0/imm32 +2370 0f 85/jump-if-not-equal $emit-segments:imm8-abort/disp32 +2371 $emit-segments:check-code-label-for-imm32: +2372 # if (!has-metadata?(word-slice, "imm32")) goto next check +2373 # . EAX = has-metadata?(EDX, "imm32") +2374 # . . push args +2375 68/push "imm32"/imm32 +2376 52/push-EDX +2377 # . . call +2378 e8/call has-metadata?/disp32 +2379 # . . discard args +2380 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2381 # . if (EAX == 0) goto next check +2382 3d/compare-EAX-and 0/imm32 +2383 74/jump-if-equal $emit-segments:check-code-label-for-disp8/disp8 +2384 +-- 33 lines: #? # dump info->address -------------------------------------------------------------------------------------------------------------------- +2417 $emit-segments:emit-code-label-imm32: +2418 # emit-hex(out, info->address, 4) +2419 # . . push args +2420 68/push 4/imm32 +2421 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8) +2422 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +2423 # . . call +2424 e8/call emit-hex/disp32 +2425 # . . discard args +2426 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2427 # continue +2428 e9/jump $emit-segments:word-loop/disp32 +2429 $emit-segments:check-code-label-for-disp8: +2430 # if (!has-metadata?(word-slice, "disp8")) goto next check +2431 # . EAX = has-metadata?(EDX, "disp8") +2432 # . . push args +2433 68/push "disp8"/imm32 +2434 52/push-EDX +2435 # . . call +2436 e8/call has-metadata?/disp32 +2437 # . . discard args +2438 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2439 # . if (EAX == 0) goto next check +2440 3d/compare-EAX-and 0/imm32 +2441 74/jump-if-equal $emit-segments:check-code-label-for-disp32/disp8 +2442 $emit-segments:emit-code-label-disp8: +2443 # emit-hex(out, info->offset - offset-of-next-instruction, 1) +2444 # . . push args +2445 68/push 1/imm32 +2446 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX +2447 29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX +2448 50/push-EAX +2449 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +2450 # . . call +2451 e8/call emit-hex/disp32 +2452 # . . discard args +2453 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2454 # continue +2455 e9/jump $emit-segments:word-loop/disp32 +2456 $emit-segments:check-code-label-for-disp32: +2457 # if (!has-metadata?(word-slice, "disp32")) abort +2458 # . EAX = has-metadata?(EDX, "disp32") +2459 # . . push args +2460 68/push "disp32"/imm32 +2461 52/push-EDX +2462 # . . call +2463 e8/call has-metadata?/disp32 +2464 # . . discard args +2465 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2466 # . if (EAX == 0) abort +2467 3d/compare-EAX-and 0/imm32 +2468 0f 84/jump-if-equal $emit-segments:abort/disp32 +2469 $emit-segments:emit-code-label-disp32: +2470 # emit-hex(out, info->offset - offset-of-next-instruction, 4) +2471 # . . push args +2472 68/push 4/imm32 +2473 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX +2474 29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX +2475 50/push-EAX +2476 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +2477 # . . call +2478 e8/call emit-hex/disp32 +2479 # . . discard args +2480 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2481 # continue +2482 e9/jump $emit-segments:word-loop/disp32 +2483 $emit-segments:next-line: +2484 # write-buffered(out, "\n") +2485 # . . push args +2486 68/push Newline/imm32 +2487 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +2488 # . . call +2489 e8/call write-buffered/disp32 +2490 # . . discard args +2491 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2492 # loop +2493 e9/jump $emit-segments:line-loop/disp32 +2494 $emit-segments:end: +2495 # . reclaim locals +2496 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x21c/imm32 # add to ESP +2497 # . restore registers +2498 5f/pop-to-EDI +2499 5e/pop-to-ESI +2500 5b/pop-to-EBX +2501 5a/pop-to-EDX +2502 59/pop-to-ECX +2503 58/pop-to-EAX +2504 # . epilog +2505 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2506 5d/pop-to-EBP +2507 c3/return +2508 +2509 $emit-segments:global-variable-abort: +2510 # . _write(2/stderr, error) +2511 # . . push args +2512 68/push "emit-segments: must refer to global variables with /disp32 or /imm32"/imm32 +2513 68/push 2/imm32/stderr +2514 # . . call +2515 e8/call _write/disp32 +2516 # . . discard args +2517 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2518 # . syscall(exit, 1) +2519 bb/copy-to-EBX 1/imm32 +2520 b8/copy-to-EAX 1/imm32/exit +2521 cd/syscall 0x80/imm8 +2522 # never gets here +2523 +2524 $emit-segments:imm8-abort: +2525 # . _write(2/stderr, error) +2526 # . . push args +2527 68/push "emit-segments: cannot refer to code labels with /imm8"/imm32 +2528 68/push 2/imm32/stderr +2529 # . . call +2530 e8/call _write/disp32 +2531 # . . discard args +2532 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2533 # . syscall(exit, 1) +2534 bb/copy-to-EBX 1/imm32 +2535 b8/copy-to-EAX 1/imm32/exit +2536 cd/syscall 0x80/imm8 +2537 # never gets here +2538 +2539 $emit-segments:abort: +2540 # print(stderr, "missing metadata in " word-slice) +2541 # . _write(2/stderr, "missing metadata in word ") +2542 # . . push args +2543 68/push "emit-segments: missing metadata in "/imm32 +2544 68/push 2/imm32/stderr +2545 # . . call +2546 e8/call _write/disp32 +2547 # . . discard args +2548 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2549 # . write-slice-buffered(Stderr, word-slice) +2550 # . . push args +2551 52/push-EDX +2552 68/push Stderr/imm32 +2553 # . . call +2554 e8/call write-slice-buffered/disp32 +2555 # . . discard args +2556 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2557 # . flush(Stderr) +2558 # . . push args +2559 68/push Stderr/imm32 +2560 # . . call +2561 e8/call flush/disp32 +2562 # . . discard args +2563 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2564 # . syscall(exit, 1) +2565 bb/copy-to-EBX 1/imm32 +2566 b8/copy-to-EAX 1/imm32/exit +2567 cd/syscall 0x80/imm8 +2568 # never gets here +2569 +2570 test-emit-segments-global-variable: +2571 # global variables always convert to absolute addresses, regardless of metadata +2572 # +2573 # input: +2574 # in: +2575 # == code 0x1000 +2576 # ab cd ef gh +2577 # ij x/disp32 +2578 # == data 0x2000 +2579 # 00 +2580 # x: +2581 # 34 +2582 # segments: +2583 # - 'code': {0x1074, 0, 9} +2584 # - 'data': {0x2079, 5, 2} +2585 # labels: +2586 # - 'x': {'data', 1, 0x207a} +2587 # +2588 # output: +2589 # ab cd ef gh +2590 # ij 7a 20 00 00 +2591 # 00 +2592 # 34 +2593 # +2594 # . prolog +2595 55/push-EBP +2596 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2597 # setup +2598 # . clear-stream(_test-input-stream) +2599 # . . push args +2600 68/push _test-input-stream/imm32 +2601 # . . call +2602 e8/call clear-stream/disp32 +2603 # . . discard args +2604 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2605 # . clear-stream(_test-output-stream) +2606 # . . push args +2607 68/push _test-output-stream/imm32 +2608 # . . call +2609 e8/call clear-stream/disp32 +2610 # . . discard args +2611 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2612 # . clear-stream(_test-output-buffered-file+4) +2613 # . . push args +2614 b8/copy-to-EAX _test-output-buffered-file/imm32 +2615 05/add-to-EAX 4/imm32 +2616 50/push-EAX +2617 # . . call +2618 e8/call clear-stream/disp32 +2619 # . . discard args +2620 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2621 # . var segments/ECX = stream(10 * 16) +2622 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP +2623 68/push 0xa0/imm32/length +2624 68/push 0/imm32/read +2625 68/push 0/imm32/write +2626 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2627 # . var labels/EDX = stream(512 * 16) +2628 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP +2629 68/push 0x2000/imm32/length +2630 68/push 0/imm32/read +2631 68/push 0/imm32/write +2632 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX +2633 # initialize input +2634 # . write(_test-input-stream, "== code 0x1000\n") +2635 # . . push args +2636 68/push "== code 0x1000\n"/imm32 +2637 68/push _test-input-stream/imm32 +2638 # . . call +2639 e8/call write/disp32 +2640 # . . discard args +2641 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2642 # . write(_test-input-stream, "ab cd ef gh\n") +2643 # . . push args +2644 68/push "ab cd ef gh\n"/imm32 +2645 68/push _test-input-stream/imm32 +2646 # . . call +2647 e8/call write/disp32 +2648 # . . discard args +2649 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2650 # . write(_test-input-stream, "ij x/disp32\n") +2651 # . . push args +2652 68/push "ij x/disp32\n"/imm32 +2653 68/push _test-input-stream/imm32 +2654 # . . call +2655 e8/call write/disp32 +2656 # . . discard args +2657 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2658 # . write(_test-input-stream, "== data 0x2000\n") +2659 # . . push args +2660 68/push "== data 0x2000\n"/imm32 +2661 68/push _test-input-stream/imm32 +2662 # . . call +2663 e8/call write/disp32 +2664 # . . discard args +2665 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2666 # . write(_test-input-stream, "00\n") +2667 # . . push args +2668 68/push "00\n"/imm32 +2669 68/push _test-input-stream/imm32 +2670 # . . call +2671 e8/call write/disp32 +2672 # . . discard args +2673 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2674 # . write(_test-input-stream, "x:\n") +2675 # . . push args +2676 68/push "x:\n"/imm32 +2677 68/push _test-input-stream/imm32 +2678 # . . call +2679 e8/call write/disp32 +2680 # . . discard args +2681 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2682 # . write(_test-input-stream, "34\n") +2683 # . . push args +2684 68/push "34\n"/imm32 +2685 68/push _test-input-stream/imm32 +2686 # . . call +2687 e8/call write/disp32 +2688 # . . discard args +2689 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2690 # . stream-add4(segments, "code", 0x1074, 0, 9) +2691 68/push 9/imm32/segment-size +2692 68/push 0/imm32/file-offset +2693 68/push 0x1074/imm32/start-address +2694 68/push "code"/imm32/segment-name +2695 51/push-ECX +2696 # . . call +2697 e8/call stream-add4/disp32 +2698 # . . discard args +2699 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +2700 # . stream-add4(segments, "data", 0x2079, 5, 2) +2701 68/push 1/imm32/segment-size +2702 68/push 5/imm32/file-offset +2703 68/push 0x2079/imm32/start-address +2704 68/push "data"/imm32/segment-name +2705 51/push-ECX +2706 # . . call +2707 e8/call stream-add4/disp32 +2708 # . . discard args +2709 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +2710 # . stream-add4(labels, "x", "data", 1, 0x207a) +2711 68/push 0x207a/imm32/label-address +2712 68/push 1/imm32/segment-offset +2713 68/push "data"/imm32/segment-name +2714 68/push "x"/imm32/label-name +2715 52/push-EDX +2716 # . . call +2717 e8/call stream-add4/disp32 +2718 # . . discard args +2719 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +2720 # component under test +2721 # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) +2722 # . . push args +2723 52/push-EDX +2724 51/push-ECX +2725 68/push _test-output-buffered-file/imm32 +2726 68/push _test-input-stream/imm32 +2727 # . . call +2728 e8/call emit-segments/disp32 +2729 # . . discard args +2730 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +2731 # checks +2732 # . flush(_test-output-buffered-file) +2733 # . . push args +2734 68/push _test-output-buffered-file/imm32 +2735 # . . call +2736 e8/call flush/disp32 +2737 # . . discard args +2738 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2739 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +2772 # . check-next-stream-line-equal(_test-output-stream, "ab cd ef gh ", msg) +2773 # . . push args +2774 68/push "F - test-emit-segments-global-variable/0"/imm32 +2775 68/push "ab cd ef gh "/imm32 +2776 68/push _test-output-stream/imm32 +2777 # . . call +2778 e8/call check-next-stream-line-equal/disp32 +2779 # . . discard args +2780 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2781 # . check-next-stream-line-equal(_test-output-stream, "ij 7a 20 00 00 ", msg) +2782 # . . push args +2783 68/push "F - test-emit-segments-global-variable/1"/imm32 +2784 68/push "ij 7a 20 00 00 "/imm32 +2785 68/push _test-output-stream/imm32 +2786 # . . call +2787 e8/call check-next-stream-line-equal/disp32 +2788 # . . discard args +2789 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2790 # . check-next-stream-line-equal(_test-output-stream, "00 ", msg) +2791 # . . push args +2792 68/push "F - test-emit-segments-global-variable/2"/imm32 +2793 68/push "00 "/imm32 +2794 68/push _test-output-stream/imm32 +2795 # . . call +2796 e8/call check-next-stream-line-equal/disp32 +2797 # . . discard args +2798 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2799 # . check-next-stream-line-equal(_test-output-stream, "34 ", msg) +2800 # . . push args +2801 68/push "F - test-emit-segments-global-variable/3"/imm32 +2802 68/push "34 "/imm32 +2803 68/push _test-output-stream/imm32 +2804 # . . call +2805 e8/call check-next-stream-line-equal/disp32 +2806 # . . discard args +2807 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2808 # . epilog +2809 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +2810 5d/pop-to-EBP +2811 c3/return +2812 +2813 test-emit-segments-code-label: +2814 # labels usually convert to displacements +2815 # +2816 # input: +2817 # in: +2818 # == code 0x1000 +2819 # ab cd +2820 # l1: +2821 # ef gh +2822 # ij l1/disp32 +2823 # segments: +2824 # - 'code': {0x1054, 0, 9} +2825 # labels: +2826 # - 'l1': {'code', 2, 0x1056} +2827 # +2828 # output: +2829 # ab cd +2830 # ef gh +2831 # ij f9 ff ff ff # -7 +2832 # +2833 # . prolog +2834 55/push-EBP +2835 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +2836 # setup +2837 # . clear-stream(_test-input-stream) +2838 # . . push args +2839 68/push _test-input-stream/imm32 +2840 # . . call +2841 e8/call clear-stream/disp32 +2842 # . . discard args +2843 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2844 # . clear-stream(_test-output-stream) +2845 # . . push args +2846 68/push _test-output-stream/imm32 +2847 # . . call +2848 e8/call clear-stream/disp32 +2849 # . . discard args +2850 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2851 # . clear-stream(_test-output-buffered-file+4) +2852 # . . push args +2853 b8/copy-to-EAX _test-output-buffered-file/imm32 +2854 05/add-to-EAX 4/imm32 +2855 50/push-EAX +2856 # . . call +2857 e8/call clear-stream/disp32 +2858 # . . discard args +2859 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2860 # . var segments/ECX = stream(10 * 16) +2861 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP +2862 68/push 0xa0/imm32/length +2863 68/push 0/imm32/read +2864 68/push 0/imm32/write +2865 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +2866 # . var labels/EDX = stream(512 * 16) +2867 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP +2868 68/push 0x2000/imm32/length +2869 68/push 0/imm32/read +2870 68/push 0/imm32/write +2871 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX +2872 # initialize input +2873 # . write(_test-input-stream, "== code 0x1000\n") +2874 # . . push args +2875 68/push "== code 0x1000\n"/imm32 +2876 68/push _test-input-stream/imm32 +2877 # . . call +2878 e8/call write/disp32 +2879 # . . discard args +2880 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2881 # . write(_test-input-stream, "ab cd\n") +2882 # . . push args +2883 68/push "ab cd\n"/imm32 +2884 68/push _test-input-stream/imm32 +2885 # . . call +2886 e8/call write/disp32 +2887 # . . discard args +2888 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2889 # . write(_test-input-stream, "l1:\n") +2890 # . . push args +2891 68/push "l1:\n"/imm32 +2892 68/push _test-input-stream/imm32 +2893 # . . call +2894 e8/call write/disp32 +2895 # . . discard args +2896 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2897 # . write(_test-input-stream, " ef gh\n") +2898 # . . push args +2899 68/push " ef gh\n"/imm32 +2900 68/push _test-input-stream/imm32 +2901 # . . call +2902 e8/call write/disp32 +2903 # . . discard args +2904 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2905 # . write(_test-input-stream, " ij l1/disp32\n") +2906 # . . push args +2907 68/push " ij l1/disp32\n"/imm32 +2908 68/push _test-input-stream/imm32 +2909 # . . call +2910 e8/call write/disp32 +2911 # . . discard args +2912 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +2913 # . stream-add4(segments, "code", 0x1054, 0, 9) +2914 68/push 9/imm32/segment-size +2915 68/push 0/imm32/file-offset +2916 68/push 0x1054/imm32/start-address +2917 68/push "code"/imm32/segment-name +2918 51/push-ECX +2919 # . . call +2920 e8/call stream-add4/disp32 +2921 # . . discard args +2922 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +2923 # . stream-add4(labels, "l1", "code", 2, 0x1056) +2924 68/push 0x1056/imm32/label-address +2925 68/push 2/imm32/segment-offset +2926 68/push "code"/imm32/segment-name +2927 68/push "l1"/imm32/label-name +2928 52/push-EDX +2929 # . . call +2930 e8/call stream-add4/disp32 +2931 # . . discard args +2932 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +2933 # component under test +2934 # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) +2935 # . . push args +2936 52/push-EDX +2937 51/push-ECX +2938 68/push _test-output-buffered-file/imm32 +2939 68/push _test-input-stream/imm32 +2940 # . . call +2941 e8/call emit-segments/disp32 +2942 # . . discard args +2943 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +2944 # checks +2945 # . flush(_test-output-buffered-file) +2946 # . . push args +2947 68/push _test-output-buffered-file/imm32 +2948 # . . call +2949 e8/call flush/disp32 +2950 # . . discard args +2951 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +2952 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +2985 # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg) +2986 # . . push args +2987 68/push "F - test-emit-segments-code-label/0"/imm32 +2988 68/push "ab cd "/imm32 +2989 68/push _test-output-stream/imm32 +2990 # . . call +2991 e8/call check-next-stream-line-equal/disp32 +2992 # . . discard args +2993 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +2994 # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg) +2995 # . . push args +2996 68/push "F - test-emit-segments-code-label/1"/imm32 +2997 68/push "ef gh "/imm32 +2998 68/push _test-output-stream/imm32 +2999 # . . call +3000 e8/call check-next-stream-line-equal/disp32 +3001 # . . discard args +3002 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +3003 # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg) +3004 # . . push args +3005 68/push "F - test-emit-segments-code-label/2"/imm32 +3006 68/push "ij f9 ff ff ff "/imm32 +3007 68/push _test-output-stream/imm32 +3008 # . . call +3009 e8/call check-next-stream-line-equal/disp32 +3010 # . . discard args +3011 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +3012 # . epilog +3013 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3014 5d/pop-to-EBP +3015 c3/return +3016 +3017 test-emit-segments-code-label-absolute: +3018 # labels can also convert to absolute addresses +3019 # +3020 # input: +3021 # in: +3022 # == code 0x1000 +3023 # ab cd +3024 # l1: +3025 # ef gh +3026 # ij l1/imm32 +3027 # segments: +3028 # - 'code': {0x1054, 0, 9} +3029 # labels: +3030 # - 'l1': {'code', 2, 0x1056} +3031 # +3032 # output: +3033 # ab cd +3034 # ef gh +3035 # ij 56 10 00 00 +3036 # +3037 # . prolog +3038 55/push-EBP +3039 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3040 # setup +3041 # . clear-stream(_test-input-stream) +3042 # . . push args +3043 68/push _test-input-stream/imm32 +3044 # . . call +3045 e8/call clear-stream/disp32 +3046 # . . discard args +3047 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3048 # . clear-stream(_test-output-stream) +3049 # . . push args +3050 68/push _test-output-stream/imm32 +3051 # . . call +3052 e8/call clear-stream/disp32 +3053 # . . discard args +3054 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3055 # . clear-stream(_test-output-buffered-file+4) +3056 # . . push args +3057 b8/copy-to-EAX _test-output-buffered-file/imm32 +3058 05/add-to-EAX 4/imm32 +3059 50/push-EAX +3060 # . . call +3061 e8/call clear-stream/disp32 +3062 # . . discard args +3063 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3064 # . var segments/ECX = stream(10 * 16) +3065 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP +3066 68/push 0xa0/imm32/length +3067 68/push 0/imm32/read +3068 68/push 0/imm32/write +3069 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +3070 # . var labels/EDX = stream(512 * 16) +3071 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP +3072 68/push 0x2000/imm32/length +3073 68/push 0/imm32/read +3074 68/push 0/imm32/write +3075 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX +3076 # initialize input +3077 # . write(_test-input-stream, "== code 0x1000\n") +3078 # . . push args +3079 68/push "== code 0x1000\n"/imm32 +3080 68/push _test-input-stream/imm32 +3081 # . . call +3082 e8/call write/disp32 +3083 # . . discard args +3084 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3085 # . write(_test-input-stream, "ab cd\n") +3086 # . . push args +3087 68/push "ab cd\n"/imm32 +3088 68/push _test-input-stream/imm32 +3089 # . . call +3090 e8/call write/disp32 +3091 # . . discard args +3092 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3093 # . write(_test-input-stream, "l1:\n") +3094 # . . push args +3095 68/push "l1:\n"/imm32 +3096 68/push _test-input-stream/imm32 +3097 # . . call +3098 e8/call write/disp32 +3099 # . . discard args +3100 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3101 # . write(_test-input-stream, " ef gh\n") +3102 # . . push args +3103 68/push " ef gh\n"/imm32 +3104 68/push _test-input-stream/imm32 +3105 # . . call +3106 e8/call write/disp32 +3107 # . . discard args +3108 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3109 # . write(_test-input-stream, " ij l1/imm32\n") +3110 # . . push args +3111 68/push " ij l1/imm32\n"/imm32 +3112 68/push _test-input-stream/imm32 +3113 # . . call +3114 e8/call write/disp32 +3115 # . . discard args +3116 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3117 # . stream-add4(segments, "code", 0x1054, 0, 9) +3118 68/push 9/imm32/segment-size +3119 68/push 0/imm32/file-offset +3120 68/push 0x1054/imm32/start-address +3121 68/push "code"/imm32/segment-name +3122 51/push-ECX +3123 # . . call +3124 e8/call stream-add4/disp32 +3125 # . . discard args +3126 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +3127 # . stream-add4(labels, "l1", "code", 2, 0x1056) +3128 68/push 0x1056/imm32/label-address +3129 68/push 2/imm32/segment-offset +3130 68/push "code"/imm32/segment-name +3131 68/push "l1"/imm32/label-name +3132 52/push-EDX +3133 # . . call +3134 e8/call stream-add4/disp32 +3135 # . . discard args +3136 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +3137 # component under test +3138 # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) +3139 # . . push args +3140 52/push-EDX +3141 51/push-ECX +3142 68/push _test-output-buffered-file/imm32 +3143 68/push _test-input-stream/imm32 +3144 # . . call +3145 e8/call emit-segments/disp32 +3146 # . . discard args +3147 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +3148 # checks +3149 # . flush(_test-output-buffered-file) +3150 # . . push args +3151 68/push _test-output-buffered-file/imm32 +3152 # . . call +3153 e8/call flush/disp32 +3154 # . . discard args +3155 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3156 +-- 33 lines: #? # dump output --------------------------------------------------------------------------------------------------------------------------- +3189 # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg) +3190 # . . push args +3191 68/push "F - test-emit-segments-code-label-absolute/0"/imm32 +3192 68/push "ab cd "/imm32 +3193 68/push _test-output-stream/imm32 +3194 # . . call +3195 e8/call check-next-stream-line-equal/disp32 +3196 # . . discard args +3197 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +3198 # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg) +3199 # . . push args +3200 68/push "F - test-emit-segments-code-label-absolute/1"/imm32 +3201 68/push "ef gh "/imm32 +3202 68/push _test-output-stream/imm32 +3203 # . . call +3204 e8/call check-next-stream-line-equal/disp32 +3205 # . . discard args +3206 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +3207 # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg) +3208 # . . push args +3209 68/push "F - test-emit-segments-code-label-absolute/2"/imm32 +3210 68/push "ij 56 10 00 00 "/imm32 +3211 68/push _test-output-stream/imm32 +3212 # . . call +3213 e8/call check-next-stream-line-equal/disp32 +3214 # . . discard args +3215 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +3216 # . epilog +3217 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3218 5d/pop-to-EBP +3219 c3/return +3220 +3221 emit-headers: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) +3222 # pseudocode: +3223 # emit-elf-header(out, segments, labels) +3224 # curr-segment = segments->data +3225 # max = segments->data + segments->write +3226 # while true +3227 # if (curr-segment >= max) break +3228 # emit-elf-program-header-entry(out, curr-segment) +3229 # curr-segment += 16 # size of a row +3230 # +3231 # . prolog +3232 55/push-EBP +3233 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3234 # . save registers +3235 50/push-EAX +3236 51/push-ECX +3237 +-- 9 lines: #? # write(2/stderr, "emit-elf-header\n") -------------------------------------------------------------------------------------------------- +3246 # emit-elf-header(out, segments, labels) +3247 # . . push args +3248 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +3249 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +3250 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3251 # . . call +3252 e8/call emit-elf-header/disp32 +3253 # . . discard args +3254 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +3255 # EAX = segments +3256 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX +3257 # ECX = segments->write +3258 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +3259 # curr-segment/EAX = segments->data +3260 8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 0xc/disp8 . # copy EAX+12 to EAX +3261 # max/ECX = segments->data + segments->write +3262 01/add 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to ECX +3263 $emit-headers:loop: +3264 # if (curr-segment >= max) break +3265 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX +3266 0f 83/jump-if-greater-or-equal-unsigned $emit-headers:end/disp32 +3267 +-- 69 lines: #? # dump curr-segment->name --------------------------------------------------------------------------------------------------------------- +3336 +-- 9 lines: #? # write(2/stderr, "emit-segment-header\n") ---------------------------------------------------------------------------------------------- +3345 # emit-elf-program-header-entry(out, curr-segment) +3346 # . . push args +3347 50/push-EAX +3348 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3349 # . . call +3350 e8/call emit-elf-program-header-entry/disp32 +3351 # . . discard args +3352 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3353 # curr-segment += 16 # size of a row +3354 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0x10/imm32 # add to EAX +3355 e9/jump $emit-headers:loop/disp32 +3356 $emit-headers:end: +3357 # . restore registers +3358 59/pop-to-ECX +3359 58/pop-to-EAX +3360 # . epilog +3361 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3362 5d/pop-to-EBP +3363 c3/return +3364 +3365 emit-elf-header: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) +3366 # pseudocode +3367 # *Elf_e_entry = get(labels, "Entry")->address +3368 # *Elf_e_phnum = segments->write / 16 # size of a row +3369 # emit-hex-array(out, Elf_header) +3370 # write-buffered(out, "\n") +3371 # +3372 # . prolog +3373 55/push-EBP +3374 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3375 # . save registers +3376 50/push-EAX +3377 51/push-ECX +3378 52/push-EDX # just because we need to call idiv +3379 # *Elf_e_entry = get(labels, "Entry")->address +3380 # . EAX = labels +3381 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX +3382 # . label-info/EAX = get(labels, "Entry", row-size=16, "label table") +3383 # . . push args +3384 68/push "label table"/imm32 +3385 68/push 0x10/imm32/row-size +3386 68/push "Entry"/imm32 +3387 50/push-EAX +3388 # . . call +3389 e8/call get/disp32 +3390 # . . discard args +3391 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP +3392 # . EAX = label-info->address +3393 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 8/disp8 . # copy *(EAX+8) to EAX +3394 # . *Elf_e_entry = EAX +3395 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_entry/disp32 # copy EAX to *Elf_e_entry +3396 # *Elf_e_phnum = segments->write / 0x10 +3397 # . EAX = segments +3398 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX +3399 # . len/EAX = segments->write +3400 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX +3401 # . EAX = len / 0x10 (destroying EDX) +3402 b9/copy-to-ECX 0x10/imm32 +3403 31/xor 3/mod/direct 2/rm32/EDX . . . 2/r32/EDX . . # clear EDX +3404 f7 7/subop/idiv 3/mod/direct 1/rm32/ECX . . . . . . # divide EDX:EAX by ECX, storing quotient in EAX and remainder in EDX +3405 # . *Elf_e_phnum = EAX +3406 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_phnum/disp32 # copy EAX to *Elf_e_phnum +3407 # emit-hex-array(out, Elf_header) +3408 # . . push args +3409 68/push Elf_header/imm32 +3410 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3411 # . . call +3412 e8/call emit-hex-array/disp32 +3413 # . . discard args +3414 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3415 # write-buffered(out, "\n") +3416 # . . push args +3417 68/push "\n"/imm32 +3418 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3419 # . . call +3420 e8/call write-buffered/disp32 +3421 # . . discard args +3422 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3423 $emit-elf-header:end: +3424 # . restore registers +3425 5a/pop-to-EDX +3426 59/pop-to-ECX +3427 58/pop-to-EAX +3428 # . epilog +3429 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3430 5d/pop-to-EBP +3431 c3/return +3432 +3433 emit-elf-program-header-entry: # out : (address buffered-file), curr-segment : (address {string, segment-info}) +3434 # pseudocode: +3435 # *Elf_p_offset = curr-segment->file-offset +3436 # *Elf_p_vaddr = curr-segment->address +3437 # *Elf_p_paddr = curr-segment->address +3438 # *Elf_p_filesz = curr-segment->size +3439 # *Elf_p_memsz = curr-segment->size +3440 # if curr-segment->name == "code" +3441 # *Elf_p_flags = 5 # r-x +3442 # else +3443 # *Elf_p_flags = 6 # rw- +3444 # emit-hex-array(out, Elf_program_header_entry) +3445 # write-buffered(out, "\n") +3446 # +3447 # . prolog +3448 55/push-EBP +3449 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3450 # . save registers +3451 50/push-EAX +3452 56/push-ESI +3453 # ESI = curr-segment +3454 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI +3455 # *Elf_p_offset = curr-segment->file-offset +3456 # . EAX = curr-segment->file-offset +3457 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 8/disp8 . # copy *(ESI+8) to EAX +3458 # . *Elf_p_offset = EAX +3459 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_offset/disp32 # copy EAX to *Elf_p_offset +3460 # *Elf_p_vaddr = curr-segment->address +3461 # . EAX = curr-segment->address +3462 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX +3463 # . *Elf_p_vaddr = EAX +3464 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_vaddr/disp32 # copy EAX to *Elf_p_vaddr +3465 # *Elf_p_paddr = curr-segment->address +3466 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_paddr/disp32 # copy EAX to *Elf_p_paddr +3467 # *Elf_p_filesz = curr-segment->size +3468 # . EAX = curr-segment->size +3469 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy *(ESI+12) to EAX +3470 # . *Elf_p_filesz = EAX +3471 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_filesz/disp32 # copy EAX to *Elf_p_filesz +3472 # *Elf_p_memsz = curr-segment->size +3473 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_memsz/disp32 # copy EAX to *Elf_p_memsz +3474 # if (!string-equal?(curr-segment->name, "code") goto next check +3475 # . EAX = curr-segment->name +3476 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX +3477 # . EAX = string-equal?(curr-segment->name, "code") +3478 # . . push args +3479 68/push "code"/imm32 +3480 50/push-EAX +3481 # . . call +3482 e8/call string-equal?/disp32 +3483 # . . discard args +3484 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3485 # . if (EAX == 0) goto next check +3486 3d/compare-EAX-and 0/imm32 +3487 74/jump-if-equal $emit-elf-program-header-entry:data/disp8 +3488 # *Elf_p_flags = r-x +3489 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 5/imm32 # copy to *Elf_p_flags +3490 eb/jump $emit-elf-program-header-entry:really-emit/disp8 +3491 $emit-elf-program-header-entry:data: +3492 # otherwise *Elf_p_flags = rw- +3493 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 6/imm32 # copy to *Elf_p_flags +3494 $emit-elf-program-header-entry:really-emit: +3495 # emit-hex-array(out, Elf_program_header_entry) +3496 # . . push args +3497 68/push Elf_program_header_entry/imm32 +3498 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3499 # . . call +3500 e8/call emit-hex-array/disp32 +3501 # . . discard args +3502 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3503 # write-buffered(out, "\n") +3504 # . . push args +3505 68/push "\n"/imm32 +3506 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3507 # . . call +3508 e8/call write-buffered/disp32 +3509 # . . discard args +3510 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3511 $emit-elf-program-header-entry:end: +3512 # . restore registers +3513 5e/pop-to-ESI +3514 58/pop-to-EAX +3515 # . epilog +3516 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3517 5d/pop-to-EBP +3518 c3/return +3519 +3520 # - some helpers for tests +3521 +3522 stream-add4: # in : (address stream byte), key : address, val1 : address, val2 : address, val3 : address +3523 # . prolog +3524 55/push-EBP +3525 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3526 # . save registers +3527 50/push-EAX +3528 51/push-ECX +3529 52/push-EDX +3530 56/push-ESI +3531 # ESI = in +3532 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +3533 # curr/EAX = in->data + in->write +3534 # . EAX = in->write +3535 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX +3536 # . EAX = ESI+EAX+12 +3537 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX +3538 # max/EDX = in->data + in->length +3539 # . EDX = in->length +3540 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 8/disp8 . # copy *(ESI+8) to EDX +3541 # . EDX = ESI+EDX+12 +3542 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ESI+EDX+12 to EDX +3543 # if (curr >= max) abort +3544 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX +3545 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 +3546 # *curr = key +3547 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX +3548 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX +3549 # curr += 4 +3550 05/add-to-EAX 4/imm32 +3551 # if (curr >= max) abort +3552 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX +3553 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 +3554 # *curr = val1 +3555 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX +3556 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX +3557 # curr += 4 +3558 05/add-to-EAX 4/imm32 +3559 # if (curr >= max) abort +3560 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX +3561 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 +3562 # *curr = val2 +3563 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x14/disp8 . # copy *(EBP+20) to ECX +3564 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX +3565 # curr += 4 +3566 05/add-to-EAX 4/imm32 +3567 # if (curr >= max) abort +3568 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX +3569 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 +3570 # *curr = val3 +3571 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x18/disp8 . # copy *(EBP+24) to ECX +3572 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX +3573 # in->write += 16 +3574 81 0/subop/add 0/mod/indirect 6/rm32/ESI . . . . . 0x10/imm32 # add to *ESI +3575 $stream-add4:end: +3576 # . restore registers +3577 5e/pop-to-ESI +3578 5a/pop-to-EDX +3579 59/pop-to-ECX +3580 58/pop-to-EAX +3581 # . epilog +3582 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3583 5d/pop-to-EBP +3584 c3/return +3585 +3586 $stream-add4:abort: +3587 # . _write(2/stderr, error) +3588 # . . push args +3589 68/push "overflow in stream-add4\n"/imm32 +3590 68/push 2/imm32/stderr +3591 # . . call +3592 e8/call _write/disp32 +3593 # . . discard args +3594 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3595 # . syscall(exit, 1) +3596 bb/copy-to-EBX 1/imm32 +3597 b8/copy-to-EAX 1/imm32/exit +3598 cd/syscall 0x80/imm8 +3599 # never gets here +3600 +3601 # some variants of 'trace' that take multiple arguments in different combinations of types: +3602 # n: int +3603 # c: character [4-bytes, will eventually be UTF-8] +3604 # s: (address string) +3605 # l: (address slice) +3606 # one gotcha: 's5' must not be empty +3607 +3608 trace-sssns: # s1 : (address string), s2 : (address string), s3 : (address string), n4 : int, s5 : (address string) +3609 # . prolog +3610 55/push-EBP +3611 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3612 # write(*Trace-stream, s1) +3613 # . . push args +3614 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3615 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3616 # . . call +3617 e8/call write/disp32 +3618 # . . discard args +3619 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3620 # write(*Trace-stream, s2) +3621 # . . push args +3622 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +3623 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3624 # . . call +3625 e8/call write/disp32 +3626 # . . discard args +3627 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3628 # write(*Trace-stream, s3) +3629 # . . push args +3630 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +3631 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3632 # . . call +3633 e8/call write/disp32 +3634 # . . discard args +3635 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3636 # print-int32(*Trace-stream, n4) +3637 # . . push args +3638 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +3639 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3640 # . . call +3641 e8/call print-int32/disp32 +3642 # . . discard args +3643 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3644 # trace(s5) # implicitly adds a newline and finalizes the trace line +3645 # . . push args +3646 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) +3647 # . . call +3648 e8/call trace/disp32 +3649 # . . discard args +3650 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3651 $trace-sssns:end: +3652 # . epilog +3653 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3654 5d/pop-to-EBP +3655 c3/return +3656 +3657 test-trace-sssns: +3658 # . prolog +3659 55/push-EBP +3660 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3661 # setup +3662 # . *Trace-stream->write = 0 +3663 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX +3664 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX +3665 # trace-sssns("A" "b" "c " 3 " e") +3666 # . . push args +3667 68/push " e"/imm32 +3668 68/push 3/imm32 +3669 68/push "c "/imm32 +3670 68/push "b"/imm32 +3671 68/push "A"/imm32 +3672 # . . call +3673 e8/call trace-sssns/disp32 +3674 # . . discard args +3675 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +3676 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- +3702 # check-trace-contains("Abc 0x00000003 e") +3703 # . . push args +3704 68/push "F - test-trace-sssns"/imm32 +3705 68/push "Abc 0x00000003 e"/imm32 +3706 # . . call +3707 e8/call check-trace-contains/disp32 +3708 # . . discard args +3709 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3710 # . epilog +3711 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3712 5d/pop-to-EBP +3713 c3/return +3714 +3715 trace-snsns: # s1 : (address string), n2 : int, s3 : (address string), n4 : int, s5 : (address string) +3716 # . prolog +3717 55/push-EBP +3718 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3719 # write(*Trace-stream, s1) +3720 # . . push args +3721 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3722 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3723 # . . call +3724 e8/call write/disp32 +3725 # . . discard args +3726 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3727 # print-int32(*Trace-stream, n2) +3728 # . . push args +3729 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +3730 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3731 # . . call +3732 e8/call print-int32/disp32 +3733 # . . discard args +3734 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3735 # write(*Trace-stream, s3) +3736 # . . push args +3737 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +3738 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3739 # . . call +3740 e8/call write/disp32 +3741 # . . discard args +3742 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3743 # print-int32(*Trace-stream, n4) +3744 # . . push args +3745 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +3746 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3747 # . . call +3748 e8/call print-int32/disp32 +3749 # . . discard args +3750 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3751 # trace(s5) # implicitly adds a newline and finalizes the trace line +3752 # . . push args +3753 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) +3754 # . . call +3755 e8/call trace/disp32 +3756 # . . discard args +3757 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3758 $trace-snsns:end: +3759 # . epilog +3760 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3761 5d/pop-to-EBP +3762 c3/return +3763 +3764 test-trace-snsns: +3765 # . prolog +3766 55/push-EBP +3767 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3768 # setup +3769 # . *Trace-stream->write = 0 +3770 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX +3771 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX +3772 # trace-snsns("A " 2 " c " 3 " e") +3773 # . . push args +3774 68/push " e"/imm32 +3775 68/push 3/imm32 +3776 68/push " c "/imm32 +3777 68/push 2/imm32 +3778 68/push "A "/imm32 +3779 # . . call +3780 e8/call trace-snsns/disp32 +3781 # . . discard args +3782 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +3783 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- +3809 # check-trace-contains("Abc 0x00000003 e") +3810 # . . push args +3811 68/push "F - test-trace-snsns"/imm32 +3812 68/push "A 0x00000002 c 0x00000003 e"/imm32 +3813 # . . call +3814 e8/call check-trace-contains/disp32 +3815 # . . discard args +3816 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3817 # . epilog +3818 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3819 5d/pop-to-EBP +3820 c3/return +3821 +3822 trace-slsls: # s1 : (address string), l2 : (address slice), s3 : (address string), l4 : (address slice), s5 : (address string) +3823 # . prolog +3824 55/push-EBP +3825 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3826 # write(*Trace-stream, s1) +3827 # . . push args +3828 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3829 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3830 # . . call +3831 e8/call write/disp32 +3832 # . . discard args +3833 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3834 # write-slice(*Trace-stream, l2) +3835 # . . push args +3836 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +3837 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3838 # . . call +3839 e8/call write-slice/disp32 +3840 # . . discard args +3841 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3842 # write(*Trace-stream, s3) +3843 # . . push args +3844 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +3845 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3846 # . . call +3847 e8/call write/disp32 +3848 # . . discard args +3849 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3850 # write-slice(*Trace-stream, l4) +3851 # . . push args +3852 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +3853 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3854 # . . call +3855 e8/call write-slice/disp32 +3856 # . . discard args +3857 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3858 # trace(s5) # implicitly adds a newline and finalizes the trace line +3859 # . . push args +3860 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) +3861 # . . call +3862 e8/call trace/disp32 +3863 # . . discard args +3864 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3865 $trace-slsls:end: +3866 # . epilog +3867 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3868 5d/pop-to-EBP +3869 c3/return +3870 +3871 test-trace-slsls: +3872 # . prolog +3873 55/push-EBP +3874 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3875 # setup +3876 # . *Trace-stream->write = 0 +3877 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX +3878 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX +3879 # (EAX..ECX) = "b" +3880 b8/copy-to-EAX "b"/imm32 +3881 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +3882 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +3883 05/add-to-EAX 4/imm32 +3884 # var b/EBX : (address slice) = {EAX, ECX} +3885 51/push-ECX +3886 50/push-EAX +3887 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX +3888 # (EAX..ECX) = "d" +3889 b8/copy-to-EAX "d"/imm32 +3890 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +3891 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +3892 05/add-to-EAX 4/imm32 +3893 # var d/EDX : (address slice) = {EAX, ECX} +3894 51/push-ECX +3895 50/push-EAX +3896 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX +3897 # trace-slsls("A" b "c" d "e") +3898 # . . push args +3899 68/push "e"/imm32 +3900 52/push-EDX +3901 68/push "c"/imm32 +3902 53/push-EBX +3903 68/push "A"/imm32 +3904 # . . call +3905 e8/call trace-slsls/disp32 +3906 # . . discard args +3907 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +3908 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- +3934 # check-trace-contains("Abcde") +3935 # . . push args +3936 68/push "F - test-trace-slsls"/imm32 +3937 68/push "Abcde"/imm32 +3938 # . . call +3939 e8/call check-trace-contains/disp32 +3940 # . . discard args +3941 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3942 # . epilog +3943 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3944 5d/pop-to-EBP +3945 c3/return +3946 +3947 trace-slsns: # s1 : (address string), l2 : (address slice), s3 : (address string), n4 : int, s5 : (address string) +3948 # . prolog +3949 55/push-EBP +3950 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +3951 # write(*Trace-stream, s1) +3952 # . . push args +3953 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +3954 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3955 # . . call +3956 e8/call write/disp32 +3957 # . . discard args +3958 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3959 # write-slice(*Trace-stream, l2) +3960 # . . push args +3961 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +3962 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3963 # . . call +3964 e8/call write-slice/disp32 +3965 # . . discard args +3966 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3967 # write(*Trace-stream, s3) +3968 # . . push args +3969 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +3970 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3971 # . . call +3972 e8/call write/disp32 +3973 # . . discard args +3974 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3975 # print-int32(*Trace-stream, n4) +3976 # . . push args +3977 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +3978 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +3979 # . . call +3980 e8/call print-int32/disp32 +3981 # . . discard args +3982 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +3983 # trace(s5) # implicitly adds a newline and finalizes the trace line +3984 # . . push args +3985 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) +3986 # . . call +3987 e8/call trace/disp32 +3988 # . . discard args +3989 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +3990 $trace-slsns:end: +3991 # . epilog +3992 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +3993 5d/pop-to-EBP +3994 c3/return +3995 +3996 test-trace-slsns: +3997 # . prolog +3998 55/push-EBP +3999 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4000 # setup +4001 # . *Trace-stream->write = 0 +4002 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX +4003 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX +4004 # (EAX..ECX) = "b" +4005 b8/copy-to-EAX "b"/imm32 +4006 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +4007 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +4008 05/add-to-EAX 4/imm32 +4009 # var b/EBX : (address slice) = {EAX, ECX} +4010 51/push-ECX +4011 50/push-EAX +4012 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX +4013 # trace-slsls("A" b "c " 3 " e") +4014 # . . push args +4015 68/push " e"/imm32 +4016 68/push 3/imm32 +4017 68/push "c "/imm32 +4018 53/push-EBX +4019 68/push "A"/imm32 +4020 # . . call +4021 e8/call trace-slsns/disp32 +4022 # . . discard args +4023 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +4024 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- +4050 # check-trace-contains("Abc 0x00000003 e") +4051 # . . push args +4052 68/push "F - test-trace-slsls"/imm32 +4053 68/push "Abc 0x00000003 e"/imm32 +4054 # . . call +4055 e8/call check-trace-contains/disp32 +4056 # . . discard args +4057 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4058 # . epilog +4059 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4060 5d/pop-to-EBP +4061 c3/return +4062 +4063 trace-slsss: # s1 : (address string), l2 : (address slice), s3 : (address string), s4 : (address string), s5 : (address string) +4064 # . prolog +4065 55/push-EBP +4066 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4067 # write(*Trace-stream, s1) +4068 # . . push args +4069 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +4070 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +4071 # . . call +4072 e8/call write/disp32 +4073 # . . discard args +4074 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4075 # write-slice(*Trace-stream, l2) +4076 # . . push args +4077 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +4078 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +4079 # . . call +4080 e8/call write-slice/disp32 +4081 # . . discard args +4082 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4083 # write(*Trace-stream, s3) +4084 # . . push args +4085 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) +4086 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +4087 # . . call +4088 e8/call write/disp32 +4089 # . . discard args +4090 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4091 # write(*Trace-stream, s4) +4092 # . . push args +4093 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) +4094 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream +4095 # . . call +4096 e8/call write/disp32 +4097 # . . discard args +4098 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4099 # trace(s5) # implicitly adds a newline and finalizes the trace line +4100 # . . push args +4101 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) +4102 # . . call +4103 e8/call trace/disp32 +4104 # . . discard args +4105 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4106 $trace-slsss:end: +4107 # . epilog +4108 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4109 5d/pop-to-EBP +4110 c3/return +4111 +4112 test-trace-slsss: +4113 # . prolog +4114 55/push-EBP +4115 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4116 # setup +4117 # . *Trace-stream->write = 0 +4118 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX +4119 c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX +4120 # (EAX..ECX) = "b" +4121 b8/copy-to-EAX "b"/imm32 +4122 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +4123 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +4124 05/add-to-EAX 4/imm32 +4125 # var b/EBX : (address slice) = {EAX, ECX} +4126 51/push-ECX +4127 50/push-EAX +4128 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX +4129 # trace-slsss("A" b "c" "d" "e") +4130 # . . push args +4131 68/push "e"/imm32 +4132 68/push "d"/imm32 +4133 68/push "c"/imm32 +4134 53/push-EBX +4135 68/push "A"/imm32 +4136 # . . call +4137 e8/call trace-slsss/disp32 +4138 # . . discard args +4139 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP +4140 +-- 26 lines: #? # dump *Trace-stream -------------------------------------------------------------------------------------------------------------------- +4166 # check-trace-contains("Abcde") +4167 # . . push args +4168 68/push "F - test-trace-slsss"/imm32 +4169 68/push "Abcde"/imm32 +4170 # . . call +4171 e8/call check-trace-contains/disp32 +4172 # . . discard args +4173 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4174 # . epilog +4175 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4176 5d/pop-to-EBP +4177 c3/return +4178 +4179 num-bytes: # line : (address stream) -> EAX : int +4180 # pseudocode: +4181 # result = 0 +4182 # while true +4183 # var word-slice = next-word(line) +4184 # if slice-empty?(word-slice) # end of line +4185 # break +4186 # if slice-starts-with?(word-slice, "#") # comment +4187 # break +4188 # if is-label?(word-slice) # no need for label declarations anymore +4189 # break +4190 # if slice-equal?(word-slice, "==") +4191 # break # no need for segment header lines +4192 # result += compute-width(word-slice) +4193 # return result +4194 # +4195 # . prolog +4196 55/push-EBP +4197 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4198 # . save registers +4199 51/push-ECX +4200 52/push-EDX +4201 53/push-EBX +4202 # var result/EAX = 0 +4203 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +4204 # var word-slice/ECX = {0, 0} +4205 68/push 0/imm32/end +4206 68/push 0/imm32/start +4207 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +4208 +-- 26 lines: #? # dump line ----------------------------------------------------------------------------------------------------------------------------- +4234 # . rewind-stream(line) +4235 # . . push args +4236 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +4237 # . . call +4238 e8/call rewind-stream/disp32 +4239 # . . discard args +4240 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4241 $num-bytes:loop: +4242 # next-word(line, word-slice) +4243 # . . push args +4244 51/push-ECX +4245 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +4246 # . . call +4247 e8/call next-word/disp32 +4248 # . . discard args +4249 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4250 +-- 46 lines: #? # dump word-slice ----------------------------------------------------------------------------------------------------------------------- +4296 $num-bytes:check0: +4297 # if (slice-empty?(word-slice)) break +4298 # . save result +4299 50/push-EAX +4300 # . EAX = slice-empty?(word-slice) +4301 # . . push args +4302 51/push-ECX +4303 # . . call +4304 e8/call slice-empty?/disp32 +4305 # . . discard args +4306 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4307 # . if (EAX != 0) break +4308 3d/compare-EAX-and 0/imm32 +4309 # . restore result now that ZF is set +4310 58/pop-to-EAX +4311 75/jump-if-not-equal $num-bytes:end/disp8 +4312 $num-bytes:check-for-comment: +4313 # if (slice-starts-with?(word-slice, "#")) break +4314 # . start/EDX = word-slice->start +4315 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX +4316 # . c/EBX = *start +4317 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +4318 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 3/r32/BL . . # copy byte at *EDX to BL +4319 # . if (EBX == '#') break +4320 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x23/imm32/hash # compare EBX +4321 74/jump-if-equal $num-bytes:end/disp8 +4322 $num-bytes:check-for-label: +4323 # if (slice-ends-with?(word-slice, ":")) break +4324 # . end/EDX = word-slice->end +4325 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX +4326 # . c/EBX = *(end-1) +4327 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +4328 8a/copy-byte 1/mod/*+disp8 2/rm32/EDX . . . 3/r32/BL -1/disp8 . # copy byte at *ECX to BL +4329 # . if (EBX == ':') break +4330 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x3a/imm32/colon # compare EBX +4331 74/jump-if-equal $num-bytes:end/disp8 +4332 $num-bytes:check-for-segment-header: +4333 # if (slice-equal?(word-slice, "==")) break +4334 # . push result +4335 50/push-EAX +4336 # . EAX = slice-equal?(word-slice, "==") +4337 # . . push args +4338 68/push "=="/imm32 +4339 51/push-ECX +4340 # . . call +4341 e8/call slice-equal?/disp32 +4342 # . . discard args +4343 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4344 # . if (EAX != 0) break +4345 3d/compare-EAX-and 0/imm32 +4346 # . restore result now that ZF is set +4347 58/pop-to-EAX +4348 75/jump-if-not-equal $num-bytes:end/disp8 +4349 $num-bytes:loop-body: +4350 # result += compute-width-of-slice(word-slice) +4351 # . copy result to EDX +4352 89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX +4353 # . EAX = compute-width-of-slice(word-slice) +4354 # . . push args +4355 51/push-ECX +4356 # . . call +4357 e8/call compute-width-of-slice/disp32 +4358 # . . discard args +4359 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4360 # . EAX += result +4361 01/add 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # add EDX to EAX +4362 e9/jump $num-bytes:loop/disp32 +4363 $num-bytes:end: +4364 # . rewind-stream(line) +4365 # . . push args +4366 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) +4367 # . . call +4368 e8/call rewind-stream/disp32 +4369 # . . discard args +4370 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4371 # . reclaim locals +4372 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4373 # . restore registers +4374 5b/pop-to-EBX +4375 5a/pop-to-EDX +4376 59/pop-to-ECX +4377 # . epilog +4378 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4379 5d/pop-to-EBP +4380 c3/return +4381 +4382 test-num-bytes-handles-empty-string: +4383 # if a line starts with '#', return 0 +4384 # . prolog +4385 55/push-EBP +4386 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4387 # setup +4388 # . clear-stream(_test-input-stream) +4389 # . . push args +4390 68/push _test-input-stream/imm32 +4391 # . . call +4392 e8/call clear-stream/disp32 +4393 # . . discard args +4394 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4395 # . clear-stream(_test-output-stream) +4396 # . . push args +4397 68/push _test-output-stream/imm32 +4398 # . . call +4399 e8/call clear-stream/disp32 +4400 # . . discard args +4401 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4402 # no contents in input +4403 # EAX = num-bytes(_test-input-stream) +4404 # . . push args +4405 68/push _test-input-stream/imm32 +4406 # . . call +4407 e8/call num-bytes/disp32 +4408 # . . discard args +4409 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4410 # check-ints-equal(EAX, 0, msg) +4411 # . . push args +4412 68/push "F - test-num-bytes-handles-empty-string"/imm32 +4413 68/push 0/imm32/true +4414 50/push-EAX +4415 # . . call +4416 e8/call check-ints-equal/disp32 +4417 # . . discard args +4418 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +4419 # . epilog +4420 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4421 5d/pop-to-EBP +4422 c3/return +4423 +4424 test-num-bytes-ignores-comments: +4425 # if a line starts with '#', return 0 +4426 # . prolog +4427 55/push-EBP +4428 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4429 # setup +4430 # . clear-stream(_test-input-stream) +4431 # . . push args +4432 68/push _test-input-stream/imm32 +4433 # . . call +4434 e8/call clear-stream/disp32 +4435 # . . discard args +4436 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4437 # . clear-stream(_test-output-stream) +4438 # . . push args +4439 68/push _test-output-stream/imm32 +4440 # . . call +4441 e8/call clear-stream/disp32 +4442 # . . discard args +4443 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4444 # initialize input +4445 # . write(_test-input-stream, "# abcd") +4446 # . . push args +4447 68/push "# abcd"/imm32 +4448 68/push _test-input-stream/imm32 +4449 # . . call +4450 e8/call write/disp32 +4451 # . . discard args +4452 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4453 # EAX = num-bytes(_test-input-stream) +4454 # . . push args +4455 68/push _test-input-stream/imm32 +4456 # . . call +4457 e8/call num-bytes/disp32 +4458 # . . discard args +4459 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4460 # check-ints-equal(EAX, 0, msg) +4461 # . . push args +4462 68/push "F - test-num-bytes-ignores-comments"/imm32 +4463 68/push 0/imm32/true +4464 50/push-EAX +4465 # . . call +4466 e8/call check-ints-equal/disp32 +4467 # . . discard args +4468 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +4469 # . epilog +4470 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4471 5d/pop-to-EBP +4472 c3/return +4473 +4474 test-num-bytes-ignores-labels: +4475 # if the first word ends with ':', return 0 +4476 # . prolog +4477 55/push-EBP +4478 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4479 # setup +4480 # . clear-stream(_test-input-stream) +4481 # . . push args +4482 68/push _test-input-stream/imm32 +4483 # . . call +4484 e8/call clear-stream/disp32 +4485 # . . discard args +4486 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4487 # . clear-stream(_test-output-stream) +4488 # . . push args +4489 68/push _test-output-stream/imm32 +4490 # . . call +4491 e8/call clear-stream/disp32 +4492 # . . discard args +4493 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4494 # initialize input +4495 # . write(_test-input-stream, "ab: # cd") +4496 # . . push args +4497 68/push "ab: # cd"/imm32 +4498 68/push _test-input-stream/imm32 +4499 # . . call +4500 e8/call write/disp32 +4501 # . . discard args +4502 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4503 # EAX = num-bytes(_test-input-stream) +4504 # . . push args +4505 68/push _test-input-stream/imm32 +4506 # . . call +4507 e8/call num-bytes/disp32 +4508 # . . discard args +4509 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4510 # check-ints-equal(EAX, 0, msg) +4511 # . . push args +4512 68/push "F - test-num-bytes-ignores-labels"/imm32 +4513 68/push 0/imm32/true +4514 50/push-EAX +4515 # . . call +4516 e8/call check-ints-equal/disp32 +4517 # . . discard args +4518 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +4519 # . epilog +4520 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4521 5d/pop-to-EBP +4522 c3/return +4523 +4524 test-num-bytes-ignores-segment-headers: +4525 # if the first word is '==', return 0 +4526 # . prolog +4527 55/push-EBP +4528 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4529 # setup +4530 # . clear-stream(_test-input-stream) +4531 # . . push args +4532 68/push _test-input-stream/imm32 +4533 # . . call +4534 e8/call clear-stream/disp32 +4535 # . . discard args +4536 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4537 # . clear-stream(_test-output-stream) +4538 # . . push args +4539 68/push _test-output-stream/imm32 +4540 # . . call +4541 e8/call clear-stream/disp32 +4542 # . . discard args +4543 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4544 # initialize input +4545 # . write(_test-input-stream, "== ab cd") +4546 # . . push args +4547 68/push "== ab cd"/imm32 +4548 68/push _test-input-stream/imm32 +4549 # . . call +4550 e8/call write/disp32 +4551 # . . discard args +4552 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4553 # EAX = num-bytes(_test-input-stream) +4554 # . . push args +4555 68/push _test-input-stream/imm32 +4556 # . . call +4557 e8/call num-bytes/disp32 +4558 # . . discard args +4559 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4560 # check-ints-equal(EAX, 0, msg) +4561 # . . push args +4562 68/push "F - test-num-bytes-ignores-segment-headers"/imm32 +4563 68/push 0/imm32/true +4564 50/push-EAX +4565 # . . call +4566 e8/call check-ints-equal/disp32 +4567 # . . discard args +4568 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +4569 # . epilog +4570 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4571 5d/pop-to-EBP +4572 c3/return +4573 +4574 test-num-bytes-counts-words-by-default: +4575 # without metadata, count words +4576 # . prolog +4577 55/push-EBP +4578 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4579 # setup +4580 # . clear-stream(_test-input-stream) +4581 # . . push args +4582 68/push _test-input-stream/imm32 +4583 # . . call +4584 e8/call clear-stream/disp32 +4585 # . . discard args +4586 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4587 # . clear-stream(_test-output-stream) +4588 # . . push args +4589 68/push _test-output-stream/imm32 +4590 # . . call +4591 e8/call clear-stream/disp32 +4592 # . . discard args +4593 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4594 # initialize input +4595 # . write(_test-input-stream, "ab cd ef") +4596 # . . push args +4597 68/push "ab cd ef"/imm32 +4598 68/push _test-input-stream/imm32 +4599 # . . call +4600 e8/call write/disp32 +4601 # . . discard args +4602 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4603 # EAX = num-bytes(_test-input-stream) +4604 # . . push args +4605 68/push _test-input-stream/imm32 +4606 # . . call +4607 e8/call num-bytes/disp32 +4608 # . . discard args +4609 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4610 # check-ints-equal(EAX, 3, msg) +4611 # . . push args +4612 68/push "F - test-num-bytes-counts-words-by-default"/imm32 +4613 68/push 3/imm32/true +4614 50/push-EAX +4615 # . . call +4616 e8/call check-ints-equal/disp32 +4617 # . . discard args +4618 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +4619 # . epilog +4620 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4621 5d/pop-to-EBP +4622 c3/return +4623 +4624 test-num-bytes-ignores-trailing-comment: +4625 # trailing comments appropriately ignored +4626 # . prolog +4627 55/push-EBP +4628 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4629 # setup +4630 # . clear-stream(_test-input-stream) +4631 # . . push args +4632 68/push _test-input-stream/imm32 +4633 # . . call +4634 e8/call clear-stream/disp32 +4635 # . . discard args +4636 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4637 # . clear-stream(_test-output-stream) +4638 # . . push args +4639 68/push _test-output-stream/imm32 +4640 # . . call +4641 e8/call clear-stream/disp32 +4642 # . . discard args +4643 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4644 # initialize input +4645 # . write(_test-input-stream, "ab cd # ef") +4646 # . . push args +4647 68/push "ab cd # ef"/imm32 +4648 68/push _test-input-stream/imm32 +4649 # . . call +4650 e8/call write/disp32 +4651 # . . discard args +4652 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4653 # EAX = num-bytes(_test-input-stream) +4654 # . . push args +4655 68/push _test-input-stream/imm32 +4656 # . . call +4657 e8/call num-bytes/disp32 +4658 # . . discard args +4659 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4660 # check-ints-equal(EAX, 2, msg) +4661 # . . push args +4662 68/push "F - test-num-bytes-ignores-trailing-comment"/imm32 +4663 68/push 2/imm32/true +4664 50/push-EAX +4665 # . . call +4666 e8/call check-ints-equal/disp32 +4667 # . . discard args +4668 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +4669 # . epilog +4670 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4671 5d/pop-to-EBP +4672 c3/return +4673 +4674 test-num-bytes-handles-imm32: +4675 # if a word has the /imm32 metadata, count it as 4 bytes +4676 # . prolog +4677 55/push-EBP +4678 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +4679 # setup +4680 # . clear-stream(_test-input-stream) +4681 # . . push args +4682 68/push _test-input-stream/imm32 +4683 # . . call +4684 e8/call clear-stream/disp32 +4685 # . . discard args +4686 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4687 # . clear-stream(_test-output-stream) +4688 # . . push args +4689 68/push _test-output-stream/imm32 +4690 # . . call +4691 e8/call clear-stream/disp32 +4692 # . . discard args +4693 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4694 # initialize input +4695 # . write(_test-input-stream, "ab cd/imm32 ef") +4696 # . . push args +4697 68/push "ab cd/imm32 ef"/imm32 +4698 68/push _test-input-stream/imm32 +4699 # . . call +4700 e8/call write/disp32 +4701 # . . discard args +4702 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +4703 # EAX = num-bytes(_test-input-stream) +4704 # . . push args +4705 68/push _test-input-stream/imm32 +4706 # . . call +4707 e8/call num-bytes/disp32 +4708 # . . discard args +4709 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +4710 # check-ints-equal(EAX, 6, msg) +4711 # . . push args +4712 68/push "F - test-num-bytes-handles-imm32"/imm32 +4713 68/push 6/imm32/true +4714 50/push-EAX +4715 # . . call +4716 e8/call check-ints-equal/disp32 +4717 # . . discard args +4718 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +4719 # . epilog +4720 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +4721 5d/pop-to-EBP +4722 c3/return +4723 +4724 == data +4725 +4726 # This block of bytes gets copied to the start of the output ELF file, with +4727 # some fields filled in. +4728 # http://www.sco.com/developers/gabi/latest/ch4.eheader.html +4729 Elf_header: +4730 # - length +4731 0x34/imm32 +4732 # - data +4733 $e_ident: +4734 7f 45/E 4c/L 46/F +4735 01/32-bit 01/little-endian 01/file-version 00/no-os-extensions +4736 00 00 00 00 00 00 00 00 # 8 bytes of padding +4737 $e_type: +4738 02 00 +4739 $e_machine: +4740 03 00 +4741 $e_version: +4742 1/imm32 +4743 Elf_e_entry: +4744 0x09000000/imm32 # approximate default; must be updated +4745 $e_phoff: +4746 0x34/imm32 # offset for the 'program header table' containing segment headers +4747 $e_shoff: +4748 0/imm32 # no sections +4749 $e_flags: +4750 0/imm32 # unused +4751 $e_ehsize: +4752 0x34 00 +4753 $e_phentsize: +4754 0x20 00 +4755 Elf_e_phnum: +4756 00 00 # number of segments; must be updated +4757 $e_shentsize: +4758 00 00 # no sections +4759 $e_shnum: +4760 00 00 +4761 $e_shstrndx: +4762 00 00 +4763 +4764 # This block of bytes gets copied after the Elf_header once for each segment. +4765 # Some fields need filling in each time. +4766 # https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-83432/index.html +4767 Elf_program_header_entry: +4768 # - length +4769 0x20/imm32 +4770 # - data +4771 $p_type: +4772 1/imm32/PT_LOAD +4773 Elf_p_offset: +4774 0/imm32 # byte offset in the file at which a segment begins; must be updated +4775 Elf_p_vaddr: +4776 0/imm32 # starting address to store the segment at before running the program +4777 Elf_p_paddr: +4778 0/imm32 # should have same value as Elf_p_vaddr +4779 Elf_p_filesz: +4780 0/imm32 +4781 Elf_p_memsz: +4782 0/imm32 # should have same value as Elf_p_filesz +4783 Elf_p_flags: +4784 6/imm32/rw- # read/write/execute permissions for the segment; must be updated for the code segment +4785 $p_align: +4786 # we hold this constant; changing it will require adjusting the way we +4787 # compute the starting address for each segment +4788 0x1000/imm32 +4789 +4790 # . . vim:nowrap:textwidth=0 diff --git a/html/apps/tests.subx.html b/html/apps/tests.subx.html index cb3f896d..0b97db0b 100644 --- a/html/apps/tests.subx.html +++ b/html/apps/tests.subx.html @@ -14,15 +14,15 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.subxH1Comment { color: #005faf; text-decoration: underline; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } +.subxH1Comment { color: #005faf; text-decoration: underline; } --> diff --git a/html/examples/ex1.subx.html b/html/examples/ex1.subx.html index 15b7a0de..2f69914a 100644 --- a/html/examples/ex1.subx.html +++ b/html/examples/ex1.subx.html @@ -15,9 +15,9 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } +.subxS2Comment { color: #8a8a8a; } .LineNr { } .SpecialChar { color: #d70000; } -.subxS2Comment { color: #8a8a8a; } --> @@ -56,7 +56,7 @@ if ('onhashchange' in window) { 1 # First program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html 2 # Just return 42. 3 # - 4 # To run (from the subx directory): + 4 # To run: 5 # $ ./subx translate examples/ex1.2.subx -o examples/ex1 6 # $ ./subx run examples/ex1 7 # Expected result: diff --git a/html/examples/ex10.subx.html b/html/examples/ex10.subx.html index dbe4a83c..c2242bc1 100644 --- a/html/examples/ex10.subx.html +++ b/html/examples/ex10.subx.html @@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.subxS1Comment { color: #0000af; } +.subxS2Comment { color: #8a8a8a; } +.subxFunction { color: #af5f00; text-decoration: underline; } .LineNr { } +.subxS1Comment { color: #0000af; } .SpecialChar { color: #d70000; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } -.subxS2Comment { color: #8a8a8a; } --> @@ -59,7 +59,7 @@ if ('onhashchange' in window) {
  1 # String comparison: return 1 iff the two args passed in at the commandline are equal.
  2 #
- 3 # To run (from the subx directory):
+ 3 # To run:
  4 #   $ ./subx translate examples/ex10.subx -o examples/ex10
  5 #   $ ./subx run examples/ex10 abc abd
  6 # Expected result:
diff --git a/html/examples/ex11.subx.html b/html/examples/ex11.subx.html
index b151ed11..131e587a 100644
--- a/html/examples/ex11.subx.html
+++ b/html/examples/ex11.subx.html
@@ -14,17 +14,17 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; }
 body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
-.subxS2Comment { color: #8a8a8a; }
-.subxH1Comment { color: #005faf; text-decoration: underline; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
+.subxTest { color: #5f8700; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
-.Constant { color: #008787; }
 .subxMinorFunction { color: #875f5f; }
-.subxTest { color: #5f8700; }
+.Constant { color: #008787; }
+.subxS2Comment { color: #8a8a8a; }
+.subxH1Comment { color: #005faf; text-decoration: underline; }
 -->
 
 
@@ -67,7 +67,7 @@ if ('onhashchange' in window) {
   5 # kernel in a few places. This layer implements a function for comparing
   6 # a null-terminated 'kernel string' with a length-prefixed 'SubX string'.
   7 #
-  8 # To run (from the subx directory):
+  8 # To run:
   9 #   $ ./subx translate examples/ex11.subx -o examples/ex11
  10 #   $ ./subx run examples/ex11  # runs a series of tests
  11 #   ......  # all tests pass
diff --git a/html/examples/ex12.subx.html b/html/examples/ex12.subx.html
index 684dc278..0694e505 100644
--- a/html/examples/ex12.subx.html
+++ b/html/examples/ex12.subx.html
@@ -15,11 +15,11 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxS2Comment { color: #8a8a8a; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -58,7 +58,7 @@ if ('onhashchange' in window) {
  1 # Example showing mmap syscall.
  2 # Create a new segment using mmap, save the address, write to it.
  3 #
- 4 # To run (from the subx directory):
+ 4 # To run:
  5 #   $ ./subx translate examples/ex12.subx -o examples/ex12
  6 #   $ ./subx run examples/ex12
  7 # You shouldn't get a segmentation fault.
diff --git a/html/examples/ex2.subx.html b/html/examples/ex2.subx.html
index 5c0cef8a..fd34b63f 100644
--- a/html/examples/ex2.subx.html
+++ b/html/examples/ex2.subx.html
@@ -15,9 +15,9 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
+.subxS2Comment { color: #8a8a8a; }
 .LineNr { }
 .SpecialChar { color: #d70000; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -55,7 +55,7 @@ if ('onhashchange' in window) {
 
  1 # Add 1 and 1, and return the result in the exit code.
  2 #
- 3 # To run (from the subx directory):
+ 3 # To run:
  4 #   $ ./subx translate examples/ex2.subx -o examples/ex2
  5 #   $ ./subx run examples/ex2
  6 # Expected result:
diff --git a/html/examples/ex3.subx.html b/html/examples/ex3.subx.html
index 198fd9c7..9a9ff088 100644
--- a/html/examples/ex3.subx.html
+++ b/html/examples/ex3.subx.html
@@ -15,12 +15,12 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxS2Comment { color: #8a8a8a; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Constant { color: #008787; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -58,7 +58,7 @@ if ('onhashchange' in window) {
 
  1 # Add the first 10 numbers, and return the result in the exit code.
  2 #
- 3 # To run (from the subx directory):
+ 3 # To run:
  4 #   $ ./subx translate examples/ex3.subx -o examples/ex3
  5 #   $ ./subx run examples/ex3
  6 # Expected result:
diff --git a/html/examples/ex4.subx.html b/html/examples/ex4.subx.html
index 3b637ef6..2c76ae70 100644
--- a/html/examples/ex4.subx.html
+++ b/html/examples/ex4.subx.html
@@ -15,10 +15,10 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
-.LineNr { }
-.SpecialChar { color: #d70000; }
 .subxS2Comment { color: #8a8a8a; }
+.LineNr { }
+.subxS1Comment { color: #0000af; }
+.SpecialChar { color: #d70000; }
 -->
 
 
@@ -56,7 +56,7 @@ if ('onhashchange' in window) {
 
  1 # Read a character from stdin, save it to a global, write it to stdout.
  2 #
- 3 # To run (from the subx directory):
+ 3 # To run:
  4 #   $ ./subx translate examples/ex4.subx -o examples/ex4
  5 #   $ ./subx run examples/ex4
  6 
diff --git a/html/examples/ex5.subx.html b/html/examples/ex5.subx.html
index 13af1b8d..62b48e8a 100644
--- a/html/examples/ex5.subx.html
+++ b/html/examples/ex5.subx.html
@@ -15,11 +15,11 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxS2Comment { color: #8a8a8a; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -57,7 +57,7 @@ if ('onhashchange' in window) {
 
  1 # Read a character from stdin, save it to a local on the stack, write it to stdout.
  2 #
- 3 # To run (from the subx directory):
+ 3 # To run:
  4 #   $ ./subx translate examples/ex5.subx -o examples/ex5
  5 #   $ ./subx run examples/ex5
  6 
diff --git a/html/examples/ex6.subx.html b/html/examples/ex6.subx.html
index faedfdfd..140d68c3 100644
--- a/html/examples/ex6.subx.html
+++ b/html/examples/ex6.subx.html
@@ -15,11 +15,11 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxS2Comment { color: #8a8a8a; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -57,7 +57,7 @@ if ('onhashchange' in window) {
 
  1 # Print out a (global variable) string to stdout.
  2 #
- 3 # To run (from the subx directory):
+ 3 # To run:
  4 #   $ ./subx translate examples/ex6.subx -o examples/ex6
  5 #   $ ./subx run examples/ex6
  6 #   Hello, world!
diff --git a/html/examples/ex7.subx.html b/html/examples/ex7.subx.html
index 6c897547..2df98c2e 100644
--- a/html/examples/ex7.subx.html
+++ b/html/examples/ex7.subx.html
@@ -15,11 +15,11 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxS2Comment { color: #8a8a8a; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -61,7 +61,7 @@ if ('onhashchange' in window) {
   4 # it for reading, read a character from it, close it, delete it, and return
   5 # the character read.
   6 #
-  7 # To run (from the subx directory):
+  7 # To run:
   8 #   $ ./subx translate examples/ex7.subx -o examples/ex7
   9 #   $ ./subx run examples/ex7
  10 # Expected result:
diff --git a/html/examples/ex8.subx.html b/html/examples/ex8.subx.html
index bb689d42..51234836 100644
--- a/html/examples/ex8.subx.html
+++ b/html/examples/ex8.subx.html
@@ -15,13 +15,13 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxS2Comment { color: #8a8a8a; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
 .Constant { color: #008787; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -59,7 +59,7 @@ if ('onhashchange' in window) {
 
  1 # Example reading commandline arguments: compute length of first arg.
  2 #
- 3 # To run (from the subx directory):
+ 3 # To run:
  4 #   $ ./subx translate examples/ex8.subx -o examples/ex8
  5 #   $ ./subx run examples/ex8 abc de fghi
  6 # Expected result:
diff --git a/html/examples/ex9.subx.html b/html/examples/ex9.subx.html
index 52e78b3a..e497713e 100644
--- a/html/examples/ex9.subx.html
+++ b/html/examples/ex9.subx.html
@@ -15,12 +15,12 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color:
 a { color:inherit; }
 * { font-size:12pt; font-size: 1em; }
 .subxComment { color: #005faf; }
-.subxS1Comment { color: #0000af; }
+.subxS2Comment { color: #8a8a8a; }
+.subxFunction { color: #af5f00; text-decoration: underline; }
 .LineNr { }
+.subxS1Comment { color: #0000af; }
 .SpecialChar { color: #d70000; }
 .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-.subxFunction { color: #af5f00; text-decoration: underline; }
-.subxS2Comment { color: #8a8a8a; }
 -->
 
 
@@ -61,7 +61,7 @@ if ('onhashchange' in window) {
  3 # Show difference between ascii codes of first letter of first arg and first
  4 # letter of second arg.
  5 #
- 6 # To run (from the subx directory):
+ 6 # To run:
  7 #   $ ./subx translate examples/ex9.subx -o examples/ex9
  8 #   $ ./subx run examples/ex9 z x
  9 # Expected result: