first commit

This commit is contained in:
David Ali
2026-01-19 17:35:37 +01:00
commit 57814ce683
7 changed files with 646 additions and 0 deletions

22
.gitignore vendored Normal file
View File

@@ -0,0 +1,22 @@
# --- Build Artifacts ---
# Directories created by Makefile
bin/
obj/
# Object files
*.o
# --- Temporary & Editor Files ---
# Vim swap files
*.swp
*.swo
# VS Code settings
.vscode/
# Linux/General backups
*~
*.bak
# --- System ---
.DS_Store

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Dávid Ali
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

20
Makefile Normal file
View File

@@ -0,0 +1,20 @@
all: bin/nos
bin:
mkdir -p bin
bin/nos: bin obj/nos.o
ld obj/nos.o -o bin/nos
obj:
mkdir -p obj
obj/nos.o: obj src/nos.asm include/syscalls.inc include/mmap.inc
nasm -g -f elf64 src/nos.asm -o obj/nos.o -Iinclude
run: bin/nos
bin/nos
@echo "Program returned $$?."
debug: bin/nos
gf2 bin/nos

90
README.md Normal file
View File

@@ -0,0 +1,90 @@
# NOS - Experimental Assembly Runtime
This project is a low-level runtime environment written in x86_64 assembly (NASM) for Linux. It implements a custom memory manager and basic list data structures.
## Project overview
The main goal is to understand how computers work at a low level by building a runtime environment from scratch. This project serves as a "bare metal" experiment in manual resource management and data representation.
Key mechanisms:
* **Custom Memory Allocation**: It uses the `mmap` system call to reserve 64 MB of RAM.
* **Cons Structure**: It implements value pairs (cons cells), which are the foundation of languages like Lisp.
* **Direct Kernel Interface**: The code bypasses the standard C library (`libc`) entirely. It relies on the x86_64 ABI to invoke Linux system calls directly.
## Project structure
The files are organized as follows:
* `src/nos.asm`: The main program logic and allocator implementation.
* `include/syscalls.inc`: Definitions of Linux system call numbers.
* `include/mmap.inc`: Constants and flags for memory management.
* `Makefile`: The script for building and testing the project.
## Requirements
To run this, you need a 64-bit Linux system and the following tools:
* `nasm` (Assembler)
* `ld` (Linker)
* `make` (Build tool)
* `gf2` (Optional, for debugging)
## Usage
You control the project using the Makefile.
1. **Build**:
Compiles the executable into the `bin` directory.
```bash
make
```
2. **Run**:
Compiles (if necessary) and runs the program.
```bash
make run
```
3. **Debug**:
Runs the program inside a debugger (default is gf2).
```bash
make debug
```
## How it works
When you run the program, it performs these steps:
1. **Heap Initialization**: Requests 64 MB of memory using `SYS_MMAP`.
2. **Allocation**: Creates a `cons` cell with values `0xAAAA` and `0xBBBB`.
3. **Output**: Prints the following to stdout in hexadecimal:
* The memory address of the new structure.
* The first value (head/car).
* The second value (tail/cdr).
4. **Exit**: Terminates the process cleanly.
## Philosophy
This project adopts a "constructivist" approach to systems programming. We avoid the standard C library (`libc`) not because it is bad, but because it hides the machinery we want to study.
* **Total transparency**: By avoiding standard libraries, we remove the "black box". Every instruction executed by the CPU is explicit in our source code. There is no hidden initialization code running before `_start`.
* **Memory control**: General-purpose allocators (like `malloc`) are optimized for average use cases. Building a language runtime requires precise control over the heap layout. We achieve this by managing raw memory pages via `mmap` directly.
* **The trade-off**: We accept a trade-off: portability for clarity. The code is tightly coupled to the Linux kernel ABI. However, this dependency allows us to interact with the operating system without any abstraction layers blurring the picture.
## Educational value
This project serves as a case study in system software engineering. It explores several core computer science concepts:
* **Memory Management**: It demystifies the heap. It shows how to request memory pages directly from the kernel without `malloc`.
* **Data Structures**: The `cons` function shows how abstract linked lists are physically represented in RAM.
* **Binary Interface (ABI)**: The code strictly follows System V AMD64 ABI conventions. It requires manual management of registers and the stack.
* **System Dependency**: It demonstrates how software interacts with the OS kernel boundary without any abstraction layers.
## TODO - Future plans
The current version is a prototype. Future development will focus on:
* [ ] **Garbage Collection (GC)**: The current linear allocator only consumes memory. A mechanism (like Mark and Sweep) is needed to reclaim unused cells.
* [ ] **Better I/O**: The `print_hex` function is only for debugging. Decimal numbers and string support are needed.
* [ ] **REPL**: The goal is to build a Read-Eval-Print Loop for interactive commands.
* [ ] **Type Tagging**: Currently, everything is a raw 64-bit value. Pointer tagging is needed to distinguish integers from pointers.
## License
MIT

45
include/mmap.inc Normal file
View File

@@ -0,0 +1,45 @@
; -----------------------------------------------------------------------------
; Memory Management Definitions
; Constants derived from <sys/mman.h> and Linux Kernel documentation.
; -----------------------------------------------------------------------------
; Memory Protection Flags
PROT_NONE equ 0x0 ; Page cannot be accessed
PROT_READ equ 0x1 ; Page can be read
PROT_WRITE equ 0x2 ; Page can be written
PROT_EXEC equ 0x4 ; Page can be executed (Code)
; --- MMAP Flags (x86-64 Linux) ---
; Sharing types (Choose one)
MAP_SHARED equ 0x01 ; Share changes
MAP_PRIVATE equ 0x02 ; Private copy-on-write
MAP_SHARED_VALIDATE equ 0x03 ; Validate flags
; Basic flags
MAP_FIXED equ 0x10 ; Interpret addr exactly
MAP_ANONYMOUS equ 0x20 ; No file backing (RAM only)
MAP_ANON equ 0x20 ; Alias for MAP_ANONYMOUS
MAP_32BIT equ 0x40 ; Allocate in first 2GB (x86-64 only)
; Advanced flags
MAP_GROWSDOWN equ 0x0100 ; Stack-like segment
MAP_DENYWRITE equ 0x0800 ; Ignored by modern kernels
MAP_EXECUTABLE equ 0x1000 ; Ignored by modern kernels
MAP_LOCKED equ 0x2000 ; Lock pages in memory
MAP_NORESERVE equ 0x4000 ; Don't reserve swap space
MAP_POPULATE equ 0x8000 ; Pre-fault read ahead
MAP_NONBLOCK equ 0x10000 ; Do not block on IO
MAP_STACK equ 0x20000 ; Allocation is a stack
MAP_HUGETLB equ 0x40000 ; Create a huge page
MAP_SYNC equ 0x80000 ; Perform synchronous page faults
MAP_FIXED_NOREPLACE equ 0x100000 ; MAP_FIXED but don't clobber
; Huge Page Sizes (Use with MAP_HUGETLB)
; Derived from (log2(size) << 26)
MAP_HUGE_2MB equ 21 << 26 ; 2MB Huge Page
MAP_HUGE_1GB equ 30 << 26 ; 1GB Huge Page
; Legacy / Unused
MAP_FILE equ 0
MAP_UNINITIALIZED equ 0 ; Usually not implemented

364
include/syscalls.inc Normal file
View File

@@ -0,0 +1,364 @@
; -----------------------------------------------------------------------------
; Linux x86_64 System Call Table
; Derived from the Linux Kernel source (arch/x86/entry/syscalls/syscall_64.tbl)
; -----------------------------------------------------------------------------
SYS_READ equ 0
SYS_WRITE equ 1
SYS_OPEN equ 2
SYS_CLOSE equ 3
SYS_STAT equ 4
SYS_FSTAT equ 5
SYS_LSTAT equ 6
SYS_POLL equ 7
SYS_LSEEK equ 8
SYS_MMAP equ 9
SYS_MPROTECT equ 10
SYS_MUNMAP equ 11
SYS_BRK equ 12
SYS_RT_SIGACTION equ 13
SYS_RT_SIGPROCMASK equ 14
SYS_RT_SIGRETURN equ 15
SYS_IOCTL equ 16
SYS_PREAD64 equ 17
SYS_PWRITE64 equ 18
SYS_READV equ 19
SYS_WRITEV equ 20
SYS_ACCESS equ 21
SYS_PIPE equ 22
SYS_SELECT equ 23
SYS_SCHED_YIELD equ 24
SYS_MREMAP equ 25
SYS_MSYNC equ 26
SYS_MINCORE equ 27
SYS_MADVISE equ 28
SYS_SHMGET equ 29
SYS_SHMAT equ 30
SYS_SHMCTL equ 31
SYS_DUP equ 32
SYS_DUP2 equ 33
SYS_PAUSE equ 34
SYS_NANOSLEEP equ 35
SYS_GETITIMER equ 36
SYS_ALARM equ 37
SYS_SETITIMER equ 38
SYS_GETPID equ 39
SYS_SENDFILE equ 40
SYS_SOCKET equ 41
SYS_CONNECT equ 42
SYS_ACCEPT equ 43
SYS_SENDTO equ 44
SYS_RECVFROM equ 45
SYS_SENDMSG equ 46
SYS_RECVMSG equ 47
SYS_SHUTDOWN equ 48
SYS_BIND equ 49
SYS_LISTEN equ 50
SYS_GETSOCKNAME equ 51
SYS_GETPEERNAME equ 52
SYS_SOCKETPAIR equ 53
SYS_SETSOCKOPT equ 54
SYS_GETSOCKOPT equ 55
SYS_CLONE equ 56
SYS_FORK equ 57
SYS_VFORK equ 58
SYS_EXECVE equ 59
SYS_EXIT equ 60
SYS_WAIT4 equ 61
SYS_KILL equ 62
SYS_UNAME equ 63
SYS_SEMGET equ 64
SYS_SEMOP equ 65
SYS_SEMCTL equ 66
SYS_SHMDT equ 67
SYS_MSGGET equ 68
SYS_MSGSND equ 69
SYS_MSGRCV equ 70
SYS_MSGCTL equ 71
SYS_FCNTL equ 72
SYS_FLOCK equ 73
SYS_FSYNC equ 74
SYS_FDATASYNC equ 75
SYS_TRUNCATE equ 76
SYS_FTRUNCATE equ 77
SYS_GETDENTS equ 78
SYS_GETCWD equ 79
SYS_CHDIR equ 80
SYS_FCHDIR equ 81
SYS_RENAME equ 82
SYS_MKDIR equ 83
SYS_RMDIR equ 84
SYS_CREAT equ 85
SYS_LINK equ 86
SYS_UNLINK equ 87
SYS_SYMLINK equ 88
SYS_READLINK equ 89
SYS_CHMOD equ 90
SYS_FCHMOD equ 91
SYS_CHOWN equ 92
SYS_FCHOWN equ 93
SYS_LCHOWN equ 94
SYS_UMASK equ 95
SYS_GETTIMEOFDAY equ 96
SYS_GETRLIMIT equ 97
SYS_GETRUSAGE equ 98
SYS_SYSINFO equ 99
SYS_TIMES equ 100
SYS_PTRACE equ 101
SYS_GETUID equ 102
SYS_SYSLOG equ 103
SYS_GETGID equ 104
SYS_SETUID equ 105
SYS_SETGID equ 106
SYS_GETEUID equ 107
SYS_GETEGID equ 108
SYS_SETPGID equ 109
SYS_GETPPID equ 110
SYS_GETPGRP equ 111
SYS_SETSID equ 112
SYS_SETREUID equ 113
SYS_SETREGID equ 114
SYS_GETGROUPS equ 115
SYS_SETGROUPS equ 116
SYS_SETRESUID equ 117
SYS_GETRESUID equ 118
SYS_SETRESGID equ 119
SYS_GETRESGID equ 120
SYS_GETPGID equ 121
SYS_SETFSUID equ 122
SYS_SETFSGID equ 123
SYS_GETSID equ 124
SYS_CAPGET equ 125
SYS_CAPSET equ 126
SYS_RT_SIGPENDING equ 127
SYS_RT_SIGTIMEDWAIT equ 128
SYS_RT_SIGQUEUEINFO equ 129
SYS_RT_SIGSUSPEND equ 130
SYS_SIGALTSTACK equ 131
SYS_UTIME equ 132
SYS_MKNOD equ 133
SYS_USELIB equ 134
SYS_PERSONALITY equ 135
SYS_USTAT equ 136
SYS_STATFS equ 137
SYS_FSTATFS equ 138
SYS_SYSFS equ 139
SYS_GETPRIORITY equ 140
SYS_SETPRIORITY equ 141
SYS_SCHED_SETPARAM equ 142
SYS_SCHED_GETPARAM equ 143
SYS_SCHED_SETSCHEDULER equ 144
SYS_SCHED_GETSCHEDULER equ 145
SYS_SCHED_GET_PRIORITY_MAX equ 146
SYS_SCHED_GET_PRIORITY_MIN equ 147
SYS_SCHED_RR_GET_INTERVAL equ 148
SYS_MLOCK equ 149
SYS_MUNLOCK equ 150
SYS_MLOCKALL equ 151
SYS_MUNLOCKALL equ 152
SYS_VHANGUP equ 153
SYS_MODIFY_LDT equ 154
SYS_PIVOT_ROOT equ 155
SYS__SYSCTL equ 156
SYS_PRCTL equ 157
SYS_ARCH_PRCTL equ 158
SYS_ADJTIMEX equ 159
SYS_SETRLIMIT equ 160
SYS_CHROOT equ 161
SYS_SYNC equ 162
SYS_ACCT equ 163
SYS_SETTIMEOFDAY equ 164
SYS_MOUNT equ 165
SYS_UMOUNT2 equ 166
SYS_SWAPON equ 167
SYS_SWAPOFF equ 168
SYS_REBOOT equ 169
SYS_SETHOSTNAME equ 170
SYS_SETDOMAINNAME equ 171
SYS_IOPL equ 172
SYS_IOPERM equ 173
SYS_CREATE_MODULE equ 174
SYS_INIT_MODULE equ 175
SYS_DELETE_MODULE equ 176
SYS_GET_KERNEL_SYMS equ 177
SYS_QUERY_MODULE equ 178
SYS_QUOTACTL equ 179
SYS_NFSSERVCTL equ 180
SYS_GETPMSG equ 181
SYS_PUTPMSG equ 182
SYS_AFS_SYSCALL equ 183
SYS_TUXCALL equ 184
SYS_SECURITY equ 185
SYS_GETTID equ 186
SYS_READAHEAD equ 187
SYS_SETXATTR equ 188
SYS_LSETXATTR equ 189
SYS_FSETXATTR equ 190
SYS_GETXATTR equ 191
SYS_LGETXATTR equ 192
SYS_FGETXATTR equ 193
SYS_LISTXATTR equ 194
SYS_LLISTXATTR equ 195
SYS_FLISTXATTR equ 196
SYS_REMOVEXATTR equ 197
SYS_LREMOVEXATTR equ 198
SYS_FREMOVEXATTR equ 199
SYS_TKILL equ 200
SYS_TIME equ 201
SYS_FUTEX equ 202
SYS_SCHED_SETAFFINITY equ 203
SYS_SCHED_GETAFFINITY equ 204
SYS_SET_THREAD_AREA equ 205
SYS_IO_SETUP equ 206
SYS_IO_DESTROY equ 207
SYS_IO_GETEVENTS equ 208
SYS_IO_SUBMIT equ 209
SYS_IO_CANCEL equ 210
SYS_GET_THREAD_AREA equ 211
SYS_LOOKUP_DCOOKIE equ 212
SYS_EPOLL_CREATE equ 213
SYS_EPOLL_CTL_OLD equ 214
SYS_EPOLL_WAIT_OLD equ 215
SYS_REMAP_FILE_PAGES equ 216
SYS_GETDENTS64 equ 217
SYS_SET_TID_ADDRESS equ 218
SYS_RESTART_SYSCALL equ 219
SYS_SEMTIMEDOP equ 220
SYS_FADVISE64 equ 221
SYS_TIMER_CREATE equ 222
SYS_TIMER_SETTIME equ 223
SYS_TIMER_GETTIME equ 224
SYS_TIMER_GETOVERRUN equ 225
SYS_TIMER_DELETE equ 226
SYS_CLOCK_SETTIME equ 227
SYS_CLOCK_GETTIME equ 228
SYS_CLOCK_GETRES equ 229
SYS_CLOCK_NANOSLEEP equ 230
SYS_EXIT_GROUP equ 231
SYS_EPOLL_WAIT equ 232
SYS_EPOLL_CTL equ 233
SYS_TGKILL equ 234
SYS_UTIMES equ 235
SYS_VSERVER equ 236
SYS_MBIND equ 237
SYS_SET_MEMPOLICY equ 238
SYS_GET_MEMPOLICY equ 239
SYS_MQ_OPEN equ 240
SYS_MQ_UNLINK equ 241
SYS_MQ_TIMEDSEND equ 242
SYS_MQ_TIMEDRECEIVE equ 243
SYS_MQ_NOTIFY equ 244
SYS_MQ_GETSETATTR equ 245
SYS_KEXEC_LOAD equ 246
SYS_WAITID equ 247
SYS_ADD_KEY equ 248
SYS_REQUEST_KEY equ 249
SYS_KEYCTL equ 250
SYS_IOPRIO_SET equ 251
SYS_IOPRIO_GET equ 252
SYS_INOTIFY_INIT equ 253
SYS_INOTIFY_ADD_WATCH equ 254
SYS_INOTIFY_RM_WATCH equ 255
SYS_MIGRATE_PAGES equ 256
SYS_OPENAT equ 257
SYS_MKDIRAT equ 258
SYS_MKNODAT equ 259
SYS_FCHOWNAT equ 260
SYS_FUTIMESAT equ 261
SYS_NEWFSTATAT equ 262
SYS_UNLINKAT equ 263
SYS_RENAMEAT equ 264
SYS_LINKAT equ 265
SYS_SYMLINKAT equ 266
SYS_READLINKAT equ 267
SYS_FCHMODAT equ 268
SYS_FACCESSAT equ 269
SYS_PSELECT6 equ 270
SYS_PPOLL equ 271
SYS_UNSHARE equ 272
SYS_SET_ROBUST_LIST equ 273
SYS_GET_ROBUST_LIST equ 274
SYS_SPLICE equ 275
SYS_TEE equ 276
SYS_SYNC_FILE_RANGE equ 277
SYS_VMSPLICE equ 278
SYS_MOVE_PAGES equ 279
SYS_UTIMENSAT equ 280
SYS_EPOLL_PWAIT equ 281
SYS_SIGNALFD equ 282
SYS_TIMERFD_CREATE equ 283
SYS_EVENTFD equ 284
SYS_FALLOCATE equ 285
SYS_TIMERFD_SETTIME equ 286
SYS_TIMERFD_GETTIME equ 287
SYS_ACCEPT4 equ 288
SYS_SIGNALFD4 equ 289
SYS_EVENTFD2 equ 290
SYS_EPOLL_CREATE1 equ 291
SYS_DUP3 equ 292
SYS_PIPE2 equ 293
SYS_INOTIFY_INIT1 equ 294
SYS_PREADV equ 295
SYS_PWRITEV equ 296
SYS_RT_TGSIGQUEUEINFO equ 297
SYS_PERF_EVENT_OPEN equ 298
SYS_RECVMMSG equ 299
SYS_FANOTIFY_INIT equ 300
SYS_FANOTIFY_MARK equ 301
SYS_PRLIMIT64 equ 302
SYS_NAME_TO_HANDLE_AT equ 303
SYS_OPEN_BY_HANDLE_AT equ 304
SYS_CLOCK_ADJTIME equ 305
SYS_SYNCFS equ 306
SYS_SENDMMSG equ 307
SYS_SETNS equ 308
SYS_GETCPU equ 309
SYS_PROCESS_VM_READV equ 310
SYS_PROCESS_VM_WRITEV equ 311
SYS_KCMP equ 312
SYS_FINIT_MODULE equ 313
SYS_SCHED_SETATTR equ 314
SYS_SCHED_GETATTR equ 315
SYS_RENAMEAT2 equ 316
SYS_SECCOMP equ 317
SYS_GETRANDOM equ 318
SYS_MEMFD_CREATE equ 319
SYS_KEXEC_FILE_LOAD equ 320
SYS_BPF equ 321
SYS_EXECVEAT equ 322
SYS_USERFAULTFD equ 323
SYS_MEMBARRIER equ 324
SYS_MLOCK2 equ 325
SYS_COPY_FILE_RANGE equ 326
SYS_PREADV2 equ 327
SYS_PWRITEV2 equ 328
SYS_PKEY_MPROTECT equ 329
SYS_PKEY_ALLOC equ 330
SYS_PKEY_FREE equ 331
SYS_STATX equ 332
STDIN equ 0
STDOUT equ 1
STDERR equ 2
%macro m_syscall 1-7
mov rax, %1
%if %0 > 1
mov rdi, %2
%endif
%if %0 > 2
mov rsi, %3
%endif
%if %0 > 3
mov rdx, %4
%endif
%if %0 > 4
mov r10, %5
%endif
%if %0 > 5
mov r8, %6
%endif
%if %0 > 6
mov r9, %7
%endif
syscall
%endmacro

84
src/nos.asm Normal file
View File

@@ -0,0 +1,84 @@
%include "syscalls.inc"
%include "mmap.inc"
HEAP_SIZE equ 64 * 1024 * 1024 ; 64 Megabytes
section .bss
heap_start: resq 1
heap_cursor: resq 1
heap_end: resq 1
section .text
global _start
_start:
call heap_init
mov rdi, 0xAAAA
mov rsi, 0xBBBB
call cons
mov rbx, rax
mov rdi, rbx
call print_hex
mov rdi, [rbx]
call print_hex
mov rdi, [rbx+8]
call print_hex
m_syscall SYS_EXIT, 0
heap_init:
m_syscall SYS_MMAP, 0, HEAP_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0
cmp rax, 0
jl .error
mov [heap_start], rax
mov [heap_cursor], rax
add rax, HEAP_SIZE
mov [heap_end], rax
ret
.error:
m_syscall SYS_WRITE, STDOUT, msg_err, msg_err_len
m_syscall SYS_EXIT, 1
cons:
mov rax, [heap_cursor]
mov rdx, rax
add rdx, 16
cmp rdx, [heap_end]
ja .heap_overflow
mov [rax], rdi
mov [rax+8], rsi
mov [heap_cursor], rdx
ret
.heap_overflow:
m_syscall SYS_WRITE, STDOUT, msg_oom, msg_oom_len
m_syscall SYS_EXIT, 1
print_hex:
sub rsp, 24
mov rcx, 16
mov rsi, rsp
add rsi, 15
mov rax, rdi
.loop:
mov rdx, rax
and rdx, 0xF
cmp dl, 9
jbe .digit
add dl, 7
.digit:
add dl, '0'
mov [rsi], dl
dec rsi
shr rax, 4
loop .loop
mov byte [rsp+16], 10
m_syscall SYS_WRITE, STDOUT, rsp, 17
add rsp, 24
ret
section .data
msg_ok: db "Heap initialized successfully.", 10
msg_ok_len: equ $ - msg_ok
msg_err: db "CRITICAL: Failed to allocate heap memory.", 10
msg_err_len: equ $ - msg_err
msg_oom: db "CRITICAL: Out of memory (Heap full).", 10
msg_oom_len: equ $ - msg_oom