Commit 005854e
Changed files (13)
platform
memory/linux/memory.h
@@ -0,0 +1,54 @@
+#ifndef NOTLIBC_HEADER_MEMORY_LINUX_MEMORY_INCLUDED
+#define NOTLIBC_HEADER_MEMORY_LINUX_MEMORY_INCLUDED
+
+#include "../../platform/platform.h"
+
+Status mem_claim( u32 page_count, Page **ptr_out) {
+ void* res = (void*)linux_mmap( 0, page_count*sizeof(Page), LINUX_PROT_NONE, MMAP_MAP_PRIVATE | MMAP_MAP_ANONYMOUS, -1, 0 );
+
+ if( LINUX_SYSCALL_ERROR(res) )
+ return S_FAILURE | ERR_MEM_MAP_FAILURE;
+
+ *ptr_out = res;
+ 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 | ERR_PLATFORM | ERR_MEM_UNMAP_FAILURE;
+ }
+
+ return S_SUCCESS;
+}
+
+Status mem_occupy( Page *start, u32 page_count ) {
+ usize res = linux_mprotect( (usize)start, page_count*sizeof(Page), LINUX_PROT_READ | LINUX_PROT_WRITE );
+
+ if( LINUX_SYSCALL_ERROR(res) ) {
+ return S_FAILURE | ERR_PLATFORM | ERR_MEM_SETPERM_FAILURE;
+ }
+
+ return S_SUCCESS;
+}
+
+Status mem_vacate( Page *start, u32 page_count ) {
+ usize amount = page_count*sizeof(Page);
+
+ usize res = linux_mprotect( (usize)start, amount, LINUX_PROT_NONE );
+
+ if( LINUX_SYSCALL_ERROR(res) ) {
+ return S_FAILURE | ERR_PLATFORM | ERR_MEM_SETPERM_FAILURE;
+ }
+
+ res = linux_madvise( (usize)start, amount, MADV_DONTNEED);
+
+ if( LINUX_SYSCALL_ERROR(res) ) {
+ return S_FAILURE | ERR_PLATFORM | ERR_MEM_SETHINT_FAILURE;
+ }
+
+ return S_SUCCESS;
+}
+
+#endif
memory/arena.h
@@ -0,0 +1,77 @@
+#ifndef NOTLIBC_HEADER_MEMORY_ARENA_INCLUDED
+#define NOTLIBC_HEADER_MEMORY_ARENA_INCLUDED
+
+#include "../platform/platform.h"
+#include "../util/mathops.h"
+#include "./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 */
+)
+
+STRUCT( HeapEntry,
+ DEBUG( usize checksum; ) /* for detecting heap corruption and bad pointers */
+ usize size;
+ struct _HeapEntry *next;
+ u8 data[]; /* The above pointer should gives a sane alignment here despite this being u8 */
+)
+
+STRUCT( Heap,
+ Arena arena; /* Heap is built on top of arena. It's just an arena + a freelist with metadata */
+ HeapEntry *freelist;
+)
+
+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 );
+
+
+IMPL(
+
+ 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_give( Arena *a, usize amount ) {
+ if( amount > a->taken ) return S_FAILURE | ERR_OUT_OF_BOUND;
+ a->taken -= amount;
+ return S_SUCCESS;
+ }
+
+)
+
+#endif
memory/memory.h
@@ -0,0 +1,51 @@
+#ifndef NOTLIBC_HEADER_MEMORY_MEMORY_INCLUDED
+#define NOTLIBC_HEADER_MEMORY_MEMORY_INCLUDED
+
+#include "../platform/platform.h"
+
+#define PLATFORM_MEMORY_HEADER \
+ LINUX("./linux/memory.h") \
+ WINDOWS("./windows/memory.h")
+
+#include PLATFORM_MEMORY_HEADER
+
+/* 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( void *source, void *destination, u64 len ) {
+ 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);
+ assert(len != 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 */
+
+#endif
platform/common/build.h
@@ -30,6 +30,8 @@
#ifdef NOTLIBC_IMPLEMENT
#define IMPL(...) __VA_ARGS__
+#else
+#define IMPL(...)
#endif
#endif
platform/linux/corefunc.h
@@ -16,6 +16,6 @@ static inline void terminate_forced(void) {
#include "./syscalls.h"
static inline void terminate(u32 code) {
- linux_exit(*(i32*)&code);
+ linux_exit((s32)code);
UNREACHABLE;
}
platform/linux/coretypes.h
@@ -8,21 +8,31 @@ typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
-typedef signed char i8;
-typedef signed short i16;
-typedef signed int i32;
-typedef signed long long i64;
+typedef signed char s8;
+typedef signed short s16;
+typedef signed int s32;
+typedef signed long long s64;
typedef float f32;
typedef double f64;
X86_64(
typedef u64 usize;
+ typedef s64 isize;
+
+ typedef struct _Page {
+ u8 data[4096];
+ } Page;
)
I386(
typedef u32 usize;
+ typedef s32 isize;
+
+ typedef struct _Page {
+ u8 data[4096];
+ } Page;
)
#endif
platform/linux/syscall_wrappers_gcclike.h
@@ -6,7 +6,7 @@
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 usize linux_syscall1(usize num, usize arg1) {
+ static inline isize linux_syscall1(usize num, usize arg1) {
register usize ret __asm__("rax") = num;
register usize a1 __asm__("rdi") = arg1;
@@ -19,7 +19,7 @@ X86_64(
);
return ret;
}
- static inline usize linux_syscall2(usize num, usize arg1, usize arg2) {
+ static inline isize linux_syscall2(usize num, usize arg1, usize arg2) {
register usize ret __asm__("rax") = num;
register usize a1 __asm__("rdi") = arg1;
@@ -33,7 +33,7 @@ X86_64(
);
return ret;
}
- static inline usize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
+ static inline isize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
register usize ret __asm__("rax") = num;
register usize a1 __asm__("rdi") = arg1;
@@ -48,7 +48,7 @@ X86_64(
);
return ret;
}
- static inline usize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
+ static inline isize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
register usize ret __asm__("rax") = num;
register usize a1 __asm__("rdi") = arg1;
@@ -65,7 +65,7 @@ X86_64(
return ret;
}
- static inline usize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
+ static inline isize 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;
@@ -83,7 +83,7 @@ X86_64(
return ret;
}
- static inline usize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
+ static inline isize 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;
@@ -103,7 +103,6 @@ X86_64(
}
)
-
I386(
ERROR("Linux syscalls not implemented for I386.");
)
platform/linux/syscall_wrappers_generic.h
@@ -6,7 +6,7 @@
X86_64(
- static inline usize linux_syscall1(usize num, usize arg1) {
+ static inline isize linux_syscall1(usize num, usize arg1) {
__asm__ volatile (
"mov %[a1], %%rdi\n"
"syscall\n"
@@ -17,7 +17,7 @@ X86_64(
return num;
}
- static inline usize linux_syscall2(usize num, usize arg1, usize arg2) {
+ static inline isize linux_syscall2(usize num, usize arg1, usize arg2) {
__asm__ volatile (
"mov %[a1], %%rdi\n"
"mov %[a2], %%rsi\n"
@@ -28,7 +28,7 @@ X86_64(
);
return num;
}
- static inline usize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
+ static inline isize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3) {
__asm__ volatile (
"mov %[a1], %%rdi\n"
"mov %[a2], %%rsi\n"
@@ -40,7 +40,7 @@ X86_64(
);
return num;
}
- static inline usize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
+ static inline isize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4) {
__asm__ volatile (
"mov %[a1], %%rdi\n"
"mov %[a2], %%rsi\n"
@@ -53,13 +53,14 @@ X86_64(
);
return num;
}
- static inline usize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
+ static inline isize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5) {
__asm__ volatile (
"mov %[a1], %%rdi\n"
"mov %[a2], %%rsi\n"
"mov %[a3], %%rdx\n"
"mov %[a4], %%r10\n"
"mov %[a5], %%r8\n"
+ "syscall\n"
: [num]"+a"(num)
: [a1]"r"(arg1), [a2]"r"(arg2), [a3]"r"(arg3), [a4]"r"(arg4), [a5]"r"(arg5)
: "rcx", "r11", "memory"
@@ -67,7 +68,7 @@ X86_64(
return num;
}
- static inline usize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
+ static inline isize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6) {
__asm__ volatile (
"mov %[a1], %%rdi\n"
"mov %[a2], %%rsi\n"
platform/linux/syscalls.h
@@ -5,12 +5,12 @@
#include "../common/compiler.h"
#include "./coretypes.h"
-static inline usize linux_syscall1(usize num, usize arg1);
-static inline usize linux_syscall2(usize num, usize arg1, usize arg2);
-static inline usize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3);
-static inline usize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4);
-static inline usize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5);
-static inline usize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5, usize arg6);
+static inline isize linux_syscall1(usize num, usize arg1);
+static inline isize linux_syscall2(usize num, usize arg1, usize arg2);
+static inline isize linux_syscall3(usize num, usize arg1, usize arg2, usize arg3);
+static inline isize linux_syscall4(usize num, usize arg1, usize arg2, usize arg3, usize arg4);
+static inline isize linux_syscall5(usize num, usize arg1, usize arg2, usize arg3, usize arg4, usize arg5);
+static inline isize 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"
@@ -18,28 +18,85 @@ static inline usize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3
#include "./syscall_wrappers_generic.h"
#endif
+#define LINUX_SYSCALL_ERROR_START ((usize)-4095)
+#define LINUX_SYSCALL_ERROR(value) ((usize)value >= LINUX_SYSCALL_ERROR_START)
-
-static inline usize linux_read( u32 fd, u8* buf, usize count ) {
+static inline isize linux_read( u32 fd, u8* buf, usize count ) {
return linux_syscall3( 0, fd, (usize)buf, count );
}
-static inline usize linux_write( u32 fd, const u8* buf, usize count ) {
+static inline isize linux_write( u32 fd, const u8* buf, usize count ) {
return linux_syscall3( 1, fd, (usize)buf, count );
}
-static inline usize linux_open( u8* path, i32 flags, i32 mode ) {
- return linux_syscall3( 2, (usize)path, *(u32*)&flags, *(u32*)&mode);
+static inline isize linux_open( const u8* path, s32 flags, s32 mode ) {
+ return linux_syscall3( 2, (usize)path, (usize)flags, (usize)&mode);
}
-static inline usize linux_close( u32 fd ) {
+static inline isize linux_close( u32 fd ) {
return linux_syscall1( 3, fd );
}
-static inline void linux_exit( i32 exitcode ) {
+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_ANONYMOUS 0x20
+
+#define MMAP_MAP_FAILED ((void *)-1)
+
+static inline isize linux_mmap( usize addr, usize len, usize prot, usize flags, usize fd, usize offset ) {
+ return linux_syscall6( 9, addr, len, prot, flags, fd, offset );
+}
+
+static inline isize linux_munmap( usize start, usize len ) {
+ return linux_syscall2( 11, start, len );
+}
+
+static inline isize linux_mprotect( usize start, usize len, usize prot ) {
+ return linux_syscall3( 11, start, len, prot );
+}
+
+
+#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 isize linux_madvise( usize start, usize len, s32 behaviour ) {
+ return linux_syscall3( 11, start, len, (usize)(u32)behaviour );
+}
#endif
platform/platform.h
@@ -1,3 +1,6 @@
+#ifndef NOTLIBC_HEADER_PLATFORM_PLATFORM_INCLUDED
+#define NOTLIBC_HEADER_PLATFORM_PLATFORM_INCLUDED
+
#include "./common/build.h"
#include "./common/compiler.h"
#include "./common/arch.h"
@@ -15,14 +18,75 @@ ASSERT( sizeof( u16 ) == 2 );
ASSERT( sizeof( u32 ) == 4 );
ASSERT( sizeof( u64 ) == 8 );
-ASSERT( sizeof( i8 ) == 1 );
-ASSERT( sizeof( i16 ) == 2 );
-ASSERT( sizeof( i32 ) == 4 );
-ASSERT( sizeof( i64 ) == 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 );
+/* Error handling types and macros. */
+
+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 {
+
+ ERR_ARG_1 = (0x1 << 20),
+ ERR_ARG_2 = (0x2 << 20),
+ ERR_ARG_3 = (0x3 << 20),
+ ERR_ARG_4 = (0x4 << 20),
+ ERR_ARG_5 = (0x5 << 20),
+ ERR_ARG_6 = (0x6 << 20),
+ ERR_ARG_7 = (0x7 << 20),
+ ERR_ARG_8 = (0x8 << 20),
+ ERR_ARG_9 = (0x9 << 20),
+ ERR_ARG_10 = (0xa << 20),
+ ERR_ARG_11 = (0xb << 20),
+ ERR_ARG_12 = (0xc << 20),
+
+ ERR_PLATFORM = (0x10 << 20), /* The error resulted inside platform code. */
+};
+
+#define S_REASON_MASK (0xfffff)
+enum _ErrorReasons {
+ ERR_GENERIC = 0, /* Even numbers are for the implementations, odd are for user-defined errors */
+
+ ERR_INVALID_ARGUMENT = 2,
+
+ ERR_OVERFLOW = 4,
+
+ ERR_OUT_OF_BOUND = 6, /* a value is out of bounds or the operation would violate certain bounds with the current arguments */
+
+ ERR_MEM_MAP_FAILURE = 0x100,
+ ERR_MEM_UNMAP_FAILURE = 0x102,
+ ERR_MEM_SETPERM_FAILURE = 0x104,
+ ERR_MEM_SETHINT_FAILURE = 0x106,
+
+};
+
+
+#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)
+
/* Core platform functions */
static inline void terminate(u32 code); /* aka exit */
@@ -30,9 +94,16 @@ static inline void terminate_forced(void); /* force exit, fault, anything that t
static inline void breakpoint(void); /* raise a debug breakpoint, if possible on the target */
+static inline void assert( usize condition ) {
+ if( !condition ) {
+ breakpoint();
+ }
+}
#define HEADER_PLATFORM_COREFUNC \
LINUX("linux/corefunc.h") \
WINDOWS("windows/corefunc.h")
#include HEADER_PLATFORM_COREFUNC
+
+#endif
util/mathops.h
@@ -0,0 +1,31 @@
+#ifndef NOTLIBC_HEADER_UTIL_MATHOPS_INCLUDED
+#define NOTLIBC_HEADER_UTIL_MATHOPS_INCLUDED
+
+#include "../platform/platform.h"
+#include "./safemath.h"
+
+
+// TODO: Add overflow and underflow checks for both signed and unsigned, as well as for gcc-likes and generic ones with portable C checks.
+
+
+#define GEN_ROUND_UP(T) \
+ static inline Status T##_round_up( T number, T multiple, T *out ) { \
+ if( multiple == 0 ) return S_FAILURE | ERR_ARG_3 | ERR_INVALID_ARGUMENT; \
+ T rem = number%multiple; \
+ \
+ if( rem == 0 ) { \
+ *out = number; \
+ } else { \
+ TRY( T##_add( number, multiple - rem, out ) ); \
+ } \
+ return S_SUCCESS; \
+ }
+
+
+
+GEN_ROUND_UP(u8)
+GEN_ROUND_UP(u16)
+GEN_ROUND_UP(u32)
+GEN_ROUND_UP(u64)
+
+#endif
util/safemath.h
@@ -0,0 +1,13 @@
+#ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_INCLUDED
+#define NOTLIBC_HEADER_UTIL_SAFEMATH_INCLUDED
+
+#include "../platform/common/compiler.h"
+
+#define SAFEMATH_HEADER \
+ GCCLIKE("./safemath_gcclike.h") \
+ TCC("./safemath_generic.h") \
+ MSVC("./safemath_generic.h")
+
+#include SAFEMATH_HEADER
+
+#endif
util/safemath_gcclike.h
@@ -0,0 +1,25 @@
+#ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_GCCLIKE_INCLUDED
+#define NOTLIBC_HEADER_UTIL_SAFEMATH_GCCLIKE_INCLUDED
+
+#include "../platform/platform.h"
+
+#define GEN_ADD(T) \
+ static inline Status T##_add( T n1, T n2, T*out ) { \
+ if( __builtin_add_overflow(n1, n2, out) ) { \
+ return S_FAILURE | ERR_OVERFLOW;\
+ } \
+ return S_SUCCESS; \
+ } \
+
+
+GEN_ADD(u8)
+GEN_ADD(u16)
+GEN_ADD(u32)
+GEN_ADD(u64)
+
+GEN_ADD(s8)
+GEN_ADD(s16)
+GEN_ADD(s32)
+GEN_ADD(s64)
+
+#endif