From 997e901497eefaf3eb879adc40c2e63f59bc2ef9 Mon Sep 17 00:00:00 2001 From: Abel Shields Date: Tue, 12 Oct 2021 17:30:47 +0100 Subject: [PATCH] Added a dynamic memory implementation using mmap --- examples/dynamic-memory.porth | 44 ++++++++++++++++++++++ std/dynamic-memory.porth | 70 +++++++++++++++++++++++++++++++++++ std/std.porth | 6 +++ 3 files changed, 120 insertions(+) create mode 100644 examples/dynamic-memory.porth create mode 100644 std/dynamic-memory.porth diff --git a/examples/dynamic-memory.porth b/examples/dynamic-memory.porth new file mode 100644 index 00000000..2b1910b6 --- /dev/null +++ b/examples/dynamic-memory.porth @@ -0,0 +1,44 @@ +include "std.porth" +include "dynamic-memory.porth" + +// Test raw memory allocation +"Allocating memory without housekeeping\n" puts + +4096 palloc_raw +"Pointer: " puts +dup print + +4096 palloc_raw +"Pointer: " puts +dup print + +// is the difference equal to page size? +"Difference: " puts +over over - abs +print +"(should be =4096 if addresses aren't randomized)\n" puts +// CLEAN UP! +4096 pfree_raw +4096 pfree_raw // needs to take the size + +"\n" puts + +// Test housekeeping +"Allocating memory with housekeeping\n" puts + +4096 palloc +"Pointer: " puts +dup print + +4096 palloc +"Pointer: " puts +dup print + +// is the difference the page size? +"Difference: " puts +over over - abs +print +"(should be >4096 due to housekeeping)\n" puts +// clean up - no need to worry about size +pfree +pfree diff --git a/std/dynamic-memory.porth b/std/dynamic-memory.porth new file mode 100644 index 00000000..dc80b972 --- /dev/null +++ b/std/dynamic-memory.porth @@ -0,0 +1,70 @@ +// requires std.porth - currently there's no include guards so do this yourself! + +// TODO: Get from include files, or run C preprocessor? +macro PROT_READ 1 end +macro PROT_WRITE 2 end +macro MAP_PRIVATE 2 end +macro MAP_ANONYMOUS 32 end + +macro exit_if_failed + // stack: ptr + // if failed: exit(1) + // if succeeded: leave ptr on stack + if dup 0 < do + "Failed to allocate memory!\n" puts + 1 exit + end +end + +macro palloc_raw + // takes length of memory to be allocated in bytes + // returns pointer to the start + // void *addr, size_t length, int prot, int flags, int fd, off_t offset SYSCALL_NUMBER + 0 swap + -1 swap + MAP_PRIVATE MAP_ANONYMOUS or swap + PROT_READ PROT_WRITE or swap + NULL + SYS_mmap + syscall6 + // stack is now: size, returncode/ptr + + exit_if_failed + cast(ptr) +end +macro palloc + // allocates a page, but no need to keep track of the size + // may allocate more in order to store the length + // pointer returned is still start of useable space (so can write to *ptr but shouldn't write to *(ptr-8)) + 8 + // need 8 bytes extra allocated for housekeeping + dup // keep size for later + + palloc_raw + + // stick size on the front, for housekeeping + swap over !64 + // left with just the pointer + 8 + +end + +macro pfree_raw + // Takes pointer, size on stack + swap + SYS_munmap + syscall2 + if dup 0 != do + "Error freeing: " puts print " not equal to 0\n" puts + else + drop + "Freed successfully\n" puts + end +end + +macro pfree + // takes pointer of allocated memory + // size stored at ptr - 8 + 8 - + dup + @64 + pfree_raw +end diff --git a/std/std.porth b/std/std.porth index 41b24325..ec6b80ae 100644 --- a/std/std.porth +++ b/std/std.porth @@ -364,6 +364,12 @@ macro dec64 dup ,64 1 - .64 end +macro abs + if dup 0 < do + 0 over - swap drop + end +end + macro strlen dup while dup , 0 != do 1 + end