A custom heap allocator written in Fortran, backed by a hand-written x86-64 NASM mmap syscall wrapper — first-fit allocation with block splitting, driven from an interactive terminal menu.
fallocator is a heap allocator built from scratch in Fortran, using iso_c_binding to bind directly to a hand-written x86-64 assembly routine that pulls raw memory straight from the kernel via the mmap syscall — no libc malloc involved anywhere in the chain.
On top of that raw memory, a linked list of C-interop block structs (size, state, next/prev pointers) is maintained manually, with a first-fit search-and-split strategy for satisfying allocation requests. The whole thing is driven from an interactive CLI menu that prints live stats (block count, free memory) and lets you allocate chunks by size or free everything back.
program shi (allocator.f90)
|
v
loop: clear screen, print banner + stats, show menu
|
+--- choice 1: allocate ---> read size in MB (capped at 100MB)
| |
| v
| findy(size, heap)
| |
| walk block linked list (heap%start -> ...)
| |
| +--- exact-size free block found -> mark busy, return
| |
| +--- larger free block found -> split() it, return front half
| |
| +--- no fit found -> gimme_ram(size + header)
| |
| v
| platform.f90: gimme_ram -> asm_gimme_ram (C interop)
| |
| v
| main.s: asm_gimme_ram -> mmap syscall -> raw pages
| |
| v
| new block appended to end of linked list
|
+--- choice 2: free ---> free_dave(heap): walk list, mark every block free
|
v
loop back to menu
| Area | Details |
|---|---|
| Raw memory sourcing | main.s implements asm_gimme_ram, a NASM routine that calls the mmap syscall (rax=9) directly to request pages from the kernel. |
| C interop bridge | platform.f90 declares a bind(C, name="asm_gimme_ram") interface and exposes a thin gimme_ram wrapper Fortran code calls. |
| Block representation | block.f90 defines a bind(C) derived type — size, state (busy/free), next, prev — laid out as a linked list directly inside the allocated arena. |
| First-fit search | findy in heap.f90 walks the block list looking for an exact-size free block first, then any large-enough free block to split. |
| Block splitting | split carves a larger free block into an allocated front portion and a new free remainder block, relinking next/prev pointers. |
| Growing the heap | When no existing block fits, findy calls gimme_ram for a fresh block-sized region and appends it to the end of the list. |
| Stats reporting | checkme counts total blocks; how_much_motion sums the size of all free blocks; fmt_bytes formats sizes as B/Kb/Mb for display. |
| Freeing | free_dave walks the entire list and marks every block free — see limitations below. |
| Interactive shell | allocator.f90 (program shi) prints an ASCII banner + live stats every loop, and reads a menu choice (allocate / free) from stdin. |
| File | Role |
|---|---|
allocator.f90 |
Entry point (program shi) — the interactive menu loop, banner, and input handling. |
heap.f90 (module heapy) |
Core allocator logic: findy (first-fit search), split, checkme, how_much_motion, free_dave, fmt_bytes. |
block.f90 (module blocks) |
Defines the block derived type — the linked-list node layout shared between Fortran and the raw memory. |
platform.f90 (module platform) |
C-interop bridge: declares the asm_gimme_ram interface and wraps it as gimme_ram. |
main.s |
NASM implementation of asm_gimme_ram — issues the mmap syscall to get memory straight from Linux. |
Built with gfortran + gcc via the included Makefile — Fortran sources are compiled and linked together with the assembled main.s object:
makeRun it:
./allocatorClean build artifacts:
make clean| Tech | Usage |
|---|---|
| Fortran (gfortran) | Allocator logic, block/heap data structures, interactive CLI |
| NASM / x86-64 assembly | Raw mmap syscall wrapper for sourcing memory from the OS |
iso_c_binding |
C-interoperable derived types (bind(C)) and interfaces linking Fortran to the asm routine |
| Linux syscalls | mmap (syscall 9) called directly, no libc malloc |
free_davefrees everything, not one block. The "free" menu option walks the entire list and marks every block free — there's no free-by-address or free-by-index, so you can't release a single allocation without releasing all of them.- No coalescing. Adjacent free blocks are never merged back together after a free, so the heap can fragment into many small free blocks over time.
- No minimum split size.
splitdoesn't check whether the leftover remainder is large enough to be useful, so it's possible to end up with tiny, effectively unusable free blocks. - Linear search.
findywalks the full block list on every allocation — there's no separate free-list, so lookup cost grows with heap size. - Single global heap, not thread-safe.
- Selective free (free a specific block by address/index instead of clearing the whole heap).
- Block coalescing on free to reduce fragmentation.
- Minimum split threshold to avoid unusable splinter blocks.
- A dedicated free-list to avoid scanning busy blocks during allocation.
Nah, this is the wildest one yet. I'm pretty sure nobody even managed to form a thought resembling this idea. The allocator is already something out of regular, and the fortran wasn't helping either. I'm not sure how this even worked, and the worst part ? assembly somehow got involved in this ! but yea it was either assembly or the use on of fortran’s allocator and cheated my way.
- as always , not a production level allocator - you wouldnt pay me a million to touch fortran again, neither this repo - the allocator is not capabel of joinging free blocks , it can only use free whole blocks - allocator cannot free specific blocks , the free option nukes the full list with keeping the blocks intact - hours spent : not really sure of this one