Commit d91f95f
Changed files (50)
fs
memory
notlibc
platform
testing
util
datatypes/array.h
@@ -1,366 +0,0 @@
-#ifndef NOTLIBC_HEADER_DATATYPES_ARRAY_INCLUDED
-#define NOTLIBC_HEADER_DATATYPES_ARRAY_INCLUDED
-
-#include "memory/heap.h"
-#include "platform/common/types.h"
-#include "platform/info/compiler.h"
-#include "platform/info/build.h"
-
-#include "./pointer.h"
-
-
-#define ARR_FOREACH( T, varname, arr) \
- for( T *varname = &arr->data[0]; varname < &arr->data[arr->a.len]; varname += 1 )
-
-STRUCT( AnyArr,
- usize len;
- DEBUG(
- Heap *heap;
- usize checksum;
- )
-);
-
-
-static inline Status AnyArr_create( usize count, AnyArr **out, Heap *h, usize elem_size );
-static inline Status AnyArr_destroy( AnyArr** arr, Heap *h );
-
-static inline Status AnyArr_extend( AnyArr **arr, usize additional_len, Heap *h, usize elem_size );
-static inline Status AnyArr_truncate( AnyArr *arr, usize cutlen, usize elem_size );
-
-static inline Status AnyArr_inflate( AnyArr **arr, usize additional_count, Heap *h, usize elem_size );
-static inline Status AnyArr_deflate( AnyArr **arr, Heap *h, usize elem_size );
-
-static inline Status AnyArr_push( AnyArr **arr, void* el, Heap *h, usize elem_size );
-static inline Status AnyArr_pop( AnyArr *arr, void* el_out, usize elem_size );
-
-static inline Status AnyArr_dup( const AnyArr *arr, AnyArr **out_arr, Heap *h, usize elem_size );
-
-DEBUG(
- static inline void _AnyArr_update_checksum( AnyArr *arr );
- static inline void _AnyArr_validate( const AnyArr *arr );
-)
-
-static inline Status AnyArr_create( usize count, AnyArr **out, Heap *h, usize elem_size ) {
- usize alloc_count = count;
- DEBUG( alloc_count++ ); /* additional poisoned element in debug */
-
- usize alloc_size = sizeof(AnyArr) + alloc_count*elem_size;
-
- TRY( Heap_alloc( h, alloc_size, (void**)out ) );
- (*out)->len = count;
- DEBUG(
- (*out)->heap = h;
- _AnyArr_update_checksum( *out )
- );
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_destroy( AnyArr** arr, Heap *h ) {
- DEBUG(
- assert( h == (*arr)->heap );
- _AnyArr_validate( *arr );
- )
-
- TRY( Heap_free( h, (void**)arr ) );
- return S_SUCCESS;
-}
-
-DEBUG(
- static inline void _AnyArr_update_checksum( AnyArr *arr ) {
- usize heapblock_size = Heap_get_asize( arr->heap, arr );
- arr->checksum = heapblock_size ^ (usize)arr->heap ^ arr->len ^ ARRAY_XOR_KEY;
- }
-
- static inline void _AnyArr_validate( const AnyArr *arr ) {
- usize heapblock_size = Heap_get_asize( arr->heap, arr );
- usize checksum = heapblock_size ^ (usize)arr->heap ^ arr->len ^ ARRAY_XOR_KEY;
- assert( arr->checksum == checksum );
- }
-)
-
-static inline Status AnyArr_inflate( AnyArr **arr, usize additional_count, Heap *h, usize elem_size ) {
- DEBUG(
- assert( h == (*arr)->heap );
- _AnyArr_validate( *arr );
- )
-
- if( additional_count == 0 ) {
- return S_COMPLETION;
- }
-
- usize newsize = ((*arr)->len + additional_count)*elem_size + sizeof(AnyArr);
- DEBUG( newsize += elem_size; )
-
- AnyArr *newarr = 0;
- TRY( Heap_alloc( h, newsize, (void**)&newarr ) );
-
- usize total_size = (*arr)->len*elem_size + sizeof(AnyArr);
- DEBUG( total_size += elem_size; )
-
- mem_copy( (*arr), newarr, total_size );
- newarr->len = (*arr)->len;
-
- DEBUG( _AnyArr_update_checksum( *arr ) );
-
- TRY( Heap_free( h, (void**)arr ) );
- *arr = newarr;
- return S_SUCCESS;
-}
-
-
-static inline Status AnyArr_extend( AnyArr **arr, usize additional_len, Heap *h, usize elem_size ) {
- DEBUG(
- assert( (*arr)->heap == h );
- _AnyArr_validate( *arr );
- usize old_len = (*arr)->len;
- )
-
- usize asize = Heap_get_asize( h, *arr );
- usize maxcount = asize - sizeof(AnyArr);
- DEBUG( maxcount--);
- maxcount /= elem_size;
- usize newlen = (*arr)->len + additional_len;
-
- if( newlen >= maxcount ) {
- TRY( AnyArr_inflate( arr, additional_len, h, elem_size ) );
- }
-
- (*arr)->len += additional_len;
-
- DEBUG(
-
- u8 *data = (u8*)((*arr) + 1);
- u8 *uninint = data + newlen*elem_size;
- mem_set( uninint, (newlen - old_len)*elem_size, MAGIC_UNINITIALIZED_MEM );
- _AnyArr_update_checksum( *arr );
- )
-
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_truncate( AnyArr *arr, usize cutlen, usize elem_size ) {
- DEBUG(
- _AnyArr_validate( arr );
- usize old_len = arr->len;
- )
- RELEASE(
- (void)elem_size;
- )
-
- if( cutlen > arr->len ) {
- DEBUG( assert(0) );
- return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_2;
- }
-
- arr->len -= cutlen;
-
- DEBUG(
- u8 *data = (u8*)(arr + 1);
- u8 *raticide = data + arr->len*elem_size;
- mem_set( raticide, (old_len - arr->len)*elem_size, MAGIC_POISONED_MEM );
-
- _AnyArr_update_checksum( arr );
- )
-
-
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_deflate( AnyArr **arr, Heap *h, usize elem_size ) { /* reallocate to just fit the currently contained elements - we assume it's on the same heap */
- DEBUG(
- assert( h == (*arr)->heap );
- _AnyArr_validate( (*arr) );
- )
-
- usize total_size = (*arr)->len*elem_size + sizeof(AnyArr);
- DEBUG( total_size += elem_size; )
-
- AnyArr *out = 0;
- TRY( Heap_alloc( h, total_size, (void**)&out ) );
- mem_copy( *arr, out, total_size );
- TRY( Heap_free( h, (void**)arr ) );
-
- *arr = out;
-
- DEBUG( _AnyArr_update_checksum( *arr ) );
-
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_copy( const AnyArr *arr, AnyArr **out, Heap *source_heap, Heap *target_heap, usize maxcount, usize len, usize elem_size ) {
- DEBUG(
- assert( source_heap == arr->heap );
- _AnyArr_validate( arr );
- )
-
- usize alloc_size = (maxcount)? maxcount*elem_size + sizeof(AnyArr) : Heap_get_asize( source_heap, arr );
- DEBUG( alloc_size += elem_size );
-
- TRY( Heap_alloc( target_heap, alloc_size, (void**)out ) );
- (*out)->len = len;
-
- DEBUG( _AnyArr_update_checksum( *out ); )
-
- mem_copy( arr + 1, *out + 1, len*elem_size );
-
- DEBUG(
- u8* data = (u8*)(arr + 1);
- usize data_size = len*elem_size;
- u8* poison_start = data + data_size;
- usize poison_amount = alloc_size - data_size - sizeof(AnyArr);
- DEBUG( poison_amount += elem_size );
-
- mem_set( poison_start, poison_amount, MAGIC_POISONED_MEM );
- )
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_move( AnyArr **arr, AnyArr **out, Heap *source_heap, Heap *target_heap, usize maxcount, usize len, usize elem_size ) {
- TRY( AnyArr_copy( *arr, out, source_heap, target_heap, maxcount, len, elem_size ) );
- TRY( Heap_free( source_heap, (void**)arr ) );
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_push( AnyArr **arr, void* el, Heap *h, usize elem_size ) {
- DEBUG(
- assert( h == (*arr)->heap );
- _AnyArr_validate( *arr );
- )
-
- usize s = Heap_get_asize(h, *arr);
- usize maxcount = (s - sizeof(AnyArr))/elem_size;
-
- DEBUG(
- maxcount--; /* Additional poisoned element */
- );
-
- if( (*arr)->len >= maxcount ) {
- AnyArr_inflate( arr, (*arr)->len, h, elem_size );
- }
-
- u8 *data = (u8*)(*arr + 1);
- void *new_elem = data + (*arr)->len*elem_size;
-
- mem_copy( el, new_elem, elem_size );
- (*arr)->len++;
-
- DEBUG(
- _AnyArr_update_checksum( *arr );
- mem_set( data + ((*arr)->len)*elem_size, elem_size, MAGIC_POISONED_MEM );
- )
-
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_pop( AnyArr *arr, void* el_out, usize elem_size ) {
- DEBUG(
- _AnyArr_validate( arr );
- )
- if( arr->len == 0 ) {
- DEBUG( assert(0) );
- return ERR_OUT_OF_BOUND;
- }
-
- arr->len--;
-
- u8 *data = (u8*)(arr + 1);
- usize offset = elem_size*arr->len;
-
- mem_copy( data + offset, el_out, elem_size );
- DEBUG(
- _AnyArr_update_checksum( arr );
- mem_set( data + offset, elem_size, MAGIC_POISONED_MEM );
- )
- return S_SUCCESS;
-}
-
-static inline Status AnyArr_dup( const AnyArr *arr, AnyArr **out_arr, Heap *h, usize elem_size ) {
- DEBUG( _AnyArr_validate( arr );)
- usize total_size = arr->len*elem_size + sizeof(AnyArr);
-
- TRY( Heap_alloc( h, total_size, (void**)out_arr ) );
- mem_copy( arr, *out_arr, total_size );
-
- return S_SUCCESS;
-}
-
-
-#define GEN_ARRAY_TYPE( T ) \
- STRUCT( T##s, \
- usize len; \
- DEBUG( \
- Heap *heap; \
- usize checksum; \
- ) \
- T data[]; \
- ); \
- ASSERT( sizeof(T##s)%sizeof(usize) == 0 ); \
- ASSERT( sizeof(T##s) == sizeof(AnyArr) ); \
- \
-static inline Status T##s_create( Heap *h, usize count, T ## s **out ) { \
- return AnyArr_create( count, (AnyArr**) out, h, sizeof(T) ); \
-} \
- \
-static inline Status T##s_push( T##s **arr, T* el, Heap *h ) { \
- return AnyArr_push( (AnyArr**)arr, el, h, sizeof(T) ); \
-} \
- \
-static inline Status T##s_pop( T##s *arr, T* el ) { \
- return AnyArr_pop( (AnyArr*)arr, el, sizeof(T) ); \
-} \
- \
-static inline Status T##s_extend( T##s **arr, usize additional_len, Heap *h ) { \
- return AnyArr_extend( (AnyArr**)arr, additional_len, h, sizeof(T) ); \
-} \
- \
-static inline Status T##s_truncate( T##s *arr, usize cutlen ) { \
- return AnyArr_truncate( (AnyArr*)arr, cutlen, sizeof(T) ); \
-} \
- \
-static inline Status T##s_inflate( T##s **arr, usize additional_count, Heap *h ) { \
- return AnyArr_inflate( (AnyArr**)arr, additional_count, h, sizeof(T) ); \
-} \
- \
-static inline Status T##s_deflate( T##s **arr, Heap *h ) { \
- return AnyArr_deflate( (AnyArr**)arr, h, sizeof(T) ); \
-} \
- \
-static inline Status T##s_dup( const T##s *arr, T##s **out_arr, Heap *h ) { \
- return AnyArr_dup( (AnyArr*)arr, (AnyArr**)out_arr, h, sizeof(T) ); \
-} \
- \
-static inline Status T ## s_destroy( T##s **arr, Heap *h ) { \
- return AnyArr_destroy( (AnyArr**)arr, h ); \
-}
-
-GEN_ARRAY_TYPE( u8 )
-GEN_ARRAY_TYPE( u16 )
-GEN_ARRAY_TYPE( u32 )
-GEN_ARRAY_TYPE( u64 )
-GEN_ARRAY_TYPE( usize )
-
-GEN_ARRAY_TYPE( s8 )
-GEN_ARRAY_TYPE( s16 )
-GEN_ARRAY_TYPE( s32 )
-GEN_ARRAY_TYPE( s64 )
-GEN_ARRAY_TYPE( ssize )
-
-GEN_ARRAY_TYPE( f32 )
-GEN_ARRAY_TYPE( f64 )
-
-GEN_ARRAY_TYPE( u8p )
-GEN_ARRAY_TYPE( u16p )
-GEN_ARRAY_TYPE( u32p )
-GEN_ARRAY_TYPE( u64p )
-GEN_ARRAY_TYPE( usizep )
-
-GEN_ARRAY_TYPE( s8p )
-GEN_ARRAY_TYPE( s16p )
-GEN_ARRAY_TYPE( s32p )
-GEN_ARRAY_TYPE( s64p )
-GEN_ARRAY_TYPE( ssizep )
-
-GEN_ARRAY_TYPE( f32p )
-GEN_ARRAY_TYPE( f64p )
-
-#endif
datatypes/common.h
@@ -1,8 +0,0 @@
-#ifndef NOTLIBC_HEADER_DATATYPES_COMMON_INCLUDED
-#define NOTLIBC_HEADER_DATATYPES_COMMON_INCLUDED
-
-#include "platform/platform.h"
-#include "./datatypes/error.h"
-#include "./datatypes/string.h"
-
-#endif
datatypes/error.h
@@ -1,74 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_ERROR_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_ERROR_INCLUDED
-
-#include "platform/common/types.h"
-
-typedef u32 Status;
-
-#define S_MASK (3 << 30)
-
-#define S_SUCCESS (1 << 30) /* Requested action performed. */
-#define S_COMPLETION (0 << 30) /* Action didn't need to be performed - desired state is already present/active. */
-#define S_FAILURE (2 << 30) /* Action failed. */
-
-#define S_SOURCE_MASK (0x3ff << 20)
-enum _ErrorSources {
-
- ERRSRC_ARG_1 = (0x1 << 20),
- ERRSRC_ARG_2 = (0x2 << 20),
- ERRSRC_ARG_3 = (0x3 << 20),
- ERRSRC_ARG_4 = (0x4 << 20),
- ERRSRC_ARG_5 = (0x5 << 20),
- ERRSRC_ARG_6 = (0x6 << 20),
- ERRSRC_ARG_7 = (0x7 << 20),
- ERRSRC_ARG_8 = (0x8 << 20),
- ERRSRC_ARG_9 = (0x9 << 20),
- ERRSRC_ARG_10 = (0xa << 20),
- ERRSRC_ARG_11 = (0xb << 20),
- ERRSRC_ARG_12 = (0xc << 20),
-
- ERRSRC_PLATFORM = (0x10 << 20), /* The error resulted inside platform code. */
-};
-
-#define S_REASON_MASK (0xfffff)
-enum _ErrorReasons {
- ERR_GENERIC = 0x0, /* Even numbers are for the implementations, odd are for user-defined errors */
-
- ERR_INVALID_ARGUMENT = 0x2,
-
- ERR_OVERFLOW = 0x4,
-
- ERR_OUT_OF_BOUND = 0x6, /* a value is out of bounds or the operation would violate certain bounds with the current arguments */
-
- ERR_PERMISSION_DENIED = 0x8,
-
-
- ERR_MEM_MAP_FAILURE = 0x100,
- ERR_MEM_UNMAP_FAILURE = 0x102,
- ERR_MEM_SETPERM_FAILURE = 0x104,
- ERR_MEM_SETHINT_FAILURE = 0x106,
-
- ERR_FILE_ALREADY_EXISTS = 0x110,
- ERR_FILE_DOESNT_EXIST = 0x112,
-
- ERR_NO_DISK_SPACE = 0x114,
-
-
-};
-
-
-#define S_OK(...) ( ((__VA_ARGS__) & S_MASK) != (Status)S_FAILURE ) /* != FAILURE, cause otherwise the expression will appear twice, which is a great footgun when it's stateful... we are having none of that here */
-#define S_NOK(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
-
-#define S_SUCCESSFUL(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_SUCCESS )
-#define S_COMPLETED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_COMPLETION )
-#define S_FAILED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
-
-#define TRY(...) do { \
- Status _res = (__VA_ARGS__); \
- if( S_NOK(_res) ) { \
- return _res; \
- } \
-} while(0)
-
-#endif
datatypes/pointer.h
@@ -1,25 +0,0 @@
-#ifndef NOTLIBC_HEADER_DATATYPES_POIUNTER_INCLUDED
-#define NOTLIBC_HEADER_DATATYPES_POIUNTER_INCLUDED
-
-#include "platform/common/types.h"
-#include "platform/info/compiler.h"
-
-#define GEN_POINTER_TYPE( T ) \
-typedef T* T##p
-
-GEN_POINTER_TYPE( u8 );
-GEN_POINTER_TYPE( u16 );
-GEN_POINTER_TYPE( u32 );
-GEN_POINTER_TYPE( u64 );
-GEN_POINTER_TYPE( usize );
-
-GEN_POINTER_TYPE( s8 );
-GEN_POINTER_TYPE( s16 );
-GEN_POINTER_TYPE( s32 );
-GEN_POINTER_TYPE( s64 );
-GEN_POINTER_TYPE( ssize );
-
-GEN_POINTER_TYPE( f32 );
-GEN_POINTER_TYPE( f64 );
-
-#endif
datatypes/string.h
@@ -1,43 +0,0 @@
-#ifndef NOTLIBC_HEADER_DATATYPES_STRING_INCLUDED
-#define NOTLIBC_HEADER_DATATYPES_STRING_INCLUDED
-
-#include "platform/common/types.h"
-
-STRUCT( Str,
- usize len;
- u8 data[];
-);
-
-STRUCT( StrSlc,
- usize len;
- u8 *data;
-);
-
-
-/* On typical platforms that already have/need nul-termination we keep the nul-termination alongside the explicit length notation.
- * Hacky, but no one wants to copy strings/paths for syscalls.
- * NOTE: on these platforms len MUST NOT include the NUL-terminator.
- * It is the indexable length of the string. */
-
-#if PLATFORM == PLATFORM_LINUX || PLATFORM == PLATFORM_WINDOWS
-
-#define STRING( varname, string ) \
- struct { \
- u64 len; \
- u8 data[sizeof(string)]; \
- } varname = { .len = sizeof(string)-1, .data = string }
-#else
- #error Str not implemented for current platform.
-
-/* For bare metal, when we get there: */
-
-#define STATIC( varname, str ) \
- const struct { \
- u64 len; \
- u8 data[sizeof( str ) - 1] __attribute__((nonstring)); \
- } varname = { .len = sizeof(str) - 1, .data = str }
-
-#endif
-
-
-#endif
fs/file.h
@@ -1,90 +0,0 @@
-#ifndef NOTLIBC_HEADER_FS_FILE_INCLUDED
-#define NOTLIBC_HEADER_FS_FILE_INCLUDED
-
-#include "datatypes/string.h"
-#include "datatypes/error.h"
-#include "platform/info/build.h"
-#include "platform/common/corefunc.h"
-#include "util/mathops.h"
-
-typedef struct _File File;
-typedef struct _FileView FileView;
-
-
-enum FileOpenFlags {
-
- FILE_ACCESS_READ = ((usize)1 << 1),
- FILE_ACCESS_WRITE = ((usize)1 << 2),
- FILE_ACCESS_APPEND = ((usize)1 << 3),
-
- FILE_ACCESS_MASK = (FILE_ACCESS_READ | FILE_ACCESS_WRITE | FILE_ACCESS_APPEND),
-
- FILE_EXISTING_OPEN = ((usize)1 << 4),
- FILE_EXISTING_TRUNCATE = ((usize)1 << 5),
- FILE_EXISTING_FAIL = ((usize)1 << 6),
-
- FILE_EXISTING_MASK = (FILE_EXISTING_OPEN | FILE_EXISTING_TRUNCATE | FILE_EXISTING_FAIL),
-
- FILE_MISSING_CREATE = ((usize)1 << 7),
- FILE_MISSING_FAIL = ((usize)1 << 8),
-
- FILE_MISSING_MASK = (FILE_MISSING_CREATE | FILE_MISSING_FAIL),
-
- FILE_LINK_FOLLOW = ((usize)1 << 9),
- FILE_LINK_FAIL = ((usize)1 << 10), /* os-dependent option - whatever the os guarantees. O_NOFOLLOW on linux. */
-
- FILE_LINK_MASK = (FILE_LINK_FOLLOW | FILE_LINK_FAIL),
-
-};
-
-static inline Status File_open_validate_flags( usize flags, Status err_source ) {
-
- usize existing_flags = flags & FILE_EXISTING_MASK;
- usize existing_flags_multiple_set = !usize_is_power_of_two( existing_flags );
-
- usize missing_flags = flags & FILE_MISSING_MASK;
- usize missing_flags_multiple_set = !usize_is_power_of_two( missing_flags );
-
- usize link_flags = flags & FILE_LINK_MASK;
- usize link_flags_multiple_set = !usize_is_power_of_two( link_flags );
-
- usize write_append_flags = flags & (FILE_ACCESS_WRITE | FILE_ACCESS_APPEND);
- usize write_append_flags_multiple_set = !usize_is_power_of_two( write_append_flags );
-
- if( existing_flags_multiple_set |
- missing_flags_multiple_set |
- link_flags_multiple_set |
- (write_append_flags && write_append_flags_multiple_set)
- ) {
- DEBUG(breakpoint());
- return S_FAILURE | ERR_INVALID_ARGUMENT | err_source;
- }
-
- return S_SUCCESS;
-}
-
-Status File_open( const Str *name, usize flags, File *out );
-Status File_close( File *f );
-
-Status File_read( const File *f, usize max_amount, usize *out_amount, u8 *out );
-Status File_write( const File *f, usize amount, usize *out_amount, const u8 *buf );
-
-Status File_seek( const File *f, usize position );
-
-Status File_delete( const Str *name );
-
-
-enum FileViewFlags {
- FILEVIEW_OWN_FILE = (1 << 1),
-/* FILEVIEW_PAGE_ALIGNED_EXTEND = (1 << 2), */
-};
-
-Status FileView_from_file( File *file, usize claim_amount, usize flags, FileView *out ); /* if claim_amount == 0 => claims exact filesize */
-Status FileView_from_path( const Str *path, usize claim_amount, usize flags, FileView *out ); /* This is for quick and easy mmaping of files. If you actually want control over the opening flags use FileView_from_file - if you don't */
-
-Status FileView_extend_file( FileView *fv, usize amount ); /* Extend the file's end by amount */
-
-Status FileView_destroy( FileView *fv );
-
-
-#endif
memory/heap/heap_debug.h
@@ -1,186 +0,0 @@
-#ifndef NOTLIBC_HEADER_MEMORY_HEAP_DEBUG_INCLUDED
-#define NOTLIBC_HEADER_MEMORY_HEAP_DEBUG_INCLUDED
-
-#include "memory/arena.h"
-
-STRUCT( HeapEntry,
- u64 header_start_guard;
- usize allowed_size;
- struct _HeapEntry *next; /* unlike in release, in debug we have a separate next pointer for linking into the freelist */
- u64 checksum; /* size xor'd with next, allowed size and the guard magic number - (likely) detects overwriting of metadata */
- usize size;
- u64 header_end_guard;
-);
-
-
-STRUCT( Heap,
- Arena arena; /* Heap is built on top of arena. It's just an arena + a freelist with metadata */
- HeapEntry freelist;
- HeapEntry blocklist; /* The existing blocks in a list */
-);
-
-static inline Status _Heap_find_block( Heap *h, HeapEntry *e, HeapEntry **out_prev ) {
- u8 ptr_correct = 0;
- HeapEntry *prev = &h->blocklist;
-
- for( HeapEntry *i = h->blocklist.next; i != 0; i = i->next ) {
- if( e == i ) {
- ptr_correct = 1;
- break;
- }
- prev = i;
- }
-
- /* The pointer is not pointing to a previously allocated block if this fails or perhaps it is a double-free. */
- assert( ptr_correct );
- if( !ptr_correct ) {
- return S_FAILURE;
- }
-
- *out_prev = prev;
- return S_SUCCESS;
-}
-
-static inline Status _Heap_check_entry( HeapEntry *e ) {
- u8 ok = 1;
-
- assert( e->checksum == (e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY) || (ok = 0) );
- assert( e->header_start_guard == HEAP_HEADER_GUARD_NUMBER || (ok = 0) );
- assert( e->header_end_guard == HEAP_HEADER_GUARD_NUMBER || (ok = 0) );
- assert( e->allowed_size >= e->size || (ok = 0) );
-
- u8* data = (u8*)(&e->header_end_guard + 1);
- assert( *(usize*)(data + e->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER || (ok = 0) );
-
- if( !ok ) {
- return S_FAILURE;
- } else {
- return S_SUCCESS;
- }
-}
-
-static inline void _Heap_unlink_entry( HeapEntry *prev, HeapEntry *e ) {
- prev->next = e->next;
- prev->checksum = prev->size ^ prev->allowed_size ^ (usize)prev->next ^ HEAP_XOR_KEY;
-}
-
-static inline void _Heap_link_free_entry( Heap *h, HeapEntry *e ) {
- e->next = h->freelist.next;
- h->freelist.next = e;
- e->checksum = e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY;
-}
-
-
-static inline void _Heap_link_block( Heap *h, HeapEntry *e ) {
- e->next = h->blocklist.next;
- h->blocklist.next = e;
- e->checksum = e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY;
-}
-
-static inline usize Heap_get_asize( Heap *h, const void *ptr ) { /* asize = allocation size */
- HeapEntry *e = (HeapEntry*)( (u8*)ptr - sizeof(HeapEntry) );
- HeapEntry *prev = 0;
- _Heap_check_entry( e );
- _Heap_find_block( h, e, &prev );
- return e->size;
-}
-
-#ifdef NOTLIBC_IMPLEMENT
-
-Status Heap_create( Heap *out, usize size ) {
- assert( out != 0 );
- assert( size != 0 );
- TRY( Arena_create( &out->arena, size ) );
- out->freelist = (HeapEntry){0};
- out->blocklist = (HeapEntry){0};
- return S_SUCCESS;
-}
-
-Status Heap_destroy( Heap *h ) {
- assert( h != 0 );
- TRY( Arena_destroy( &h->arena ) );
- mem_set( h, sizeof(*h), 0 );
- return S_SUCCESS;
-}
-
-Status Heap_alloc( Heap *h, usize amount, void **out ) {
- assert( h != 0 );
- assert( amount > 0 ); /* If your code can try to allocate 0 amount of memory you should consider rewriting it (or getting some help) */
-
- TRY( usize_round_up( amount, sizeof(usize), &amount ) );
- usize total_amount = amount + sizeof(HeapEntry) + sizeof(usize); /* usize for end guard */
-
- HeapEntry *new = 0;
- HeapEntry *prev = &h->freelist;
-
- usize max_size = 0;
- TRY( usize_mul(total_amount, 4, &max_size) );
-
-
- for( HeapEntry *i = h->freelist.next; i != 0; i = i->next ) {
-
- u8* data = (u8*)(&i->header_end_guard + 1);
- /* If any of these fails, then your freelist has been corrupted somehow - it should not be iterated */
- _Heap_check_entry(i);
-
- if( i->allowed_size >= amount && i->allowed_size <= max_size ) {
- new = i;
- for( usize i = 0; i < new->allowed_size; ++i ) {
- assert( data[i] == MAGIC_FREED_MEM );
- }
- _Heap_unlink_entry( prev, new );
- new->next = 0;
- break;
- }
- prev = i;
- }
-
- if( !new ) {
- TRY( Arena_take( &h->arena, total_amount, (u8**)&new ) );
- new->allowed_size = amount;
- }
-
- new->size = amount;
-
- u8 *data = (u8*)(&new->header_end_guard + 1);
- mem_set( data, new->size, MAGIC_UNINITIALIZED_MEM );
- mem_set( data + new->size, new->allowed_size - new->size, MAGIC_POISONED_MEM );
-
- *(usize*)(data + new->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER;
-
- new->size = amount;
- new->header_start_guard = HEAP_HEADER_GUARD_NUMBER;
- new->header_end_guard = HEAP_HEADER_GUARD_NUMBER;
- _Heap_link_block( h, new );
-
- *out = data;
-
- return S_SUCCESS;
-}
-
-Status Heap_free( Heap *h, void **ptr ) {
- assert( h != 0 );
- assert( ptr != 0 );
-
- HeapEntry *e = (HeapEntry*)( (u8*)*ptr - sizeof(HeapEntry) );
-
- HeapEntry *prev = 0;
-
- assert(S_OK( _Heap_find_block( h, e, &prev ) ));
- assert(S_OK( _Heap_check_entry( e ) ));
-
- _Heap_unlink_entry( prev, e );
- _Heap_link_free_entry( h, e );
-
- u8* data = (u8*)(&e->header_end_guard + 1);
- mem_set( data, e->allowed_size, MAGIC_FREED_MEM );
- *(usize*)(data + e->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER;
-
- *ptr = 0;
-
- return S_SUCCESS;
-}
-
-#endif
-
-#endif
memory/heap/heap_release.h
@@ -1,91 +0,0 @@
-#ifndef NOTLIBC_HEADER_MEMORY_HEAP_RELEASE_INCLUDED
-#define NOTLIBC_HEADER_MEMORY_HEAP_RELEASE_INCLUDED
-
-#include "memory/arena.h"
-
-STRUCT( HeapEntry,
- usize size; /* The next pointer is stored in the data when the block is added to the freelist */
-);
-
-STRUCT( Heap,
- Arena arena; /* Heap is built on top of arena. It's just an arena + a freelist with metadata */
- HeapEntry freelist;
- HeapEntry *freelist_data;
-);
-
-static inline usize Heap_get_asize( Heap *h, const void *ptr ) {
- (void)h;
- return *((usize*)ptr - 1);
-}
-
-#ifdef NOTLIBC_IMPLEMENT
-
-Status Heap_create( Heap *out, usize size ) {
- TRY( Arena_create( &out->arena, size ) );
- out->freelist = (HeapEntry){0};
- out->freelist_data = 0;
- return S_SUCCESS;
-}
-
-Status Heap_destroy( Heap *h ) {
- TRY( Arena_destroy( &h->arena ) );
- h->freelist = (HeapEntry){0};
- h->freelist_data = 0;
- return S_SUCCESS;
-}
-
-Status Heap_alloc( Heap *h, usize amount, void **out ) {
- if( amount == 0 ) return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_2;
-
- usize required_amount = usize_max(amount, sizeof(void*)); /* A pointer must fit into data, otherwise it can not be linked into the freelist when freed. */
- TRY( usize_add( required_amount, sizeof(HeapEntry), &required_amount ) );
- TRY( usize_round_up( required_amount, sizeof(usize), &required_amount ) ); /* word-align */
-
- HeapEntry *new = 0;
-
- /* Check freelist */
- HeapEntry *prev = &h->freelist;
-
- usize max_size = 0;
- TRY( usize_mul(required_amount, 4, &max_size) );
-
- for( HeapEntry *i = h->freelist_data; i != 0; i = *(HeapEntry**)(&i->size + 1) ) {
- if( i->size >= required_amount && i->size <= max_size ) {
- new = i;
- *(HeapEntry**)(&prev->size + 1) = *(HeapEntry**)(&new->size + 1); /* unlink entry */
- break;
- }
- prev = i;
- }
-
- /* New allocation */
- if( !new ) {
- TRY( Arena_take( &h->arena, required_amount, (u8**)&new ) );
- new->size = required_amount;
- }
- /* otherwise we leave original size */
-
- *out = (u8*)(&new->size + 1);
-
- return S_SUCCESS;
-}
-
-Status Heap_free( Heap *h, void **ptr ) {
- if( h == 0 ) return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_1;
- if( ptr == 0 ) return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_2;
-
- HeapEntry *e = (HeapEntry*)( (u8*)*ptr - sizeof(HeapEntry) );
-
- /* Link into freelist */
- *((HeapEntry**)(&e->size + 1)) = h->freelist_data;
- h->freelist_data = e;
-
- *ptr = 0;
-
- return S_SUCCESS;
-}
-
-#endif
-
-
-#endif
memory/arena.h
@@ -1,88 +0,0 @@
-#ifndef NOTLIBC_HEADER_MEMORY_ARENA_INCLUDED
-#define NOTLIBC_HEADER_MEMORY_ARENA_INCLUDED
-
-#include "util/mathops.h"
-#include "memory/memory.h"
-
-STRUCT( Arena,
- Page *start; /* The address where the arena starts */
- usize claimed; /* Total size of the arena */
- usize occupied; /* The actually occupied (backed) range */
- usize taken; /* The top of the arena */
-);
-
-Status Arena_create( Arena *out, usize size );
-Status Arena_destroy( Arena *a );
-
-Status Arena_take( Arena *a, usize amount, u8 **out );
-Status Arena_give( Arena *a, usize amount );
-Status Arena_align( Arena *a, usize alignment );
-
-
-#ifdef NOTLIBC_IMPLEMENT
- Status Arena_create( Arena *out, usize size ) {
- TRY( u64_round_up( size, 0x1000, &size ) );
- TRY( mem_claim( size/0x1000, &out->start ) );
-
- out->claimed = size;
- out->occupied = 0;
- out->taken = 0;
-
- return S_SUCCESS;
- }
-
- Status Arena_destroy( Arena *a ) {
- TRY( mem_relinquish( a->start, a->claimed ) );
-
- mem_set( a, sizeof(*a), 0 );
- return S_SUCCESS;
- }
-
- Status Arena_align( Arena *a, usize alignment ) {
- u64 take_amount = 0;
- TRY( u64_round_up( a->taken, alignment, &take_amount ) );
- take_amount -= a->taken;
-
- if( take_amount != 0 ) {
- u8* discard;
- TRY( Arena_take( a, take_amount, &discard ) );
- }
-
- return S_SUCCESS;
- }
-
- Status Arena_take( Arena *a, usize amount, u8 **out ) {
- assert( out != 0 );
- assert( amount != 0 );
-
- if( a->claimed - a->taken < amount ) { /* no overflow risk this way */
- return S_FAILURE | ERR_OUT_OF_BOUND;
- }
-
- u64 new_taken = a->taken + amount;
-
- if( new_taken > a->occupied ) {
- u64 occupy_amount = 0;
-
- TRY( u64_round_up( new_taken - a->occupied , sizeof(Page), &occupy_amount ) );
- TRY( mem_occupy( a->start + a->occupied/sizeof(Page), occupy_amount/0x1000 ) );
-
- a->occupied += occupy_amount;
- }
-
- *out = ((u8*)a->start + a->taken);
- a->taken = new_taken;
-
- return S_SUCCESS;
- }
-
-
- Status Arena_give( Arena *a, usize amount ) {
- if( amount > a->taken ) return S_FAILURE | ERR_OUT_OF_BOUND;
- a->taken -= amount;
- return S_SUCCESS;
- }
-
-#endif
-
-#endif
memory/heap.h
@@ -1,26 +0,0 @@
-#ifndef NOTLIBC_HEADER_MEMORY_HEAP_INCLUDED
-#define NOTLIBC_HEADER_MEMORY_HEAP_INCLUDED
-
-#include "datatypes/error.h"
-#include "platform/info/build.h"
-
-#if BUILD_TYPE == BUILD_RELEASE
- #include "./heap/heap_release.h"
-#elif BUILD_TYPE == BUILD_DEBUG
- #include "./heap/heap_debug.h"
-#endif
-
-ASSERT( sizeof(HeapEntry)%sizeof(usize) == 0 );
-
-typedef struct _Heap Heap;
-
-Status Heap_create( Heap *out, usize size ); /* size - size of underlying arena. The heap will hold less, due to bookkeeping overhead for allocations. */
-
-Status Heap_alloc( Heap *h, usize amount, void **out );
-Status Heap_free( Heap *h, void **ptr ); /* u8** cause it zeroes the pointer on success automatically. */
-
-static inline usize Heap_get_asize( Heap *h, const void *ptr );
-
-Status Heap_destroy( Heap *h );
-
-#endif
memory/memory.h
@@ -1,74 +0,0 @@
-#ifndef NOTLIBC_HEADER_MEMORY_MEMORY_INCLUDED
-#define NOTLIBC_HEADER_MEMORY_MEMORY_INCLUDED
-
-#include "../platform/platform.h"
-
-/* Platform memory header */
-#if PLATFORM == PLATFORM_LINUX
- #include "../platform/linux/memory.h"
-#elif PLATFORM == PLATFORM_WINDOWS
- #include "../platform/windows/memory.h"
-#endif
-
-
-/* Memory units */
-
-#define KiB(n) ((u64)(n) << 10)
-#define MiB(n) ((u64)(n) << 20)
-#define GiB(n) ((u64)(n) << 30)
-#define TiB(n) ((u64)(n) << 40)
-
-static inline void* mem_copy( const void *source, void *destination, u64 len ) {
- const u8 *src = source;
- u8 *dst = destination;
- u64 i = 0;
-
- for( ; i < len; ++i ) {
- dst[i] = src[i];
- }
-
- return &dst[i];
-}
-
-static inline void* mem_set( void *start, u64 len, u8 value ) {
- assert(start != 0);
- u8 *s = start;
- u64 i = 0;
-
- for( ; i < len; ++i ) {
- s[i] = value;
- }
-
- return &s[len];
-}
-
-
-Status mem_claim( u32 page_count, Page **ptr_out); /* Request virtual memory range */
-Status mem_relinquish( Page *start, u32 page_count ); /* Free virtual memory range */
-
-Status mem_occupy( Page *start, u32 page_count ); /* Set up physical backing */
-Status mem_vacate( Page *start, u32 page_count ); /* Allow removal of physical backing */
-
-#ifdef NOTLIBC_IMPLEMENT
-
-extern void *memset( void* ptr, int value, unsigned long count );
-
-void *memset( void* ptr, int value, unsigned long count ) {
- mem_set( ptr, count, value );
- return ptr;
-}
-
- void *memcpy( void *dest, const void *src, unsigned long n );
-
-void *memcpy( void *dest, const void *src, unsigned long n ) {
- char *d = dest;
- const char *s = src;
- while(n--)
- *d++ = *s++;
- return dest;
-}
-
-#endif
-
-
-#endif
notlibc/core.h
@@ -1,14 +0,0 @@
-#ifndef NOTLIBC_HEADER_NOTLIBC_CORE_INCLUDED
-#define NOTLIBC_HEADER_NOTLIBC_CORE_INCLUDED
-
-#include "../memory/memory.h"
-#include "../memory/arena.h"
-#include "../memory/heap.h"
-
-#include "../datatypes/string.h"
-
-#include "../fs/file.h"
-
-#include "../platform/platform.h"
-
-#endif
platform/common/all.h
@@ -1,8 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_COMMON_ALL_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_COMMON_ALL_INCLUDED
-
-#include "./corefunc.h"
-#include "./headers.h"
-#include "./types.h"
-
-#endif
platform/common/corefunc.h
@@ -1,22 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_COREFUNC_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_COREFUNC_INCLUDED
-
-#include "./types.h"
-#include "./headers.h"
-
-#ifdef NOTLIBC_IMPLEMENT
- #include PLATFORM_FUNC_HEADER
-#endif
-
-static inline void terminate(u32 code); /* aka exit */
-static inline void terminate_forced(void); /* force exit, fault, anything that terminates forcefully */
-
-static inline void breakpoint(void); /* raise a debug breakpoint, if possible on the target */
-
-static inline void assert( usize condition ) {
- if( !condition ) {
- breakpoint();
- }
-}
-
-#endif
platform/common/headers.h
@@ -1,14 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_HEADERS_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_HEADERS_INCLUDED
-
-#include "../info/os.h"
-
-#if PLATFORM == PLATFORM_LINUX
- #define PLATFORM_TYPES_HEADER "platform/linux/core/types.h"
- #define PLATFORM_FUNC_HEADER "platform/linux/core/func.h"
- #define PLATFORM_ENTRYPOINT_HEADER "platform/linux/core/entry.h"
- #define PLATFORM_FILE_HEADER "platform/linux/file.h"
-#elif PLATFORM == PLATFORM_WINDOWS
-#endif
-
-#endif
platform/common/types.h
@@ -1,23 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_TYPES_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_TYPES_INCLUDED
-
-#include "./headers.h"
-#include "../info/compiler.h"
-
-#include PLATFORM_TYPES_HEADER
-
-/* Type sanity checks */
-ASSERT( sizeof( u8 ) == 1 );
-ASSERT( sizeof( u16 ) == 2 );
-ASSERT( sizeof( u32 ) == 4 );
-ASSERT( sizeof( u64 ) == 8 );
-
-ASSERT( sizeof( s8 ) == 1 );
-ASSERT( sizeof( s16 ) == 2 );
-ASSERT( sizeof( s32 ) == 4 );
-ASSERT( sizeof( s64 ) == 8 );
-
-ASSERT( sizeof( f32 ) == 4 );
-ASSERT( sizeof( f64 ) == 8 );
-
-#endif
platform/info/arch.h
@@ -1,34 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_ARCH_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_ARCH_INCLUDED
-
-#define ARCH_I386 1
-#define ARCH_X86_64 2
-
-
-#ifndef ARCH
- #if defined(__x86_64__) || defined(_M_X64)
- #define ARCH ARCH_X86_64
- #define ARCH_NAME "x86_64"
- #define X86_64(...) __VA_ARGS__
- #elif defined(__i386__) || defined(_M_IX86)
- #define ARCH ARCH_I386
- #define ARCH_NAME "i386"
- #define I386(...) __VA_ARGS__
- #endif
-#endif
-
-#if !defined(ARCH) || !defined(ARCH_NAME)
- #error Failed to identify architecture. Please specify it via -DARCH=number (choose the most compatible option from above) and -DARCH_NAME=name to override the automatic detection.
-#endif
-
-/* These are only for in-macro use, in case they are absolutely necessary. Not to be abused. They lead to messy code in debuggers */
-#ifndef X86_64
-#define X86_64(...)
-#endif
-
-#ifndef I386
-#define I386(...)
-#endif
-
-
-#endif
platform/info/build.h
@@ -1,37 +0,0 @@
-#ifndef NOTLIBC_HEADER_BUILD_INCLUDED
-#define NOTLIBC_HEADER_BUILD_INCLUDED
-
-#define BUILD_DEBUG 1
-#define BUILD_RELEASE 2
-
-#ifndef BUILD_TYPE
-#define BUILD_TYPE 0
-#endif
-
-#if BUILD_TYPE == 1
- #define BUILD BUILD_DEBUG
- #define DEBUG(...) __VA_ARGS__
-#elif BUILD_TYPE == 2
- #define BUILD BUILD_RELEASE
- #define RELEASE(...) __VA_ARGS__
-#endif
-
-#ifndef BUILD
- #error No build type was specified. There is no defaulting to debug builds.
-#endif
-
-#ifndef DEBUG
-#define DEBUG(...)
-#endif
-
-#ifndef RELEASE
-#define RELEASE(...)
-#endif
-
-#ifdef NOTLIBC_IMPLEMENT
-#define IMPL(...) __VA_ARGS__
-#else
-#define IMPL(...)
-#endif
-
-#endif
platform/info/compiler.h
@@ -1,162 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_COMPILER_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_COMPILER_INCLUDED
-
-/* Compiler information detection */
-
-#define COMPILER_GCC 1
-#define COMPILER_CLANG 2
-#define COMPILER_TCC 3
-#define COMPILER_MSVC 4
-
-#ifndef COMPILER /* skip if -DCOMPILER=<something> was used */
- #if defined(__clang__) || defined(__llvm__)
- #define COMPILER COMPILER_CLANG
- #define COMPILER_NAME "clang"
-
- #define CLANG(...) __VA_ARGS__
- #define GCCLIKE(...) __VA_ARGS__
-
- #elif defined(__GNUC__) && !defined(__clang__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
- #define COMPILER COMPILER_GCC
- #define COMPILER_NAME "gcc"
-
- #define GCC(...) __VA_ARGS__
- #define GCCLIKE(...) __VA_ARGS__
-
- #elif defined(__TINYC__)
- #define COMPILER COMPILER_TCC
- #define COMPILER_NAME "tcc"
-
- #define TCC(...) __VA_ARGS__
-
- #elif defined( _MSC_VER )
- #define COMPILER_MSVC
- #define COMPILER_NAME "msvc"
-
- #define MSVC(...) __VA_ARGS__
- #endif
-#endif
-
-#if !defined(COMPILER) || !defined(COMPILER_NAME)
- #error Failed to identify compiler. Please specify it via -DCOMPILER=number (choose the most compatible option from above) and -DCOMPILER_NAME=name to override the automatic detection.
-#endif
-
-/* Code compiler-predicators (aka conditional compilation based on compiler) */
-
-#ifndef CLANG
-#define CLANG(...)
-#endif
-
-#ifndef GCC
-#define GCC(...)
-#endif
-
-#ifndef GCCLIKE
-#define GCCLIKE(...)
-#endif
-
-#ifndef TCC
-#define TCC(...)
-#endif
-
-#ifndef MSVC
-#define MSVC(...)
-#endif
-
-/* Macro trickery */
-#define MACRO_EMPTY()
-
-#define MACRO_DEFER( macro ) macro MACRO_EMPTY()
-#define MACRO_OBSTRUCT( ... ) __VA_ARGS__ MACRO_DEFER( MACRO_EMPTY )()
-#define MACRO_EXPAND( ... ) __VA_ARGS__
-
-#define MACRO_STRING_JOIN( str1, str2 ) str1##str2
-
-#define UNIQUE_NAME( name ) MACRO_EXPAND(MACRO_DEFER(MACRO_STRING_JOIN)(name, __LINE__))
-
-/* Warnings and errors */
-
-#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
- #define PRAGMA(pragma) _Pragma(#pragma)
-#elif COMPILER == COMPILER_MSVC
- #define PRAGMA(pragma) __pragma(pragma)
-#endif
-
-#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
- #define WARNING(...) PRAGMA(GCC warning __VA_ARGS__)
- #define ERROR(...) PRAGMA(GCC error __VA_ARGS__)
-#endif
-
-#if COMPILER == COMPILER_TCC
- #define WARN(...)
- #define ERROR(...) (*(void*)0 = 0)
- #ifndef NOTLIBC_SILENCE
- #warning Compiling with tcc. Pragmas are not supported, so warnings will just not be printed and errors will give an 'assignment to void' error, but the line number should still point to the right location.
- #endif
-#endif
-
-#ifndef WARNING
-#define WARNING(...)
-#ifndef NOTLIBC_SILENCE
-#warning No warning directive is implemented for this compiler. No warnings will be emitted from the code.
-#endif
-#endif
-
-#ifndef ERROR
-#define ERROR(...)
-#error No error directive is implemented for this compiler, thus errors can not be emitted.
-#endif
-
-/* Struct shorthand declaration */
-#define STRUCT( name, ...) \
-typedef struct _##name { \
- __VA_ARGS__ \
-} name
-
-
-#define STRUCT_FIELD_OFFSET( T, fieldname ) \
- ((usize)&(((T*)0)->fieldname))
-
-/* Cross-compiler packed struct declarator */
-#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG || COMPILER == COMPILER_TCC
-
- #define PACKED_STRUCT( name, ...) \
- typedef struct __attribute__((packed)) _##name { \
- __VA_ARGS__ \
- } name;
-
-#elif COMPILER == COMPILER_MSVC
-
- #define PACKED_STRUCT( name, ...) \
- PRAGMA(pack(push, 1)) \
- typedef struct _##name { \
- __VA_ARGS__ \
- } name; \
- PRAGMA(pack(pop))
-
-#endif
-
-#ifndef PACKED_STRUCT
-#error PACKED_STRUCT macro undefined.
-#endif
-
-/* Compile-time assertion */
-#define ASSERT( expression ) \
- typedef char UNIQUE_NAME(compile_time_assert)[(expression)? 1 : -1]
-
-
-#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
- #define UNREACHABLE __builtin_unreachable()
-#elif COMPILER == COPMILER_MSVC
- #define UNREACHABLE __assume(0)
-#endif
-
-#ifndef UNREACHABLE
-#define UNREACHABLE
-#ifndef NOTLIBC_SILENCE
-#warning UNREACHABLE is not defined for the current compiler. Compiler may not perform all optimizations it could based on unreachability in some special cases.
-#endif
-#endif
-
-
-#endif
platform/info/os.h
@@ -1,23 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_OS_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_OS_INCLUDED
-
-#define OS_LINUX 1
-#define OS_WINDOWS 2
-
-#ifndef OS
- #if defined(__linux__)
- #define OS OS_LINUX
- #define OS_NAME "linux"
-
- #elif defined(_WIN32) || defined(_WIN64)
- #define OS OS_WINDOWS
- #define OS_NAME "windows"
-
- #endif
-#endif
-
-#if !defined(OS) || !defined(OS_NAME)
- #error Failed to identify operating system. Please specify it via -DOS=number (choose the most compatible option from above) and -DOS_NAME=name to override the automatic detection.
-#endif
-
-#endif
platform/linux/core/entry.h
@@ -1,27 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_LINUX_ENTRY_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_LINUX_ENTRY_INCLUDED
-
-#include "platform/info/build.h"
-#include "platform/common/types.h"
-
-u8* linux_startup_sp = 0;
-
-void entry(void); /* aka main */
-
-#if ARCH == ARCH_X86_64
- __asm__ (
- ".section .text\n"
- ".global _start\n"
- ".type _start, @function\n"
- "_start:\n"
- "leaq linux_startup_sp(%rip), %rax\n"
- "movq %rsp, (%rax)\n" /* save original stack pointer */
- "xor %rax, %rax\n"
- "call entry\n"
- "ud2\n"
- );
-#elif ARCH == ARCH_I386
- #error "i386 entrypoint not implemented"
-#endif
-
-#endif
platform/linux/core/func.h
@@ -1,23 +0,0 @@
-#ifndef HEADER_PLATFORM_LINUX_CORE_FUNC_INCLUDED
-#define HEADER_PLATFORM_LINUX_CORE_FUNC_INCLUDED
-
-static inline void breakpoint(void) {
- __asm__ volatile (
- "int $3\n"
- );
-}
-
-static inline void terminate_forced(void) {
- __asm__ volatile (
- "ud2\n"
- );
-}
-
-#include "../syscalls.h"
-
-static inline void terminate(u32 code) {
- linux_exit((s32)code);
- UNREACHABLE;
-}
-
-#endif
platform/linux/core/types.h
@@ -1,39 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_LINUX_TYPES_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_LINUX_TYPES_INCLUDED
-
-#include "../../info/arch.h"
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-typedef unsigned long long u64;
-
-typedef signed char s8;
-typedef signed short s16;
-typedef signed int s32;
-typedef signed long long s64;
-
-typedef float f32;
-typedef double f64;
-
-#if ARCH == ARCH_X86_64
-
- typedef u64 usize;
- typedef s64 ssize;
-
- typedef struct _Page {
- u8 data[4096];
- } Page;
-
-#elif ARCH == ARCH_I386
-
- typedef u32 usize;
- typedef s32 ssize;
-
- typedef struct _Page {
- u8 data[4096];
- } Page;
-
-#endif
-
-#endif
platform/linux/file.h
@@ -1,246 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_LINUX_FILE_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_LINUX_FILE_INCLUDED
-
-#include "datatypes/error.h"
-#include "platform/common/types.h"
-#include "platform/common/corefunc.h"
-#include "platform/info/build.h"
-#include "platform/info/os.h"
-#include "platform/linux/syscalls.h"
-#include "platform/linux/memory.h"
-#include "fs/file.h"
-
-STRUCT( File,
- s32 fd;
-);
-
-STRUCT( FileView,
- File file;
- Page *start;
- usize claimed;
- usize filesize;
- usize flags;
-);
-
-Status File_open( const Str *name, usize flags, File *out ) {
- DEBUG( assert( name->data[name->len] == 0 ) );
-
- if(
- !(flags & FILE_ACCESS_WRITE) &&
- !(flags & FILE_ACCESS_APPEND) &&
- (flags & FILE_EXISTING_TRUNCATE)
- ) {
- DEBUG( breakpoint() ); /* Can not truncate a file without write access. */
- return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
- }
-
- if( (flags & FILE_EXISTING_FAIL) && (flags & FILE_MISSING_FAIL) ) {
- DEBUG( breakpoint() ); /* Useless flag combination: error if there is a file, error if there isn't one aka always error */
- return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
- }
-
- TRY( File_open_validate_flags( flags, ERRSRC_ARG_3 ) );
-
- usize syscall_flags = O_CLOEXEC; /* Close all files on exec */
-
- switch( flags & FILE_ACCESS_MASK ) {
- case FILE_ACCESS_READ:
- syscall_flags |= O_RDONLY;
- break;
-
- case FILE_ACCESS_WRITE:
- syscall_flags |= O_WRONLY;
- break;
-
- case FILE_ACCESS_APPEND:
- syscall_flags |= O_WRONLY | O_APPEND;
- break;
-
- case FILE_ACCESS_READ | FILE_ACCESS_WRITE:
- syscall_flags |= O_RDWR;
- break;
-
- case FILE_ACCESS_READ | FILE_ACCESS_APPEND:
- syscall_flags |= O_RDWR | O_APPEND;
- break;
-
- default:
- UNREACHABLE;
- return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
- }
-
- switch( flags & FILE_EXISTING_MASK ) {
- case FILE_EXISTING_OPEN:
- /* done by default on linux */
- break;
- case FILE_EXISTING_FAIL:
- syscall_flags |= O_CREAT | O_EXCL;
- break;
- case FILE_EXISTING_TRUNCATE:
- syscall_flags |= O_TRUNC;
- break;
- default:
- UNREACHABLE;
- return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
- }
-
- switch( flags & FILE_MISSING_MASK ) {
- case FILE_MISSING_CREATE:
- syscall_flags |= O_CREAT;
- break;
- case FILE_MISSING_FAIL:
- /* done by default on linux */
- break;
- default:
- UNREACHABLE;
- return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
- }
-
- switch( flags & FILE_LINK_MASK ) {
- case FILE_LINK_FOLLOW:
- /* Default on linux */
- break;
- case FILE_LINK_FAIL:
- syscall_flags |= O_NOFOLLOW;
- break;
- }
-
- return linux_open( &name->data[0], syscall_flags, 0666, &out->fd );
-}
-
-Status File_close( File *f ) {
- return linux_close( &f->fd );
-}
-
-
-Status File_read( const File *f, usize max_amount, usize *out_amount, u8 *out ) {
- return linux_read( f->fd, max_amount, out_amount, out);
-}
-
-Status File_write( const File *f, usize amount, usize *out_amount, const u8 *buf ) {
- return linux_write( f->fd, amount, out_amount, buf );
-}
-
-Status File_delete( const Str *name ) {
- usize res = linux_unlink( (const u8*)&name->data );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- return S_SUCCESS;
- } else {
- switch( res ) {
- case -EACCES:
- case -EPERM:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_PERMISSION_DENIED;
- case -EFAULT:
- return S_FAILURE | ERRSRC_ARG_1 | ERR_OUT_OF_BOUND;
- case -ENOENT:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_FILE_DOESNT_EXIST;
- default:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
- }
- }
-}
-
-Status File_seek( const File *f, usize position ) {
- return linux_lseek( f->fd, position, SEEK_SET );
-}
-
-Status FileView_from_file( File *file, usize claim_amount, usize flags, FileView *out ) {
- DEBUG( assert( claim_amount%sizeof(Page) == 0 ) );
-
- if( claim_amount%sizeof(Page) != 0 ) {
- return ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- }
-
- TRY( mem_claim( claim_amount/sizeof(Page), &out->start ) );
- out->claimed = claim_amount;
-
- /* Get filesize */
- struct stat s = {0};
- TRY( linux_fstat( file->fd, &s ) );
-
- out->filesize = s.st_size;
-
- void *discard;
-
- if( out->filesize > 0 ) { /* Nothing to map in an empty file */
- TRY( linux_mmap(
- (usize)out->start,
- out->filesize,
- LINUX_PROT_READ | LINUX_PROT_WRITE,
- MMAP_MAP_FIXED | MMAP_MAP_SHARED,
- file->fd,
- 0,
- &discard
- ));
- }
-
- /* Finalize output */
- out->file = *file;
- out->flags = flags;
-
- if( flags & FILEVIEW_OWN_FILE ) {
- file->fd = -1;
- }
-
- return S_SUCCESS;
-}
-
-Status FileView_from_path( const Str *path, usize claim_amount, usize flags, FileView *out ) {
- File file = {0};
- TRY( File_open( path,
- FILE_EXISTING_OPEN |
- FILE_MISSING_CREATE |
- FILE_LINK_FOLLOW |
- FILE_ACCESS_READ | FILE_ACCESS_WRITE,
- &file
- ));
-
- return FileView_from_file(&file, claim_amount, flags, out);
-}
-
-Status FileView_extend_file( FileView *fv, usize amount ) {
- if( amount > fv->claimed - fv->filesize ) {
- return S_FAILURE | ERR_OUT_OF_BOUND;
- }
-
- usize map_start_offset = 0;
- TRY( usize_round_down( fv->filesize, sizeof(Page), &map_start_offset ) );
-
- usize map_start_addr = (u64)((u8*)fv->start + map_start_offset);
-
- TRY( linux_fallocate( fv->file.fd, 0, fv->filesize, amount ) );
-
- fv->filesize += amount;
-
- void *discard;
-
- TRY( linux_mmap(
- map_start_addr,
- fv->filesize - map_start_offset + amount,
- LINUX_PROT_READ | LINUX_PROT_WRITE,
- MMAP_MAP_FIXED | MMAP_MAP_SHARED,
- fv->file.fd,
- map_start_offset,
- &discard
- ));
-
- return S_SUCCESS;
-}
-
-Status FileView_destroy( FileView *fv ) {
- if( fv->flags & FILEVIEW_OWN_FILE ) {
- TRY(File_close( &fv->file ));
- fv->file.fd = -1;
- }
-
- TRY( linux_munmap( (usize)fv->start, fv->claimed ) );
-
- fv->flags = 0;
- fv->filesize = 0;
- fv->claimed = 0;
- fv->start = 0;
- return S_SUCCESS;
-}
-
-#endif
platform/linux/memory.h
@@ -1,50 +0,0 @@
-#ifndef NOTLIBC_HEADER_MEMORY_LINUX_MEMORY_INCLUDED
-#define NOTLIBC_HEADER_MEMORY_LINUX_MEMORY_INCLUDED
-
-#include "../common/types.h"
-#include "./datatypes/error.h"
-#include "./syscalls.h"
-
-Status mem_claim( u32 page_count, Page **ptr_out) {
- TRY( linux_mmap(
- 0,
- page_count*sizeof(Page),
- LINUX_PROT_NONE,
- MMAP_MAP_PRIVATE | MMAP_MAP_ANONYMOUS,
- -1,
- 0,
- (void**)ptr_out
- ));
-
- return S_SUCCESS;
-}
-
-Status mem_relinquish( Page *start, u32 page_count ) {
- usize res = linux_munmap( (usize)start, page_count*sizeof(Page) );
-
- if( LINUX_SYSCALL_ERROR(res) ) {
- return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_UNMAP_FAILURE;
- }
-
- return S_SUCCESS;
-}
-
-Status mem_occupy( Page *start, u32 page_count ) {
- return linux_mprotect(
- (usize)start,
- page_count*sizeof(Page),
- LINUX_PROT_READ | LINUX_PROT_WRITE
- );
-
-}
-
-Status mem_vacate( Page *start, u32 page_count ) {
- usize amount = page_count*sizeof(Page);
-
- TRY( linux_mprotect( (usize)start, amount, LINUX_PROT_NONE ) );
- TRY( linux_madvise( (usize)start, amount, MADV_DONTNEED) );
-
- return S_SUCCESS;
-}
-
-#endif
platform/linux/syscall_wrappers_gcclike.h
@@ -1,103 +0,0 @@
-#ifndef HEADER_PLATFORM_LINUX_SYSCALL_WRAPPERS_GCCLIKE_INCLUDED
-#define HEADER_PLATFORM_LINUX_SYSCALL_WRAPPERS_GCCLIKE_INCLUDED
-
-#include "platform/common/types.h"
-#include "datatypes/error.h"
-
-#if ARCH == ARCH_X86_64
- /* All this mess, just so *maybe* the compiler can optimize register usage when inlining. Check the generic wrappers for a more typical way of going about this. This here is unusual, from what I have seen. */
- static inline ssize linux_syscall1(usize num, usize arg1) {
- register usize ret __asm__("rax") = num;
- register usize a1 __asm__("rdi") = arg1;
-
- __asm__ volatile(
- "syscall\n"
- : "+r"(ret)
- : "r"(a1)
- : "rcx", "r11", "memory"
- );
- return ret;
- }
- static inline ssize linux_syscall2(usize num, usize arg1, usize arg2) {
- register usize ret __asm__("rax") = num;
- register usize a1 __asm__("rdi") = arg1;
- register usize a2 __asm__("rsi") = arg2;
-
- __asm__ volatile(
- "syscall\n"
- : "+r"(ret)
- : "r"(a1), "r"(a2)
- : "rcx", "r11", "memory"
- );
- return ret;
- }
- static inline ssize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
- register usize ret __asm__("rax") = num;
- register usize a1 __asm__("rdi") = arg1;
- register usize a2 __asm__("rsi") = arg2;
- register usize a3 __asm__("rdx") = arg3;
-
- __asm__ volatile(
- "syscall\n"
- : "+r"(ret)
- : "r"(a1), "r"(a2), "r"(a3)
- : "rcx", "r11", "memory"
- );
- return ret;
- }
- static inline ssize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
- register usize ret __asm__("rax") = num;
- register usize a1 __asm__("rdi") = arg1;
- register usize a2 __asm__("rsi") = arg2;
- register usize a3 __asm__("rdx") = arg3;
- register usize a4 __asm__("r10") = arg4;
-
- __asm__ volatile(
- "syscall\n"
- : "+r"(ret)
- : "r"(a1), "r"(a2), "r"(a3), "r"(a4)
- : "rcx", "r11", "memory"
- );
- return ret;
- }
-
- static inline ssize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
- register usize ret __asm__("rax") = num;
- register usize a1 __asm__("rdi") = arg1;
- register usize a2 __asm__("rsi") = arg2;
- register usize a3 __asm__("rdx") = arg3;
- register usize a4 __asm__("r10") = arg4;
- register usize a5 __asm__("r8") = arg5;
-
- __asm__ volatile(
- "syscall\n"
- : "+r"(ret)
- : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
- : "rcx", "r11", "memory"
- );
- return ret;
- }
-
- static inline ssize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
- register usize ret __asm__("rax") = num;
- register usize a1 __asm__("rdi") = arg1;
- register usize a2 __asm__("rsi") = arg2;
- register usize a3 __asm__("rdx") = arg3;
- register usize a4 __asm__("r10") = arg4;
- register usize a5 __asm__("r8") = arg5;
- register usize a6 __asm__("r9") = arg6;
-
- __asm__ volatile(
- "syscall\n"
- : "+r"(ret)
- : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6)
- : "rcx", "r11", "memory"
- );
- return ret;
- }
-
-#elif ARCH == ARCH_I386
- #error "Linux syscalls not implemented for I386."
-#endif
-
-#endif
platform/linux/syscall_wrappers_generic.h
@@ -1,89 +0,0 @@
-#ifndef HEADER_PLATFORM_LINUX_SYSCALL_WRAPPERS_GCCLIKE_INCLUDED
-#define HEADER_PLATFORM_LINUX_SYSCALL_WRAPPERS_GCCLIKE_INCLUDED
-
-#include "../common/types.h"
-
-#if ARCH == ARCH_X86_64
- static inline ssize linux_syscall1(usize num, usize arg1) {
- __asm__ volatile (
- "movq %[a1], %%rdi\n"
- "syscall\n"
- : [num]"+a"(num)
- : [a1]"m"(arg1) /* memory operands are forced, because otherwise tcc does not generate correct inline asm - it uses mm registers, which have bogus values... */
- : "rcx", "r11", "memory", "rdi"
- );
- return num;
- }
-
- static inline ssize linux_syscall2(usize num, usize arg1, usize arg2) {
- __asm__ volatile (
- "movq %[a1], %%rdi\n"
- "movq %[a2], %%rsi\n"
- "syscall\n"
- : [num]"+a"(num)
- : [a1]"m"(arg1), [a2]"m"(arg2)
- : "rcx", "r11", "memory", "rdi", "rsi"
- );
- return num;
- }
- static inline ssize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
- __asm__ volatile (
- "movq %[a1], %%rdi\n"
- "movq %[a2], %%rsi\n"
- "movq %[a3], %%rdx\n"
- "syscall\n"
- : [num]"+a"(num)
- : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3)
- : "rcx", "r11", "memory", "rdi", "rsi", "rdx"
- );
- return num;
- }
- static inline ssize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
- __asm__ volatile (
- "movq %[a1], %%rdi\n"
- "movq %[a2], %%rsi\n"
- "movq %[a3], %%rdx\n"
- "movq %[a4], %%r10\n"
- "syscall\n"
- : [num]"+a"(num)
- : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4)
- : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10"
- );
- return num;
- }
- static inline ssize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
- __asm__ volatile (
- "movq %[a1], %%rdi\n"
- "movq %[a2], %%rsi\n"
- "movq %[a3], %%rdx\n"
- "movq %[a4], %%r10\n"
- "movq %[a5], %%r8\n"
- "syscall\n"
- : [num]"+a"(num)
- : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4), [a5]"m"(arg5)
- : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10", "r8"
- );
- return num;
- }
-
- static inline ssize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
- __asm__ volatile (
- "movq %[a1], %%rdi\n"
- "movq %[a2], %%rsi\n"
- "movq %[a3], %%rdx\n"
- "movq %[a4], %%r10\n"
- "movq %[a5], %%r8\n"
- "movq %[a6], %%r9\n"
- "syscall\n"
- : [num]"+a"(num)
- : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4), [a5]"m"(arg5), [a6]"m"(arg6)
- : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10", "r8", "r9"
- );
- return num;
- }
-
-#elif ARCH == ARCH_I386
- #error "Linux syscalls not implemented for I386."
-#endif
-
-#endif
platform/linux/syscalls.h
@@ -1,434 +0,0 @@
-#ifndef HEADER_PLATFORM_LINUX_SYSCALLS_INCLUDED
-#define HEADER_PLATFORM_LINUX_SYSCALLS_INCLUDED
-
-#include "datatypes/error.h"
-#include "platform/common/types.h"
-#include "platform/info/build.h"
-
-static inline ssize linux_syscall1(usize num, usize arg1);
-static inline ssize linux_syscall2(usize num, usize arg1, usize arg2);
-static inline ssize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3);
-static inline ssize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4);
-static inline ssize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5);
-static inline ssize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6);
-
-#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
- #include "./syscall_wrappers_gcclike.h"
-#else
- #include "./syscall_wrappers_generic.h"
-#endif
-
-#define LINUX_SYSCALL_ERROR_RANGE_START ((usize)-4095)
-#define LINUX_SYSCALL_ERROR(value) ((usize)value >= LINUX_SYSCALL_ERROR_RANGE_START)
-
-#define EPERM 1 /* Operation not permitted */
-#define ENOENT 2 /* No such file or directory */
-#define ESRCH 3 /* No such process */
-#define EINTR 4 /* Interrupted system call */
-#define EIO 5 /* I/O error */
-#define ENXIO 6 /* No such device or address */
-#define E2BIG 7 /* Argument list too long */
-#define ENOEXEC 8 /* Exec format error */
-#define EBADF 9 /* Bad file number */
-#define ECHILD 10 /* No child processes */
-#define EAGAIN 11 /* Try again */
-#define ENOMEM 12 /* Out of memory */
-#define EACCES 13 /* Permission denied */
-#define EFAULT 14 /* Bad address */
-#define ENOTBLK 15 /* Block device required */
-#define EBUSY 16 /* Device or resource busy */
-#define EEXIST 17 /* File exists */
-#define EXDEV 18 /* Cross-device link */
-#define ENODEV 19 /* No such device */
-#define ENOTDIR 20 /* Not a directory */
-#define EISDIR 21 /* Is a directory */
-#define EINVAL 22 /* Invalid argument */
-#define ENFILE 23 /* File table overflow */
-#define EMFILE 24 /* Too many open files */
-#define ENOTTY 25 /* Not a typewriter */
-#define ETXTBSY 26 /* Text file busy */
-#define EFBIG 27 /* File too large */
-#define ENOSPC 28 /* No space left on device */
-#define ESPIPE 29 /* Illegal seek */
-#define EROFS 30 /* Read-only file system */
-#define EMLINK 31 /* Too many links */
-#define EPIPE 32 /* Broken pipe */
-#define EDOM 33 /* Math argument out of domain of func */
-#define ERANGE 34 /* Math result not representable */
-#define EDEADLK 35 /* Resource deadlock would occur */
-#define ENAMETOOLONG 36 /* File name too long */
-#define ENOLCK 37 /* No record locks available */
-#define ENOSYS 38 /* Invalid system call number */
-#define ENOTEMPTY 39 /* Directory not empty */
-#define ELOOP 40 /* Too many symbolic links encountered */
-#define EWOULDBLOCK EAGAIN /* Operation would block */
-#define ENOMSG 42 /* No message of desired type */
-#define EIDRM 43 /* Identifier removed */
-#define ECHRNG 44 /* Channel number out of range */
-#define EL2NSYNC 45 /* Level 2 not synchronized */
-#define EL3HLT 46 /* Level 3 halted */
-#define EL3RST 47 /* Level 3 reset */
-#define ELNRNG 48 /* Link number out of range */
-#define EUNATCH 49 /* Protocol driver not attached */
-#define ENOCSI 50 /* No CSI structure available */
-#define EL2HLT 51 /* Level 2 halted */
-#define EBADE 52 /* Invalid exchange */
-#define EBADR 53 /* Invalid request descriptor */
-#define EXFULL 54 /* Exchange full */
-#define ENOANO 55 /* No anode */
-#define EBADRQC 56 /* Invalid request code */
-#define EBADSLT 57 /* Invalid slot */
-#define EDEADLOCK EDEADLK
-#define EBFONT 59 /* Bad font file format */
-#define ENOSTR 60 /* Device not a stream */
-#define ENODATA 61 /* No data available */
-#define ETIME 62 /* Timer expired */
-#define ENOSR 63 /* Out of streams resources */
-#define ENONET 64 /* Machine is not on the network */
-#define ENOPKG 65 /* Package not installed */
-#define EREMOTE 66 /* Object is remote */
-#define ENOLINK 67 /* Link has been severed */
-#define EADV 68 /* Advertise error */
-#define ESRMNT 69 /* Srmount error */
-#define ECOMM 70 /* Communication error on send */
-#define EPROTO 71 /* Protocol error */
-#define EMULTIHOP 72 /* Multihop attempted */
-#define EDOTDOT 73 /* RFS specific error */
-#define EBADMSG 74 /* Not a data message */
-#define EFSBADCRC EBADMSG /* Bad CRC detected */
-#define EOVERFLOW 75 /* Value too large for defined data type */
-#define ENOTUNIQ 76 /* Name not unique on network */
-#define EBADFD 77 /* File descriptor in bad state */
-#define EREMCHG 78 /* Remote address changed */
-#define ELIBACC 79 /* Can not access a needed shared library */
-#define ELIBBAD 80 /* Accessing a corrupted shared library */
-#define ELIBSCN 81 /* .lib section in a.out corrupted */
-#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
-#define ELIBEXEC 83 /* Cannot exec a shared library directly */
-#define EILSEQ 84 /* Illegal byte sequence */
-#define ERESTART 85 /* Interrupted system call should be restarted */
-#define ESTRPIPE 86 /* Streams pipe error */
-#define EUSERS 87 /* Too many users */
-#define ENOTSOCK 88 /* Socket operation on non-socket */
-#define EDESTADDRREQ 89 /* Destination address required */
-#define EMSGSIZE 90 /* Message too long */
-#define EPROTOTYPE 91 /* Protocol wrong type for socket */
-#define ENOPROTOOPT 92 /* Protocol not available */
-#define EPROTONOSUPPORT 93 /* Protocol not supported */
-#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
-#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
-#define EPFNOSUPPORT 96 /* Protocol family not supported */
-#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
-#define EADDRINUSE 98 /* Address already in use */
-#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
-#define ENETDOWN 100 /* Network is down */
-#define ENETUNREACH 101 /* Network is unreachable */
-#define ENETRESET 102 /* Network dropped connection because of reset */
-#define ECONNABORTED 103 /* Software caused connection abort */
-#define ECONNRESET 104 /* Connection reset by peer */
-#define ENOBUFS 105 /* No buffer space available */
-#define EISCONN 106 /* Transport endpoint is already connected */
-#define ENOTCONN 107 /* Transport endpoint is not connected */
-#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
-#define ETOOMANYREFS 109 /* Too many references: cannot splice */
-#define ETIMEDOUT 110 /* Connection timed out */
-#define ECONNREFUSED 111 /* Connection refused */
-#define EHOSTDOWN 112 /* Host is down */
-#define EHOSTUNREACH 113 /* No route to host */
-#define EALREADY 114 /* Operation already in progress */
-#define EINPROGRESS 115 /* Operation now in progress */
-#define ESTALE 116 /* Stale file handle */
-#define EUCLEAN 117 /* Structure needs cleaning */
-#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
-#define ENOTNAM 118 /* Not a XENIX named type file */
-#define ENAVAIL 119 /* No XENIX semaphores available */
-#define EISNAM 120 /* Is a named type file */
-#define EREMOTEIO 121 /* Remote I/O error */
-#define EDQUOT 122 /* Quota exceeded */
-#define ENOMEDIUM 123 /* No medium found */
-#define EMEDIUMTYPE 124 /* Wrong medium type */
-#define ECANCELED 125 /* Operation Canceled */
-#define ENOKEY 126 /* Required key not available */
-#define EKEYEXPIRED 127 /* Key has expired */
-#define EKEYREVOKED 128 /* Key has been revoked */
-#define EKEYREJECTED 129 /* Key was rejected by service */
-#define EOWNERDEAD 130 /* Owner died */
-#define ENOTRECOVERABLE 131 /* State not recoverable */
-#define ERFKILL 132 /* Operation not possible due to RF-kill */
-#define EHWPOISON 133 /* Memory page has hardware error */
-
-static inline Status linux_read( u32 fd, usize max_amount, usize *out_amount, u8 *out ) {
- usize res = linux_syscall3( 0, fd, (usize)out, max_amount );
- if( !LINUX_SYSCALL_ERROR(res) ) {
- *out_amount = res;
- return S_SUCCESS;
- } else {
- switch(res) {
- case -EBADF:
- return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
- case -EFAULT:
- return S_FAILURE | ERRSRC_ARG_3 | ERR_OUT_OF_BOUND;
- default:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
- }
- }
-}
-
-static inline Status linux_write( u32 fd, usize amount, usize *out_amount, const u8 *buf ) {
- usize res = linux_syscall3( 1, fd, (usize)buf, amount );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- *out_amount = res;
- return S_SUCCESS;
- } else {
- switch(res) {
- case -EBADF:
- return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
- case -EFAULT:
- return S_FAILURE | ERRSRC_ARG_3 | ERR_OUT_OF_BOUND;
- default:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
- }
- }
-}
-
-/* Copied from some header included by linux/fcntl */
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_ACCMODE 03
-#define O_CREAT 0100
-#define O_EXCL 0200
-#define O_NOCTTY 0400
-#define O_TRUNC 01000
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_DSYNC 010000
-#define FASYNC 020000
-#define O_DIRECT 040000
-#define O_LARGEFILE 0100000
-#define O_DIRECTORY 0200000
-#define O_NOFOLLOW 0400000
-#define O_NOATIME 01000000
-#define O_CLOEXEC 02000000
-#define __O_SYNC 04000000
-#define O_SYNC (__O_SYNC|O_DSYNC)
-#define O_PATH 010000000
-#define __O_TMPFILE 020000000
-#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
-
-
-static inline Status linux_open( const u8* path, s32 flags, s32 mode, s32 *out_fd ) {
- ssize res = linux_syscall3( 2, (usize)path, (usize)flags, (usize)mode);
-
- if( !LINUX_SYSCALL_ERROR( res ) ) {
- *out_fd = res;
- return S_SUCCESS;
- } else {
- switch( res ) {
- case -EACCES:
- case -EPERM:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_PERMISSION_DENIED;
- case -EEXIST:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_FILE_ALREADY_EXISTS;
- case -EINVAL:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_INVALID_ARGUMENT;
- case -ENOENT:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_FILE_DOESNT_EXIST;
- case -ENAMETOOLONG:
- return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
- case -ENOSPC:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_NO_DISK_SPACE;
- default:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
- }
- }
-}
-
-static inline Status linux_close( s32 *fd ) {
- usize res = linux_syscall1( 3, *fd );
-
- if( !LINUX_SYSCALL_ERROR( res ) ) {
- *fd = -1;
- return S_SUCCESS;
- } else {
- switch( res ) {
- case -EBADF:
- return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
- default:
- return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
- }
- }
-}
-
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-
-static inline Status linux_lseek( u32 fd, usize offset, usize whence ) {
-
- usize res = linux_syscall3( 8, fd, offset, whence );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- return S_SUCCESS;
- } else {
- switch( res ) {
- case -EBADF:
- return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
- case -EOVERFLOW:
- return S_FAILURE | ERR_OVERFLOW;
- default:
- return S_FAILURE | ERR_GENERIC;
- }
- }
-}
-
-#if ARCH == ARCH_X86_64
-struct stat {
- u64 st_dev;
- u64 st_ino;
- u64 st_nlink;
-
- u32 st_mode;
- u32 st_uid;
- u32 st_gid;
- u32 __pad0;
-
- u64 st_rdev;
-
- s64 st_size;
- s64 st_blksize;
- s64 st_blocks;
-
- u64 st_atime;
- u64 st_atime_nsec;
- u64 st_mtime;
- u64 st_mtime_nsec;
- u64 st_ctime;
- u64 st_ctime_nsec;
-
- s64 __unused[3];
-};
-
-#else
-#error struct stat is not defined
-#endif
-
-
-static inline ssize linux_stat( const char* path, struct stat *statbuf ) {
- return linux_syscall2( 4, (usize)path, (usize)statbuf );
-}
-
-static inline Status linux_fstat( s32 fd, struct stat *statbuf ) {
- ssize res = linux_syscall2( 5, (usize)fd, (usize)statbuf );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- return S_SUCCESS;
- } else {
- return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
- }
-}
-
-static inline void linux_exit( s32 exitcode ) {
- (void)linux_syscall1( 60, exitcode );
- UNREACHABLE;
-}
-
-#define LINUX_PROT_NONE (0x0)
-#define LINUX_PROT_READ (0x1)
-#define LINUX_PROT_WRITE (0x2)
-#define LINUX_PROT_EXEC (0x4)
-
-#define MMAP_MAP_SHARED (0x1)
-#define MMAP_MAP_PRIVATE (0x2)
-#define MMAP_MAP_SHARED_VALIDATE (0x3)
-#define MMAP_MAP_SHARED_DROPPABLE (0x08)
-#define MMAP_MAP_FIXED (0x10)
-#define MMAP_MAP_ANONYMOUS (0x20)
-
-#define MMAP_MAP_FAILED ((void *)-1)
-
-static inline Status linux_mmap( usize addr, usize len, usize prot, usize flags, usize fd, usize offset, void **out ) {
- ssize res = linux_syscall6( 9, addr, len, prot, flags, fd, offset );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- *out = (void*)res;
- return S_SUCCESS;
- } else {
- return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_MAP_FAILURE;
- }
-}
-
-static inline Status linux_munmap( usize start, usize len ) {
- ssize res = linux_syscall2( 11, start, len );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- return S_SUCCESS;
- } else {
- return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_UNMAP_FAILURE;
- }
-}
-
-static inline Status linux_mprotect( usize start, usize len, usize prot ) {
- ssize res = linux_syscall3( 10, start, len, prot );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- return S_SUCCESS;
- } else {
- return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_SETPERM_FAILURE;
- }
-}
-
-#define MADV_NORMAL 0
-#define MADV_RANDOM 1
-#define MADV_SEQUENTIAL 2
-#define MADV_WILLNEED 3
-#define MADV_DONTNEED 4
-#define MADV_FREE 8
-#define MADV_REMOVE 9
-#define MADV_DONTFORK 10
-#define MADV_DOFORK 11
-#define MADV_MERGEABLE 12
-#define MADV_UNMERGEABLE 13
-#define MADV_HUGEPAGE 14
-#define MADV_NOHUGEPAGE 15
-#define MADV_DONTDUMP 16
-#define MADV_DODUMP 17
-#define MADV_WIPEONFORK 18
-#define MADV_KEEPONFORK 19
-#define MADV_COLD 20
-#define MADV_PAGEOUT 21
-#define MADV_POPULATE_READ 22
-#define MADV_POPULATE_WRITE 23
-#define MADV_DONTNEED_LOCKED 24
-#define MADV_COLLAPSE 25
-#define MADV_HWPOISON 100
-#define MADV_GUARD_INSTALL 102
-#define MADV_GUARD_REMOVE 103
-
-static inline Status linux_madvise( usize start, usize len, s32 behaviour ) {
- ssize res = linux_syscall3( 11, start, len, (usize)(u32)behaviour );
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- return S_SUCCESS;
- } else {
- return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_SETHINT_FAILURE;
- }
-}
-
-
-static inline ssize linux_unlink( const u8 *path ) {
- return linux_syscall1( 87, (usize)path );
-}
-
-static inline Status linux_fallocate( s32 fd, s32 mode, usize offset, usize len ) {
- ssize res = linux_syscall4(285, fd, mode, offset, len);
-
- if( !LINUX_SYSCALL_ERROR(res) ) {
- return S_SUCCESS;
- } else {
- return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
- }
-}
-
-#endif
platform/platform.h
@@ -1,39 +0,0 @@
-#ifndef NOTLIBC_HEADER_PLATFORM_PLATFORM_INCLUDED
-#define NOTLIBC_HEADER_PLATFORM_PLATFORM_INCLUDED
-
-#include "platform/info/build.h"
-#include "platform/info/arch.h"
-#include "platform/info/os.h"
-
-#include "platform/info/compiler.h"
-#include "platform/common/corefunc.h"
-#include "platform/common/headers.h"
-#include "platform/common/types.h"
-
-#ifdef NOTLIBC_IMPLEMENT
- #include PLATFORM_ENTRYPOINT_HEADER
- #include PLATFORM_FILE_HEADER
-#endif
-
-#define HEAP_HEADER_GUARD_NUMBER 0xc0dedeaddeadc0de
-#define HEAP_OVERRUN_GUARD_NUMBER 0xeeeedeaddeadeeee
-#define HEAP_XOR_KEY 0x0e1e2e3e4e5e6e7e
-
-#define ARRAY_XOR_KEY 0x0a1a2a3a4a5a6a7a
-
-#define MAGIC_UNINITIALIZED_MEM 0xf0
-#define MAGIC_POISONED_MEM 0xfc
-#define MAGIC_FREED_MEM 0xfe
-
-
-/* Compiler-specific debugging/checking system implementations */
-#if (COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG) && defined(NOTLIBC_IMPLEMENT)
- /* This is so that GCC can detect stack smashing via canaries and crash the program when it happens. */
- void __stack_chk_fail(void) {
- assert(0);
- }
-#endif
-
-
-
-#endif
testing/tests/000_entry_exit.c
@@ -1,4 +1,4 @@
-#include "notlibc/core.h"
+#include "notlibc.c"
void entry(void) {
terminate(0);
testing/tests/001_safemath.c
@@ -1,244 +1,253 @@
-#include "notlibc/core.h"
+#include "notlibc.c"
#define N 12
void entry(void) {
- u64 res = 0; /* make sure all writes actually happen */
+ union {
+ u64 u64;
+ u32 u32;
+ u16 u16;
+ u8 u8;
+ s64 s64;
+ s32 s32;
+ s16 s16;
+ s8 s8;
+ } res;
assert( (-1^1) == -2 ); /* All safemath code assumes 2's complement. Assert it here, too. */
/* Validate correct basic addition and subtraction behaviour */
- assert( S_OK( u64_add( 3, 2, &res ))); assert( res == 5 );
- assert( S_OK( u32_add( 3, 2, (u32*)&res ))); assert( res == 5 );
- assert( S_OK( u16_add( 3, 2, (u16*)&res ))); assert( res == 5 );
- assert( S_OK( u8_add( 3, 2, (u8 *)&res ))); assert( res == 5 );
-
- assert( S_OK( u64_sub( 3, 2, &res ))); assert( res == 1 );
- assert( S_OK( u32_sub( 3, 2, (u32*)&res ))); assert( res == 1 );
- assert( S_OK( u16_sub( 3, 2, (u16*)&res ))); assert( res == 1 );
- assert( S_OK( u8_sub( 3, 2, (u8 *)&res ))); assert( res == 1 );
-
- assert( S_OK( s64_add( 3, 2, (s64*)&res ))); assert( res == 5 );
- assert( S_OK( s32_add( 3, 2, (s32*)&res ))); assert( res == 5 );
- assert( S_OK( s16_add( 3, 2, (s16*)&res ))); assert( res == 5 );
- assert( S_OK( s8_add( 3, 2, (s8 *)&res ))); assert( res == 5 );
-
- assert( S_OK( s64_sub( 3, 2, (s64*)&res ))); assert( res == 1 );
- assert( S_OK( s32_sub( 3, 2, (s32*)&res ))); assert( res == 1 );
- assert( S_OK( s16_sub( 3, 2, (s16*)&res ))); assert( res == 1 );
- assert( S_OK( s8_sub( 3, 2, (s8 *)&res ))); assert( res == 1 );
+ assert( S_OK( u64_add( 3, 2, &res.u64 ))); assert( res.u64 == 5 );
+ assert( S_OK( u32_add( 3, 2, &res.u32 ))); assert( res.u32 == 5 );
+ assert( S_OK( u16_add( 3, 2, &res.u16 ))); assert( res.u16 == 5 );
+ assert( S_OK( u8_add( 3, 2, &res.u8 ))); assert( res.u8 == 5 );
+
+ assert( S_OK( u64_sub( 3, 2, &res.u64 ))); assert( res.u64 == 1 );
+ assert( S_OK( u32_sub( 3, 2, &res.u32 ))); assert( res.u32 == 1 );
+ assert( S_OK( u16_sub( 3, 2, &res.u16 ))); assert( res.u16 == 1 );
+ assert( S_OK( u8_sub( 3, 2, &res.u8 ))); assert( res.u8 == 1 );
+
+ assert( S_OK( s64_add( 3, 2, &res.s64 ))); assert( res.s64 == 5 );
+ assert( S_OK( s32_add( 3, 2, &res.s32 ))); assert( res.s32 == 5 );
+ assert( S_OK( s16_add( 3, 2, &res.s16 ))); assert( res.s16 == 5 );
+ assert( S_OK( s8_add( 3, 2, &res.s8 ))); assert( res.s8 == 5 );
+
+ assert( S_OK( s64_sub( 3, 2, &res.s64 ))); assert( res.s64 == 1 );
+ assert( S_OK( s32_sub( 3, 2, &res.s32 ))); assert( res.s32 == 1 );
+ assert( S_OK( s16_sub( 3, 2, &res.s16 ))); assert( res.s16 == 1 );
+ assert( S_OK( s8_sub( 3, 2, &res.s8 ))); assert( res.s8 == 1 );
/* Catch potential off-by-one implementation errors */
/* Unsigned */
- assert( S_OK( u64_add( u64_MAX - 1, 1, &res ))); assert( res == u64_MAX );
- assert( S_OK( u32_add( u32_MAX - 1, 1, (u32*)&res ))); assert( (u32)res == u32_MAX );
- assert( S_OK( u16_add( u16_MAX - 1, 1, (u16*)&res ))); assert( (u16)res == u16_MAX );
- assert( S_OK( u8_add( u8_MAX - 1, 1, (u8 *)&res ))); assert( ( u8)res == u8_MAX );
+ assert( S_OK( u64_add( u64_MAX - 1, 1, &res.u64 ))); assert( res.u64 == u64_MAX );
+ assert( S_OK( u32_add( u32_MAX - 1, 1, &res.u32 ))); assert( res.u32 == u32_MAX );
+ assert( S_OK( u16_add( u16_MAX - 1, 1, &res.u16 ))); assert( res.u16 == u16_MAX );
+ assert( S_OK( u8_add( u8_MAX - 1, 1, &res.u8 ))); assert( res.u8 == u8_MAX );
- assert( S_OK( u64_sub( u64_MIN + 1, 1, &res ))); assert( res == u64_MIN );
- assert( S_OK( u32_sub( u32_MIN + 1, 1, (u32*)&res ))); assert( (u32)res == u32_MIN );
- assert( S_OK( u16_sub( u16_MIN + 1, 1, (u16*)&res ))); assert( (u16)res == u16_MIN );
- assert( S_OK( u8_sub( u8_MIN + 1, 1, (u8 *)&res ))); assert( ( u8)res == u8_MIN );
+ assert( S_OK( u64_sub( u64_MIN + 1, 1, &res.u64 ))); assert( res.u64 == u64_MIN );
+ assert( S_OK( u32_sub( u32_MIN + 1, 1, &res.u32 ))); assert( res.u32 == u32_MIN );
+ assert( S_OK( u16_sub( u16_MIN + 1, 1, &res.u16 ))); assert( res.u16 == u16_MIN );
+ assert( S_OK( u8_sub( u8_MIN + 1, 1, &res.u8 ))); assert( res.u8 == u8_MIN );
/* Signed */
- assert( S_OK( s64_add( s64_MAX - 1, 1, (s64*)&res ))); assert( (s64)res == s64_MAX );
- assert( S_OK( s32_add( s32_MAX - 1, 1, (s32*)&res ))); assert( (s32)res == s32_MAX );
- assert( S_OK( s16_add( s16_MAX - 1, 1, (s16*)&res ))); assert( (s16)res == s16_MAX );
- assert( S_OK( s8_add( s8_MAX - 1, 1, (s8 *)&res ))); assert( ( s8)res == s8_MAX );
-
- assert( S_OK( s64_sub( s64_MAX - 1, -1, (s64*)&res ))); assert( (s64)res == s64_MAX );
- assert( S_OK( s32_sub( s32_MAX - 1, -1, (s32*)&res ))); assert( (s32)res == s32_MAX );
- assert( S_OK( s16_sub( s16_MAX - 1, -1, (s16*)&res ))); assert( (s16)res == s16_MAX );
- assert( S_OK( s8_sub( s8_MAX - 1, -1, (s8 *)&res ))); assert( ( s8)res == s8_MAX );
-
- assert( S_OK( s64_sub( s64_MIN + 1, 1, (s64*)&res ))); assert( (s64)res == s64_MIN );
- assert( S_OK( s32_sub( s32_MIN + 1, 1, (s32*)&res ))); assert( (s32)res == s32_MIN );
- assert( S_OK( s16_sub( s16_MIN + 1, 1, (s16*)&res ))); assert( (s16)res == s16_MIN );
- assert( S_OK( s8_sub( s8_MIN + 1, 1, (s8 *)&res ))); assert( ( s8)res == s8_MIN );
-
- assert( S_OK( s64_add( s64_MIN + 1, -1, (s64*)&res ))); assert( (s64)res == s64_MIN );
- assert( S_OK( s32_add( s32_MIN + 1, -1, (s32*)&res ))); assert( (s32)res == s32_MIN );
- assert( S_OK( s16_add( s16_MIN + 1, -1, (s16*)&res ))); assert( (s16)res == s16_MIN );
- assert( S_OK( s8_add( s8_MIN + 1, -1, (s8 *)&res ))); assert( ( s8)res == s8_MIN );
+ assert( S_OK( s64_add( s64_MAX - 1, 1, &res.s64 ))); assert( res.s64 == s64_MAX );
+ assert( S_OK( s32_add( s32_MAX - 1, 1, &res.s32 ))); assert( res.s32 == s32_MAX );
+ assert( S_OK( s16_add( s16_MAX - 1, 1, &res.s16 ))); assert( res.s16 == s16_MAX );
+ assert( S_OK( s8_add( s8_MAX - 1, 1, &res.s8 ))); assert( res.s8 == s8_MAX );
+
+ assert( S_OK( s64_sub( s64_MAX - 1, -1, &res.s64 ))); assert( res.s64 == s64_MAX );
+ assert( S_OK( s32_sub( s32_MAX - 1, -1, &res.s32 ))); assert( res.s32 == s32_MAX );
+ assert( S_OK( s16_sub( s16_MAX - 1, -1, &res.s16 ))); assert( res.s16 == s16_MAX );
+ assert( S_OK( s8_sub( s8_MAX - 1, -1, &res.s8 ))); assert( res.s8 == s8_MAX );
+
+ assert( S_OK( s64_sub( s64_MIN + 1, 1, &res.s64 ))); assert( res.s64 == s64_MIN );
+ assert( S_OK( s32_sub( s32_MIN + 1, 1, &res.s32 ))); assert( res.s32 == s32_MIN );
+ assert( S_OK( s16_sub( s16_MIN + 1, 1, &res.s16 ))); assert( res.s16 == s16_MIN );
+ assert( S_OK( s8_sub( s8_MIN + 1, 1, &res.s8 ))); assert( res.s8 == s8_MIN );
+
+ assert( S_OK( s64_add( s64_MIN + 1, -1, &res.s64 ))); assert( res.s64 == s64_MIN );
+ assert( S_OK( s32_add( s32_MIN + 1, -1, &res.s32 ))); assert( res.s32 == s32_MIN );
+ assert( S_OK( s16_add( s16_MIN + 1, -1, &res.s16 ))); assert( res.s16 == s16_MIN );
+ assert( S_OK( s8_add( s8_MIN + 1, -1, &res.s8 ))); assert( res.s8 == s8_MIN );
/* Overflow */
/* Unsigned */
- assert( S_FAILED( u64_add( u64_MAX, N, &res )));
- assert( S_FAILED( u32_add( u32_MAX, N, (u32*)&res )));
- assert( S_FAILED( u16_add( u16_MAX, N, (u16*)&res )));
- assert( S_FAILED( u8_add( u8_MAX, N, (u8 *)&res )));
+ assert( S_FAILED( u64_add( u64_MAX, N, &res.u64 )));
+ assert( S_FAILED( u32_add( u32_MAX, N, &res.u32 )));
+ assert( S_FAILED( u16_add( u16_MAX, N, &res.u16 )));
+ assert( S_FAILED( u8_add( u8_MAX, N, &res.u8 )));
- assert( S_FAILED( u64_add( u64_MAX, 1, &res )));
- assert( S_FAILED( u32_add( u32_MAX, 1, (u32*)&res )));
- assert( S_FAILED( u16_add( u16_MAX, 1, (u16*)&res )));
- assert( S_FAILED( u8_add( u8_MAX, 1, (u8 *)&res )));
+ assert( S_FAILED( u64_add( u64_MAX, 1, &res.u64 )));
+ assert( S_FAILED( u32_add( u32_MAX, 1, &res.u32 )));
+ assert( S_FAILED( u16_add( u16_MAX, 1, &res.u16 )));
+ assert( S_FAILED( u8_add( u8_MAX, 1, &res.u8 )));
/* Signed */
- assert( S_FAILED( s64_add( s64_MAX, N, (s64*)&res )));
- assert( S_FAILED( s32_add( s32_MAX, N, (s32*)&res )));
- assert( S_FAILED( s16_add( s16_MAX, N, (s16*)&res )));
- assert( S_FAILED( s8_add( s8_MAX, N, (s8 *)&res )));
- assert( S_FAILED( s64_sub( s64_MAX, -N, (s64*)&res )));
- assert( S_FAILED( s32_sub( s32_MAX, -N, (s32*)&res )));
- assert( S_FAILED( s16_sub( s16_MAX, -N, (s16*)&res )));
- assert( S_FAILED( s8_sub( s8_MAX, -N, (s8 *)&res )));
-
- assert( S_FAILED( s64_add( s64_MAX, 1, (s64*)&res )));
- assert( S_FAILED( s32_add( s32_MAX, 1, (s32*)&res )));
- assert( S_FAILED( s16_add( s16_MAX, 1, (s16*)&res )));
- assert( S_FAILED( s8_add( s8_MAX, 1, (s8 *)&res )));
- assert( S_FAILED( s64_sub( s64_MAX, -1, (s64*)&res )));
- assert( S_FAILED( s32_sub( s32_MAX, -1, (s32*)&res )));
- assert( S_FAILED( s16_sub( s16_MAX, -1, (s16*)&res )));
- assert( S_FAILED( s8_sub( s8_MAX, -1, (s8 *)&res )));
+ assert( S_FAILED( s64_add( s64_MAX, N, &res.s64 )));
+ assert( S_FAILED( s32_add( s32_MAX, N, &res.s32 )));
+ assert( S_FAILED( s16_add( s16_MAX, N, &res.s16 )));
+ assert( S_FAILED( s8_add( s8_MAX, N, &res.s8 )));
+ assert( S_FAILED( s64_sub( s64_MAX, -N, &res.s64 )));
+ assert( S_FAILED( s32_sub( s32_MAX, -N, &res.s32 )));
+ assert( S_FAILED( s16_sub( s16_MAX, -N, &res.s16 )));
+ assert( S_FAILED( s8_sub( s8_MAX, -N, &res.s8 )));
+
+ assert( S_FAILED( s64_add( s64_MAX, 1, &res.s64 )));
+ assert( S_FAILED( s32_add( s32_MAX, 1, &res.s32 )));
+ assert( S_FAILED( s16_add( s16_MAX, 1, &res.s16 )));
+ assert( S_FAILED( s8_add( s8_MAX, 1, &res.s8 )));
+ assert( S_FAILED( s64_sub( s64_MAX, -1, &res.s64 )));
+ assert( S_FAILED( s32_sub( s32_MAX, -1, &res.s32 )));
+ assert( S_FAILED( s16_sub( s16_MAX, -1, &res.s16 )));
+ assert( S_FAILED( s8_sub( s8_MAX, -1, &res.s8 )));
/* Underflow */
/* Unsigned */
- assert( S_FAILED( u64_sub( u64_MIN, N, &res )));
- assert( S_FAILED( u32_sub( u32_MIN, N, (u32*)&res )));
- assert( S_FAILED( u16_sub( u16_MIN, N, (u16*)&res )));
- assert( S_FAILED( u8_sub( u8_MIN, N, (u8 *)&res )));
- assert( S_FAILED( u64_sub( u64_MIN, 1, &res )));
- assert( S_FAILED( u32_sub( u32_MIN, 1, (u32*)&res )));
- assert( S_FAILED( u16_sub( u16_MIN, 1, (u16*)&res )));
- assert( S_FAILED( u8_sub( u8_MIN, 1, (u8 *)&res )));
+ assert( S_FAILED( u64_sub( u64_MIN, N, &res.u64 )));
+ assert( S_FAILED( u32_sub( u32_MIN, N, &res.u32 )));
+ assert( S_FAILED( u16_sub( u16_MIN, N, &res.u16 )));
+ assert( S_FAILED( u8_sub( u8_MIN, N, &res.u8 )));
+
+ assert( S_FAILED( u64_sub( u64_MIN, 1, &res.u64 )));
+ assert( S_FAILED( u32_sub( u32_MIN, 1, &res.u32 )));
+ assert( S_FAILED( u16_sub( u16_MIN, 1, &res.u16 )));
+ assert( S_FAILED( u8_sub( u8_MIN, 1, &res.u8 )));
/* Signed */
- assert( S_FAILED( s64_sub( s64_MIN, N, (s64*)&res )));
- assert( S_FAILED( s32_sub( s32_MIN, N, (s32*)&res )));
- assert( S_FAILED( s16_sub( s16_MIN, N, (s16*)&res )));
- assert( S_FAILED( s8_sub( s8_MIN, N, (s8 *)&res )));
- assert( S_FAILED( s64_sub( s64_MIN, 1, (s64*)&res )));
- assert( S_FAILED( s32_sub( s32_MIN, 1, (s32*)&res )));
- assert( S_FAILED( s16_sub( s16_MIN, 1, (s16*)&res )));
- assert( S_FAILED( s8_sub( s8_MIN, 1, (s8 *)&res )));
-
- assert( S_FAILED( s64_add( s64_MIN, -N, (s64*)&res )));
- assert( S_FAILED( s32_add( s32_MIN, -N, (s32*)&res )));
- assert( S_FAILED( s16_add( s16_MIN, -N, (s16*)&res )));
- assert( S_FAILED( s8_add( s8_MIN, -N, (s8 *)&res )));
- assert( S_FAILED( s64_add( s64_MIN, -1, (s64*)&res )));
- assert( S_FAILED( s32_add( s32_MIN, -1, (s32*)&res )));
- assert( S_FAILED( s16_add( s16_MIN, -1, (s16*)&res )));
- assert( S_FAILED( s8_add( s8_MIN, -1, (s8 *)&res )));
+ assert( S_FAILED( s64_sub( s64_MIN, N, &res.s64 )));
+ assert( S_FAILED( s32_sub( s32_MIN, N, &res.s32 )));
+ assert( S_FAILED( s16_sub( s16_MIN, N, &res.s16 )));
+ assert( S_FAILED( s8_sub( s8_MIN, N, &res.s8 )));
+ assert( S_FAILED( s64_sub( s64_MIN, 1, &res.s64 )));
+ assert( S_FAILED( s32_sub( s32_MIN, 1, &res.s32 )));
+ assert( S_FAILED( s16_sub( s16_MIN, 1, &res.s16 )));
+ assert( S_FAILED( s8_sub( s8_MIN, 1, &res.s8 )));
+
+ assert( S_FAILED( s64_add( s64_MIN, -N, &res.s64 )));
+ assert( S_FAILED( s32_add( s32_MIN, -N, &res.s32 )));
+ assert( S_FAILED( s16_add( s16_MIN, -N, &res.s16 )));
+ assert( S_FAILED( s8_add( s8_MIN, -N, &res.s8 )));
+ assert( S_FAILED( s64_add( s64_MIN, -1, &res.s64 )));
+ assert( S_FAILED( s32_add( s32_MIN, -1, &res.s32 )));
+ assert( S_FAILED( s16_add( s16_MIN, -1, &res.s16 )));
+ assert( S_FAILED( s8_add( s8_MIN, -1, &res.s8 )));
/* Basic multiplication */
- assert( S_OK( u64_mul( 3, 2, &res ))); assert( res == 6 );
- assert( S_OK( u32_mul( 3, 2, (u32*)&res ))); assert( (u32)res == 6 );
- assert( S_OK( u16_mul( 3, 2, (u16*)&res ))); assert( (u16)res == 6 );
- assert( S_OK( u8_mul( 3, 2, (u8 *)&res ))); assert( ( u8)res == 6 );
+ assert( S_OK( u64_mul( 3, 2, &res.u64 ))); assert( res.u64 == 6 );
+ assert( S_OK( u32_mul( 3, 2, &res.u32 ))); assert( res.u32 == 6 );
+ assert( S_OK( u16_mul( 3, 2, &res.u16 ))); assert( res.u16 == 6 );
+ assert( S_OK( u8_mul( 3, 2, &res.u8 ))); assert( res.u8 == 6 );
- assert( S_OK( s64_mul( 3, 2, (s64*)&res ))); assert( (s64)res == 6 );
- assert( S_OK( s32_mul( 3, 2, (s32*)&res ))); assert( (s32)res == 6 );
- assert( S_OK( s16_mul( 3, 2, (s16*)&res ))); assert( (s16)res == 6 );
- assert( S_OK( s8_mul( 3, 2, (s8 *)&res ))); assert( ( s8)res == 6 );
+ assert( S_OK( s64_mul( 3, 2, &res.s64 ))); assert( res.s64 == 6 );
+ assert( S_OK( s32_mul( 3, 2, &res.s32 ))); assert( res.s32 == 6 );
+ assert( S_OK( s16_mul( 3, 2, &res.s16 ))); assert( res.s16 == 6 );
+ assert( S_OK( s8_mul( 3, 2, &res.s8 ))); assert( res.s8 == 6 );
- assert( S_OK( s64_mul( -3, 2, (s64*)&res ))); assert( (s64)res == -6 );
- assert( S_OK( s32_mul( -3, 2, (s32*)&res ))); assert( (s32)res == -6 );
- assert( S_OK( s16_mul( -3, 2, (s16*)&res ))); assert( (s16)res == -6 );
- assert( S_OK( s8_mul( -3, 2, (s8 *)&res ))); assert( ( s8)res == -6 );
+ assert( S_OK( s64_mul( -3, 2, &res.s64 ))); assert( res.s64 == -6 );
+ assert( S_OK( s32_mul( -3, 2, &res.s32 ))); assert( res.s32 == -6 );
+ assert( S_OK( s16_mul( -3, 2, &res.s16 ))); assert( res.s16 == -6 );
+ assert( S_OK( s8_mul( -3, 2, &res.s8 ))); assert( res.s8 == -6 );
/* Zero */
- assert( S_OK( u64_mul( u64_MAX, 0, &res ))); assert( res == 0 );
- assert( S_OK( u32_mul( u32_MAX, 0, (u32*)&res ))); assert( res == 0 );
- assert( S_OK( u16_mul( u16_MAX, 0, (u16*)&res ))); assert( res == 0 );
- assert( S_OK( u8_mul( u8_MAX, 0, (u8 *)&res ))); assert( res == 0 );
-
- assert( S_OK( s64_mul( s64_MAX, 0, (s64*)&res ))); assert( res == 0 );
- assert( S_OK( s32_mul( s32_MAX, 0, (s32*)&res ))); assert( res == 0 );
- assert( S_OK( s16_mul( s16_MAX, 0, (s16*)&res ))); assert( res == 0 );
- assert( S_OK( s8_mul( s8_MAX, 0, (s8 *)&res ))); assert( res == 0 );
-
- assert( S_OK( u64_mul( 0, u64_MAX, &res ))); assert( res == 0 );
- assert( S_OK( u32_mul( 0, u32_MAX, (u32*)&res ))); assert( (u32)res == 0 );
- assert( S_OK( u16_mul( 0, u16_MAX, (u16*)&res ))); assert( (u16)res == 0 );
- assert( S_OK( u8_mul( 0, u8_MAX, (u8 *)&res ))); assert( ( u8)res == 0 );
-
- assert( S_OK( s64_mul( 0, s64_MIN, (s64*)&res ))); assert( (s64)res == 0 );
- assert( S_OK( s32_mul( 0, s32_MIN, (s32*)&res ))); assert( (s32)res == 0 );
- assert( S_OK( s16_mul( 0, s16_MIN, (s16*)&res ))); assert( (s16)res == 0 );
- assert( S_OK( s8_mul( 0, s8_MIN, (s8 *)&res ))); assert( ( s8)res == 0 );
+ assert( S_OK( u64_mul( u64_MAX, 0, &res.u64 ))); assert( res.u64 == 0 );
+ assert( S_OK( u32_mul( u32_MAX, 0, &res.u32 ))); assert( res.u32 == 0 );
+ assert( S_OK( u16_mul( u16_MAX, 0, &res.u16 ))); assert( res.u16 == 0 );
+ assert( S_OK( u8_mul( u8_MAX, 0, &res.u8 ))); assert( res.u8 == 0 );
+
+ assert( S_OK( s64_mul( s64_MAX, 0, &res.s64 ))); assert( res.s64 == 0 );
+ assert( S_OK( s32_mul( s32_MAX, 0, &res.s32 ))); assert( res.s32 == 0 );
+ assert( S_OK( s16_mul( s16_MAX, 0, &res.s16 ))); assert( res.s16 == 0 );
+ assert( S_OK( s8_mul( s8_MAX, 0, &res.s8 ))); assert( res.s8 == 0 );
+
+ assert( S_OK( u64_mul( 0, u64_MAX, &res.u64 ))); assert( res.u64 == 0 );
+ assert( S_OK( u32_mul( 0, u32_MAX, &res.u32 ))); assert( res.u32 == 0 );
+ assert( S_OK( u16_mul( 0, u16_MAX, &res.u16 ))); assert( res.u16 == 0 );
+ assert( S_OK( u8_mul( 0, u8_MAX, &res.u8 ))); assert( res.u8 == 0 );
+
+ assert( S_OK( s64_mul( 0, s64_MIN, &res.s64 ))); assert( res.s64 == 0 );
+ assert( S_OK( s32_mul( 0, s32_MIN, &res.s32 ))); assert( res.s32 == 0 );
+ assert( S_OK( s16_mul( 0, s16_MIN, &res.s16 ))); assert( res.s16 == 0 );
+ assert( S_OK( s8_mul( 0, s8_MIN, &res.s8 ))); assert( res.s8 == 0 );
/* Overflow */
- assert( S_FAILED( u64_mul( u64_MAX, 2, &res )));
- assert( S_FAILED( u32_mul( u32_MAX, 2, (u32*)&res )));
- assert( S_FAILED( u16_mul( u16_MAX, 2, (u16*)&res )));
- assert( S_FAILED( u8_mul( u8_MAX, 2, (u8 *)&res )));
-
- assert( S_FAILED( s64_mul( s64_MIN, 2, (s64*)&res )));
- assert( S_FAILED( s32_mul( s32_MIN, 2, (s32*)&res )));
- assert( S_FAILED( s16_mul( s16_MIN, 2, (s16*)&res )));
- assert( S_FAILED( s8_mul( s8_MIN, 2, (s8 *)&res )));
-
- assert( S_FAILED( s64_mul( s64_MAX, 2, (s64*)&res )));
- assert( S_FAILED( s32_mul( s32_MAX, 2, (s32*)&res )));
- assert( S_FAILED( s16_mul( s16_MAX, 2, (s16*)&res )));
- assert( S_FAILED( s8_mul( s8_MAX, 2, (s8 *)&res )));
-
- assert( S_FAILED( s64_mul( s64_MIN, -1, (s64*)&res )));
- assert( S_FAILED( s32_mul( s32_MIN, -1, (s32*)&res )));
- assert( S_FAILED( s16_mul( s16_MIN, -1, (s16*)&res )));
- assert( S_FAILED( s8_mul( s8_MIN, -1, (s8 *)&res )));
-
- assert( S_FAILED( s64_mul( s64_MIN/2, -2, (s64*)&res )));
- assert( S_FAILED( s32_mul( s32_MIN/2, -2, (s32*)&res )));
- assert( S_FAILED( s16_mul( s16_MIN/2, -2, (s16*)&res )));
- assert( S_FAILED( s8_mul( s8_MIN/2, -2, (s8 *)&res )));
+ assert( S_FAILED( u64_mul( u64_MAX, 2, &res.u64 )));
+ assert( S_FAILED( u32_mul( u32_MAX, 2, &res.u32 )));
+ assert( S_FAILED( u16_mul( u16_MAX, 2, &res.u16 )));
+ assert( S_FAILED( u8_mul( u8_MAX, 2, &res.u8 )));
+
+ assert( S_FAILED( s64_mul( s64_MIN, 2, &res.s64 )));
+ assert( S_FAILED( s32_mul( s32_MIN, 2, &res.s32 )));
+ assert( S_FAILED( s16_mul( s16_MIN, 2, &res.s16 )));
+ assert( S_FAILED( s8_mul( s8_MIN, 2, &res.s8 )));
+
+ assert( S_FAILED( s64_mul( s64_MAX, 2, &res.s64 )));
+ assert( S_FAILED( s32_mul( s32_MAX, 2, &res.s32 )));
+ assert( S_FAILED( s16_mul( s16_MAX, 2, &res.s16 )));
+ assert( S_FAILED( s8_mul( s8_MAX, 2, &res.s8 )));
+
+ assert( S_FAILED( s64_mul( s64_MIN, -1, &res.s64 )));
+ assert( S_FAILED( s32_mul( s32_MIN, -1, &res.s32 )));
+ assert( S_FAILED( s16_mul( s16_MIN, -1, &res.s16 )));
+ assert( S_FAILED( s8_mul( s8_MIN, -1, &res.s8 )));
+
+ assert( S_FAILED( s64_mul( s64_MIN/2, -2, &res.s64 )));
+ assert( S_FAILED( s32_mul( s32_MIN/2, -2, &res.s32 )));
+ assert( S_FAILED( s16_mul( s16_MIN/2, -2, &res.s16 )));
+ assert( S_FAILED( s8_mul( s8_MIN/2, -2, &res.s8 )));
/* Signed-specific */
- assert( S_OK( s64_mul( s64_MAX, -1, (s64*)&res )));
- assert( S_OK( s32_mul( s32_MAX, -1, (s32*)&res )));
- assert( S_OK( s16_mul( s16_MAX, -1, (s16*)&res )));
- assert( S_OK( s8_mul( s8_MAX, -1, (s8 *)&res )));
-
- assert( S_OK( s64_mul( s64_MIN + 1, -1, (s64*)&res ))); assert( (s64)res == s64_MAX );
- assert( S_OK( s32_mul( s32_MIN + 1, -1, (s32*)&res ))); assert( (s32)res == s32_MAX );
- assert( S_OK( s16_mul( s16_MIN + 1, -1, (s16*)&res ))); assert( (s16)res == s16_MAX );
- assert( S_OK( s8_mul( s8_MIN + 1, -1, (s8 *)&res ))); assert( ( s8)res == s8_MAX );
-
- assert( S_OK( s64_mul( s64_MIN / -2, -2, (s64*)&res ))); assert( (s64)res == s64_MIN );
- assert( S_OK( s32_mul( s32_MIN / -2, -2, (s32*)&res ))); assert( (s32)res == s32_MIN );
- assert( S_OK( s16_mul( s16_MIN / -2, -2, (s16*)&res ))); assert( (s16)res == s16_MIN );
- assert( S_OK( s8_mul( s8_MIN / -2, -2, (s8 *)&res ))); assert( ( s8)res == s8_MIN );
-
- assert( S_OK( s64_mul( s64_MIN / 2 + 1, -2, (s64*)&res ))); assert( (s64)res == s64_MAX - 1 );
- assert( S_OK( s32_mul( s32_MIN / 2 + 1, -2, (s32*)&res ))); assert( (s32)res == s32_MAX - 1 );
- assert( S_OK( s16_mul( s16_MIN / 2 + 1, -2, (s16*)&res ))); assert( (s16)res == s16_MAX - 1 );
- assert( S_OK( s8_mul( s8_MIN / 2 + 1, -2, (s8 *)&res ))); assert( ( s8)res == s8_MAX - 1 );
-
-
+ assert( S_OK( s64_mul( s64_MAX, -1, &res.s64 )));
+ assert( S_OK( s32_mul( s32_MAX, -1, &res.s32 )));
+ assert( S_OK( s16_mul( s16_MAX, -1, &res.s16 )));
+ assert( S_OK( s8_mul( s8_MAX, -1, &res.s8 )));
+
+ assert( S_OK( s64_mul( s64_MIN + 1, -1, &res.s64 ))); assert( res.s64 == s64_MAX );
+ assert( S_OK( s32_mul( s32_MIN + 1, -1, &res.s32 ))); assert( res.s32 == s32_MAX );
+ assert( S_OK( s16_mul( s16_MIN + 1, -1, &res.s16 ))); assert( res.s16 == s16_MAX );
+ assert( S_OK( s8_mul( s8_MIN + 1, -1, &res.s8 ))); assert( res.s8 == s8_MAX );
+
+ assert( S_OK( s64_mul( s64_MIN / -2, -2, &res.s64 ))); assert( res.s64 == s64_MIN );
+ assert( S_OK( s32_mul( s32_MIN / -2, -2, &res.s32 ))); assert( res.s32 == s32_MIN );
+ assert( S_OK( s16_mul( s16_MIN / -2, -2, &res.s16 ))); assert( res.s16 == s16_MIN );
+ assert( S_OK( s8_mul( s8_MIN / -2, -2, &res.s8 ))); assert( res.s8 == s8_MIN );
+
+ assert( S_OK( s64_mul( s64_MIN / 2 + 1, -2, &res.s64 ))); assert( res.s64 == s64_MAX - 1 );
+ assert( S_OK( s32_mul( s32_MIN / 2 + 1, -2, &res.s32 ))); assert( res.s32 == s32_MAX - 1 );
+ assert( S_OK( s16_mul( s16_MIN / 2 + 1, -2, &res.s16 ))); assert( res.s16 == s16_MAX - 1 );
+ assert( S_OK( s8_mul( s8_MIN / 2 + 1, -2, &res.s8 ))); assert( res.s8 == s8_MAX - 1 );
+
/* Catch potential off-by-one errors */
- assert( S_OK( u64_mul( u64_MAX/2, 2, &res ))); assert( res == u64_MAX - 1 );
- assert( S_OK( u32_mul( u32_MAX/2, 2, (u32*)&res ))); assert( (u32)res == u32_MAX - 1 );
- assert( S_OK( u16_mul( u16_MAX/2, 2, (u16*)&res ))); assert( (u16)res == u16_MAX - 1);
- assert( S_OK( u8_mul( u8_MAX/2, 2, (u8 *)&res ))); assert( ( u8)res == u8_MAX - 1);
-
- assert( S_FAILED( u64_mul( u64_MAX / 2 + 1, 2, &res )));
- assert( S_FAILED( u32_mul( u32_MAX / 2 + 1, 2, (u32*)&res )));
- assert( S_FAILED( u16_mul( u16_MAX / 2 + 1, 2, (u16*)&res )));
- assert( S_FAILED( u8_mul( u8_MAX / 2 + 1, 2, (u8 *)&res )));
-
- assert( S_OK( s64_mul( s64_MAX/2, 2, (s64*)&res ))); assert( (s64)res == s64_MAX - 1 );
- assert( S_OK( s32_mul( s32_MAX/2, 2, (s32*)&res ))); assert( (s32)res == s32_MAX - 1 );
- assert( S_OK( s16_mul( s16_MAX/2, 2, (s16*)&res ))); assert( (s16)res == s16_MAX - 1 );
- assert( S_OK( s8_mul( s8_MAX/2, 2, (s8 *)&res ))); assert( ( s8)res == s8_MAX - 1 );
-
- assert( S_OK( s64_mul( s64_MIN/2, 2, (s64*)&res ))); assert( (s64)res == s64_MIN );
- assert( S_OK( s32_mul( s32_MIN/2, 2, (s32*)&res ))); assert( (s32)res == s32_MIN );
- assert( S_OK( s16_mul( s16_MIN/2, 2, (s16*)&res ))); assert( (s16)res == s16_MIN );
- assert( S_OK( s8_mul( s8_MIN/2, 2, (s8 *)&res ))); assert( ( s8)res == s8_MIN );
-
- assert( S_FAILED( s64_mul( s64_MAX/2 + 1, 2, (s64*)&res )));
- assert( S_FAILED( s32_mul( s32_MAX/2 + 1, 2, (s32*)&res )));
- assert( S_FAILED( s16_mul( s16_MAX/2 + 1, 2, (s16*)&res )));
- assert( S_FAILED( s8_mul( s8_MAX/2 + 1, 2, (s8 *)&res )));
-
- assert( S_FAILED( s64_mul( s64_MIN/2 - 1, 2, (s64*)&res )));
- assert( S_FAILED( s32_mul( s32_MIN/2 - 1, 2, (s32*)&res )));
- assert( S_FAILED( s16_mul( s16_MIN/2 - 1, 2, (s16*)&res )));
- assert( S_FAILED( s8_mul( s8_MIN/2 - 1, 2, (s8 *)&res )));
+ assert( S_OK( u64_mul( u64_MAX/2, 2, &res.u64 ))); assert( res.u64 == u64_MAX - 1 );
+ assert( S_OK( u32_mul( u32_MAX/2, 2, &res.u32 ))); assert( res.u32 == u32_MAX - 1 );
+ assert( S_OK( u16_mul( u16_MAX/2, 2, &res.u16 ))); assert( res.u16 == u16_MAX - 1 );
+ assert( S_OK( u8_mul( u8_MAX/2, 2, &res.u8 ))); assert( res.u8 == u8_MAX - 1 );
+
+ assert( S_FAILED( u64_mul( u64_MAX / 2 + 1, 2, &res.u64 )));
+ assert( S_FAILED( u32_mul( u32_MAX / 2 + 1, 2, &res.u32 )));
+ assert( S_FAILED( u16_mul( u16_MAX / 2 + 1, 2, &res.u16 )));
+ assert( S_FAILED( u8_mul( u8_MAX / 2 + 1, 2, &res.u8 )));
+
+ assert( S_OK( s64_mul( s64_MAX/2, 2, &res.s64 ))); assert( res.s64 == s64_MAX - 1 );
+ assert( S_OK( s32_mul( s32_MAX/2, 2, &res.s32 ))); assert( res.s32 == s32_MAX - 1 );
+ assert( S_OK( s16_mul( s16_MAX/2, 2, &res.s16 ))); assert( res.s16 == s16_MAX - 1 );
+ assert( S_OK( s8_mul( s8_MAX/2, 2, &res.s8 ))); assert( res.s8 == s8_MAX - 1 );
+
+ assert( S_OK( s64_mul( s64_MIN/2, 2, &res.s64 ))); assert( res.s64 == s64_MIN );
+ assert( S_OK( s32_mul( s32_MIN/2, 2, &res.s32 ))); assert( res.s32 == s32_MIN );
+ assert( S_OK( s16_mul( s16_MIN/2, 2, &res.s16 ))); assert( res.s16 == s16_MIN );
+ assert( S_OK( s8_mul( s8_MIN/2, 2, &res.s8 ))); assert( res.s8 == s8_MIN );
+
+ assert( S_FAILED( s64_mul( s64_MAX/2 + 1, 2, &res.s64 )));
+ assert( S_FAILED( s32_mul( s32_MAX/2 + 1, 2, &res.s32 )));
+ assert( S_FAILED( s16_mul( s16_MAX/2 + 1, 2, &res.s16 )));
+ assert( S_FAILED( s8_mul( s8_MAX/2 + 1, 2, &res.s8 )));
+
+ assert( S_FAILED( s64_mul( s64_MIN/2 - 1, 2, &res.s64 )));
+ assert( S_FAILED( s32_mul( s32_MIN/2 - 1, 2, &res.s32 )));
+ assert( S_FAILED( s16_mul( s16_MIN/2 - 1, 2, &res.s16 )));
+ assert( S_FAILED( s8_mul( s8_MIN/2 - 1, 2, &res.s8 )));
terminate(0);
}
testing/tests/002_round.c
@@ -1,4 +1,4 @@
-#include "notlibc/core.h"
+#include "notlibc.c"
#define N 13
testing/tests/012_mem_basic.c
@@ -1,5 +1,4 @@
-#include "memory/memory.h"
-#include "platform/platform.h"
+#include "notlibc.c"
#define PAGECOUNT 2
testing/tests/013_arena_basic.c
@@ -1,4 +1,4 @@
-#include "notlibc/core.h"
+#include "notlibc.c"
Arena a = {0};
testing/tests/014_heap.c
@@ -1,4 +1,4 @@
-#include "notlibc/core.h"
+#include "notlibc.c"
void entry(void) {
testing/tests/015_array_basic.c
@@ -1,4 +1,4 @@
-#include "datatypes/array.h"
+#include "notlibc.c"
void entry(void) {
Heap h = {0};
testing/tests/020_file_basic.c
@@ -1,4 +1,4 @@
-#include "notlibc/core.h"
+#include "notlibc.c"
void test_existing_open_missing_create(void);
void test_existing_truncate_missing_create(void);
testing/tests/021_fileview.c
@@ -1,4 +1,4 @@
-#include "notlibc/core.h"
+#include "notlibc.c"
void entry(void) {
util/mathops/i_round_down.h
@@ -1,41 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_I_ROUND_DOWN_INCLUDED
-#define NOTLIBC_HEADER_UTIL_MATHOPS_I_ROUND_DOWN_INCLUDED
-
-#include "platform/common/types.h"
-#include "../safemath.h"
-
-static inline Status u64_round_down(u64 number, u64 multiple, u64 *out) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- *out = number - (number%multiple);
- return S_SUCCESS;
-}
-
-static inline Status u32_round_down(u32 number, u32 multiple, u32 *out) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- *out = number - (number%multiple);
- return S_SUCCESS;
-}
-
-static inline Status u16_round_down(u16 number, u16 multiple, u16 *out) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- *out = number - (number%multiple);
- return S_SUCCESS;
-}
-
-static inline Status u8_round_down(u8 number, u8 multiple, u8 *out) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- *out = number - (number%multiple);
- return S_SUCCESS;
-}
-
-#if ARCH == ARCH_X86_64
-static inline Status usize_round_down( usize number, usize multiple, usize *out ) {
- return u64_round_down(number, multiple, out);
-}
-#elif ARCH == ARCH_I386
-static inline Status usize_round_down( usize number, usize multiple, usize *out ) {
- return u32_round_down(number, multiple, out);
-}
-#endif
-
-#endif
util/mathops/i_round_up.h
@@ -1,61 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_I_ROUND_UP_INCLUDED
-#define NOTLIBC_HEADER_UTIL_MATHOPS_I_ROUND_UP_INCLUDED
-
-#include "platform/common/types.h"
-#include "../safemath.h"
-
-static inline Status u64_round_up( u64 number, u64 multiple, u64 *out ) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- u64 rem = number%multiple;
- if( rem == 0 ) {
- *out = number;
- } else {
- TRY( u64_add( number, multiple - rem, out ) );
- }
- return S_SUCCESS;
-}
-
-static inline Status u32_round_up( u32 number, u32 multiple, u32 *out ) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- u32 rem = number%multiple;
- if( rem == 0 ) {
- *out = number;
- } else {
- TRY( u32_add( number, multiple - rem, out ) );
- }
- return S_SUCCESS;
-}
-
-static inline Status u16_round_up( u16 number, u16 multiple, u16 *out ) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- u16 rem = number%multiple;
- if( rem == 0 ) {
- *out = number;
- } else {
- TRY( u16_add( number, multiple - rem, out ) );
- }
- return S_SUCCESS;
-}
-
-static inline Status u8_round_up( u8 number, u8 multiple, u8 *out ) {
- if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
- u8 rem = number%multiple;
- if( rem == 0 ) {
- *out = number;
- } else {
- TRY( u8_add( number, multiple - rem, out ) );
- }
- return S_SUCCESS;
-}
-
-#if ARCH == ARCH_X86_64
-static inline Status usize_round_up( usize number, usize multiple, usize *out ) {
- return u64_round_up(number, multiple, out);
-}
-#elif ARCH == ARCH_I386
-static inline Status usize_round_up( usize number, usize multiple, usize *out ) {
- return u32_round_up(number, multiple, out);
-}
-#endif
-
-#endif
util/mathops/is_power_of_two.h
@@ -1,26 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_IS_POWER_OF_TWO_INCLUDED
-#define NOTLIBC_HEADER_UTIL_MATHOPS_IS_POWER_OF_TWO_INCLUDED
-
-#include "platform/common/types.h"
-
-static inline u8 u64_is_power_of_two( u64 num ) {
- return num && !(num & (num - 1));
-}
-
-static inline u8 u32_is_power_of_two( u32 num ) {
- return num && !(num & (num - 1));
-}
-
-static inline u8 u16_is_power_of_two( u16 num ) {
- return num && !(num & (num - 1));
-}
-
-static inline u8 u8_is_power_of_two( u8 num ) {
- return num && !(num & (num - 1));
-}
-
-static inline u8 usize_is_power_of_two( usize num ) {
- return num && !(num & (num - 1));
-}
-
-#endif
util/mathops/max.h
@@ -1,42 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_MAX_INCLUDED
-#define NOTLIBC_HEADER_UTIL_MATHOPS_MAX_INCLUDED
-
-#include "platform/common/types.h"
-
-static inline u64 u64_max( u64 n1, u64 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline u32 u32_max( u32 n1, u32 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline u16 u16_max( u16 n1, u16 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline u8 u8_max( u8 n1, u8 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline usize usize_max( usize n1, usize n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline s64 s64_max( s64 n1, s64 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline s32 s32_max( s32 n1, s32 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline s16 s16_max( s16 n1, s16 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-static inline s8 s8_max( s8 n1, s8 n2 ) {
- return (n1 >= n2)? n1 : n2;
-}
-
-#endif
util/mathops/min.h
@@ -1,42 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_MIN_INCLUDED
-#define NOTLIBC_HEADER_UTIL_MATHOPS_MIN_INCLUDED
-
-#include "platform/common/types.h"
-
-static inline u64 u64_min( u64 n1, u64 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline u32 u32_min( u32 n1, u32 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline u16 u16_min( u16 n1, u16 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline u8 u8_min( u8 n1, u8 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline usize usize_min( usize n1, usize n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline s64 s64_min( s64 n1, s64 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline s32 s32_min( s32 n1, s32 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline s16 s16_min( s16 n1, s16 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-static inline s8 s8_min( s8 n1, s8 n2 ) {
- return (n2 >= n1)? n1 : n2;
-}
-
-#endif
util/limits.h
@@ -1,29 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_LIMITS_INCLUDED
-#define NOTLIBC_HEADER_UTIL_LIMITS_INCLUDED
-
-#include "../platform/common/types.h"
-
-#define u8_MIN 0
-#define u16_MIN 0
-#define u32_MIN 0
-#define u64_MIN 0
-
-#define u8_MAX ((u8)-1)
-#define u16_MAX ((u16)-1)
-#define u32_MAX ((u32)-1)
-#define u64_MAX ((u64)-1)
-
-/* We assume 2's complement */
-ASSERT( (-1^1) == -2 );
-
-#define s8_MAX ((s8)( (u8)-1 >> 1))
-#define s16_MAX ((s16)((u16)-1 >> 1))
-#define s32_MAX ((s32)((u32)-1 >> 1))
-#define s64_MAX ((s64)((u64)-1 >> 1))
-
-#define s8_MIN (- s8_MAX - 1)
-#define s16_MIN (-s16_MAX - 1)
-#define s32_MIN (-s32_MAX - 1)
-#define s64_MIN (-s64_MAX - 1)
-
-#endif
util/mathops.h
@@ -1,11 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_INCLUDED
-#define NOTLIBC_HEADER_UTIL_MATHOPS_INCLUDED
-
-#include "./safemath.h"
-#include "./mathops/min.h"
-#include "./mathops/max.h"
-#include "./mathops/is_power_of_two.h"
-#include "./mathops/i_round_up.h"
-#include "./mathops/i_round_down.h"
-
-#endif
util/safemath.h
@@ -1,55 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_INCLUDED
-#define NOTLIBC_HEADER_UTIL_SAFEMATH_INCLUDED
-
-#include "platform/common/types.h"
-#include "datatypes/error.h"
-#include "./limits.h"
-
-
-/* Ensure limit sanity - at least for unsigned */
-ASSERT( u64_MAX == 0xffffffffffffffff );
-ASSERT( u32_MAX == 0xffffffff );
-ASSERT( u16_MAX == 0xffff );
-ASSERT( u8_MAX == 0xff );
-
-static inline Status u8_add(u8 n1, u8 n2, u8 *out);
-static inline Status u16_add(u16 n1, u16 n2, u16 *out);
-static inline Status u32_add(u32 n1, u32 n2, u32 *out);
-static inline Status u64_add(u64 n1, u64 n2, u64 *out);
-
-static inline Status u8_mul(u8 n1, u8 n2, u8 *out);
-static inline Status u16_mul(u16 n1, u16 n2, u16 *out);
-static inline Status u32_mul(u32 n1, u32 n2, u32 *out);
-static inline Status u64_mul(u64 n1, u64 n2, u64 *out);
-
-static inline Status usize_add(usize n1, usize n2, usize *out) {
- #if ARCH == ARCH_X86_64
- return u64_add( n1, n2, out );
- #elif ARCH == ARCH_I386
- return u32_add( n1, n2, out );
- #endif
-}
-
-static inline Status usize_mul(usize n1, usize n2, usize *out) {
- #if ARCH == ARCH_X86_64
- return u64_mul( n1, n2, out );
- #elif ARCH == ARCH_I386
- return u32_mul( n1, n2, out );
- #endif
-}
-
-static inline Status s8_add(s8 n1, s8 n2, s8 *out);
-static inline Status s16_add(s16 n1, s16 n2, s16 *out);
-static inline Status s32_add(s32 n1, s32 n2, s32 *out);
-static inline Status s64_add(s64 n1, s64 n2, s64 *out);
-
-
-#ifdef NOTLIBC_IMPLEMENT
- #if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
- #include "./safemath_gcclike.h"
- #else
- #include "./safemath_generic.h"
- #endif
-#endif
-
-#endif
util/safemath_gcclike.h
@@ -1,186 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_GCCLIKE_INCLUDED
-#define NOTLIBC_HEADER_UTIL_SAFEMATH_GCCLIKE_INCLUDED
-
-#include "datatypes/error.h"
-
-/* Unsigned addition */
-
-static inline Status u64_add( u64 n1, u64 n2, u64 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u32_add( u32 n1, u32 n2, u32 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u16_add( u16 n1, u16 n2, u16 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u8_add( u8 n1, u8 n2, u8 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-
-/* Signed addition */
-
-static inline Status s64_add( s64 n1, s64 n2, s64 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s32_add( s32 n1, s32 n2, s32 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s16_add( s16 n1, s16 n2, s16 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s8_add( s8 n1, s8 n2, s8 *out ) {
- if( __builtin_add_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-
-/* Unsigned subtraction */
-
-static inline Status u64_sub( u64 n1, u64 n2, u64 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u32_sub( u32 n1, u32 n2, u32 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u16_sub( u16 n1, u16 n2, u16 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u8_sub( u8 n1, u8 n2, u8 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-/* Signed subtraction */
-
-static inline Status s64_sub( s64 n1, s64 n2, s64 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s32_sub( s32 n1, s32 n2, s32 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s16_sub( s16 n1, s16 n2, s16 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s8_sub( s8 n1, s8 n2, s8 *out ) {
- if( __builtin_sub_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-/* Unsigned multiplication */
-
-static inline Status u64_mul( u64 n1, u64 n2, u64 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u32_mul( u32 n1, u32 n2, u32 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u16_mul( u16 n1, u16 n2, u16 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status u8_mul( u8 n1, u8 n2, u8 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s64_mul( s64 n1, s64 n2, s64 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s32_mul( s32 n1, s32 n2, s32 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s16_mul( s16 n1, s16 n2, s16 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-static inline Status s8_mul( s8 n1, s8 n2, s8 *out ) {
- if( __builtin_mul_overflow(n1, n2, out) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- return S_SUCCESS;
-}
-
-#endif
util/safemath_generic.h
@@ -1,230 +0,0 @@
-#ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_GENERIC_INCLUDED
-#define NOTLIBC_HEADER_UTIL_SAFEMATH_GENERIC_INCLUDED
-
-#include "platform/common/types.h"
-#include "datatypes/error.h"
-#include "./limits.h"
-
-/* Unsigned addition */
-
-static inline Status u64_add( u64 n1, u64 n2, u64 *out ) {
- if( n1 > (u64_MAX) - n2 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-static inline Status u32_add( u32 n1, u32 n2, u32 *out ) {
- if( n1 > (u32_MAX) - n2 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-static inline Status u16_add( u16 n1, u16 n2, u16 *out ) {
- if( n1 > (u16_MAX) - n2 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-static inline Status u8_add( u8 n1, u8 n2, u8 *out ) {
- if( n1 > (u8_MAX) - n2 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-/* Signed addition */
-
-static inline Status s64_add( s64 n1, s64 n2, s64 *out ) {
- if( (n1 >= 0 && n2 > s64_MAX - n1) || (n1 < 0 && n2 < s64_MIN - n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-static inline Status s32_add( s32 n1, s32 n2, s32 *out ) {
- if( (n1 >= 0 && n2 > s32_MAX - n1) || (n1 < 0 && n2 < s32_MIN - n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-static inline Status s16_add( s16 n1, s16 n2, s16 *out ) {
- if( (n1 >= 0 && n2 > s16_MAX - n1) || (n1 < 0 && n2 < s16_MIN - n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-static inline Status s8_add( s8 n1, s8 n2, s8 *out ) {
- if( (n1 >= 0 && n2 > s8_MAX - n1) || (n1 < 0 && n2 < s8_MIN - n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 + n2;
- return S_SUCCESS;
-}
-
-/* Unsigned subtraction */
-
-static inline Status u64_sub( u64 n1, u64 n2, u64 *out ) {
- if( n2 > n1 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-static inline Status u32_sub( u32 n1, u32 n2, u32 *out ) {
- if( n2 > n1 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-static inline Status u16_sub( u16 n1, u16 n2, u16 *out ) {
- if( n2 > n1 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-static inline Status u8_sub( u8 n1, u8 n2, u8 *out ) {
- if( n2 > n1 ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-/* Signed Subtraction */
-
-static inline Status s64_sub( s64 n1, s64 n2, s64 *out ) {
- if( (n2 > 0 && n1 < s64_MIN + n2) || (n2 < 0 && n1 > s64_MAX + n2) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-static inline Status s32_sub( s32 n1, s32 n2, s32 *out ) {
- if( (n2 > 0 && n1 < s32_MIN + n2) || (n2 < 0 && n1 > s32_MAX + n2) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-static inline Status s16_sub( s16 n1, s16 n2, s16 *out ) {
- if( (n2 > 0 && n1 < s16_MIN + n2) || (n2 < 0 && n1 > s16_MAX + n2) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-static inline Status s8_sub( s8 n1, s8 n2, s8 *out ) {
- if( (n2 > 0 && n1 < s8_MIN + n2) || (n2 < 0 && n1 > s8_MAX + n2) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1 - n2;
- return S_SUCCESS;
-}
-
-/* Unsigned multiplication */
-static inline Status u64_mul( u64 n1, u64 n2, u64 *out ) {
- if( n1 && n2 > (u64_MAX/n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1*n2;
- return S_SUCCESS;
-}
-
-static inline Status u32_mul( u32 n1, u32 n2, u32 *out ) {
- if( n1 && n2 > (u32_MAX/n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1*n2;
- return S_SUCCESS;
-}
-
-static inline Status u16_mul( u16 n1, u16 n2, u16 *out ) {
- if( n1 && n2 > (u16_MAX/n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1*n2;
- return S_SUCCESS;
-}
-
-static inline Status u8_mul( u8 n1, u8 n2, u8 *out ) {
- if( n1 && n2 > (u8_MAX/n1) ) {
- return S_FAILURE | ERR_OVERFLOW;
- }
- *out = n1*n2;
- return S_SUCCESS;
-}
-
-/* Signed multiplication */
-static inline Status s64_mul( s64 n1, s64 n2, s64 *out ) {
- if(
- ( n2 > 0 && n1 >= s64_MIN/n2 && n1 <= s64_MAX/n2 ) ||
- ( n2 == 0 ) ||
- ( n2 == -1 && n1 >= -s64_MAX ) ||
- ( n2 < -1 && n1 >= s64_MAX/n2 && n1 <= s64_MIN/n2 )
- ) {
- *out = n1*n2;
- return S_SUCCESS;
- }
- return S_FAILURE | ERR_OVERFLOW;
-}
-
-static inline Status s32_mul( s32 n1, s32 n2, s32 *out ) {
- if(
- ( n2 > 0 && n1 >= s32_MIN/n2 && n1 <= s32_MAX/n2 ) ||
- ( n2 == 0 ) ||
- ( n2 == -1 && n1 >= -s32_MAX ) ||
- ( n2 < -1 && n1 >= s32_MAX/n2 && n1 <= s32_MIN/n2 )
- ) {
- *out = n1*n2;
- return S_SUCCESS;
- }
- return S_FAILURE | ERR_OVERFLOW;
-}
-
-static inline Status s16_mul( s16 n1, s16 n2, s16 *out ) {
- if(
- ( n2 > 0 && n1 >= s16_MIN/n2 && n1 <= s16_MAX/n2 ) ||
- ( n2 == 0 ) ||
- ( n2 == -1 && n1 >= -s16_MAX ) ||
- ( n2 < -1 && n1 >= s16_MAX/n2 && n1 <= s16_MIN/n2 )
- ) {
- *out = n1*n2;
- return S_SUCCESS;
- }
- return S_FAILURE | ERR_OVERFLOW;
-}
-
-static inline Status s8_mul( s8 n1, s8 n2, s8 *out ) {
- if(
- ( n2 > 0 && n1 >= s8_MIN/n2 && n1 <= s8_MAX/n2 ) ||
- ( n2 == 0 ) ||
- ( n2 == -1 && n1 >= -s8_MAX ) ||
- ( n2 < -1 && n1 >= s8_MAX/n2 && n1 <= s8_MIN/n2 )
- ) {
- *out = n1*n2;
- return S_SUCCESS;
- }
- return S_FAILURE | ERR_OVERFLOW;
-}
-
-#endif
notlibc.c
@@ -0,0 +1,1252 @@
+#include "./notlibc.h"
+
+/******************************************************************************/
+/* COMMON CODE TO ALL PLATFORMS */
+/******************************************************************************/
+
+/*============================== Compiler ====================================*/
+
+/* Compiler-specific debugging/checking system implementations */
+#if (COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG) && defined(NOTLIBC_IMPLEMENT)
+ /* This is so that GCC can detect stack smashing via canaries and crash the program when it happens. */
+ void __stack_chk_fail(void) {
+ assert(0);
+ }
+#endif
+
+/*=============================== Memory =====================================*/
+void *memset( void* ptr, int value, unsigned long count ) {
+ mem_set( ptr, count, value );
+ return ptr;
+}
+
+
+void *memcpy( void *dest, const void *src, unsigned long n ) {
+ char *d = dest;
+ const char *s = src;
+ while(n--)
+ *d++ = *s++;
+ return dest;
+}
+
+
+
+
+/*================================ Arena =====================================*/
+ Status Arena_create( Arena *out, usize size ) {
+ TRY( u64_round_up( size, 0x1000, &size ) );
+ TRY( mem_claim( size/0x1000, &out->start ) );
+
+ out->claimed = size;
+ out->occupied = 0;
+ out->taken = 0;
+
+ return S_SUCCESS;
+ }
+
+ Status Arena_destroy( Arena *a ) {
+ TRY( mem_relinquish( a->start, a->claimed ) );
+
+ mem_set( a, sizeof(*a), 0 );
+ return S_SUCCESS;
+ }
+
+ Status Arena_align( Arena *a, usize alignment ) {
+ u64 take_amount = 0;
+ TRY( u64_round_up( a->taken, alignment, &take_amount ) );
+ take_amount -= a->taken;
+
+ if( take_amount != 0 ) {
+ u8* discard;
+ TRY( Arena_take( a, take_amount, &discard ) );
+ }
+
+ return S_SUCCESS;
+ }
+
+ Status Arena_take( Arena *a, usize amount, u8 **out ) {
+ assert( out != 0 );
+ assert( amount != 0 );
+
+ if( a->claimed - a->taken < amount ) { /* no overflow risk this way */
+ return S_FAILURE | ERR_OUT_OF_BOUND;
+ }
+
+ u64 new_taken = a->taken + amount;
+
+ if( new_taken > a->occupied ) {
+ u64 occupy_amount = 0;
+
+ TRY( u64_round_up( new_taken - a->occupied , sizeof(Page), &occupy_amount ) );
+ TRY( mem_occupy( a->start + a->occupied/sizeof(Page), occupy_amount/0x1000 ) );
+
+ a->occupied += occupy_amount;
+ }
+
+ *out = ((u8*)a->start + a->taken);
+ a->taken = new_taken;
+
+ return S_SUCCESS;
+ }
+
+ Status Arena_give( Arena *a, usize amount ) {
+ if( amount > a->taken ) return S_FAILURE | ERR_OUT_OF_BOUND;
+ a->taken -= amount;
+ return S_SUCCESS;
+ }
+
+
+/*================================ Heap ======================================*/
+#if BUILD_TYPE == BUILD_DEBUG
+ static inline Status _Heap_find_block( Heap *h, HeapEntry *e, HeapEntry **out_prev ) {
+ u8 ptr_correct = 0;
+ HeapEntry *prev = &h->blocklist;
+
+ for( HeapEntry *i = h->blocklist.next; i != 0; i = i->next ) {
+ if( e == i ) {
+ ptr_correct = 1;
+ break;
+ }
+ prev = i;
+ }
+
+ /* The pointer is not pointing to a previously allocated block if this fails or perhaps it is a double-free. */
+ assert( ptr_correct );
+ if( !ptr_correct ) {
+ return S_FAILURE;
+ }
+
+ *out_prev = prev;
+ return S_SUCCESS;
+ }
+
+ static inline Status _Heap_check_entry( HeapEntry *e ) {
+ u8 ok = 1;
+
+ assert( e->checksum == (e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY) || (ok = 0) );
+ assert( e->header_start_guard == HEAP_HEADER_GUARD_NUMBER || (ok = 0) );
+ assert( e->header_end_guard == HEAP_HEADER_GUARD_NUMBER || (ok = 0) );
+ assert( e->allowed_size >= e->size || (ok = 0) );
+
+ u8* data = (u8*)(&e->header_end_guard + 1);
+ assert( *(usize*)(data + e->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER || (ok = 0) );
+
+ if( !ok ) {
+ return S_FAILURE;
+ } else {
+ return S_SUCCESS;
+ }
+ }
+
+ static inline void _Heap_unlink_entry( HeapEntry *prev, HeapEntry *e ) {
+ prev->next = e->next;
+ prev->checksum = prev->size ^ prev->allowed_size ^ (usize)prev->next ^ HEAP_XOR_KEY;
+ }
+
+ static inline void _Heap_link_free_entry( Heap *h, HeapEntry *e ) {
+ e->next = h->freelist.next;
+ h->freelist.next = e;
+ e->checksum = e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY;
+ }
+
+
+ static inline void _Heap_link_block( Heap *h, HeapEntry *e ) {
+ e->next = h->blocklist.next;
+ h->blocklist.next = e;
+ e->checksum = e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY;
+ }
+
+ usize Heap_get_asize( Heap *h, const void *ptr ) { /* asize = allocation size */
+ HeapEntry *e = (HeapEntry*)( (u8*)ptr - sizeof(HeapEntry) );
+ HeapEntry *prev = 0;
+ _Heap_check_entry( e );
+ _Heap_find_block( h, e, &prev );
+ return e->size;
+ }
+
+ Status Heap_create( Heap *out, usize size ) {
+ assert( out != 0 );
+ assert( size != 0 );
+ TRY( Arena_create( &out->arena, size ) );
+ out->freelist = (HeapEntry){0};
+ out->blocklist = (HeapEntry){0};
+ return S_SUCCESS;
+ }
+
+ Status Heap_destroy( Heap *h ) {
+ assert( h != 0 );
+ TRY( Arena_destroy( &h->arena ) );
+ mem_set( h, sizeof(*h), 0 );
+ return S_SUCCESS;
+ }
+
+ Status Heap_alloc( Heap *h, usize amount, void **out ) {
+ assert( h != 0 );
+ assert( amount > 0 ); /* If your code can try to allocate 0 amount of memory you should consider rewriting it (or getting some help) */
+
+ TRY( usize_round_up( amount, sizeof(usize), &amount ) );
+ usize total_amount = amount + sizeof(HeapEntry) + sizeof(usize); /* usize for end guard */
+
+ HeapEntry *new = 0;
+ HeapEntry *prev = &h->freelist;
+
+ usize max_size = 0;
+ TRY( usize_mul(total_amount, 4, &max_size) );
+
+
+ for( HeapEntry *i = h->freelist.next; i != 0; i = i->next ) {
+
+ u8* data = (u8*)(&i->header_end_guard + 1);
+ /* If any of these fails, then your freelist has been corrupted somehow - it should not be iterated */
+ _Heap_check_entry(i);
+
+ if( i->allowed_size >= amount && i->allowed_size <= max_size ) {
+ new = i;
+ for( usize i = 0; i < new->allowed_size; ++i ) {
+ assert( data[i] == MAGIC_FREED_MEM );
+ }
+ _Heap_unlink_entry( prev, new );
+ new->next = 0;
+ break;
+ }
+ prev = i;
+ }
+
+ if( !new ) {
+ TRY( Arena_take( &h->arena, total_amount, (u8**)&new ) );
+ new->allowed_size = amount;
+ }
+
+ new->size = amount;
+
+ u8 *data = (u8*)(&new->header_end_guard + 1);
+ mem_set( data, new->size, MAGIC_UNINITIALIZED_MEM );
+ mem_set( data + new->size, new->allowed_size - new->size, MAGIC_POISONED_MEM );
+
+ *(usize*)(data + new->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER;
+
+ new->size = amount;
+ new->header_start_guard = HEAP_HEADER_GUARD_NUMBER;
+ new->header_end_guard = HEAP_HEADER_GUARD_NUMBER;
+ _Heap_link_block( h, new );
+
+ *out = data;
+
+ return S_SUCCESS;
+ }
+
+ Status Heap_free( Heap *h, void **ptr ) {
+ assert( h != 0 );
+ assert( ptr != 0 );
+
+ HeapEntry *e = (HeapEntry*)( (u8*)*ptr - sizeof(HeapEntry) );
+
+ HeapEntry *prev = 0;
+
+ assert(S_OK( _Heap_find_block( h, e, &prev ) ));
+ assert(S_OK( _Heap_check_entry( e ) ));
+
+ _Heap_unlink_entry( prev, e );
+ _Heap_link_free_entry( h, e );
+
+ u8* data = (u8*)(&e->header_end_guard + 1);
+ mem_set( data, e->allowed_size, MAGIC_FREED_MEM );
+ *(usize*)(data + e->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER;
+
+ *ptr = 0;
+
+ return S_SUCCESS;
+ }
+
+#elif BUILD_TYPE == BUILD_RELEASE
+
+ usize Heap_get_asize( Heap *h, const void *ptr ) {
+ (void)h;
+ return *((usize*)ptr - 1);
+ }
+
+ Status Heap_create( Heap *out, usize size ) {
+ TRY( Arena_create( &out->arena, size ) );
+ out->freelist = (HeapEntry){0};
+ out->freelist_data = 0;
+ return S_SUCCESS;
+ }
+
+ Status Heap_destroy( Heap *h ) {
+ TRY( Arena_destroy( &h->arena ) );
+ h->freelist = (HeapEntry){0};
+ h->freelist_data = 0;
+ return S_SUCCESS;
+ }
+
+ Status Heap_alloc( Heap *h, usize amount, void **out ) {
+ if( amount == 0 ) return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_2;
+
+ usize required_amount = usize_max(amount, sizeof(void*)); /* A pointer must fit into data, otherwise it can not be linked into the freelist when freed. */
+ TRY( usize_add( required_amount, sizeof(HeapEntry), &required_amount ) );
+ TRY( usize_round_up( required_amount, sizeof(usize), &required_amount ) ); /* word-align */
+
+ HeapEntry *new = 0;
+
+ /* Check freelist */
+ HeapEntry *prev = &h->freelist;
+
+ usize max_size = 0;
+ TRY( usize_mul(required_amount, 4, &max_size) );
+
+ for( HeapEntry *i = h->freelist_data; i != 0; i = *(HeapEntry**)(&i->size + 1) ) {
+ if( i->size >= required_amount && i->size <= max_size ) {
+ new = i;
+ *(HeapEntry**)(&prev->size + 1) = *(HeapEntry**)(&new->size + 1); /* unlink entry */
+ break;
+ }
+ prev = i;
+ }
+
+ /* New allocation */
+ if( !new ) {
+ TRY( Arena_take( &h->arena, required_amount, (u8**)&new ) );
+ new->size = required_amount;
+ }
+ /* otherwise we leave original size */
+
+ *out = (u8*)(&new->size + 1);
+
+ return S_SUCCESS;
+ }
+
+ Status Heap_free( Heap *h, void **ptr ) {
+ if( h == 0 ) return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_1;
+ if( ptr == 0 ) return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_2;
+
+ HeapEntry *e = (HeapEntry*)( (u8*)*ptr - sizeof(HeapEntry) );
+
+ /* Link into freelist */
+ *((HeapEntry**)(&e->size + 1)) = h->freelist_data;
+ h->freelist_data = e;
+
+ *ptr = 0;
+
+ return S_SUCCESS;
+ }
+
+#endif
+
+/*=============================== Arrays =====================================*/
+
+Status AnyArr_create( usize count, AnyArr **out, Heap *h, usize elem_size ) {
+ usize alloc_count = count;
+ DEBUG( alloc_count++ ); /* additional poisoned element in debug */
+
+ usize alloc_size = sizeof(AnyArr) + alloc_count*elem_size;
+
+ TRY( Heap_alloc( h, alloc_size, (void**)out ) );
+ (*out)->len = count;
+ DEBUG(
+ (*out)->heap = h;
+ _AnyArr_update_checksum( *out )
+ );
+ return S_SUCCESS;
+}
+
+Status AnyArr_destroy( AnyArr** arr, Heap *h ) {
+ DEBUG(
+ assert( h == (*arr)->heap );
+ _AnyArr_validate( *arr );
+ )
+
+ TRY( Heap_free( h, (void**)arr ) );
+ return S_SUCCESS;
+}
+
+#if BUILD_TYPE == BUILD_DEBUG
+ void _AnyArr_update_checksum( AnyArr *arr ) {
+ usize heapblock_size = Heap_get_asize( arr->heap, arr );
+ arr->checksum = heapblock_size ^ (usize)arr->heap ^ arr->len ^ ARRAY_XOR_KEY;
+ }
+
+ void _AnyArr_validate( const AnyArr *arr ) {
+ usize heapblock_size = Heap_get_asize( arr->heap, arr );
+ usize checksum = heapblock_size ^ (usize)arr->heap ^ arr->len ^ ARRAY_XOR_KEY;
+ assert( arr->checksum == checksum );
+ }
+
+#endif
+
+Status AnyArr_inflate( AnyArr **arr, usize additional_count, Heap *h, usize elem_size ) {
+ DEBUG(
+ assert( h == (*arr)->heap );
+ _AnyArr_validate( *arr );
+ )
+
+ if( additional_count == 0 ) {
+ return S_COMPLETION;
+ }
+
+ usize newsize = ((*arr)->len + additional_count)*elem_size + sizeof(AnyArr);
+ DEBUG( newsize += elem_size; )
+
+ AnyArr *newarr = 0;
+ TRY( Heap_alloc( h, newsize, (void**)&newarr ) );
+
+ usize total_size = (*arr)->len*elem_size + sizeof(AnyArr);
+ DEBUG( total_size += elem_size; )
+
+ mem_copy( (*arr), newarr, total_size );
+ newarr->len = (*arr)->len;
+
+ DEBUG( _AnyArr_update_checksum( *arr ) );
+
+ TRY( Heap_free( h, (void**)arr ) );
+ *arr = newarr;
+ return S_SUCCESS;
+}
+
+Status AnyArr_extend( AnyArr **arr, usize additional_len, Heap *h, usize elem_size ) {
+ DEBUG(
+ assert( (*arr)->heap == h );
+ _AnyArr_validate( *arr );
+ usize old_len = (*arr)->len;
+ )
+
+ usize asize = Heap_get_asize( h, *arr );
+ usize maxcount = asize - sizeof(AnyArr);
+ DEBUG( maxcount--);
+ maxcount /= elem_size;
+ usize newlen = (*arr)->len + additional_len;
+
+ if( newlen >= maxcount ) {
+ TRY( AnyArr_inflate( arr, additional_len, h, elem_size ) );
+ }
+
+ (*arr)->len += additional_len;
+
+ DEBUG(
+
+ u8 *data = (u8*)((*arr) + 1);
+ u8 *uninint = data + newlen*elem_size;
+ mem_set( uninint, (newlen - old_len)*elem_size, MAGIC_UNINITIALIZED_MEM );
+ _AnyArr_update_checksum( *arr );
+ )
+
+ return S_SUCCESS;
+}
+
+Status AnyArr_truncate( AnyArr *arr, usize cutlen, usize elem_size ) {
+ DEBUG(
+ _AnyArr_validate( arr );
+ usize old_len = arr->len;
+ )
+ RELEASE(
+ (void)elem_size;
+ )
+
+ if( cutlen > arr->len ) {
+ DEBUG( assert(0) );
+ return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_2;
+ }
+
+ arr->len -= cutlen;
+
+ DEBUG(
+ u8 *data = (u8*)(arr + 1);
+ u8 *raticide = data + arr->len*elem_size;
+ mem_set( raticide, (old_len - arr->len)*elem_size, MAGIC_POISONED_MEM );
+
+ _AnyArr_update_checksum( arr );
+ )
+
+
+ return S_SUCCESS;
+}
+
+Status AnyArr_deflate( AnyArr **arr, Heap *h, usize elem_size ) { /* reallocate to just fit the currently contained elements - we assume it's on the same heap */
+ DEBUG(
+ assert( h == (*arr)->heap );
+ _AnyArr_validate( (*arr) );
+ )
+
+ usize total_size = (*arr)->len*elem_size + sizeof(AnyArr);
+ DEBUG( total_size += elem_size; )
+
+ AnyArr *out = 0;
+ TRY( Heap_alloc( h, total_size, (void**)&out ) );
+ mem_copy( *arr, out, total_size );
+ TRY( Heap_free( h, (void**)arr ) );
+
+ *arr = out;
+
+ DEBUG( _AnyArr_update_checksum( *arr ) );
+
+ return S_SUCCESS;
+}
+
+Status AnyArr_copy( const AnyArr *arr, AnyArr **out, Heap *source_heap, Heap *target_heap, usize maxcount, usize len, usize elem_size ) {
+ DEBUG(
+ assert( source_heap == arr->heap );
+ _AnyArr_validate( arr );
+ )
+
+ usize alloc_size = (maxcount)? maxcount*elem_size + sizeof(AnyArr) : Heap_get_asize( source_heap, arr );
+ DEBUG( alloc_size += elem_size );
+
+ TRY( Heap_alloc( target_heap, alloc_size, (void**)out ) );
+ (*out)->len = len;
+
+ DEBUG( _AnyArr_update_checksum( *out ); )
+
+ mem_copy( arr + 1, *out + 1, len*elem_size );
+
+ DEBUG(
+ u8* data = (u8*)(arr + 1);
+ usize data_size = len*elem_size;
+ u8* poison_start = data + data_size;
+ usize poison_amount = alloc_size - data_size - sizeof(AnyArr);
+ DEBUG( poison_amount += elem_size );
+
+ mem_set( poison_start, poison_amount, MAGIC_POISONED_MEM );
+ )
+ return S_SUCCESS;
+}
+
+Status AnyArr_move( AnyArr **arr, AnyArr **out, Heap *source_heap, Heap *target_heap, usize maxcount, usize len, usize elem_size ) {
+ TRY( AnyArr_copy( *arr, out, source_heap, target_heap, maxcount, len, elem_size ) );
+ TRY( Heap_free( source_heap, (void**)arr ) );
+ return S_SUCCESS;
+}
+
+Status AnyArr_push( AnyArr **arr, void* el, Heap *h, usize elem_size ) {
+ DEBUG(
+ assert( h == (*arr)->heap );
+ _AnyArr_validate( *arr );
+ )
+
+ usize s = Heap_get_asize(h, *arr);
+ usize maxcount = (s - sizeof(AnyArr))/elem_size;
+
+ DEBUG(
+ maxcount--; /* Additional poisoned element */
+ );
+
+ if( (*arr)->len >= maxcount ) {
+ AnyArr_inflate( arr, (*arr)->len, h, elem_size );
+ }
+
+ u8 *data = (u8*)(*arr + 1);
+ void *new_elem = data + (*arr)->len*elem_size;
+
+ mem_copy( el, new_elem, elem_size );
+ (*arr)->len++;
+
+ DEBUG(
+ _AnyArr_update_checksum( *arr );
+ mem_set( data + ((*arr)->len)*elem_size, elem_size, MAGIC_POISONED_MEM );
+ )
+
+ return S_SUCCESS;
+}
+
+Status AnyArr_pop( AnyArr *arr, void* el_out, usize elem_size ) {
+ DEBUG(
+ _AnyArr_validate( arr );
+ )
+ if( arr->len == 0 ) {
+ DEBUG( assert(0) );
+ return ERR_OUT_OF_BOUND;
+ }
+
+ arr->len--;
+
+ u8 *data = (u8*)(arr + 1);
+ usize offset = elem_size*arr->len;
+
+ mem_copy( data + offset, el_out, elem_size );
+ DEBUG(
+ _AnyArr_update_checksum( arr );
+ mem_set( data + offset, elem_size, MAGIC_POISONED_MEM );
+ )
+ return S_SUCCESS;
+}
+
+Status AnyArr_dup( const AnyArr *arr, AnyArr **out_arr, Heap *h, usize elem_size ) {
+ DEBUG( _AnyArr_validate( arr );)
+ usize total_size = arr->len*elem_size + sizeof(AnyArr);
+
+ TRY( Heap_alloc( h, total_size, (void**)out_arr ) );
+ mem_copy( arr, *out_arr, total_size );
+
+ return S_SUCCESS;
+}
+
+
+/******************************************************************************/
+/* LINUX-SPECIFIC CODE */
+/******************************************************************************/
+
+#if OS == OS_LINUX
+/*============================= Entrypoint ===================================*/
+#if ARCH == ARCH_X86_64
+ u8* linux_startup_sp = 0;
+
+ __asm__ (
+ ".section .text\n"
+ ".global _start\n"
+ ".type _start, @function\n"
+ "_start:\n"
+ "leaq linux_startup_sp(%rip), %rax\n"
+ "movq %rsp, (%rax)\n" /* save original stack pointer */
+ "xor %rax, %rax\n"
+ "call entry\n"
+ "ud2\n"
+ );
+#elif ARCH == ARCH_I386
+ #error "i386 entrypoint not implemented"
+#endif
+
+
+/*=============================== Memory =====================================*/
+
+Status mem_claim( u32 page_count, Page **ptr_out) {
+ TRY( linux_mmap(
+ 0,
+ page_count*sizeof(Page),
+ LINUX_PROT_NONE,
+ MMAP_MAP_PRIVATE | MMAP_MAP_ANONYMOUS,
+ -1,
+ 0,
+ (void**)ptr_out
+ ));
+
+ return S_SUCCESS;
+}
+
+Status mem_relinquish( Page *start, u32 page_count ) {
+ usize res = linux_munmap( (usize)start, page_count*sizeof(Page) );
+
+ if( LINUX_SYSCALL_ERROR(res) ) {
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_UNMAP_FAILURE;
+ }
+
+ return S_SUCCESS;
+}
+
+Status mem_occupy( Page *start, u32 page_count ) {
+ return linux_mprotect(
+ (usize)start,
+ page_count*sizeof(Page),
+ LINUX_PROT_READ | LINUX_PROT_WRITE
+ );
+
+}
+
+Status mem_vacate( Page *start, u32 page_count ) {
+ usize amount = page_count*sizeof(Page);
+
+ TRY( linux_mprotect( (usize)start, amount, LINUX_PROT_NONE ) );
+ TRY( linux_madvise( (usize)start, amount, MADV_DONTNEED) );
+
+ return S_SUCCESS;
+}
+
+
+/*============================= Filesystem ===================================*/
+
+Status File_open( const Str *name, usize flags, File *out ) {
+ DEBUG( assert( name->data[name->len] == 0 ) );
+
+ if(
+ !(flags & FILE_ACCESS_WRITE) &&
+ !(flags & FILE_ACCESS_APPEND) &&
+ (flags & FILE_EXISTING_TRUNCATE)
+ ) {
+ DEBUG( breakpoint() ); /* Can not truncate a file without write access. */
+ return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
+ }
+
+ if( (flags & FILE_EXISTING_FAIL) && (flags & FILE_MISSING_FAIL) ) {
+ DEBUG( breakpoint() ); /* Useless flag combination: error if there is a file, error if there isn't one aka always error */
+ return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
+ }
+
+ TRY( File_open_validate_flags( flags, ERRSRC_ARG_3 ) );
+
+ usize syscall_flags = O_CLOEXEC; /* Close all files on exec */
+
+ switch( flags & FILE_ACCESS_MASK ) {
+ case FILE_ACCESS_READ:
+ syscall_flags |= O_RDONLY;
+ break;
+
+ case FILE_ACCESS_WRITE:
+ syscall_flags |= O_WRONLY;
+ break;
+
+ case FILE_ACCESS_APPEND:
+ syscall_flags |= O_WRONLY | O_APPEND;
+ break;
+
+ case FILE_ACCESS_READ | FILE_ACCESS_WRITE:
+ syscall_flags |= O_RDWR;
+ break;
+
+ case FILE_ACCESS_READ | FILE_ACCESS_APPEND:
+ syscall_flags |= O_RDWR | O_APPEND;
+ break;
+
+ default:
+ UNREACHABLE;
+ return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
+ }
+
+ switch( flags & FILE_EXISTING_MASK ) {
+ case FILE_EXISTING_OPEN:
+ /* done by default on linux */
+ break;
+ case FILE_EXISTING_FAIL:
+ syscall_flags |= O_CREAT | O_EXCL;
+ break;
+ case FILE_EXISTING_TRUNCATE:
+ syscall_flags |= O_TRUNC;
+ break;
+ default:
+ UNREACHABLE;
+ return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
+ }
+
+ switch( flags & FILE_MISSING_MASK ) {
+ case FILE_MISSING_CREATE:
+ syscall_flags |= O_CREAT;
+ break;
+ case FILE_MISSING_FAIL:
+ /* done by default on linux */
+ break;
+ default:
+ UNREACHABLE;
+ return S_FAILURE | ERR_INVALID_ARGUMENT | ERRSRC_ARG_3;
+ }
+
+ switch( flags & FILE_LINK_MASK ) {
+ case FILE_LINK_FOLLOW:
+ /* Default on linux */
+ break;
+ case FILE_LINK_FAIL:
+ syscall_flags |= O_NOFOLLOW;
+ break;
+ }
+
+ return linux_open( &name->data[0], syscall_flags, 0666, &out->fd );
+}
+
+Status File_close( File *f ) {
+ return linux_close( &f->fd );
+}
+
+
+Status File_read( const File *f, usize max_amount, usize *out_amount, u8 *out ) {
+ return linux_read( f->fd, max_amount, out_amount, out);
+}
+
+Status File_write( const File *f, usize amount, usize *out_amount, const u8 *buf ) {
+ return linux_write( f->fd, amount, out_amount, buf );
+}
+
+Status File_delete( const Str *name ) {
+ return linux_unlink( (const u8*)&name->data );
+
+}
+
+Status File_seek( const File *f, usize position ) {
+ return linux_lseek( f->fd, position, SEEK_SET );
+}
+
+Status FileView_from_file( File *file, usize claim_amount, usize flags, FileView *out ) {
+ DEBUG( assert( claim_amount%sizeof(Page) == 0 ) );
+
+ if( claim_amount%sizeof(Page) != 0 ) {
+ return ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ }
+
+ TRY( mem_claim( claim_amount/sizeof(Page), &out->start ) );
+ out->claimed = claim_amount;
+
+ /* Get filesize */
+ struct stat s = {0};
+ TRY( linux_fstat( file->fd, &s ) );
+
+ out->filesize = s.st_size;
+
+ void *discard;
+
+ if( out->filesize > 0 ) { /* Nothing to map in an empty file */
+ TRY( linux_mmap(
+ (usize)out->start,
+ out->filesize,
+ LINUX_PROT_READ | LINUX_PROT_WRITE,
+ MMAP_MAP_FIXED | MMAP_MAP_SHARED,
+ file->fd,
+ 0,
+ &discard
+ ));
+ }
+
+ /* Finalize output */
+ out->file = *file;
+ out->flags = flags;
+
+ if( flags & FILEVIEW_OWN_FILE ) {
+ file->fd = -1;
+ }
+
+ return S_SUCCESS;
+}
+
+Status FileView_from_path( const Str *path, usize claim_amount, usize flags, FileView *out ) {
+ File file = {0};
+ TRY( File_open( path,
+ FILE_EXISTING_OPEN |
+ FILE_MISSING_CREATE |
+ FILE_LINK_FOLLOW |
+ FILE_ACCESS_READ | FILE_ACCESS_WRITE,
+ &file
+ ));
+
+ return FileView_from_file(&file, claim_amount, flags, out);
+}
+
+Status FileView_extend_file( FileView *fv, usize amount ) {
+ if( amount > fv->claimed - fv->filesize ) {
+ return S_FAILURE | ERR_OUT_OF_BOUND;
+ }
+
+ usize map_start_offset = 0;
+ TRY( usize_round_down( fv->filesize, sizeof(Page), &map_start_offset ) );
+
+ usize map_start_addr = (u64)((u8*)fv->start + map_start_offset);
+
+ TRY( linux_fallocate( fv->file.fd, 0, fv->filesize, amount ) );
+
+ fv->filesize += amount;
+
+ void *discard;
+
+ TRY( linux_mmap(
+ map_start_addr,
+ fv->filesize - map_start_offset + amount,
+ LINUX_PROT_READ | LINUX_PROT_WRITE,
+ MMAP_MAP_FIXED | MMAP_MAP_SHARED,
+ fv->file.fd,
+ map_start_offset,
+ &discard
+ ));
+
+ return S_SUCCESS;
+}
+
+Status FileView_destroy( FileView *fv ) {
+ if( fv->flags & FILEVIEW_OWN_FILE ) {
+ TRY(File_close( &fv->file ));
+ fv->file.fd = -1;
+ }
+
+ TRY( linux_munmap( (usize)fv->start, fv->claimed ) );
+
+ fv->flags = 0;
+ fv->filesize = 0;
+ fv->claimed = 0;
+ fv->start = 0;
+ return S_SUCCESS;
+}
+
+
+/*============================ System calls ==================================*/
+
+/* System call wrappers */
+#if COMPILER == COMPILER_TCC
+ #if ARCH == ARCH_X86_64
+ ssize linux_syscall1(usize num, usize arg1) {
+ __asm__ volatile (
+ "movq %[a1], %%rdi\n"
+ "syscall\n"
+ : [num]"+a"(num)
+ : [a1]"m"(arg1) /* memory operands are forced, because otherwise tcc does not generate correct inline asm - it uses mm registers, which have bogus values... */
+ : "rcx", "r11", "memory", "rdi"
+ );
+ return num;
+ }
+
+ ssize linux_syscall2(usize num, usize arg1, usize arg2) {
+ __asm__ volatile (
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "syscall\n"
+ : [num]"+a"(num)
+ : [a1]"m"(arg1), [a2]"m"(arg2)
+ : "rcx", "r11", "memory", "rdi", "rsi"
+ );
+ return num;
+ }
+ ssize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
+ __asm__ volatile (
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
+ "syscall\n"
+ : [num]"+a"(num)
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx"
+ );
+ return num;
+ }
+ ssize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
+ __asm__ volatile (
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
+ "movq %[a4], %%r10\n"
+ "syscall\n"
+ : [num]"+a"(num)
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10"
+ );
+ return num;
+ }
+ ssize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
+ __asm__ volatile (
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
+ "movq %[a4], %%r10\n"
+ "movq %[a5], %%r8\n"
+ "syscall\n"
+ : [num]"+a"(num)
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4), [a5]"m"(arg5)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10", "r8"
+ );
+ return num;
+ }
+
+ ssize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
+ __asm__ volatile (
+ "movq %[a1], %%rdi\n"
+ "movq %[a2], %%rsi\n"
+ "movq %[a3], %%rdx\n"
+ "movq %[a4], %%r10\n"
+ "movq %[a5], %%r8\n"
+ "movq %[a6], %%r9\n"
+ "syscall\n"
+ : [num]"+a"(num)
+ : [a1]"m"(arg1), [a2]"m"(arg2), [a3]"m"(arg3), [a4]"m"(arg4), [a5]"m"(arg5), [a6]"m"(arg6)
+ : "rcx", "r11", "memory", "rdi", "rsi", "rdx", "r10", "r8", "r9"
+ );
+ return num;
+ }
+
+ #elif ARCH == ARCH_I386
+ #error "Linux syscalls not implemented for I386."
+ #endif
+#elif COMPILER == COMPILER_CLANG || COMPILER == COMPILER_GCC
+ #if ARCH == ARCH_X86_64
+ /* All this mess, just so *maybe* the compiler can optimize register usage when inlining. Check the generic wrappers for a more typical way of going about this. This here is unusual, from what I have seen. */
+ ssize linux_syscall1(usize num, usize arg1) {
+ register usize ret __asm__("rax") = num;
+ register usize a1 __asm__("rdi") = arg1;
+
+ __asm__ volatile(
+ "syscall\n"
+ : "+r"(ret)
+ : "r"(a1)
+ : "rcx", "r11", "memory"
+ );
+ return ret;
+ }
+ ssize linux_syscall2(usize num, usize arg1, usize arg2) {
+ register usize ret __asm__("rax") = num;
+ register usize a1 __asm__("rdi") = arg1;
+ register usize a2 __asm__("rsi") = arg2;
+
+ __asm__ volatile(
+ "syscall\n"
+ : "+r"(ret)
+ : "r"(a1), "r"(a2)
+ : "rcx", "r11", "memory"
+ );
+ return ret;
+ }
+ ssize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
+ register usize ret __asm__("rax") = num;
+ register usize a1 __asm__("rdi") = arg1;
+ register usize a2 __asm__("rsi") = arg2;
+ register usize a3 __asm__("rdx") = arg3;
+
+ __asm__ volatile(
+ "syscall\n"
+ : "+r"(ret)
+ : "r"(a1), "r"(a2), "r"(a3)
+ : "rcx", "r11", "memory"
+ );
+ return ret;
+ }
+ ssize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
+ register usize ret __asm__("rax") = num;
+ register usize a1 __asm__("rdi") = arg1;
+ register usize a2 __asm__("rsi") = arg2;
+ register usize a3 __asm__("rdx") = arg3;
+ register usize a4 __asm__("r10") = arg4;
+
+ __asm__ volatile(
+ "syscall\n"
+ : "+r"(ret)
+ : "r"(a1), "r"(a2), "r"(a3), "r"(a4)
+ : "rcx", "r11", "memory"
+ );
+ return ret;
+ }
+
+ ssize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
+ register usize ret __asm__("rax") = num;
+ register usize a1 __asm__("rdi") = arg1;
+ register usize a2 __asm__("rsi") = arg2;
+ register usize a3 __asm__("rdx") = arg3;
+ register usize a4 __asm__("r10") = arg4;
+ register usize a5 __asm__("r8") = arg5;
+
+ __asm__ volatile(
+ "syscall\n"
+ : "+r"(ret)
+ : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
+ : "rcx", "r11", "memory"
+ );
+ return ret;
+ }
+
+ ssize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
+ register usize ret __asm__("rax") = num;
+ register usize a1 __asm__("rdi") = arg1;
+ register usize a2 __asm__("rsi") = arg2;
+ register usize a3 __asm__("rdx") = arg3;
+ register usize a4 __asm__("r10") = arg4;
+ register usize a5 __asm__("r8") = arg5;
+ register usize a6 __asm__("r9") = arg6;
+
+ __asm__ volatile(
+ "syscall\n"
+ : "+r"(ret)
+ : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6)
+ : "rcx", "r11", "memory"
+ );
+ return ret;
+ }
+
+ #elif ARCH == ARCH_I386
+ #error "Linux syscalls not implemented for I386."
+ #endif
+#endif
+
+
+/* Actual system calls */
+
+Status linux_read( u32 fd, usize max_amount, usize *out_amount, u8 *out ) {
+ usize res = linux_syscall3( 0, fd, (usize)out, max_amount );
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ *out_amount = res;
+ return S_SUCCESS;
+ } else {
+ switch(res) {
+ case -EBADF:
+ return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
+ case -EFAULT:
+ return S_FAILURE | ERRSRC_ARG_3 | ERR_OUT_OF_BOUND;
+ default:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
+ }
+ }
+}
+
+Status linux_write( u32 fd, usize amount, usize *out_amount, const u8 *buf ) {
+ usize res = linux_syscall3( 1, fd, (usize)buf, amount );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ *out_amount = res;
+ return S_SUCCESS;
+ } else {
+ switch(res) {
+ case -EBADF:
+ return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
+ case -EFAULT:
+ return S_FAILURE | ERRSRC_ARG_3 | ERR_OUT_OF_BOUND;
+ default:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
+ }
+ }
+}
+
+Status linux_open( const u8* path, s32 flags, s32 mode, s32 *out_fd ) {
+ ssize res = linux_syscall3( 2, (usize)path, (usize)flags, (usize)mode);
+
+ if( !LINUX_SYSCALL_ERROR( res ) ) {
+ *out_fd = res;
+ return S_SUCCESS;
+ } else {
+ switch( res ) {
+ case -EACCES:
+ case -EPERM:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_PERMISSION_DENIED;
+ case -EEXIST:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_FILE_ALREADY_EXISTS;
+ case -EINVAL:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_INVALID_ARGUMENT;
+ case -ENOENT:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_FILE_DOESNT_EXIST;
+ case -ENAMETOOLONG:
+ return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
+ case -ENOSPC:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_NO_DISK_SPACE;
+ default:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
+ }
+ }
+}
+
+Status linux_close( s32 *fd ) {
+ usize res = linux_syscall1( 3, *fd );
+
+ if( !LINUX_SYSCALL_ERROR( res ) ) {
+ *fd = -1;
+ return S_SUCCESS;
+ } else {
+ switch( res ) {
+ case -EBADF:
+ return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
+ default:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
+ }
+ }
+}
+
+Status linux_lseek( u32 fd, usize offset, usize whence ) {
+ usize res = linux_syscall3( 8, fd, offset, whence );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ return S_SUCCESS;
+ } else {
+ switch( res ) {
+ case -EBADF:
+ return S_FAILURE | ERRSRC_ARG_1 | ERR_INVALID_ARGUMENT;
+ case -EOVERFLOW:
+ return S_FAILURE | ERR_OVERFLOW;
+ default:
+ return S_FAILURE | ERR_GENERIC;
+ }
+ }
+}
+
+ssize linux_stat( const char* path, struct stat *statbuf ) {
+ return linux_syscall2( 4, (usize)path, (usize)statbuf );
+}
+
+Status linux_fstat( s32 fd, struct stat *statbuf ) {
+ ssize res = linux_syscall2( 5, (usize)fd, (usize)statbuf );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ return S_SUCCESS;
+ } else {
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
+ }
+}
+
+void linux_exit( s32 exitcode ) {
+ (void)linux_syscall1( 60, exitcode );
+ UNREACHABLE;
+}
+
+
+Status linux_mmap( usize addr, usize len, usize prot, usize flags, usize fd, usize offset, void **out ) {
+ ssize res = linux_syscall6( 9, addr, len, prot, flags, fd, offset );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ *out = (void*)res;
+ return S_SUCCESS;
+ } else {
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_MAP_FAILURE;
+ }
+}
+
+Status linux_munmap( usize start, usize len ) {
+ ssize res = linux_syscall2( 11, start, len );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ return S_SUCCESS;
+ } else {
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_UNMAP_FAILURE;
+ }
+}
+
+Status linux_mprotect( usize start, usize len, usize prot ) {
+ ssize res = linux_syscall3( 10, start, len, prot );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ return S_SUCCESS;
+ } else {
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_SETPERM_FAILURE;
+ }
+}
+
+Status linux_madvise( usize start, usize len, s32 behaviour ) {
+ ssize res = linux_syscall3( 11, start, len, (usize)(u32)behaviour );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ return S_SUCCESS;
+ } else {
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_MEM_SETHINT_FAILURE;
+ }
+}
+
+ssize linux_unlink( const u8 *path ) {
+ ssize res = linux_syscall1( 87, (usize)path );
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ return S_SUCCESS;
+ } else {
+ switch( res ) {
+ case -EACCES:
+ case -EPERM:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_PERMISSION_DENIED;
+ case -EFAULT:
+ return S_FAILURE | ERRSRC_ARG_1 | ERR_OUT_OF_BOUND;
+ case -ENOENT:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_FILE_DOESNT_EXIST;
+ default:
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
+ }
+ }
+}
+
+Status linux_fallocate( s32 fd, s32 mode, usize offset, usize len ) {
+ ssize res = linux_syscall4(285, fd, mode, offset, len);
+
+ if( !LINUX_SYSCALL_ERROR(res) ) {
+ return S_SUCCESS;
+ } else {
+ return S_FAILURE | ERRSRC_PLATFORM | ERR_GENERIC;
+ }
+}
+/*=========================== Core functions =================================*/
+
+void breakpoint(void) {
+ __asm__ volatile (
+ "int $3\n"
+ );
+}
+
+void terminate_forced(void) {
+ __asm__ volatile (
+ "ud2\n"
+ );
+}
+
+void terminate(u32 code) {
+ linux_exit((s32)code);
+ UNREACHABLE;
+}
+
+#endif /* OS == OS_LINUX */
notlibc.h
@@ -0,0 +1,1776 @@
+#ifndef NOTLIBC_HEADER_INCLUDED
+#define NOTLIBC_HEADER_INCLUDED
+
+/******************************************************************************/
+/* PLATFORM CORE */
+/******************************************************************************/
+
+
+/*===================== Name/ID macros for important things ==================*/
+
+/* -DBUILD_TYPE */
+#define BUILD_DEBUG 1
+#define BUILD_RELEASE 2
+
+#define ARCH_I386 1
+#define ARCH_X86_64 2
+
+#define OS_LINUX 1
+#define OS_WINDOWS 2
+
+#define COMPILER_GCC 1
+#define COMPILER_CLANG 2
+#define COMPILER_TCC 3
+#define COMPILER_MSVC 4
+
+#define HEAP_HEADER_GUARD_NUMBER 0xc0dedeaddeadc0de
+#define HEAP_OVERRUN_GUARD_NUMBER 0xeeeedeaddeadeeee
+#define HEAP_XOR_KEY 0x0e1e2e3e4e5e6e7e
+
+#define ARRAY_XOR_KEY 0x0a1a2a3a4a5a6a7a
+
+#define MAGIC_UNINITIALIZED_MEM 0xf0
+#define MAGIC_POISONED_MEM 0xfc
+#define MAGIC_FREED_MEM 0xfe
+
+
+/*============================== Build info =================================*/
+
+#ifndef BUILD_TYPE
+#define BUILD_TYPE 0
+#endif
+
+#if BUILD_TYPE == 1
+ #define BUILD BUILD_DEBUG
+ #define DEBUG(...) __VA_ARGS__
+ #define RELEASE(...)
+#elif BUILD_TYPE == 2
+ #define BUILD BUILD_RELEASE
+ #define RELEASE(...) __VA_ARGS__
+ #define DEBUG(...)
+#else
+ #error No build type was specified. There is no defaulting to debug builds.
+#endif
+
+
+/*========================== Architecture info ==============================*/
+
+#ifndef ARCH
+ #if defined(__x86_64__) || defined(_M_X64)
+ #define ARCH ARCH_X86_64
+ #define ARCH_NAME "x86_64"
+ #define X86_64(...) __VA_ARGS__
+ #elif defined(__i386__) || defined(_M_IX86)
+ #define ARCH ARCH_I386
+ #define ARCH_NAME "i386"
+ #define I386(...) __VA_ARGS__
+ #endif
+#endif
+
+#if !defined(ARCH) || !defined(ARCH_NAME)
+ #error Failed to identify architecture. Please specify it via -DARCH=number (choose the most compatible option from above) and -DARCH_NAME=name to override the automatic detection.
+#endif
+
+/* These are only for in-macro use, in case they are absolutely necessary. Not to be abused. They lead to messy code in debuggers */
+#ifndef X86_64
+#define X86_64(...)
+#endif
+
+#ifndef I386
+#define I386(...)
+#endif
+
+
+/*======================== Operating System Info =============================*/
+
+#ifndef OS
+ #if defined(__linux__)
+ #define OS OS_LINUX
+ #define OS_NAME "linux"
+
+ #elif defined(_WIN32) || defined(_WIN64)
+ #define OS OS_WINDOWS
+ #define OS_NAME "windows"
+
+ #endif
+#endif
+
+#if !defined(OS) || !defined(OS_NAME)
+ #error Failed to identify operating system. Please specify it via -DOS=number (choose the most compatible option from above) and -DOS_NAME=name to override the automatic detection.
+#endif
+
+
+/*====================== Compiler-specific abstractions ======================*/
+
+#ifndef COMPILER /* skip if -DCOMPILER=<something> was used */
+ #if defined(__clang__) || defined(__llvm__)
+ #define COMPILER COMPILER_CLANG
+ #define COMPILER_NAME "clang"
+
+ #elif defined(__GNUC__) && !defined(__clang__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
+ #define COMPILER COMPILER_GCC
+ #define COMPILER_NAME "gcc"
+
+ #elif defined(__TINYC__)
+ #define COMPILER COMPILER_TCC
+ #define COMPILER_NAME "tcc"
+
+ #elif defined( _MSC_VER )
+ #define COMPILER_MSVC
+ #define COMPILER_NAME "msvc"
+ #endif
+#endif
+
+#if !defined(COMPILER) || !defined(COMPILER_NAME)
+ #error Failed to identify compiler. Please specify it via \
+ -DCOMPILER=number (choose the most compatible option from above) and \
+ -DCOMPILER_NAME=name to override the automatic detection.
+#endif
+
+
+/* Struct and union macros */
+#define STRUCT( name, ...) \
+typedef struct _##name { \
+ __VA_ARGS__ \
+} name
+
+
+/* Packed struct */
+#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG || COMPILER == COMPILER_TCC
+ #define PACKED_STRUCT( name, ...) \
+ typedef struct __attribute__((packed)) _##name { \
+ __VA_ARGS__ \
+ } name;
+#elif COMPILER == COMPILER_MSVC
+ #define PACKED_STRUCT( name, ...) \
+ PRAGMA(pack(push, 1)) \
+ typedef struct _##name { \
+ __VA_ARGS__ \
+ } name; \
+ PRAGMA(pack(pop))
+#else
+ #error PACKED_STRUCT macro undefined.
+#endif
+
+#define STRUCT_FIELD_OFFSET( T, fieldname ) \
+ ((usize)&(((T*)0)->fieldname))
+
+
+#define UNION( name, ...) \
+typedef union _##name { \
+ __VA_ARGS__ \
+} name
+
+
+/* Warnings and errors */
+
+#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
+ #define PRAGMA(pragma) _Pragma(#pragma)
+#elif COMPILER == COMPILER_MSVC
+ #define PRAGMA(pragma) __pragma(pragma)
+#endif
+
+#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
+ #define WARNING(...) PRAGMA(GCC warning __VA_ARGS__)
+ #define ERROR(...) PRAGMA(GCC error __VA_ARGS__)
+#elif COMPILER == COMPILER_TCC
+ #define WARN(...)
+ #define ERROR(...) (*(void*)0 = 0)
+ #ifndef NOTLIBC_SILENCE
+ #warning Compiling with tcc. Pragmas are not supported, \
+ so warnings will just not be printed and errors will give an \
+ 'assignment to void' error, but the line number should \
+ still point to the right location.
+ #endif
+#else
+ #define WARNING(...)
+ #ifndef NOTLIBC_SILENCE
+ #warning No warning directive is implemented for this compiler. \
+ No warnings will be emitted from the code.
+ #endif
+ #error No error directive is implemented for this compiler, thus errors can not be emitted.
+#endif
+
+
+#if COMPILER == COMPILER_GCC || COMPILER == COMPILER_CLANG
+ #define UNREACHABLE __builtin_unreachable()
+#elif COMPILER == COPMILER_MSVC
+ #define UNREACHABLE __assume(0)
+#else
+ #if !defined(NOTLIBC_SILENCE)
+ #warning UNREACHABLE is not defined for the current compiler. \
+ Compiler may not perform all optimizations it could based on \
+ unreachability in some special cases.
+ #endif
+ #define UNREACHABLE
+#endif
+
+
+/*============================= Macro Tricks =================================*/
+
+#define MACRO_EMPTY()
+
+#define MACRO_DEFER( macro ) macro MACRO_EMPTY()
+#define MACRO_OBSTRUCT( ... ) __VA_ARGS__ MACRO_DEFER( MACRO_EMPTY )()
+#define MACRO_EXPAND( ... ) __VA_ARGS__
+
+#define MACRO_STRING_JOIN( str1, str2 ) str1##str2
+
+#define UNIQUE_NAME( name ) \
+ MACRO_EXPAND(MACRO_DEFER(MACRO_STRING_JOIN)(name, __LINE__))
+
+/* Compile-time assertion */
+#define ASSERT( expression ) \
+ typedef char UNIQUE_NAME(compile_time_assert)[(expression)? 1 : -1]
+
+
+/*=========================== Core Datatypes =================================*/
+
+#if OS == OS_LINUX || OS == OS_WINDOWS
+ typedef unsigned char u8;
+ typedef unsigned short u16;
+ typedef unsigned int u32;
+ typedef unsigned long long u64;
+
+ typedef signed char s8;
+ typedef signed short s16;
+ typedef signed int s32;
+ typedef signed long long s64;
+
+ typedef float f32;
+ typedef double f64;
+#endif
+
+#if ARCH == ARCH_X86_64
+
+ typedef u64 usize;
+ typedef s64 ssize;
+
+ typedef struct _Page {
+ u8 data[4096];
+ } Page;
+
+#elif ARCH == ARCH_I386
+
+ typedef u32 usize;
+ typedef s32 ssize;
+
+ typedef struct _Page {
+ u8 data[4096];
+ } Page;
+
+#endif
+
+ASSERT( sizeof( u8 ) == 1 );
+ASSERT( sizeof( u16 ) == 2 );
+ASSERT( sizeof( u32 ) == 4 );
+ASSERT( sizeof( u64 ) == 8 );
+
+ASSERT( sizeof( s8 ) == 1 );
+ASSERT( sizeof( s16 ) == 2 );
+ASSERT( sizeof( s32 ) == 4 );
+ASSERT( sizeof( s64 ) == 8 );
+
+ASSERT( sizeof( f32 ) == 4 );
+ASSERT( sizeof( f64 ) == 8 );
+
+
+void *memset( void* ptr, int value, unsigned long count );
+void *memcpy( void *dest, const void *src, unsigned long n );
+
+/*========================== Derived Datatypes ===============================*/
+
+/* Pointers */
+
+/* Status */
+
+#define GEN_POINTER_TYPE( T ) \
+typedef T* T##p
+
+GEN_POINTER_TYPE( u8 );
+GEN_POINTER_TYPE( u16 );
+GEN_POINTER_TYPE( u32 );
+GEN_POINTER_TYPE( u64 );
+GEN_POINTER_TYPE( usize );
+
+GEN_POINTER_TYPE( s8 );
+GEN_POINTER_TYPE( s16 );
+GEN_POINTER_TYPE( s32 );
+GEN_POINTER_TYPE( s64 );
+GEN_POINTER_TYPE( ssize );
+
+GEN_POINTER_TYPE( f32 );
+GEN_POINTER_TYPE( f64 );
+
+typedef u32 Status;
+
+#define S_MASK (3 << 30)
+
+#define S_SUCCESS (1 << 30) /* Requested action performed. */
+#define S_COMPLETION (0 << 30) /* Action didn't need to be performed - desired state is already present/active. */
+#define S_FAILURE (2 << 30) /* Action failed. */
+
+#define S_SOURCE_MASK (0x3ff << 20)
+enum _ErrorSources {
+
+ ERRSRC_ARG_1 = (0x1 << 20),
+ ERRSRC_ARG_2 = (0x2 << 20),
+ ERRSRC_ARG_3 = (0x3 << 20),
+ ERRSRC_ARG_4 = (0x4 << 20),
+ ERRSRC_ARG_5 = (0x5 << 20),
+ ERRSRC_ARG_6 = (0x6 << 20),
+ ERRSRC_ARG_7 = (0x7 << 20),
+ ERRSRC_ARG_8 = (0x8 << 20),
+ ERRSRC_ARG_9 = (0x9 << 20),
+ ERRSRC_ARG_10 = (0xa << 20),
+ ERRSRC_ARG_11 = (0xb << 20),
+ ERRSRC_ARG_12 = (0xc << 20),
+
+ ERRSRC_PLATFORM = (0x10 << 20), /* The error resulted inside platform code. */
+};
+
+#define S_REASON_MASK (0xfffff)
+enum _ErrorReasons {
+ ERR_GENERIC = 0x0, /* Even numbers are for the implementations, odd are for user-defined errors */
+
+ ERR_INVALID_ARGUMENT = 0x2,
+
+ ERR_OVERFLOW = 0x4,
+
+ ERR_OUT_OF_BOUND = 0x6, /* a value is out of bounds or the operation would violate certain bounds with the current arguments */
+
+ ERR_PERMISSION_DENIED = 0x8,
+
+
+ ERR_MEM_MAP_FAILURE = 0x100,
+ ERR_MEM_UNMAP_FAILURE = 0x102,
+ ERR_MEM_SETPERM_FAILURE = 0x104,
+ ERR_MEM_SETHINT_FAILURE = 0x106,
+
+ ERR_FILE_ALREADY_EXISTS = 0x110,
+ ERR_FILE_DOESNT_EXIST = 0x112,
+
+ ERR_NO_DISK_SPACE = 0x114,
+
+};
+
+
+#define S_OK(...) ( ((__VA_ARGS__) & S_MASK) != (Status)S_FAILURE ) /* != FAILURE, cause otherwise the expression will appear twice, which is a great footgun when it's stateful... we are having none of that here */
+#define S_NOK(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
+
+#define S_SUCCESSFUL(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_SUCCESS )
+#define S_COMPLETED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_COMPLETION )
+#define S_FAILED(...) ( ((__VA_ARGS__) & S_MASK) == (Status)S_FAILURE )
+
+#define TRY(...) do { \
+ Status _res = (__VA_ARGS__); \
+ if( S_NOK(_res) ) { \
+ return _res; \
+ } \
+} while(0)
+
+
+/******************************************************************************/
+/* MATH STUFF */
+/******************************************************************************/
+
+#define u8_MIN 0
+#define u16_MIN 0
+#define u32_MIN 0
+#define u64_MIN 0
+
+#define u8_MAX ((u8)-1)
+#define u16_MAX ((u16)-1)
+#define u32_MAX ((u32)-1)
+#define u64_MAX ((u64)-1)
+
+/* We assume 2's complement */
+ASSERT( (-1^1) == -2 );
+
+#define s8_MAX ((s8)( (u8)-1 >> 1))
+#define s16_MAX ((s16)((u16)-1 >> 1))
+#define s32_MAX ((s32)((u32)-1 >> 1))
+#define s64_MAX ((s64)((u64)-1 >> 1))
+
+#define s8_MIN (- s8_MAX - 1)
+#define s16_MIN (-s16_MAX - 1)
+#define s32_MIN (-s32_MAX - 1)
+#define s64_MIN (-s64_MAX - 1)
+
+
+/* Ensure limit sanity - at least for unsigned */
+ASSERT( u64_MAX == 0xffffffffffffffff );
+ASSERT( u32_MAX == 0xffffffff );
+ASSERT( u16_MAX == 0xffff );
+ASSERT( u8_MAX == 0xff );
+
+/* Addition */
+
+static inline Status u8_add(u8 n1, u8 n2, u8 *out);
+static inline Status u16_add(u16 n1, u16 n2, u16 *out);
+static inline Status u32_add(u32 n1, u32 n2, u32 *out);
+static inline Status u64_add(u64 n1, u64 n2, u64 *out);
+
+static inline Status usize_add(usize n1, usize n2, usize *out) {
+ #if ARCH == ARCH_X86_64
+ return u64_add( n1, n2, out );
+ #elif ARCH == ARCH_I386
+ return u32_add( n1, n2, out );
+ #endif
+}
+
+static inline Status s8_add(s8 n1, s8 n2, s8 *out);
+static inline Status s16_add(s16 n1, s16 n2, s16 *out);
+static inline Status s32_add(s32 n1, s32 n2, s32 *out);
+static inline Status s64_add(s64 n1, s64 n2, s64 *out);
+
+static inline Status ssize_add(ssize n1, ssize n2, ssize *out) {
+ #if ARCH == ARCH_X86_64
+ return s64_add( n1, n2, out );
+ #elif ARCH == ARCH_I386
+ return s32_add( n1, n2, out );
+ #endif
+}
+
+/* Subtraction */
+
+static inline Status u8_sub(u8 n1, u8 n2, u8 *out);
+static inline Status u16_sub(u16 n1, u16 n2, u16 *out);
+static inline Status u32_sub(u32 n1, u32 n2, u32 *out);
+static inline Status u64_sub(u64 n1, u64 n2, u64 *out);
+
+static inline Status usize_sub(usize n1, usize n2, usize *out) {
+ #if ARCH == ARCH_X86_64
+ return u64_sub( n1, n2, out );
+ #elif ARCH == ARCH_I386
+ return u32_sub( n1, n2, out );
+ #endif
+}
+
+static inline Status s8_sub(s8 n1, s8 n2, s8 *out);
+static inline Status s16_sub(s16 n1, s16 n2, s16 *out);
+static inline Status s32_sub(s32 n1, s32 n2, s32 *out);
+static inline Status s64_sub(s64 n1, s64 n2, s64 *out);
+
+static inline Status ssize_sub(ssize n1, ssize n2, ssize *out) {
+ #if ARCH == ARCH_X86_64
+ return s64_sub( n1, n2, out );
+ #elif ARCH == ARCH_I386
+ return s32_sub( n1, n2, out );
+ #endif
+}
+
+
+
+/* Multiplication */
+
+static inline Status u8_mul(u8 n1, u8 n2, u8 *out);
+static inline Status u16_mul(u16 n1, u16 n2, u16 *out);
+static inline Status u32_mul(u32 n1, u32 n2, u32 *out);
+static inline Status u64_mul(u64 n1, u64 n2, u64 *out);
+
+static inline Status s8_mul( s8 n1, s8 n2, s8 *out);
+static inline Status s16_mul(s16 n1, s16 n2, s16 *out);
+static inline Status s32_mul(s32 n1, s32 n2, s32 *out);
+static inline Status s64_mul(s64 n1, s64 n2, s64 *out);
+
+static inline Status usize_mul(usize n1, usize n2, usize *out) {
+ #if ARCH == ARCH_X86_64
+ return u64_mul( n1, n2, out );
+ #elif ARCH == ARCH_I386
+ return u32_mul( n1, n2, out );
+ #endif
+}
+
+
+/* Maximum */
+
+static inline u64 u64_max( u64 n1, u64 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline u32 u32_max( u32 n1, u32 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline u16 u16_max( u16 n1, u16 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline u8 u8_max( u8 n1, u8 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline usize usize_max( usize n1, usize n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline s64 s64_max( s64 n1, s64 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline s32 s32_max( s32 n1, s32 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline s16 s16_max( s16 n1, s16 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+static inline s8 s8_max( s8 n1, s8 n2 ) {
+ return (n1 >= n2)? n1 : n2;
+}
+
+
+/* Minimum */
+static inline u64 u64_min( u64 n1, u64 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline u32 u32_min( u32 n1, u32 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline u16 u16_min( u16 n1, u16 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline u8 u8_min( u8 n1, u8 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline usize usize_min( usize n1, usize n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline s64 s64_min( s64 n1, s64 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline s32 s32_min( s32 n1, s32 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline s16 s16_min( s16 n1, s16 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+static inline s8 s8_min( s8 n1, s8 n2 ) {
+ return (n2 >= n1)? n1 : n2;
+}
+
+/* Round Down */
+
+static inline Status u64_round_down(u64 number, u64 multiple, u64 *out) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ *out = number - (number%multiple);
+ return S_SUCCESS;
+}
+
+static inline Status u32_round_down(u32 number, u32 multiple, u32 *out) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ *out = number - (number%multiple);
+ return S_SUCCESS;
+}
+
+static inline Status u16_round_down(u16 number, u16 multiple, u16 *out) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ *out = number - (number%multiple);
+ return S_SUCCESS;
+}
+
+static inline Status u8_round_down(u8 number, u8 multiple, u8 *out) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ *out = number - (number%multiple);
+ return S_SUCCESS;
+}
+
+#if ARCH == ARCH_X86_64
+static inline Status usize_round_down( usize number, usize multiple, usize *out ) {
+ return u64_round_down(number, multiple, out);
+}
+#elif ARCH == ARCH_I386
+static inline Status usize_round_down( usize number, usize multiple, usize *out ) {
+ return u32_round_down(number, multiple, out);
+}
+#endif
+
+/* Round Up */
+
+static inline Status u64_round_up( u64 number, u64 multiple, u64 *out ) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ u64 rem = number%multiple;
+ if( rem == 0 ) {
+ *out = number;
+ } else {
+ TRY( u64_add( number, multiple - rem, out ) );
+ }
+ return S_SUCCESS;
+}
+
+static inline Status u32_round_up( u32 number, u32 multiple, u32 *out ) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ u32 rem = number%multiple;
+ if( rem == 0 ) {
+ *out = number;
+ } else {
+ TRY( u32_add( number, multiple - rem, out ) );
+ }
+ return S_SUCCESS;
+}
+
+static inline Status u16_round_up( u16 number, u16 multiple, u16 *out ) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ u16 rem = number%multiple;
+ if( rem == 0 ) {
+ *out = number;
+ } else {
+ TRY( u16_add( number, multiple - rem, out ) );
+ }
+ return S_SUCCESS;
+}
+
+static inline Status u8_round_up( u8 number, u8 multiple, u8 *out ) {
+ if( multiple == 0 ) return S_FAILURE | ERRSRC_ARG_2 | ERR_INVALID_ARGUMENT;
+ u8 rem = number%multiple;
+ if( rem == 0 ) {
+ *out = number;
+ } else {
+ TRY( u8_add( number, multiple - rem, out ) );
+ }
+ return S_SUCCESS;
+}
+
+#if ARCH == ARCH_X86_64
+static inline Status usize_round_up( usize number, usize multiple, usize *out ) {
+ return u64_round_up(number, multiple, out);
+}
+#elif ARCH == ARCH_I386
+static inline Status usize_round_up( usize number, usize multiple, usize *out ) {
+ return u32_round_up(number, multiple, out);
+}
+#endif
+
+
+/* Is Power Of Two */
+
+static inline u8 u64_is_power_of_two( u64 num ) {
+ return num && !(num & (num - 1));
+}
+
+static inline u8 u32_is_power_of_two( u32 num ) {
+ return num && !(num & (num - 1));
+}
+
+static inline u8 u16_is_power_of_two( u16 num ) {
+ return num && !(num & (num - 1));
+}
+
+static inline u8 u8_is_power_of_two( u8 num ) {
+ return num && !(num & (num - 1));
+}
+
+static inline u8 usize_is_power_of_two( usize num ) {
+ return num && !(num & (num - 1));
+}
+
+
+#if COMPILER == COPMILER_GCC || COMPILER == COMPILER_CLANG
+ static inline Status u64_add( u64 n1, u64 n2, u64 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u32_add( u32 n1, u32 n2, u32 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u16_add( u16 n1, u16 n2, u16 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u8_add( u8 n1, u8 n2, u8 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ /* Signed addition */
+
+ static inline Status s64_add( s64 n1, s64 n2, s64 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s32_add( s32 n1, s32 n2, s32 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s16_add( s16 n1, s16 n2, s16 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s8_add( s8 n1, s8 n2, s8 *out ) {
+ if( __builtin_add_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+
+ /* Unsigned subtraction */
+
+ static inline Status u64_sub( u64 n1, u64 n2, u64 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u32_sub( u32 n1, u32 n2, u32 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u16_sub( u16 n1, u16 n2, u16 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u8_sub( u8 n1, u8 n2, u8 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ /* Signed subtraction */
+
+ static inline Status s64_sub( s64 n1, s64 n2, s64 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s32_sub( s32 n1, s32 n2, s32 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s16_sub( s16 n1, s16 n2, s16 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s8_sub( s8 n1, s8 n2, s8 *out ) {
+ if( __builtin_sub_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ /* Unsigned multiplication */
+
+ static inline Status u64_mul( u64 n1, u64 n2, u64 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u32_mul( u32 n1, u32 n2, u32 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u16_mul( u16 n1, u16 n2, u16 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status u8_mul( u8 n1, u8 n2, u8 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s64_mul( s64 n1, s64 n2, s64 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s32_mul( s32 n1, s32 n2, s32 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s16_mul( s16 n1, s16 n2, s16 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+
+ static inline Status s8_mul( s8 n1, s8 n2, s8 *out ) {
+ if( __builtin_mul_overflow(n1, n2, out) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ return S_SUCCESS;
+ }
+#else
+ /* Unsigned addition */
+ static inline Status u64_add( u64 n1, u64 n2, u64 *out ) {
+ if( n1 > (u64_MAX) - n2 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u32_add( u32 n1, u32 n2, u32 *out ) {
+ if( n1 > (u32_MAX) - n2 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u16_add( u16 n1, u16 n2, u16 *out ) {
+ if( n1 > (u16_MAX) - n2 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u8_add( u8 n1, u8 n2, u8 *out ) {
+ if( n1 > (u8_MAX) - n2 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ /* Signed addition */
+ static inline Status s64_add( s64 n1, s64 n2, s64 *out ) {
+ if( (n1 >= 0 && n2 > s64_MAX - n1) || (n1 < 0 && n2 < s64_MIN - n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status s32_add( s32 n1, s32 n2, s32 *out ) {
+ if( (n1 >= 0 && n2 > s32_MAX - n1) || (n1 < 0 && n2 < s32_MIN - n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status s16_add( s16 n1, s16 n2, s16 *out ) {
+ if( (n1 >= 0 && n2 > s16_MAX - n1) || (n1 < 0 && n2 < s16_MIN - n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status s8_add( s8 n1, s8 n2, s8 *out ) {
+ if( (n1 >= 0 && n2 > s8_MAX - n1) || (n1 < 0 && n2 < s8_MIN - n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 + n2;
+ return S_SUCCESS;
+ }
+
+ /* Unsigned subtraction */
+
+ static inline Status u64_sub( u64 n1, u64 n2, u64 *out ) {
+ if( n2 > n1 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u32_sub( u32 n1, u32 n2, u32 *out ) {
+ if( n2 > n1 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u16_sub( u16 n1, u16 n2, u16 *out ) {
+ if( n2 > n1 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u8_sub( u8 n1, u8 n2, u8 *out ) {
+ if( n2 > n1 ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ /* Signed Subtraction */
+
+ static inline Status s64_sub( s64 n1, s64 n2, s64 *out ) {
+ if( (n2 > 0 && n1 < s64_MIN + n2) || (n2 < 0 && n1 > s64_MAX + n2) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status s32_sub( s32 n1, s32 n2, s32 *out ) {
+ if( (n2 > 0 && n1 < s32_MIN + n2) || (n2 < 0 && n1 > s32_MAX + n2) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status s16_sub( s16 n1, s16 n2, s16 *out ) {
+ if( (n2 > 0 && n1 < s16_MIN + n2) || (n2 < 0 && n1 > s16_MAX + n2) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status s8_sub( s8 n1, s8 n2, s8 *out ) {
+ if( (n2 > 0 && n1 < s8_MIN + n2) || (n2 < 0 && n1 > s8_MAX + n2) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1 - n2;
+ return S_SUCCESS;
+ }
+
+ /* Unsigned multiplication */
+ static inline Status u64_mul( u64 n1, u64 n2, u64 *out ) {
+ if( n1 && n2 > (u64_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u32_mul( u32 n1, u32 n2, u32 *out ) {
+ if( n1 && n2 > (u32_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u16_mul( u16 n1, u16 n2, u16 *out ) {
+ if( n1 && n2 > (u16_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+
+ static inline Status u8_mul( u8 n1, u8 n2, u8 *out ) {
+ if( n1 && n2 > (u8_MAX/n1) ) {
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+
+ /* Signed multiplication */
+ static inline Status s64_mul( s64 n1, s64 n2, s64 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s64_MIN/n2 && n1 <= s64_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s64_MAX ) ||
+ ( n2 < -1 && n1 >= s64_MAX/n2 && n1 <= s64_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+
+ static inline Status s32_mul( s32 n1, s32 n2, s32 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s32_MIN/n2 && n1 <= s32_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s32_MAX ) ||
+ ( n2 < -1 && n1 >= s32_MAX/n2 && n1 <= s32_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+
+ static inline Status s16_mul( s16 n1, s16 n2, s16 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s16_MIN/n2 && n1 <= s16_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s16_MAX ) ||
+ ( n2 < -1 && n1 >= s16_MAX/n2 && n1 <= s16_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+
+ static inline Status s8_mul( s8 n1, s8 n2, s8 *out ) {
+ if(
+ ( n2 > 0 && n1 >= s8_MIN/n2 && n1 <= s8_MAX/n2 ) ||
+ ( n2 == 0 ) ||
+ ( n2 == -1 && n1 >= -s8_MAX ) ||
+ ( n2 < -1 && n1 >= s8_MAX/n2 && n1 <= s8_MIN/n2 )
+ ) {
+ *out = n1*n2;
+ return S_SUCCESS;
+ }
+ return S_FAILURE | ERR_OVERFLOW;
+ }
+
+#endif
+
+
+/* Arena */
+
+STRUCT( Arena,
+ Page *start; /* The address where the arena starts */
+ usize claimed; /* Total size of the arena */
+ usize occupied; /* The actually occupied (backed) range */
+ usize taken; /* The top of the arena */
+);
+
+Status Arena_create( Arena *out, usize size );
+Status Arena_destroy( Arena *a );
+
+Status Arena_take( Arena *a, usize amount, u8 **out );
+Status Arena_give( Arena *a, usize amount );
+Status Arena_align( Arena *a, usize alignment );
+
+/* Heap */
+
+#if BUILD_TYPE == BUILD_RELEASE
+ STRUCT( HeapEntry,
+ usize size; /* The next pointer is stored in the data when the block is added to the freelist */
+ );
+
+ STRUCT( Heap,
+ Arena arena; /* Heap is built on top of arena. It's just an arena + a freelist with metadata */
+ HeapEntry freelist;
+ HeapEntry *freelist_data;
+ );
+
+#elif BUILD_TYPE == BUILD_DEBUG
+ STRUCT( HeapEntry,
+ u64 header_start_guard;
+ usize allowed_size;
+ struct _HeapEntry *next; /* unlike in release, in debug we have a separate next pointer for linking into the freelist */
+ u64 checksum; /* size xor'd with next, allowed size and the guard magic number - (likely) detects overwriting of metadata */
+ usize size;
+ u64 header_end_guard;
+ );
+
+ STRUCT( Heap,
+ Arena arena; /* Heap is built on top of arena. It's just an arena + a freelist with metadata */
+ HeapEntry freelist;
+ HeapEntry blocklist; /* The existing blocks in a list */
+ );
+#endif
+ASSERT( sizeof(HeapEntry)%sizeof(usize) == 0 );
+
+Status Heap_create( Heap *out, usize size ); /* size - size of underlying arena. The heap will hold less, due to bookkeeping overhead for allocations. */
+Status Heap_destroy( Heap *h );
+
+Status Heap_alloc( Heap *h, usize amount, void **out );
+Status Heap_free( Heap *h, void **ptr ); /* u8** cause it zeroes the pointer on success automatically. */
+
+usize Heap_get_asize( Heap *h, const void *ptr );
+
+/* Arrays */
+
+#define ARR_FOREACH( T, varname, arr) \
+ for( T *varname = &arr->data[0]; varname < &arr->data[arr->a.len]; varname += 1 )
+
+STRUCT( AnyArr,
+ usize len;
+ DEBUG(
+ Heap *heap;
+ usize checksum;
+ )
+);
+
+Status AnyArr_create( usize count, AnyArr **out, Heap *h, usize elem_size );
+Status AnyArr_destroy( AnyArr** arr, Heap *h );
+
+Status AnyArr_extend( AnyArr **arr, usize additional_len, Heap *h, usize elem_size );
+Status AnyArr_truncate( AnyArr *arr, usize cutlen, usize elem_size );
+
+Status AnyArr_inflate( AnyArr **arr, usize additional_count, Heap *h, usize elem_size );
+Status AnyArr_deflate( AnyArr **arr, Heap *h, usize elem_size );
+
+Status AnyArr_push( AnyArr **arr, void* el, Heap *h, usize elem_size );
+Status AnyArr_pop( AnyArr *arr, void* el_out, usize elem_size );
+
+Status AnyArr_dup( const AnyArr *arr, AnyArr **out_arr, Heap *h, usize elem_size );
+
+DEBUG(
+ void _AnyArr_update_checksum( AnyArr *arr );
+ void _AnyArr_validate( const AnyArr *arr );
+)
+
+#define GEN_ARRAY_TYPE( T ) \
+ STRUCT( T##s, \
+ usize len; \
+ DEBUG( \
+ Heap *heap; \
+ usize checksum; \
+ ) \
+ T data[]; \
+ ); \
+ ASSERT( sizeof(T##s)%sizeof(usize) == 0 ); \
+ ASSERT( sizeof(T##s) == sizeof(AnyArr) ); \
+ \
+static inline Status T##s_create( Heap *h, usize count, T ## s **out ) { \
+ return AnyArr_create( count, (AnyArr**) out, h, sizeof(T) ); \
+} \
+ \
+static inline Status T##s_push( T##s **arr, T* el, Heap *h ) { \
+ return AnyArr_push( (AnyArr**)arr, el, h, sizeof(T) ); \
+} \
+ \
+static inline Status T##s_pop( T##s *arr, T* el ) { \
+ return AnyArr_pop( (AnyArr*)arr, el, sizeof(T) ); \
+} \
+ \
+static inline Status T##s_extend( T##s **arr, usize additional_len, Heap *h ) { \
+ return AnyArr_extend( (AnyArr**)arr, additional_len, h, sizeof(T) ); \
+} \
+ \
+static inline Status T##s_truncate( T##s *arr, usize cutlen ) { \
+ return AnyArr_truncate( (AnyArr*)arr, cutlen, sizeof(T) ); \
+} \
+ \
+static inline Status T##s_inflate( T##s **arr, usize additional_count, Heap *h ) { \
+ return AnyArr_inflate( (AnyArr**)arr, additional_count, h, sizeof(T) ); \
+} \
+ \
+static inline Status T##s_deflate( T##s **arr, Heap *h ) { \
+ return AnyArr_deflate( (AnyArr**)arr, h, sizeof(T) ); \
+} \
+ \
+static inline Status T##s_dup( const T##s *arr, T##s **out_arr, Heap *h ) { \
+ return AnyArr_dup( (AnyArr*)arr, (AnyArr**)out_arr, h, sizeof(T) ); \
+} \
+ \
+static inline Status T ## s_destroy( T##s **arr, Heap *h ) { \
+ return AnyArr_destroy( (AnyArr**)arr, h ); \
+}
+
+GEN_ARRAY_TYPE( u8 )
+GEN_ARRAY_TYPE( u16 )
+GEN_ARRAY_TYPE( u32 )
+GEN_ARRAY_TYPE( u64 )
+GEN_ARRAY_TYPE( usize )
+
+GEN_ARRAY_TYPE( s8 )
+GEN_ARRAY_TYPE( s16 )
+GEN_ARRAY_TYPE( s32 )
+GEN_ARRAY_TYPE( s64 )
+GEN_ARRAY_TYPE( ssize )
+
+GEN_ARRAY_TYPE( f32 )
+GEN_ARRAY_TYPE( f64 )
+
+GEN_ARRAY_TYPE( u8p )
+GEN_ARRAY_TYPE( u16p )
+GEN_ARRAY_TYPE( u32p )
+GEN_ARRAY_TYPE( u64p )
+GEN_ARRAY_TYPE( usizep )
+
+GEN_ARRAY_TYPE( s8p )
+GEN_ARRAY_TYPE( s16p )
+GEN_ARRAY_TYPE( s32p )
+GEN_ARRAY_TYPE( s64p )
+GEN_ARRAY_TYPE( ssizep )
+
+GEN_ARRAY_TYPE( f32p )
+GEN_ARRAY_TYPE( f64p )
+
+
+
+
+/* String */
+
+STRUCT( Str,
+ usize len;
+ u8 data[];
+);
+
+STRUCT( StrSlc,
+ usize len;
+ u8 *data;
+);
+
+/* On typical platforms that already have/need nul-termination we keep the nul-termination alongside the explicit length notation.
+ * Hacky, but no one wants to copy strings/paths for syscalls.
+ * NOTE: on these platforms len MUST NOT include the NUL-terminator.
+ * It is the indexable length of the string. */
+#if PLATFORM == PLATFORM_LINUX || PLATFORM == PLATFORM_WINDOWS
+
+#define STRING( varname, string ) \
+ struct { \
+ u64 len; \
+ u8 data[sizeof(string)]; \
+ } varname = { .len = sizeof(string)-1, .data = string }
+
+#define STRING_SLICE( varname, stringname, start_index, len ) \
+ StrSlc varname = { .len = len, .data = &stringname[start_index] };
+
+#define STRING_SLICE_LITERAL( varname, literal) \
+ u8 varname_data[] = literal; \
+ StrSlc varname = { .len = sizeof(literal) - 1, .data = &varname_data[0] };
+#else
+ #error Str not implemented for current platform.
+
+/* For bare metal, when we get there: */
+
+#define STATIC( varname, str ) \
+ const struct { \
+ u64 len; \
+ u8 data[sizeof( str ) - 1] __attribute__((nonstring)); \
+ } varname = { .len = sizeof(str) - 1, .data = str }
+
+#endif
+
+
+/* String assembler */
+STRUCT( StrAsm,
+ Arena *a;
+);
+
+Status StrSlc_from_Str( StrSlc *out, const Str *s, usize start, usize len );
+
+u8 StrSlc_equals( const StrSlc sl1, const StrSlc sl2 );
+u8 StrSlc_equals_by_ref( const StrSlc *sl1, const StrSlc *sl2 );
+
+u8 StrSlc_equals_Str( const StrSlc sl, const Str* s2 );
+u8 StrSlc_equals_Str_by_ref( const StrSlc *s1, const StrSlc s2 );
+
+/* String assembler */
+
+Status StrAsm_create( StrAsm *out, usize max_size );
+Status StrAsm_destroy( StrAsm *out );
+
+Status StrAsm_store_into_arena( StrAsm *sa, Arena *dst, void **out);
+Status StrAsm_store_onto_heap( StrAsm *sa, Heap *dst, void **out );
+
+/* String, character */
+Status StrAsm_cat_char ( StrAsm *sa, u8 value );
+Status StrAsm_cat_Str( StrAsm *sa, const Str *s );
+Status StrAsm_cat_StrSlc( StrAsm *sa, StrSlc sl );
+Status StrAsm_cat_StrSlc_by_ref( StrAsm *sa, const StrSlc *sl );
+
+/* Hex */
+Status StrAsm_fmtx_u8 ( StrAsm *sa, u8 value);
+Status StrAsm_fmtx_u16( StrAsm *sa, u16 value);
+Status StrAsm_fmtx_u32( StrAsm *sa, u32 value);
+Status StrAsm_fmtx_u64( StrAsm *sa, u64 value);
+Status StrAsm_fmtx_usize( StrAsm *sa, usize value);
+Status StrAsm_fmtx_s8 ( StrAsm *sa, s8 value);
+Status StrAsm_fmtx_s16( StrAsm *sa, s16 value);
+Status StrAsm_fmtx_s32( StrAsm *sa, s32 value);
+Status StrAsm_fmtx_s64( StrAsm *sa, s64 value);
+Status StrAsm_fmtx_ssize( StrAsm *sa, ssize value);
+
+/* Decimal */
+Status StrAsm_fmtd_u8 ( StrAsm *sa, u8 value);
+Status StrAsm_fmtd_u16( StrAsm *sa, u16 value);
+Status StrAsm_fmtd_u32( StrAsm *sa, u32 value);
+Status StrAsm_fmtd_u64( StrAsm *sa, u64 value);
+Status StrAsm_fmtd_usize( StrAsm *sa, usize value);
+Status StrAsm_fmtd_s8 ( StrAsm *sa, s8 value);
+Status StrAsm_fmtd_s16( StrAsm *sa, s16 value);
+Status StrAsm_fmtd_s32( StrAsm *sa, s32 value);
+Status StrAsm_fmtd_s64( StrAsm *sa, s64 value);
+Status StrAsm_fmtd_ssize( StrAsm *sa, ssize value);
+
+/* File */
+
+#if OS == OS_LINUX
+ STRUCT( File,
+ s32 fd;
+ );
+#else
+ #error File not defined.
+#endif
+
+
+enum FileOpenFlags {
+
+ FILE_ACCESS_READ = ((usize)1 << 1),
+ FILE_ACCESS_WRITE = ((usize)1 << 2),
+ FILE_ACCESS_APPEND = ((usize)1 << 3),
+
+ FILE_ACCESS_MASK = (FILE_ACCESS_READ | FILE_ACCESS_WRITE | FILE_ACCESS_APPEND),
+
+ FILE_EXISTING_OPEN = ((usize)1 << 4),
+ FILE_EXISTING_TRUNCATE = ((usize)1 << 5),
+ FILE_EXISTING_FAIL = ((usize)1 << 6),
+
+ FILE_EXISTING_MASK = (FILE_EXISTING_OPEN | FILE_EXISTING_TRUNCATE | FILE_EXISTING_FAIL),
+
+ FILE_MISSING_CREATE = ((usize)1 << 7),
+ FILE_MISSING_FAIL = ((usize)1 << 8),
+
+ FILE_MISSING_MASK = (FILE_MISSING_CREATE | FILE_MISSING_FAIL),
+
+ FILE_LINK_FOLLOW = ((usize)1 << 9),
+ FILE_LINK_FAIL = ((usize)1 << 10), /* os-dependent option - whatever the os guarantees. O_NOFOLLOW on linux. */
+
+ FILE_LINK_MASK = (FILE_LINK_FOLLOW | FILE_LINK_FAIL),
+
+};
+
+static inline Status File_open_validate_flags( usize flags, Status err_source );
+
+
+Status File_open( const Str *name, usize flags, File *out );
+Status File_close( File *f );
+
+Status File_read( const File *f, usize max_amount, usize *out_amount, u8 *out );
+Status File_write( const File *f, usize amount, usize *out_amount, const u8 *buf );
+
+Status File_seek( const File *f, usize position );
+
+Status File_delete( const Str *name );
+
+STRUCT( FileView,
+ File file;
+ Page *start;
+ usize claimed;
+ usize filesize;
+ usize flags;
+);
+
+enum FileViewFlags {
+ FILEVIEW_OWN_FILE = (1 << 1),
+/* FILEVIEW_PAGE_ALIGNED_EXTEND = (1 << 2), */
+};
+
+Status FileView_from_file( File *file, usize claim_amount, usize flags, FileView *out ); /* if claim_amount == 0 => claims exact filesize */
+Status FileView_from_path( const Str *path, usize claim_amount, usize flags, FileView *out ); /* This is for quick and easy mmaping of files. If you actually want control over the opening flags use FileView_from_file - if you don't */
+
+Status FileView_extend_file( FileView *fv, usize amount ); /* Extend the file's end by amount */
+
+Status FileView_destroy( FileView *fv );
+
+/*=========================== Core functions =================================*/
+
+void terminate(u32 code); /* aka exit */
+void terminate_forced(void); /* force exit, fault, anything that terminates forcefully */
+
+void breakpoint(void); /* raise a debug breakpoint, if possible on the target */
+
+static inline void assert( usize condition ) {
+ if( !condition ) {
+ breakpoint();
+ }
+}
+
+/*=============================== Memory =====================================*/
+#define KiB(n) ((u64)(n) << 10)
+#define MiB(n) ((u64)(n) << 20)
+#define GiB(n) ((u64)(n) << 30)
+#define TiB(n) ((u64)(n) << 40)
+
+static inline void* mem_copy( const void *source, void *destination, u64 len ) {
+ const u8 *src = source;
+ u8 *dst = destination;
+ u64 i = 0;
+
+ for( ; i < len; ++i ) {
+ dst[i] = src[i];
+ }
+
+ return &dst[i];
+}
+
+static inline void* mem_set( void *start, u64 len, u8 value ) {
+ assert(start != 0);
+ u8 *s = start;
+ u64 i = 0;
+
+ for( ; i < len; ++i ) {
+ s[i] = value;
+ }
+
+ return &s[len];
+}
+
+Status mem_claim( u32 page_count, Page **ptr_out); /* Request virtual memory range */
+Status mem_relinquish( Page *start, u32 page_count ); /* Free virtual memory range */
+
+Status mem_occupy( Page *start, u32 page_count ); /* Set up physical backing */
+Status mem_vacate( Page *start, u32 page_count ); /* Allow removal of physical backing */
+
+
+
+/******************************************************************************/
+/* COMMON PLATFORM IMPLEMENTATION */
+/******************************************************************************/
+
+static inline Status File_open_validate_flags( usize flags, Status err_source ) {
+
+ usize existing_flags = flags & FILE_EXISTING_MASK;
+ usize existing_flags_multiple_set = !usize_is_power_of_two( existing_flags );
+
+ usize missing_flags = flags & FILE_MISSING_MASK;
+ usize missing_flags_multiple_set = !usize_is_power_of_two( missing_flags );
+
+ usize link_flags = flags & FILE_LINK_MASK;
+ usize link_flags_multiple_set = !usize_is_power_of_two( link_flags );
+
+ usize write_append_flags = flags & (FILE_ACCESS_WRITE | FILE_ACCESS_APPEND);
+ usize write_append_flags_multiple_set = !usize_is_power_of_two( write_append_flags );
+
+ if( existing_flags_multiple_set |
+ missing_flags_multiple_set |
+ link_flags_multiple_set |
+ (write_append_flags && write_append_flags_multiple_set)
+ ) {
+ DEBUG(breakpoint());
+ return S_FAILURE | ERR_INVALID_ARGUMENT | err_source;
+ }
+
+ return S_SUCCESS;
+}
+
+#if OS == OS_LINUX
+/******************************************************************************/
+/* LINUX PLATFORM IMPLEMENTATION */
+/******************************************************************************/
+
+
+/*============================= Entrypoint ===================================*/
+
+extern u8* linux_startup_sp;
+void entry(void);
+
+/*============================ Linux defines =================================*/
+
+#define LINUX_SYSCALL_ERROR_RANGE_START ((usize)-4095)
+#define LINUX_SYSCALL_ERROR(value) ((usize)value >= LINUX_SYSCALL_ERROR_RANGE_START)
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define EDEADLK 35 /* Resource deadlock would occur */
+#define ENAMETOOLONG 36 /* File name too long */
+#define ENOLCK 37 /* No record locks available */
+#define ENOSYS 38 /* Invalid system call number */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+#define EDEADLOCK EDEADLK
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EFSBADCRC EBADMSG /* Bad CRC detected */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#define ELIBSCN 81 /* .lib section in a.out corrupted */
+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+#define EDQUOT 122 /* Quota exceeded */
+#define ENOMEDIUM 123 /* No medium found */
+#define EMEDIUMTYPE 124 /* Wrong medium type */
+#define ECANCELED 125 /* Operation Canceled */
+#define ENOKEY 126 /* Required key not available */
+#define EKEYEXPIRED 127 /* Key has expired */
+#define EKEYREVOKED 128 /* Key has been revoked */
+#define EKEYREJECTED 129 /* Key was rejected by service */
+#define EOWNERDEAD 130 /* Owner died */
+#define ENOTRECOVERABLE 131 /* State not recoverable */
+#define ERFKILL 132 /* Operation not possible due to RF-kill */
+#define EHWPOISON 133 /* Memory page has hardware error */
+
+/* Copied from some header included by linux/fcntl */
+#define O_RDONLY 00
+#define O_WRONLY 01
+#define O_RDWR 02
+#define O_ACCMODE 03
+#define O_CREAT 0100
+#define O_EXCL 0200
+#define O_NOCTTY 0400
+#define O_TRUNC 01000
+#define O_APPEND 02000
+#define O_NONBLOCK 04000
+#define O_DSYNC 010000
+#define FASYNC 020000
+#define O_DIRECT 040000
+#define O_LARGEFILE 0100000
+#define O_DIRECTORY 0200000
+#define O_NOFOLLOW 0400000
+#define O_NOATIME 01000000
+#define O_CLOEXEC 02000000
+#define __O_SYNC 04000000
+#define O_SYNC (__O_SYNC|O_DSYNC)
+#define O_PATH 010000000
+#define __O_TMPFILE 020000000
+#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#if ARCH == ARCH_X86_64
+struct stat {
+ u64 st_dev;
+ u64 st_ino;
+ u64 st_nlink;
+
+ u32 st_mode;
+ u32 st_uid;
+ u32 st_gid;
+ u32 __pad0;
+
+ u64 st_rdev;
+
+ s64 st_size;
+ s64 st_blksize;
+ s64 st_blocks;
+
+ u64 st_atime;
+ u64 st_atime_nsec;
+ u64 st_mtime;
+ u64 st_mtime_nsec;
+ u64 st_ctime;
+ u64 st_ctime_nsec;
+
+ s64 __unused[3];
+};
+
+#else
+ #error struct stat is not defined
+#endif
+
+#define LINUX_PROT_NONE (0x0)
+#define LINUX_PROT_READ (0x1)
+#define LINUX_PROT_WRITE (0x2)
+#define LINUX_PROT_EXEC (0x4)
+
+#define MMAP_MAP_SHARED (0x1)
+#define MMAP_MAP_PRIVATE (0x2)
+#define MMAP_MAP_SHARED_VALIDATE (0x3)
+#define MMAP_MAP_SHARED_DROPPABLE (0x08)
+#define MMAP_MAP_FIXED (0x10)
+#define MMAP_MAP_ANONYMOUS (0x20)
+
+#define MMAP_MAP_FAILED ((void *)-1)
+
+#define MADV_NORMAL 0
+#define MADV_RANDOM 1
+#define MADV_SEQUENTIAL 2
+#define MADV_WILLNEED 3
+#define MADV_DONTNEED 4
+#define MADV_FREE 8
+#define MADV_REMOVE 9
+#define MADV_DONTFORK 10
+#define MADV_DOFORK 11
+#define MADV_MERGEABLE 12
+#define MADV_UNMERGEABLE 13
+#define MADV_HUGEPAGE 14
+#define MADV_NOHUGEPAGE 15
+#define MADV_DONTDUMP 16
+#define MADV_DODUMP 17
+#define MADV_WIPEONFORK 18
+#define MADV_KEEPONFORK 19
+#define MADV_COLD 20
+#define MADV_PAGEOUT 21
+#define MADV_POPULATE_READ 22
+#define MADV_POPULATE_WRITE 23
+#define MADV_DONTNEED_LOCKED 24
+#define MADV_COLLAPSE 25
+#define MADV_HWPOISON 100
+#define MADV_GUARD_INSTALL 102
+#define MADV_GUARD_REMOVE 103
+
+
+/*============================ System calls ==================================*/
+
+/* System call assembly wrappers */
+ssize linux_syscall1(usize num, usize arg1);
+ssize linux_syscall2(usize num, usize arg1, usize arg2);
+ssize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3);
+ssize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4);
+ssize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5);
+ssize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6);
+
+/* Actual system calls */
+Status linux_read( u32 fd, usize max_amount, usize *out_amount, u8 *out );
+Status linux_write( u32 fd, usize amount, usize *out_amount, const u8 *buf );
+Status linux_open( const u8* path, s32 flags, s32 mode, s32 *out_fd );
+Status linux_close( s32 *fd );
+Status linux_lseek( u32 fd, usize offset, usize whence );
+ssize linux_stat( const char* path, struct stat *statbuf );
+Status linux_fstat( s32 fd, struct stat *statbuf );
+void linux_exit( s32 exitcode );
+Status linux_mmap( usize addr, usize len, usize prot, usize flags, usize fd, usize offset, void **out );
+Status linux_munmap( usize start, usize len );
+Status linux_mprotect( usize start, usize len, usize prot );
+Status linux_madvise( usize start, usize len, s32 behaviour );
+ssize linux_unlink( const u8 *path );
+Status linux_fallocate( s32 fd, s32 mode, usize offset, usize len );
+
+#endif
+
+#endif
+