matter.c

Cross-platform minimalist libc
git clone git://git.finwo.net/lib/matter.c
Log | Files | Refs | README | LICENSE

commit 8af08a2c4b42e48c04d966781316ad36c4a5a47d
parent b199ea8bf5b300e338141994b680e3ddab853af8
Author: Yersa Nordman <finwo@pm.me>
Date:   Sat, 27 May 2023 00:29:54 +0200

Copy old code, redefined exports

Diffstat:
AREADME.md | 6++++++
Aconfig.mk | 2++
Ainclude/bits/alltypes.h | 23+++++++++++++++++++++++
Ainclude/float.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/malloc.h | 11+++++++++++
Ainclude/matter/page_size.h | 11+++++++++++
Ainclude/stdarg.h | 20++++++++++++++++++++
Ainclude/stdbool.h | 14++++++++++++++
Ainclude/stddef.h | 16++++++++++++++++
Ainclude/stdint.h | 316+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/stdlib.h | 10++++++++++
Ainclude/string.h | 11+++++++++++
Ainclude/unistd.h | 9+++++++++
Mpackage.ini | 12+++++++++++-
Asrc/malloc/malloc.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/prng/rand.c | 13+++++++++++++
Asrc/string/memcmp.c | 14++++++++++++++
Asrc/string/memcpy.c | 10++++++++++
Asrc/string/memset.c | 8++++++++
Asrc/string/strlen.c | 15+++++++++++++++
Asrc/unistd/brk.c | 31+++++++++++++++++++++++++++++++
21 files changed, 721 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md @@ -0,0 +1,6 @@ +finwo/matter +============ + +Just a small embeddable standard C library for your wasm projects, because that stuff matters + + diff --git a/config.mk b/config.mk @@ -0,0 +1,2 @@ +override CFLAGS+=-nostdinc -nobuiltininc +SRC+=$(wildcard __DIRNAME/*/*.c) diff --git a/include/bits/alltypes.h b/include/bits/alltypes.h @@ -0,0 +1,23 @@ +#ifndef _BITS_ALLTYPES_H_ +#define _BITS_ALLTYPES_H_ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if __WORDSIZE == 32 +#define _Addr int +#endif + +#if __WORDSIZE == 64 +#define _Addr long +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _BITS_ALLTYPES_H_ + diff --git a/include/float.h b/include/float.h @@ -0,0 +1,50 @@ +#ifndef _FLOAT_H_ +#define _FLOAT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int __flt_rounds(void); +#define FLT_ROUNDS (__flt_rounds()) + +#define FLT_RADIX 2 + +#define FLT_TRUE_MIN 1.40129846432481707092e-45F +#define FLT_MIN 1.17549435082228750797e-38F +#define FLT_MAX 3.40282346638528859812e+38F +#define FLT_EPSILON 1.1920928955078125e-07F + +#define FLT_MANT_DIG 24 +#define FLT_MIN_EXP (-125) +#define FLT_MAX_EXP 128 +#define FLT_HAS_SUBNORM 1 + +#define FLT_DIG 6 +#define FLT_DECIMAL_DIG 9 +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_10_EXP 38 + +#define DBL_TRUE_MIN 4.94065645841246544177e-324 +#define DBL_MIN 2.22507385850720138309e-308 +#define DBL_MAX 1.79769313486231570815e+308 +#define DBL_EPSILON 2.22044604925031308085e-16 + +#define DBL_MANT_DIG 53 +#define DBL_MIN_EXP (-1021) +#define DBL_MAX_EXP 1024 +#define DBL_HAS_SUBNORM 1 + +#define DBL_DIG 15 +#define DBL_DECIMAL_DIG 17 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_10_EXP 308 + +#define LDBL_HAS_SUBNORM 1 +#define LDBL_DECIMAL_DIG DECIMAL_DIG + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FLOAT_H_ diff --git a/include/malloc.h b/include/malloc.h @@ -0,0 +1,11 @@ +#ifndef _MALLOC_H_ +#define _MALLOC_H_ + +#include <stddef.h> + +void *malloc(size_t n); +void free(void *p); +void *realloc(void *ptr, size_t size); +void *calloc(size_t nelem, size_t elsize); + +#endif // _MALLOC_H_ diff --git a/include/matter/page_size.h b/include/matter/page_size.h @@ -0,0 +1,11 @@ +#ifndef _MATTER_PAGE_SIZE_H_ +#define _MATTER_PAGE_SIZE_H_ + +#define PAGE_SIZE (4*1024) + +#ifdef __wasm__ +#undef PAGE_SIZE +#define PAGE_SIZE (64*1024) +#endif + +#endif diff --git a/include/stdarg.h b/include/stdarg.h @@ -0,0 +1,20 @@ +#ifndef _STDARG_H_ +#define _STDARG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef __builtin_va_list va_list; +typedef __builtin_va_list __isoc_va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _STDARG_H_ diff --git a/include/stdbool.h b/include/stdbool.h @@ -0,0 +1,14 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus + +#define true 1 +#define false 0 +#define bool _Bool + +#define __bool_true_false_are_defined 1 + +#endif + +#endif diff --git a/include/stddef.h b/include/stddef.h @@ -0,0 +1,16 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#include <bits/alltypes.h> + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +typedef unsigned _Addr size_t; +typedef _Addr ssize_t; +typedef _Addr ptrdiff_t; + +#endif // _STDDEF_H_ diff --git a/include/stdint.h b/include/stdint.h @@ -0,0 +1,316 @@ +/* Copyright (C) 1997,1998,1999,2000,2001,2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* + * ISO C99: 7.18 Integer types <stdint.h> + */ + +#ifndef _STDINT_H_ +#define _STDINT_H_ + +/* Exact integral types. */ + +/* Signed. */ + +/* There is some amount of overlap with <sys/types.h> as known by inet code */ +#ifndef __int8_t_defined +# define __int8_t_defined +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +# if __WORDSIZE == 64 +typedef long int int64_t; +# else +__extension__ +typedef long long int int64_t; +# endif +#endif + +/* Unsigned. */ +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +#ifndef __uint32_t_defined +typedef unsigned int uint32_t; +# define __uint32_t_defined +#endif +#if __WORDSIZE == 64 +typedef unsigned long int uint64_t; +#else +__extension__ +typedef unsigned long long int uint64_t; +#endif + + +/* Small types. */ + +/* Signed. */ +typedef signed char int_least8_t; +typedef short int int_least16_t; +typedef int int_least32_t; +#if __WORDSIZE == 64 +typedef long int int_least64_t; +#else +__extension__ +typedef long long int int_least64_t; +#endif + +/* Unsigned. */ +typedef unsigned char uint_least8_t; +typedef unsigned short int uint_least16_t; +typedef unsigned int uint_least32_t; +#if __WORDSIZE == 64 +typedef unsigned long int uint_least64_t; +#else +__extension__ +typedef unsigned long long int uint_least64_t; +#endif + + +/* Fast types. */ + +/* Signed. */ +typedef signed char int_fast8_t; +#if __WORDSIZE == 64 +typedef long int int_fast16_t; +typedef long int int_fast32_t; +typedef long int int_fast64_t; +#else +typedef int int_fast16_t; +typedef int int_fast32_t; +__extension__ +typedef long long int int_fast64_t; +#endif + +/* Unsigned. */ +typedef unsigned char uint_fast8_t; +#if __WORDSIZE == 64 +typedef unsigned long int uint_fast16_t; +typedef unsigned long int uint_fast32_t; +typedef unsigned long int uint_fast64_t; +#else +typedef unsigned int uint_fast16_t; +typedef unsigned int uint_fast32_t; +__extension__ +typedef unsigned long long int uint_fast64_t; +#endif + + +/* Types for `void *' pointers. */ +#if __WORDSIZE == 64 +# ifndef __intptr_t_defined +typedef long int intptr_t; +# define __intptr_t_defined +# endif +typedef unsigned long int uintptr_t; +#else +# ifndef __intptr_t_defined +typedef int intptr_t; +# define __intptr_t_defined +# endif +typedef unsigned int uintptr_t; +#endif + + +/* Largest integral types. */ +#if __WORDSIZE == 64 +typedef long int intmax_t; +typedef unsigned long int uintmax_t; +#else +__extension__ +typedef long long int intmax_t; +__extension__ +typedef unsigned long long int uintmax_t; +#endif + + +/* The ISO C99 standard specifies that in C++ implementations these + macros should only be defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_LIMIT_MACROS + +# if __WORDSIZE == 64 +# define __INT64_C(c) c ## L +# define __UINT64_C(c) c ## UL +# else +# define __INT64_C(c) c ## LL +# define __UINT64_C(c) c ## ULL +# endif + +/* Limits of integral types. */ + +/* Minimum of signed integral types. */ +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types. */ +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +# define INT64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types. */ +# define UINT8_MAX (255) +# define UINT16_MAX (65535) +# define UINT32_MAX (4294967295U) +# define UINT64_MAX (__UINT64_C(18446744073709551615)) + + +/* Minimum of signed integral types having a minimum size. */ +# define INT_LEAST8_MIN (-128) +# define INT_LEAST16_MIN (-32767-1) +# define INT_LEAST32_MIN (-2147483647-1) +# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types having a minimum size. */ +# define INT_LEAST8_MAX (127) +# define INT_LEAST16_MAX (32767) +# define INT_LEAST32_MAX (2147483647) +# define INT_LEAST64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types having a minimum size. */ +# define UINT_LEAST8_MAX (255) +# define UINT_LEAST16_MAX (65535) +# define UINT_LEAST32_MAX (4294967295U) +# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615)) + + +/* Minimum of fast signed integral types having a minimum size. */ +# define INT_FAST8_MIN (-128) +# if __WORDSIZE == 64 +# define INT_FAST16_MIN (-9223372036854775807L-1) +# define INT_FAST32_MIN (-9223372036854775807L-1) +# else +# define INT_FAST16_MIN (-2147483647-1) +# define INT_FAST32_MIN (-2147483647-1) +# endif +# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of fast signed integral types having a minimum size. */ +# define INT_FAST8_MAX (127) +# if __WORDSIZE == 64 +# define INT_FAST16_MAX (9223372036854775807L) +# define INT_FAST32_MAX (9223372036854775807L) +# else +# define INT_FAST16_MAX (2147483647) +# define INT_FAST32_MAX (2147483647) +# endif +# define INT_FAST64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of fast unsigned integral types having a minimum size. */ +# define UINT_FAST8_MAX (255) +# if __WORDSIZE == 64 +# define UINT_FAST16_MAX (18446744073709551615UL) +# define UINT_FAST32_MAX (18446744073709551615UL) +# else +# define UINT_FAST16_MAX (4294967295U) +# define UINT_FAST32_MAX (4294967295U) +# endif +# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615)) + + +/* Values to test for integral types holding `void *' pointer. */ +# if __WORDSIZE == 64 +# define INTPTR_MIN (-9223372036854775807L-1) +# define INTPTR_MAX (9223372036854775807L) +# define UINTPTR_MAX (18446744073709551615UL) +# else +# define INTPTR_MIN (-2147483647-1) +# define INTPTR_MAX (2147483647) +# define UINTPTR_MAX (4294967295U) +# endif + + +/* Minimum for largest signed integral type. */ +# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum for largest signed integral type. */ +# define INTMAX_MAX (__INT64_C(9223372036854775807)) + +/* Maximum for largest unsigned integral type. */ +# define UINTMAX_MAX (__UINT64_C(18446744073709551615)) + +/* Limits of other integer types. */ + +/* Limits of `ptrdiff_t' type. */ +# if __WORDSIZE == 64 +# define PTRDIFF_MIN (-9223372036854775807L-1) +# define PTRDIFF_MAX (9223372036854775807L) +# else +# define PTRDIFF_MIN (-2147483647-1) +# define PTRDIFF_MAX (2147483647) +# endif + +/* Limits of `sig_atomic_t'. */ +# define SIG_ATOMIC_MIN (-2147483647-1) +# define SIG_ATOMIC_MAX (2147483647) + +/* Limit of `size_t' type. */ +# if __WORDSIZE == 64 +# define SIZE_MAX (18446744073709551615UL) +# else +# define SIZE_MAX (4294967295U) +# endif + +#ifdef __UCLIBC_HAS_WCHAR__ +/* Limits of `wchar_t'. */ +# ifndef WCHAR_MIN +/* These constants might also be defined in <wchar.h>. */ +# define WCHAR_MIN __WCHAR_MIN +# define WCHAR_MAX __WCHAR_MAX +# endif + +/* Limits of `wint_t'. */ +# define WINT_MIN (0u) +# define WINT_MAX (4294967295u) +#endif /* __UCLIBC_HAS_WCHAR__ */ + +#endif /* C++ && limit macros */ + + +/* The ISO C99 standard specifies that in C++ implementations these + should only be defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS + +/* Signed. */ +# define INT8_C(c) c +# define INT16_C(c) c +# define INT32_C(c) c +# if __WORDSIZE == 64 +# define INT64_C(c) c ## L +# else +# define INT64_C(c) c ## LL +# endif + +/* Unsigned. */ +# define UINT8_C(c) c +# define UINT16_C(c) c +# define UINT32_C(c) c ## U +# if __WORDSIZE == 64 +# define UINT64_C(c) c ## UL +# else +# define UINT64_C(c) c ## ULL +# endif + +/* Maximal type. */ +# if __WORDSIZE == 64 +# define INTMAX_C(c) c ## L +# define UINTMAX_C(c) c ## UL +# else +# define INTMAX_C(c) c ## LL +# define UINTMAX_C(c) c ## ULL +# endif + +#endif /* C++ && constant macros */ + +#endif // _STDINT_H_ diff --git a/include/stdlib.h b/include/stdlib.h @@ -0,0 +1,10 @@ +#ifndef _STDLIB_H_ +#define _STDLIB_H_ + +#include <stdint.h> +#include <malloc.h> + +void srand(unsigned s); +int rand(void); + +#endif // _STDLIB_H_ diff --git a/include/string.h b/include/string.h @@ -0,0 +1,11 @@ +#ifndef _STRING_H_ +#define _STRING_H_ + +#include <stddef.h> + +int memcmp (const void *str1, const void *str2, int count); +void *memcpy (void *dest, const void *src, size_t len); +void *memset (void *dest, int val, size_t len); +static unsigned int strlen(const char *s); + +#endif // _STRING_H_ diff --git a/include/unistd.h b/include/unistd.h @@ -0,0 +1,9 @@ +#ifndef _UNISTD_H_ +#define _UNISTD_H_ + +#include <stddef.h> + +int brk(void *addr); +void *sbrk(ssize_t increment); + +#endif // _UNISTD_H_ diff --git a/package.ini b/package.ini @@ -3,4 +3,14 @@ name=finwo/matter [export] config.mk=config.mk -include/finwo/matter.h=src/matter.h +include/bits/alltypes.h=include/bits/alltypes.h +include/matter/page_size.h=include/matter/page_size.h +include/float.h=include/float.h +include/malloc.h=include/malloc.h +include/stdarg.h=include/stdarg.h +include/stdbool.h=include/stdbool.h +include/stddef.h=include/stddef.h +include/stdint.h=include/stdint.h +include/stdlib.h=include/stdlib.h +include/string.h=include/string.h +include/unistd.h=include/unistd.h diff --git a/src/malloc/malloc.c b/src/malloc/malloc.c @@ -0,0 +1,120 @@ +#include <malloc.h> +#include <string.h> +#include <unistd.h> + +// Implementation copied from https://danluu.com/malloc-tutorial/ + +struct block_meta { + size_t size; + struct block_meta *next; + int free; +}; + +#define META_SIZE sizeof(struct block_meta) + +void *global_base = NULL; + +struct block_meta *find_free_block(struct block_meta **last, size_t size) { + struct block_meta *current = global_base; + while (current && !(current->free && current->size >= size)) { + *last = current; + current = current->next; + } + return current; +} + +struct block_meta *request_space(struct block_meta* last, size_t size) { + struct block_meta *block; + block = sbrk(0); + void *request = sbrk(size + META_SIZE); + // assert((void*)block == request); // Not thread safe. + if (request == (void*) -1) { + return NULL; // sbrk failed. + } + + if (last) { // NULL on first request. + last->next = block; + } + block->size = size; + block->next = NULL; + block->free = 0; + return block; +} + + +void *malloc(size_t size) { + struct block_meta *block; + // TODO: align size? + + if (size <= 0) { + return NULL; + } + + if (!global_base) { // First call. + block = request_space(NULL, size); + if (!block) { + return NULL; + } + global_base = block; + } else { + struct block_meta *last = global_base; + block = find_free_block(&last, size); + if (!block) { // Failed to find free block. + block = request_space(last, size); + if (!block) { + return NULL; + } + } else { // Found free block + // TODO: consider splitting block here. + block->free = 0; + } + } + + return(block+1); +} + +struct block_meta *get_block_ptr(void *ptr) { + return (struct block_meta*)ptr - 1; +} + +void free(void *ptr) { + if (!ptr) { + return; + } + + // TODO: consider merging blocks once splitting blocks is implemented. + struct block_meta* block_ptr = get_block_ptr(ptr); + // assert(block_ptr->free == 0); + block_ptr->free = 1; +} + +void *realloc(void *ptr, size_t size) { + if (!ptr) { + // NULL ptr. realloc should act like malloc. + return malloc(size); + } + + struct block_meta* block_ptr = get_block_ptr(ptr); + if (block_ptr->size >= size) { + // We have enough space. Could free some once we implement split. + return ptr; + } + + // Need to really realloc. Malloc new space and free old space. + // Then copy old data to new space. + void *new_ptr; + new_ptr = malloc(size); + if (!new_ptr) { + return NULL; // TODO: set errno on failure. + } + memcpy(new_ptr, ptr, block_ptr->size); + free(ptr); + return new_ptr; +} + +void *calloc(size_t nelem, size_t elsize) { + size_t size = nelem * elsize; // TODO: check for overflow. + void *ptr = malloc(size); + memset(ptr, 0, size); + return ptr; +} diff --git a/src/prng/rand.c b/src/prng/rand.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include <stdint.h> + +static uint64_t seed; + +void srand(unsigned s) { + seed = s-1; +} + +int rand(void) { + seed = 6364136223846793005ULL*seed + 1; + return seed>>33; +} diff --git a/src/string/memcmp.c b/src/string/memcmp.c @@ -0,0 +1,14 @@ +#include <string.h> + +int memcmp (const void *str1, const void *str2, int count) { + const unsigned char *s1 = str1; + const unsigned char *s2 = str2; + + while (count-- > 0) { + if (*s1++ != *s2++) { + return s1[-1] < s2[-1] ? -1 : 1; + } + } + + return 0; +} diff --git a/src/string/memcpy.c b/src/string/memcpy.c @@ -0,0 +1,10 @@ +#include <string.h> + +void * memcpy (void *dest, const void *src, size_t len) { + char *d = dest; + const char *s = src; + while (len--) { + *d++ = *s++; + } + return dest; +} diff --git a/src/string/memset.c b/src/string/memset.c @@ -0,0 +1,8 @@ +#include <string.h> + +void * memset (void *dest, int val, size_t len) { + unsigned char *ptr = dest; + while (len-- > 0) + *ptr++ = val; + return dest; +} diff --git a/src/string/strlen.c b/src/string/strlen.c @@ -0,0 +1,15 @@ +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static unsigned int strlen(const char *s) { + unsigned int len = 0; + while (s[len] != '\0') len++; + return len; +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/unistd/brk.c b/src/unistd/brk.c @@ -0,0 +1,31 @@ +#include <stddef.h> +#include <unistd.h> + +#include <matter/page_size.h> + + +extern unsigned char __heap_base; +void *break_pointer = &__heap_base; + +int brk(void *addr) { + break_pointer = addr; + return 0; +} + +#ifdef __wasm__ + +void * sbrk(ssize_t increment) { + size_t current_pages = __builtin_wasm_memory_size(0); + void *heap_limit = (void *)(current_pages * PAGE_SIZE); + + void *ret = break_pointer; + break_pointer += increment; + + if (break_pointer > heap_limit) { + __builtin_wasm_memory_grow(0, ((break_pointer - heap_limit) / PAGE_SIZE) + 1); + } + + return ret; +} + +#endif // __wasm__