diff options
author | Kartik Agaram <vc@akkartik.com> | 2019-05-10 17:21:17 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2019-05-10 17:21:17 -0700 |
commit | c12e85e1038f1118da0e22a810801b402a67a444 (patch) | |
tree | b41ad0e2b9c6d90bed31a09e8ca1fe56438eeef8 | |
parent | 34a005d0fbe666a22d5fa164f9b7e466400c7d9d (diff) | |
parent | 1ebb7614921a2b426ed84c4c51b100176e2a4187 (diff) | |
download | mu-c12e85e1038f1118da0e22a810801b402a67a444.tar.gz |
Merge branch 'master' into dquotes-1
Segfault in this branch is now fixed.
-rw-r--r-- | subx/012elf.cc | 28 | ||||
-rw-r--r-- | subx/013direct_addressing.cc | 2 | ||||
-rw-r--r-- | subx/020syscalls.cc | 21 | ||||
-rw-r--r-- | subx/037heap.cc | 29 | ||||
-rw-r--r-- | subx/038---literal_strings.cc | 7 | ||||
-rw-r--r-- | subx/039debug.cc | 6 | ||||
-rw-r--r-- | subx/053new-segment.subx | 47 | ||||
-rw-r--r-- | subx/069allocate.subx | 8 | ||||
-rw-r--r-- | subx/070new-stream.subx | 15 | ||||
-rw-r--r-- | subx/072slice.subx | 16 | ||||
-rw-r--r-- | subx/074print-int-decimal.subx | 122 | ||||
-rwxr-xr-x | subx/apps/assort | bin | 21771 -> 21961 bytes | |||
-rw-r--r-- | subx/apps/assort.subx | 24 | ||||
-rwxr-xr-x | subx/apps/crenshaw2-1 | bin | 18959 -> 19120 bytes | |||
-rwxr-xr-x | subx/apps/crenshaw2-1b | bin | 19518 -> 19679 bytes | |||
-rw-r--r-- | subx/apps/dquotes.subx | 24 | ||||
-rwxr-xr-x | subx/apps/factorial | bin | 17875 -> 18036 bytes | |||
-rwxr-xr-x | subx/apps/handle | bin | 18649 -> 18863 bytes | |||
-rw-r--r-- | subx/apps/handle.subx | 74 | ||||
-rwxr-xr-x | subx/apps/hex | bin | 21968 -> 22129 bytes | |||
-rwxr-xr-x | subx/apps/pack | bin | 36560 -> 36721 bytes |
21 files changed, 277 insertions, 146 deletions
diff --git a/subx/012elf.cc b/subx/012elf.cc index 0f058504..d0a3fbd2 100644 --- a/subx/012elf.cc +++ b/subx/012elf.cc @@ -66,6 +66,7 @@ void load_elf_contents(uint8_t* elf_contents, size_t size, int argc, char* argv[ assert(overlap.find(STACK_SEGMENT) == overlap.end()); Mem.push_back(vma(STACK_SEGMENT)); assert(overlap.find(AFTER_STACK) == overlap.end()); + // The stack grows downward. Reg[ESP].u = AFTER_STACK; Reg[EBP].u = 0; EIP = e_entry; @@ -129,15 +130,24 @@ void load_segment_from_program_header(uint8_t* elf_contents, int segment_index, } :(before "End Includes") -// Very primitive/fixed/insecure ELF segments for now: just consecutive VMAs. -// code: 0x09000000 -> 0x09ffffff -// data/heap: 0x0a000000 -> 0x0affffff -// stack: 0x0b000ffc -> 0x0b000000 (downward) -const int CODE_SEGMENT = 0x09000000; -const int DATA_SEGMENT = 0x0a000000; // keep sync'd with `Heap.limit` in allocate.subx -const int STACK_SEGMENT = 0x0b000000; -const int AFTER_STACK = 0x0c000000; -const int ARGV_DATA_SEGMENT = 0x0c000000; +// Very primitive/fixed/insecure ELF segments for now. +// code: 0x09000000 -> 0x09ffffff (specified in ELF binary) +// data: 0x0a000000 -> 0x0affffff (specified in ELF binary) +// --- heap gets mmap'd somewhere here --- +// stack: 0x7dffffff -> 0x7d000000 (downward; not in ELF binary) +// argv hack: 0x7f000000 -> 0x7fffffff (not in ELF binary) +// +// For now we avoid addresses with the most significant bit set; SubX doesn't +// support unsigned comparison yet (https://github.com/akkartik/mu/issues/30) +// Once we do, we can go up to 0xc0000000; higher addresses are reserved for +// the Linux kernel. +const int CODE_SEGMENT = 0x09000000; +const int DATA_SEGMENT = 0x0a000000; +const int STACK_SEGMENT = 0x7d000000; +const int AFTER_STACK = 0x7e000000; +const int ARGV_DATA_SEGMENT = 0x7f000000; +// When updating the above memory map, don't forget to update `mmap`'s +// implementation in the 'syscalls' layer. :(before "End Dump Info for Instruction") //? dump_stack(); // slow :(code) diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index 779c7e0a..c2dfa911 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -488,7 +488,7 @@ void test_shift_right_logical_r32_with_cl() { } :(before "End Op d3 Subops") -case 5: { // shift right r/m32 by CL, preserving sign +case 5: { // shift right r/m32 by CL, padding zeroes trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while padding zeroes" << end(); uint8_t count = Reg[ECX].u & 0x1f; // OF is only defined if count is 1 diff --git a/subx/020syscalls.cc b/subx/020syscalls.cc index a17e9525..6b9faa2c 100644 --- a/subx/020syscalls.cc +++ b/subx/020syscalls.cc @@ -24,14 +24,14 @@ void process_int80() { trace(Callstack_depth+1, "run") << "read: " << Reg[EBX].u << ' ' << Reg[ECX].u << ' ' << Reg[EDX].u << end(); Reg[EAX].i = read(/*file descriptor*/Reg[EBX].u, /*memory buffer*/mem_addr_u8(Reg[ECX].u), /*size*/Reg[EDX].u); trace(Callstack_depth+1, "run") << "result: " << Reg[EAX].i << end(); - if (Reg[EAX].i == -1) raise << strerror(errno) << '\n' << end(); + if (Reg[EAX].i == -1) raise << "read: " << strerror(errno) << '\n' << end(); break; case 4: trace(Callstack_depth+1, "run") << "write: " << Reg[EBX].u << ' ' << Reg[ECX].u << ' ' << Reg[EDX].u << end(); trace(Callstack_depth+1, "run") << Reg[ECX].u << " => " << mem_addr_string(Reg[ECX].u, Reg[EDX].u) << end(); Reg[EAX].i = write(/*file descriptor*/Reg[EBX].u, /*memory buffer*/mem_addr_u8(Reg[ECX].u), /*size*/Reg[EDX].u); trace(Callstack_depth+1, "run") << "result: " << Reg[EAX].i << end(); - if (Reg[EAX].i == -1) raise << strerror(errno) << '\n' << end(); + if (Reg[EAX].i == -1) raise << "write: " << strerror(errno) << '\n' << end(); break; case 5: { check_flags(ECX); @@ -40,14 +40,14 @@ void process_int80() { trace(Callstack_depth+1, "run") << Reg[EBX].u << " => " << mem_addr_kernel_string(Reg[EBX].u) << end(); Reg[EAX].i = open(/*filename*/mem_addr_kernel_string(Reg[EBX].u), /*flags*/Reg[ECX].u, /*mode*/0640); trace(Callstack_depth+1, "run") << "result: " << Reg[EAX].i << end(); - if (Reg[EAX].i == -1) raise << strerror(errno) << '\n' << end(); + if (Reg[EAX].i == -1) raise << "open: " << strerror(errno) << '\n' << end(); break; } case 6: trace(Callstack_depth+1, "run") << "close: " << Reg[EBX].u << end(); Reg[EAX].i = close(/*file descriptor*/Reg[EBX].u); trace(Callstack_depth+1, "run") << "result: " << Reg[EAX].i << end(); - if (Reg[EAX].i == -1) raise << strerror(errno) << '\n' << end(); + if (Reg[EAX].i == -1) raise << "close: " << strerror(errno) << '\n' << end(); break; case 8: check_mode(ECX); @@ -55,14 +55,14 @@ void process_int80() { trace(Callstack_depth+1, "run") << Reg[EBX].u << " => " << mem_addr_kernel_string(Reg[EBX].u) << end(); Reg[EAX].i = creat(/*filename*/mem_addr_kernel_string(Reg[EBX].u), /*mode*/0640); trace(Callstack_depth+1, "run") << "result: " << Reg[EAX].i << end(); - if (Reg[EAX].i == -1) raise << strerror(errno) << '\n' << end(); + if (Reg[EAX].i == -1) raise << "creat: " << strerror(errno) << '\n' << end(); break; case 10: trace(Callstack_depth+1, "run") << "unlink: " << Reg[EBX].u << end(); trace(Callstack_depth+1, "run") << Reg[EBX].u << " => " << mem_addr_kernel_string(Reg[EBX].u) << end(); Reg[EAX].i = unlink(/*filename*/mem_addr_kernel_string(Reg[EBX].u)); trace(Callstack_depth+1, "run") << "result: " << Reg[EAX].i << end(); - if (Reg[EAX].i == -1) raise << strerror(errno) << '\n' << end(); + if (Reg[EAX].i == -1) raise << "unlink: " << strerror(errno) << '\n' << end(); break; case 38: trace(Callstack_depth+1, "run") << "rename: " << Reg[EBX].u << " -> " << Reg[ECX].u << end(); @@ -70,7 +70,7 @@ void process_int80() { trace(Callstack_depth+1, "run") << Reg[ECX].u << " => " << mem_addr_kernel_string(Reg[ECX].u) << end(); Reg[EAX].i = rename(/*old filename*/mem_addr_kernel_string(Reg[EBX].u), /*new filename*/mem_addr_kernel_string(Reg[ECX].u)); trace(Callstack_depth+1, "run") << "result: " << Reg[EAX].i << end(); - if (Reg[EAX].i == -1) raise << strerror(errno) << '\n' << end(); + if (Reg[EAX].i == -1) raise << "rename: " << strerror(errno) << '\n' << end(); break; case 45: // brk: modify size of data segment trace(Callstack_depth+1, "run") << "grow data segment to " << Reg[EBX].u << end(); @@ -110,7 +110,12 @@ void check_mode(int reg) { } :(before "End Globals") -uint32_t Next_segment = 0xb0000000; // 0xc0000000 and up is reserved for Linux kernel +// Very primitive/fixed/insecure mmap segments for now. +// For now we avoid addresses with the most significant bit set; SubX doesn't +// support unsigned comparison yet (https://github.com/akkartik/mu/issues/30) +// Once we do, we can go up to 0xc0000000; higher addresses are reserved for +// the Linux kernel. +uint32_t Next_segment = 0x7c000000; const uint32_t SPACE_FOR_SEGMENT = 0x01000000; :(code) uint32_t new_segment(uint32_t length) { diff --git a/subx/037heap.cc b/subx/037heap.cc deleted file mode 100644 index 315fd0d5..00000000 --- a/subx/037heap.cc +++ /dev/null @@ -1,29 +0,0 @@ -//: Support for dynamic allocation. -//: -//: Just provide a special label marking the first unused address in the data -//: segment. Then we'll write SubX helpers to make use of it. - -:(before "Begin rewrite_global_variables") -insert_heap_global_variable(p); -:(code) -void insert_heap_global_variable(program& p) { - if (SIZE(p.segments) < 2) - return; // no data segment defined - // Start-of-heap: - p.segments.at(1).lines.push_back(label("Start-of-heap")); -} - -line label(string s) { - line result; - result.words.push_back(word()); - result.words.back().data = (s+":"); - return result; -} - -line imm32(const string& s) { - line result; - result.words.push_back(word()); - result.words.back().data = s; - result.words.back().metadata.push_back("imm32"); - return result; -} diff --git a/subx/038---literal_strings.cc b/subx/038---literal_strings.cc index 65a7740b..9b2c3902 100644 --- a/subx/038---literal_strings.cc +++ b/subx/038---literal_strings.cc @@ -184,6 +184,13 @@ void skip_comment(istream& in) { } } +line label(string s) { + line result; + result.words.push_back(word()); + result.words.back().data = (s+":"); + return result; +} + // helper for tests void parse_instruction_character_by_character(const string& line_data) { vector<line> out; diff --git a/subx/039debug.cc b/subx/039debug.cc index 26bb5f7a..8aa40558 100644 --- a/subx/039debug.cc +++ b/subx/039debug.cc @@ -46,14 +46,14 @@ else :(code) string debug_info(uint32_t inst_address) { - uint8_t op = read_mem_u8(EIP); + uint8_t op = read_mem_u8(inst_address); if (op != 0xe8) { ostringstream out; out << HEXBYTE << NUM(op); return out.str(); } - int32_t offset = read_mem_i32(EIP+/*skip op*/1); - uint32_t next_eip = EIP+/*inst length*/5+offset; + int32_t offset = read_mem_i32(inst_address+/*skip op*/1); + uint32_t next_eip = inst_address+/*inst length*/5+offset; if (contains_key(Symbol_name, next_eip)) return "e8/call "+get(Symbol_name, next_eip); ostringstream out; diff --git a/subx/053new-segment.subx b/subx/053new-segment.subx index 1669b097..83c890ea 100644 --- a/subx/053new-segment.subx +++ b/subx/053new-segment.subx @@ -1,4 +1,15 @@ -# Create a new segment (for data) using mmap(). +# Create a new segment (pool of memory for allocating chunks from) in the form +# of an *allocation descriptor* that can be passed to the memory allocator +# (defined in a later layer). +# +# Currently an allocation descriptor consists of just the bounds of the pool of +# available memory: +# +# curr : address +# end : address +# +# This isn't enough information to reclaim individual allocations. We can't +# support arbitrary reclamation yet. == code # instruction effective address register displacement immediate @@ -6,39 +17,54 @@ # . 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 Entry: # manual test - # EAX = new-segment(0x1000) + # var ad/ECX : (address allocation-descriptor) = {0, 0} + 68/push 0/imm32/limit + 68/push 0/imm32/curr + 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + # new-segment(0x1000, ad) # . . push args + 51/push-ECX 68/push 0x1000/imm32 # . . call e8/call new-segment/disp32 # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # EAX = ad->curr + 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX # write to *EAX to check that we have access to the newly-allocated segment c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX - # syscall(exit, EAX) 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -new-segment: # len : int -> address +new-segment: # len : int, ad : (address allocation-descriptor) # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # . save registers + 50/push-EAX 53/push-EBX # copy len to _mmap-new-segment->len - # TODO: compute _mmap-new-segment+4 before runtime 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX - bb/copy-to-EBX _mmap-new-segment/imm32 - 89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4) + 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX _mmap-new-segment:len/disp32 # copy EAX to *_mmap-new-segment:len # mmap(_mmap-new-segment) bb/copy-to-EBX _mmap-new-segment/imm32 b8/copy-to-EAX 0x5a/imm32/mmap cd/syscall 0x80/imm8 + # copy {EAX, EAX+len} to *ad + # . EBX = ad + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX + # . *EBX = EAX + 89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX + # . *(EBX+4) = EAX+len + 03/add 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # add *(EBP+8) to EAX + 89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4) $new-segment:end: - # . epilog + # . restore registers 5b/pop-to-EBX + 58/pop-to-EAX + # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return @@ -49,6 +75,7 @@ $new-segment:end: _mmap-new-segment: # type mmap_arg_struct # addr 0/imm32 +_mmap-new-segment:len: # len 0/imm32 # protection flags diff --git a/subx/069allocate.subx b/subx/069allocate.subx index 402467fe..14e9fd50 100644 --- a/subx/069allocate.subx +++ b/subx/069allocate.subx @@ -16,14 +16,6 @@ # very same 'allocate' helper. They just need a new allocation descriptor for # their book-keeping. -== data - -# The 'global' allocation descriptor. Pass this into 'allocate' to claim a -# hitherto unused bit of memory. -Heap: - Start-of-heap/imm32 # curr - 0x0b000000/imm32 # limit; keep sync'd with DATA_SEGMENT + SEGMENT_ALIGNMENT - == code # instruction effective address register displacement immediate # . op subop mod rm32 base index scale r32 diff --git a/subx/070new-stream.subx b/subx/070new-stream.subx index ad6ab68d..8a833581 100644 --- a/subx/070new-stream.subx +++ b/subx/070new-stream.subx @@ -68,20 +68,21 @@ test-new-stream: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # var ad/ECX : (address allocation-descriptor) = allocate-region(Heap, 512) - # . EAX = allocate-region(Heap, 512) + # var heap/ECX : (address allocation-descriptor) = {0, 0} + 68/push 0/imm32/limit + 68/push 0/imm32/curr + 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + # heap = new-segment(512) # . . push args + 51/push-ECX 68/push 0x200/imm32 - 68/push Heap/imm32 # . . call - e8/call allocate-region/disp32 + e8/call new-segment/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . ECX = EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX # var start/EDX = ad->curr 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # EAX = new-stream(ad, 3, 2) + # EAX = new-stream(heap, 3, 2) # . . push args 68/push 2/imm32 68/push 3/imm32 diff --git a/subx/072slice.subx b/subx/072slice.subx index 9892f2a1..82ce883e 100644 --- a/subx/072slice.subx +++ b/subx/072slice.subx @@ -917,14 +917,26 @@ test-slice-to-string: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # var heap/EDX : (address allocation-descriptor) = {0, 0} + 68/push 0/imm32/limit + 68/push 0/imm32/curr + 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX + # heap = new-segment(512) + # . . push args + 52/push-EDX + 68/push 0x200/imm32 + # . . call + e8/call new-segment/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # var slice/ECX = "Abc" 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # EAX = slice-to-string(Heap, slice) + # EAX = slice-to-string(heap, slice) # . . push args 51/push-ECX - 68/push Heap/imm32 + 52/push-EDX # . . call e8/call slice-to-string/disp32 # . . discard args diff --git a/subx/074print-int-decimal.subx b/subx/074print-int-decimal.subx index 86015a00..04385795 100644 --- a/subx/074print-int-decimal.subx +++ b/subx/074print-int-decimal.subx @@ -6,7 +6,8 @@ # . 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 #? Entry: # run a single test, while debugging -#? e8/call test-print-int32-decimal/disp32 +#? e8/call test-print-int32-decimal-negative/disp32 +#? #? # syscall(exit, Num-test-failures) #? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX #? b8/copy-to-EAX 1/imm32/exit @@ -17,27 +18,30 @@ print-int32-decimal: # out : (address stream), n : int32 # to the stack, before popping them one by one into the stream # # pseudocode: - # copy ESP to EBX - # EAX = |n| + # push sentinel + # EAX = abs(n) # while true - # if (EAX == 0) break # sign-extend EAX into EDX # EAX, EDX = EAX/10, EAX%10 + # EDX += '0' # push EDX + # if (EAX == 0) break # if n < 0 - # push '-' - '0' = -3 - # max/ECX = &out->data[out->length] - # w/EAX = out->write - # curr/EDI = &out->data[out->write] + # push '-' + # w = out->write + # curr = &out->data[out->write] + # max = &out->data[out->length] # while true - # if (ESP == EBX) break + # pop into EAX + # if (EAX == sentinel) break # if (curr >= max) abort - # pop into EDX - # EDX += '0' # convert decimal digit to ascii - # *curr = DL + # *curr = AL # ++curr # ++w # out->write = w + # (based on K&R itoa: https://en.wikibooks.org/wiki/C_Programming/stdlib.h/itoa) + # (this pseudocode contains registers because operations like division + # require specific registers in x86) # # . prolog 55/push-EBP @@ -48,67 +52,63 @@ print-int32-decimal: # out : (address stream), n : int32 52/push-EDX 53/push-EBX 57/push-EDI - # copy ESP to EBX - 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX # ten/ECX = 10 b9/copy-to-ECX 0xa/imm32 - # EAX = |n| + # push sentinel + 68/push 0/imm32/sentinel + # EAX = abs(n) 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX 3d/compare-EAX-with 0/imm32 - 7d/jump-if-greater-or-equal $print-int32-decimal:read-loop/disp8 + 7d/jump-if-greater-or-equal $print-int32-decimal:read-loop/disp8 $print-int32-decimal:negative: f7 3/subop/negate 3/mod/direct 0/rm32/EAX . . . . . . # negate EAX $print-int32-decimal:read-loop: - # if (EAX == 0) break - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $print-int32-decimal:read-break/disp8 - # sign-extend + # EAX, EDX = EAX / 10, EAX % 10 99/sign-extend-EAX-into-EDX - # EAX, EDX = divide-with-remainder EAX/ten, EAX%ten - f7 7/subop/divide-by 3/mod/direct 1/rm32/ECX . . . . . . # divide EDX:EAX by ECX, storing quotient in EAX and remainder in EDX + f7 7/subop/idiv 3/mod/direct 1/rm32/ECX . . . . . . # divide EDX:EAX by ECX, storing quotient in EAX and remainder in EDX + # EDX += '0' + 81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 0x30/imm32 # add to EDX # push EDX 52/push-EDX - eb/jump $print-int32-decimal:read-loop/disp8 + # if (EAX == 0) break + 3d/compare-EAX-and 0/imm32 + 7f/jump-if-greater $print-int32-decimal:read-loop/disp8 $print-int32-decimal:read-break: # if (n < 0) push('-') 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 0/imm32 # compare *(EBP+12) - 7d/jump-if-greater-or-equal $print-int32-decimal:write/disp8 + 7d/jump-if-greater-or-equal $print-int32-decimal:write/disp8 $print-int32-decimal:push-negative: - 68/push -3/imm32/dash-minus-zero - # fall through + 68/push 0x2d/imm32/- $print-int32-decimal:write: # EDI = out 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI - # max/ECX = &out->data[out->length] - 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 8/disp8 . # copy *(EDI+8) to ECX - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 1/r32/ECX 0xc/disp8 . # copy EDI+ECX+12 to ECX - # w/EAX = out->write - 8b/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy *EDI to EAX - # curr/EDI = &out->data[out->write] - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 7/r32/EDI 0xc/disp8 . # copy EDI+EAX+12 to EDI + # w/EDX = out->write + 8b/copy 0/mod/indirect 7/rm32/EDI . . . 2/r32/EDX . . # copy *EDI to EDX + # curr/ECX = &out->data[out->write] + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 1/r32/ECX 0xc/disp8 . # copy EBX+EDX+12 to ECX + # max/EBX = &out->data[out->length] + 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 3/r32/EBX 8/disp8 . # copy *(EDI+8) to EBX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 3/index/EBX . 3/r32/EBX 0xc/disp8 . # copy EDI+EBX+12 to EBX $print-int32-decimal:write-loop: - # if (ESP == EBX) break - 39/compare 3/mod/direct 4/rm32/ESP . . . 3/r32/EBX . . # compare ESP and EBX + # pop into EAX + 58/pop-to-EAX + # if (EAX == sentinel) break + 3d/compare-EAX-and 0/imm32/sentinel 74/jump-if-equal $print-int32-decimal:write-break/disp8 # if (curr >= max) abort - 39/compare 3/mod/direct 7/rm32/EDI . . . 1/r32/ECX . . # compare EDI and ECX + 39/compare 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # compare ECX with EBX 7d/jump-if-greater-or-equal $print-int32-decimal:abort/disp8 - # pop into EDX - 5a/pop-into-EDX - # EDX += '0' - 81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 0x30/imm32/zero # add to EDX $print-int32-decimal:write-char: - # *curr = DL - 88/copy-byte 0/mod/indirect 7/rm32/EDI . . . 2/r32/DL . . # copy DL to byte at *ECX + # *curr = AL + 88/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy AL to byte at *ECX # ++curr - 47/increment-EDI + 41/increment-ECX # ++w - 40/increment-EAX + 42/increment-EDX eb/jump $print-int32-decimal:write-loop/disp8 $print-int32-decimal:write-break: # out->write = w - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI - 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI + 89/copy 0/mod/indirect 7/rm32/EDI . . . 2/r32/EDX . . # copy EDX to *EDI $print-int32-decimal:end: # . restore registers 5f/pop-to-EDI @@ -166,6 +166,36 @@ test-print-int32-decimal: # . end c3/return +test-print-int32-decimal-zero: + # - check that 0 converts correctly + # setup + # . clear-stream(_test-stream) + # . . push args + 68/push _test-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # print-int32-decimal(_test-stream, 0) + # . . push args + 68/push 0/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call print-int32-decimal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # check-stream-equal(_test-stream, "0", msg) + # . . push args + 68/push "F - test-print-int32-decimal-zero"/imm32 + 68/push "0"/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call check-stream-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # . end + c3/return + test-print-int32-decimal-multiple-digits: # - check that a multi-digit number converts correctly # setup diff --git a/subx/apps/assort b/subx/apps/assort index b5961b66..fb24828b 100755 --- a/subx/apps/assort +++ b/subx/apps/assort Binary files differdiff --git a/subx/apps/assort.subx b/subx/apps/assort.subx index 20566806..7498cc3a 100644 --- a/subx/apps/assort.subx +++ b/subx/apps/assort.subx @@ -26,12 +26,30 @@ Entry: # run tests if necessary, convert stdin if not # for debugging: run a single test +#? # . Heap = new-segment(4096) +#? # . . push args +#? 68/push Heap/imm32 +#? 68/push 0x1000/imm32 +#? # . . call +#? e8/call new-segment/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # . test() #? e8/call test-convert/disp32 #? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX #? eb/jump $main:end/disp8 # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # initialize heap + # . Heap = new-segment(4096) + # . . push args + 68/push Heap/imm32 + 68/push 0x1000/imm32 + # . . call + e8/call new-segment/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # - if argc > 1 and argv[1] == "test", then return run_tests() # . argc > 1 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP @@ -1316,4 +1334,10 @@ Segment-size: 0x100/imm32 #? 0x1000/imm32/4KB +Heap: + # curr + 0/imm32 + # limit + 0/imm32 + # . . vim:nowrap:textwidth=0 diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 index 8a927771..2ffc8a84 100755 --- a/subx/apps/crenshaw2-1 +++ b/subx/apps/crenshaw2-1 Binary files differdiff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b index 7856904e..6144d591 100755 --- a/subx/apps/crenshaw2-1b +++ b/subx/apps/crenshaw2-1b Binary files differdiff --git a/subx/apps/dquotes.subx b/subx/apps/dquotes.subx index 514c2d06..e6b24698 100644 --- a/subx/apps/dquotes.subx +++ b/subx/apps/dquotes.subx @@ -22,12 +22,30 @@ Entry: # run tests if necessary, convert stdin if not # for debugging: run a single test +#? # . Heap = new-segment(4096) +#? # . . push args +#? 68/push Heap/imm32 +#? 68/push 0x1000/imm32 +#? # . . call +#? e8/call new-segment/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # . test() #? e8/call test-emit-string-literal-data/disp32 #? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX #? eb/jump $main:end/disp8 # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # initialize heap + # . Heap = new-segment(4096) + # . . push args + 68/push Heap/imm32 + 68/push 0x1000/imm32 + # . . call + e8/call new-segment/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # - if argc > 1 and argv[1] == "test", then return run_tests() # . argc > 1 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP @@ -1692,6 +1710,12 @@ Segment-size: Next-string-literal: # tracks the next auto-generated variable name 1/imm32 +Heap: + # curr + 0/imm32 + # limit + 0/imm32 + # length-prefixed string containing just a single space Space: # size diff --git a/subx/apps/factorial b/subx/apps/factorial index 92c70b86..d1bd5f17 100755 --- a/subx/apps/factorial +++ b/subx/apps/factorial Binary files differdiff --git a/subx/apps/handle b/subx/apps/handle index b4bf7240..b77ebba6 100755 --- a/subx/apps/handle +++ b/subx/apps/handle Binary files differdiff --git a/subx/apps/handle.subx b/subx/apps/handle.subx index f866ea59..0ed12067 100644 --- a/subx/apps/handle.subx +++ b/subx/apps/handle.subx @@ -79,17 +79,29 @@ test-new: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # var heap/EDX : (address allocation-descriptor) = {0, 0} + 68/push 0/imm32/limit + 68/push 0/imm32/curr + 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX + # heap = new-segment(512) + # . . push args + 52/push-EDX + 68/push 0x200/imm32 + # . . call + e8/call new-segment/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # *Next-alloc-id = 0x34 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id # var handle/ECX = {0, 0} 68/push 0/imm32/address 68/push 0/imm32/alloc-id 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # new(Heap, 2, handle/ECX) + # new(heap, 2, handle/ECX) # . . push args 51/push-ECX 68/push 2/imm32/size - 68/push Heap/imm32 + 52/push-EDX # . . call e8/call new/disp32 # . . discard args @@ -234,17 +246,29 @@ test-lookup-success: 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # . save registers + # var heap/EBX : (address allocation-descriptor) = {0, 0} + 68/push 0/imm32/limit + 68/push 0/imm32/curr + 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX + # heap = new-segment(512) + # . . push args + 53/push-EBX + 68/push 0x200/imm32 + # . . call + e8/call new-segment/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # var handle/ECX = {0, 0} 68/push 0/imm32/address 68/push 0/imm32/alloc-id 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var old_top/EDX = Heap->curr - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 2/r32/EDX Heap/disp32 . # copy *Heap to EDX - # new(Heap, 2, handle) + # var old_top/EDX = heap->curr + 8b/copy 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # copy *EBX to EDX + # new(heap, 2, handle) # . . push args 51/push-ECX 68/push 2/imm32/size - 68/push Heap/imm32 + 53/push-EBX # . . call e8/call new/disp32 # . . discard args @@ -256,7 +280,7 @@ test-lookup-success: e8/call lookup/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # EAX contains old top of Heap, except skipping the alloc id in the payload + # EAX contains old top of heap, except skipping the alloc id in the payload # . check-ints-equal(EAX, old_top+4, msg) # . . push args 68/push "F - test-lookup-success"/imm32 @@ -282,38 +306,46 @@ test-lookup-failure: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX + # var heap/ESI : (address allocation-descriptor) = {0, 0} + 68/push 0/imm32/limit + 68/push 0/imm32/curr + 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + # heap = new-segment(512) + # . . push args + 56/push-ESI + 68/push 0x200/imm32 + # . . call + e8/call new-segment/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # var h1/ECX = {0, 0} 68/push 0/imm32/address 68/push 0/imm32/alloc-id 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var old_top/EBX = Heap->curr - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Heap/disp32 . # copy *Heap to EBX + # var old_top/EBX = heap->curr + 8b/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy *ESI to EBX # first allocation, to h1 - # . new(Heap, 2, h1) + # . new(heap, 2, h1) # . . push args 51/push-ECX 68/push 2/imm32/size - 68/push Heap/imm32 + 56/push-ESI # . . call e8/call new/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # reset Heap->curr to mimic reclamation - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Heap/disp32 . # copy EBX to *Heap + # reset heap->curr to mimic reclamation + 89/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy EBX to *ESI # second allocation that returns the same address as the first # var h2/EDX = {0, 0} 68/push 0/imm32/address 68/push 0/imm32/alloc-id 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # . new(Heap, 2, h2) + # . new(heap, 2, h2) # . . push args 52/push-EDX 68/push 2/imm32/size - 68/push Heap/imm32 + 56/push-ESI # . . call e8/call new/disp32 # . . discard args @@ -338,10 +370,6 @@ test-lookup-failure: # clean up # . *Next-alloc-id = 1 c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP diff --git a/subx/apps/hex b/subx/apps/hex index 796e532e..dde157e3 100755 --- a/subx/apps/hex +++ b/subx/apps/hex Binary files differdiff --git a/subx/apps/pack b/subx/apps/pack index ba40c5a1..1154be78 100755 --- a/subx/apps/pack +++ b/subx/apps/pack Binary files differ |