diff options
author | Kartik Agaram <vc@akkartik.com> | 2019-05-10 16:45:22 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2019-05-10 16:45:22 -0700 |
commit | c88b9e31259d433c7e63fcb19d430daf9b1c723c (patch) | |
tree | 12de1a20312a788d07ef6564084b7ca81aa15ba1 /subx | |
parent | cdfb2dbfcf18cd2f23bf74199082392c3692a599 (diff) | |
download | mu-c88b9e31259d433c7e63fcb19d430daf9b1c723c.tar.gz |
5151 - use mmap everywhere we need a heap
All tests passing now. Things are very explicit; before a program can `allocate` memory, it has to first obtain a segment from the OS using `new-segment`.
Diffstat (limited to 'subx')
-rw-r--r-- | subx/012elf.cc | 17 | ||||
-rw-r--r-- | subx/020syscalls.cc | 21 | ||||
-rw-r--r-- | subx/070new-stream.subx | 15 | ||||
-rw-r--r-- | subx/072slice.subx | 16 | ||||
-rwxr-xr-x | subx/apps/assort | bin | 21414 -> 21492 bytes | |||
-rw-r--r-- | subx/apps/assort.subx | 24 | ||||
-rwxr-xr-x | subx/apps/crenshaw2-1 | bin | 18602 -> 18651 bytes | |||
-rwxr-xr-x | subx/apps/crenshaw2-1b | bin | 19161 -> 19210 bytes | |||
-rw-r--r-- | subx/apps/dquotes | bin | 20916 -> 21106 bytes | |||
-rw-r--r-- | subx/apps/dquotes.subx | 24 | ||||
-rwxr-xr-x | subx/apps/factorial | bin | 17518 -> 17567 bytes | |||
-rwxr-xr-x | subx/apps/handle | bin | 18292 -> 18394 bytes | |||
-rw-r--r-- | subx/apps/handle.subx | 74 | ||||
-rwxr-xr-x | subx/apps/hex | bin | 21611 -> 21660 bytes | |||
-rwxr-xr-x | subx/apps/pack | bin | 36203 -> 36252 bytes |
15 files changed, 146 insertions, 45 deletions
diff --git a/subx/012elf.cc b/subx/012elf.cc index 11e0e4bc..d0a3fbd2 100644 --- a/subx/012elf.cc +++ b/subx/012elf.cc @@ -134,13 +134,20 @@ void load_segment_from_program_header(uint8_t* elf_contents, int segment_index, // code: 0x09000000 -> 0x09ffffff (specified in ELF binary) // data: 0x0a000000 -> 0x0affffff (specified in ELF binary) // --- heap gets mmap'd somewhere here --- -// stack: 0xbdffffff -> 0xbd000000 (downward; not in ELF binary) -// argv hack: 0xbf000000 -> 0xc0000000 (not in ELF binary) +// 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 = 0xbd000000; -const int AFTER_STACK = 0xbe000000; -const int ARGV_DATA_SEGMENT = 0xbf000000; +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/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/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 9c285097..683c4c7b 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/apps/assort b/subx/apps/assort index a0e89c63..e331ce8a 100755 --- a/subx/apps/assort +++ b/subx/apps/assort Binary files differdiff --git a/subx/apps/assort.subx b/subx/apps/assort.subx index ecb1c213..cfdef5e1 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 9e07eb8d..eb187bb3 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 173ea621..e8d72937 100755 --- a/subx/apps/crenshaw2-1b +++ b/subx/apps/crenshaw2-1b Binary files differdiff --git a/subx/apps/dquotes b/subx/apps/dquotes index e1d12550..b63744d1 100644 --- a/subx/apps/dquotes +++ b/subx/apps/dquotes Binary files differdiff --git a/subx/apps/dquotes.subx b/subx/apps/dquotes.subx index b236ac2f..fcac2698 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-next-word-returns-string-with-escapes/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 @@ -1054,4 +1072,10 @@ Segment-size: Next-string-literal: # tracks the next auto-generated variable name 1/imm32 +Heap: + # curr + 0/imm32 + # limit + 0/imm32 + # . . vim:nowrap:textwidth=0 diff --git a/subx/apps/factorial b/subx/apps/factorial index 8313b27a..2c47ab8a 100755 --- a/subx/apps/factorial +++ b/subx/apps/factorial Binary files differdiff --git a/subx/apps/handle b/subx/apps/handle index fa345498..274677fe 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 8992e424..70734450 100755 --- a/subx/apps/hex +++ b/subx/apps/hex Binary files differdiff --git a/subx/apps/pack b/subx/apps/pack index 1da1a476..7e8cc761 100755 --- a/subx/apps/pack +++ b/subx/apps/pack Binary files differ |