meta: move photon/libc to root

This commit is contained in:
2026-02-08 20:45:25 +00:00
parent f00e74260d
commit 345a37962e
140 changed files with 0 additions and 0 deletions

46
libc/ctype/ctype.c Normal file
View File

@@ -0,0 +1,46 @@
#include <stdbool.h>
static unsigned int random_seed = 53455346;
int isupper(int c) { return (c >= 65 && c <= 90); }
int islower(int c) { return (c >= 97 && c <= 122); }
int toupper(int c) {
if (!islower(c)) {
return c;
}
return c - 32;
}
int tolower(int c) {
if (!isupper(c)) {
return c;
}
return c + 32;
}
int isdigit(int c) { return (c >= 48 && c <= 57); }
int isalpha(int c) { return (c >= 65 && c <= 90) || (c >= 97 && c <= 122); }
int isalnum(int c) { return isalpha(c) | isdigit(c); }
int iscntrl(int c) { return (c <= 31) || (c == 127); }
int isprint(int c) { return (c >= 32 && c <= 126) || (c >= 128 && c <= 254); }
int isgraph(int c) { return isprint(c) && c != 32; }
int ispunct(int c) { return isgraph(c) && !isalnum(c); }
int isspace(int c) {
return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\v') ||
(c == '\f') || (c == '\r');
}
int isxdigit(int c) {
return isdigit(c) || (c >= 65 && c <= 70) || (c >= 97 && c <= 102);
}

9
libc/errno/errno.c Normal file
View File

@@ -0,0 +1,9 @@
/* XXX This isn't thread safe */
static int __errno = 0;
int *__errno_location(void)
{
return &__errno;
}

8
libc/include/assert.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef PHOTON_ASSERT_H_
#define PHOTON_ASSERT_H_
#define assert(x) if (!(x)) { __assert_fail(#x, __FUNCTION__, __FILE__, __LINE__); }
extern void _Noreturn __assert_fail(const char *, const char *, const char *, int);
#endif

27
libc/include/ctype.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef TYPES_H_
#define TYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
extern int isalnum(int c);
extern int isalpha(int c);
extern int iscntrl(int c);
extern int isdigit(int c);
extern int isgraph(int c);
extern int islower(int c);
extern int isprint(int c);
extern int ispunct(int c);
extern int isspace(int c);
extern int isupper(int c);
extern int isxdigit(int c);
extern int tolower(int c);
extern int toupper(int c);
extern int fill_random(unsigned char *buffer, unsigned int size);
#ifdef __cplusplus
}
#endif
#endif

14
libc/include/dirent.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef DIRENT_H_
#define DIRENT_H_
#include <sys/_dirent.h>
extern DIR *opendir(const char *path);
extern int closedir(DIR *d);
extern struct dirent *readdir(DIR *d);
extern int readdir_r(DIR *d, struct dirent *entry, struct dirent **result);
extern void rewinddir(DIR *d);
extern void seekdir(DIR *d, long int off);
extern long int telldir(DIR *d);
#endif

14
libc/include/dlfcn.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef DLFCN_H_
#define DLFCN_H_
#define RTLD_LAZY 0
#define RTLD_NOW 1
#define RTLD_GLOBAL 2
#define RTLD_LOCAL 3
extern void *dlopen(const char *path, int mode);
extern void *dlsym(void *handle, const char *name);
extern int dlclose(void *handle);
extern char *dlerror(void);
#endif

19
libc/include/errno.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef ERRNO_H_
#define ERRNO_H_
#include <sys/_errno.h>
#define errno (__get_errno())
#if defined(__cplusplus)
extern "C" {
#endif
extern void __set_errno(int v);
extern int __get_errno(void);
#if defined(__cplusplus)
}
#endif
#endif

195
libc/include/inttypes.h Normal file
View File

@@ -0,0 +1,195 @@
#ifndef INTTYPES_H__
#define INTTYPES_H__
#include <stdint.h>
#define __PRI_8_LENGTH_MODIFIER__ "hh"
#define __PRI_64_LENGTH_MODIFIER__ "ll"
#define __SCN_64_LENGTH_MODIFIER__ "ll"
#define __PRI_MAX_LENGTH_MODIFIER__ "j"
#define __SCN_MAX_LENGTH_MODIFIER__ "j"
#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d"
#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i"
#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o"
#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u"
#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x"
#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#define PRId32 "d"
#define PRIi32 "i"
#define PRIo32 "o"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIX32 "X"
#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d"
#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i"
#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o"
#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u"
#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x"
#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X"
#define PRIdLEAST8 PRId8
#define PRIiLEAST8 PRIi8
#define PRIoLEAST8 PRIo8
#define PRIuLEAST8 PRIu8
#define PRIxLEAST8 PRIx8
#define PRIXLEAST8 PRIX8
#define PRIdLEAST16 PRId16
#define PRIiLEAST16 PRIi16
#define PRIoLEAST16 PRIo16
#define PRIuLEAST16 PRIu16
#define PRIxLEAST16 PRIx16
#define PRIXLEAST16 PRIX16
#define PRIdLEAST32 PRId32
#define PRIiLEAST32 PRIi32
#define PRIoLEAST32 PRIo32
#define PRIuLEAST32 PRIu32
#define PRIxLEAST32 PRIx32
#define PRIXLEAST32 PRIX32
#define PRIdLEAST64 PRId64
#define PRIiLEAST64 PRIi64
#define PRIoLEAST64 PRIo64
#define PRIuLEAST64 PRIu64
#define PRIxLEAST64 PRIx64
#define PRIXLEAST64 PRIX64
#define PRIdFAST8 PRId8
#define PRIiFAST8 PRIi8
#define PRIoFAST8 PRIo8
#define PRIuFAST8 PRIu8
#define PRIxFAST8 PRIx8
#define PRIXFAST8 PRIX8
#define PRIdFAST16 PRId16
#define PRIiFAST16 PRIi16
#define PRIoFAST16 PRIo16
#define PRIuFAST16 PRIu16
#define PRIxFAST16 PRIx16
#define PRIXFAST16 PRIX16
#define PRIdFAST32 PRId32
#define PRIiFAST32 PRIi32
#define PRIoFAST32 PRIo32
#define PRIuFAST32 PRIu32
#define PRIxFAST32 PRIx32
#define PRIXFAST32 PRIX32
#define PRIdFAST64 PRId64
#define PRIiFAST64 PRIi64
#define PRIoFAST64 PRIo64
#define PRIuFAST64 PRIu64
#define PRIxFAST64 PRIx64
#define PRIXFAST64 PRIX64
/* int32_t is 'int', but intptr_t is 'long'. */
#define PRIdPTR "ld"
#define PRIiPTR "li"
#define PRIoPTR "lo"
#define PRIuPTR "lu"
#define PRIxPTR "lx"
#define PRIXPTR "lX"
#define PRIdMAX __PRI_MAX_LENGTH_MODIFIER__ "d"
#define PRIiMAX __PRI_MAX_LENGTH_MODIFIER__ "i"
#define PRIoMAX __PRI_MAX_LENGTH_MODIFIER__ "o"
#define PRIuMAX __PRI_MAX_LENGTH_MODIFIER__ "u"
#define PRIxMAX __PRI_MAX_LENGTH_MODIFIER__ "x"
#define PRIXMAX __PRI_MAX_LENGTH_MODIFIER__ "X"
#define SCNd8 __PRI_8_LENGTH_MODIFIER__ "d"
#define SCNi8 __PRI_8_LENGTH_MODIFIER__ "i"
#define SCNo8 __PRI_8_LENGTH_MODIFIER__ "o"
#define SCNu8 __PRI_8_LENGTH_MODIFIER__ "u"
#define SCNx8 __PRI_8_LENGTH_MODIFIER__ "x"
#define SCNd16 "hd"
#define SCNi16 "hi"
#define SCNo16 "ho"
#define SCNu16 "hu"
#define SCNx16 "hx"
#define SCNd32 "d"
#define SCNi32 "i"
#define SCNo32 "o"
#define SCNu32 "u"
#define SCNx32 "x"
#define SCNd64 __SCN_64_LENGTH_MODIFIER__ "d"
#define SCNi64 __SCN_64_LENGTH_MODIFIER__ "i"
#define SCNo64 __SCN_64_LENGTH_MODIFIER__ "o"
#define SCNu64 __SCN_64_LENGTH_MODIFIER__ "u"
#define SCNx64 __SCN_64_LENGTH_MODIFIER__ "x"
#define SCNdLEAST8 SCNd8
#define SCNiLEAST8 SCNi8
#define SCNoLEAST8 SCNo8
#define SCNuLEAST8 SCNu8
#define SCNxLEAST8 SCNx8
#define SCNdLEAST16 SCNd16
#define SCNiLEAST16 SCNi16
#define SCNoLEAST16 SCNo16
#define SCNuLEAST16 SCNu16
#define SCNxLEAST16 SCNx16
#define SCNdLEAST32 SCNd32
#define SCNiLEAST32 SCNi32
#define SCNoLEAST32 SCNo32
#define SCNuLEAST32 SCNu32
#define SCNxLEAST32 SCNx32
#define SCNdLEAST64 SCNd64
#define SCNiLEAST64 SCNi64
#define SCNoLEAST64 SCNo64
#define SCNuLEAST64 SCNu64
#define SCNxLEAST64 SCNx64
#define SCNdFAST8 SCNd8
#define SCNiFAST8 SCNi8
#define SCNoFAST8 SCNo8
#define SCNuFAST8 SCNu8
#define SCNxFAST8 SCNx8
#define SCNdFAST16 SCNd16
#define SCNiFAST16 SCNi16
#define SCNoFAST16 SCNo16
#define SCNuFAST16 SCNu16
#define SCNxFAST16 SCNx16
#define SCNdFAST32 SCNd32
#define SCNiFAST32 SCNi32
#define SCNoFAST32 SCNo32
#define SCNuFAST32 SCNu32
#define SCNxFAST32 SCNx32
#define SCNdFAST64 SCNd64
#define SCNiFAST64 SCNi64
#define SCNoFAST64 SCNo64
#define SCNuFAST64 SCNu64
#define SCNxFAST64 SCNx64
#define SCNdPTR "ld"
#define SCNiPTR "li"
#define SCNoPTR "lo"
#define SCNuPTR "lu"
#define SCNxPTR "lx"
#define SCNdMAX __SCN_MAX_LENGTH_MODIFIER__ "d"
#define SCNiMAX __SCN_MAX_LENGTH_MODIFIER__ "i"
#define SCNoMAX __SCN_MAX_LENGTH_MODIFIER__ "o"
#define SCNuMAX __SCN_MAX_LENGTH_MODIFIER__ "u"
#define SCNxMAX __SCN_MAX_LENGTH_MODIFIER__ "x"
#endif

37
libc/include/limits.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef LIMITS_H_
#define LIMITS_H_
#include <sys/_fconst.h>
#define CHAR_BIT 8
#define SCHAR_MIN -127
#define SCHAR_MAX 127
#define UCHAR_MAX 255
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
#define MB_LEN_MAX 1
#define SHRT_MIN -32767
#define SHRT_MAX 32767
#define USHRT_MAX 65535
#define INT_MIN -2147483648
#define INT_MAX 2147483648
#define UINT_MAX 4294967295
#define LONG_MIN -2147483647
#define LONG_MAX 2147483647
#define ULONG_MAX 4294967295
#define LLONG_MIN -9223372036854775807
#define LLONG_MAX 9223372036854775807
#define ULLONG_MAX 18446744073709551615
#define INT8_MIN SCHAR_MIN
#define INT8_MAX SCHAR_MAX
#define INT16_MIN SHRT_MIN
#define INT16_MAX SHRT_MAX
#define INT32_MIN INT_MIN
#define INT32_MAX INT_MAX
#define INT64_MIN LLONG_MIN
#define INT64_MAX LLONG_MAX
#define UINT64_MAX ULLONG_MAX
#define NAME_MAX __FILENAME_MAX
#endif /* LIMITS_H_ */

4
libc/include/locale.h Normal file
View File

@@ -0,0 +1,4 @@
#ifndef LOCALE_H_
#define LOCALE_H_
#endif

View File

@@ -0,0 +1,249 @@
#ifndef MACHINE__STDINT_H
#define MACHINE__STDINT_H
#define __EXP(x) __##x##__
#if ( defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff) ) \
|| ( defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff) )
#define __have_longlong64 1
#endif
#if __EXP(LONG_MAX) > 0x7fffffff
#define __have_long64 1
#elif __EXP(LONG_MAX) == 0x7fffffff && !defined(__SPU__)
#define __have_long32 1
#endif
#if defined(__cplusplus)
extern "C" {
#endif /* defined(__cplusplus) */
#ifdef __INT8_TYPE__
typedef __INT8_TYPE__ __int8_t;
#ifdef __UINT8_TYPE__
typedef __UINT8_TYPE__ __uint8_t;
#else
typedef unsigned __INT8_TYPE__ __uint8_t;
#endif
#define ___int8_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7f
typedef signed char __int8_t ;
typedef unsigned char __uint8_t ;
#define ___int8_t_defined 1
#endif
#ifdef __INT16_TYPE__
typedef __INT16_TYPE__ __int16_t;
#ifdef __UINT16_TYPE__
typedef __UINT16_TYPE__ __uint16_t;
#else
typedef unsigned __INT16_TYPE__ __uint16_t;
#endif
#define ___int16_t_defined 1
#elif __EXP(INT_MAX) == 0x7fff
typedef signed int __int16_t;
typedef unsigned int __uint16_t;
#define ___int16_t_defined 1
#elif __EXP(SHRT_MAX) == 0x7fff
typedef signed short __int16_t;
typedef unsigned short __uint16_t;
#define ___int16_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7fff
typedef signed char __int16_t;
typedef unsigned char __uint16_t;
#define ___int16_t_defined 1
#endif
#ifdef __INT32_TYPE__
typedef __INT32_TYPE__ __int32_t;
#ifdef __UINT32_TYPE__
typedef __UINT32_TYPE__ __uint32_t;
#else
typedef unsigned __INT32_TYPE__ __uint32_t;
#endif
#define ___int32_t_defined 1
#elif __EXP(INT_MAX) == 0x7fffffffL
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(LONG_MAX) == 0x7fffffffL
typedef signed long __int32_t;
typedef unsigned long __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(SHRT_MAX) == 0x7fffffffL
typedef signed short __int32_t;
typedef unsigned short __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7fffffffL
typedef signed char __int32_t;
typedef unsigned char __uint32_t;
#define ___int32_t_defined 1
#endif
#ifdef __INT64_TYPE__
typedef __INT64_TYPE__ __int64_t;
#ifdef __UINT64_TYPE__
typedef __UINT64_TYPE__ __uint64_t;
#else
typedef unsigned __INT64_TYPE__ __uint64_t;
#endif
#define ___int64_t_defined 1
#elif __EXP(LONG_MAX) > 0x7fffffff
typedef signed long __int64_t;
typedef unsigned long __uint64_t;
#define ___int64_t_defined 1
/* GCC has __LONG_LONG_MAX__ */
#elif defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff)
typedef signed long long __int64_t;
typedef unsigned long long __uint64_t;
#define ___int64_t_defined 1
/* POSIX mandates LLONG_MAX in <limits.h> */
#elif defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff)
typedef signed long long __int64_t;
typedef unsigned long long __uint64_t;
#define ___int64_t_defined 1
#elif __EXP(INT_MAX) > 0x7fffffff
typedef signed int __int64_t;
typedef unsigned int __uint64_t;
#define ___int64_t_defined 1
#endif
#ifdef __INT_LEAST8_TYPE__
typedef __INT_LEAST8_TYPE__ __int_least8_t;
#ifdef __UINT_LEAST8_TYPE__
typedef __UINT_LEAST8_TYPE__ __uint_least8_t;
#else
typedef unsigned __INT_LEAST8_TYPE__ __uint_least8_t;
#endif
#define ___int_least8_t_defined 1
#elif defined(___int8_t_defined)
typedef __int8_t __int_least8_t;
typedef __uint8_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int16_t_defined)
typedef __int16_t __int_least8_t;
typedef __uint16_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least8_t;
typedef __uint32_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least8_t;
typedef __uint64_t __uint_least8_t;
#define ___int_least8_t_defined 1
#endif
#ifdef __INT_LEAST16_TYPE__
typedef __INT_LEAST16_TYPE__ __int_least16_t;
#ifdef __UINT_LEAST16_TYPE__
typedef __UINT_LEAST16_TYPE__ __uint_least16_t;
#else
typedef unsigned __INT_LEAST16_TYPE__ __uint_least16_t;
#endif
#define ___int_least16_t_defined 1
#elif defined(___int16_t_defined)
typedef __int16_t __int_least16_t;
typedef __uint16_t __uint_least16_t;
#define ___int_least16_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least16_t;
typedef __uint32_t __uint_least16_t;
#define ___int_least16_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least16_t;
typedef __uint64_t __uint_least16_t;
#define ___int_least16_t_defined 1
#endif
#ifdef __INT_LEAST32_TYPE__
typedef __INT_LEAST32_TYPE__ __int_least32_t;
#ifdef __UINT_LEAST32_TYPE__
typedef __UINT_LEAST32_TYPE__ __uint_least32_t;
#else
typedef unsigned __INT_LEAST32_TYPE__ __uint_least32_t;
#endif
#define ___int_least32_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least32_t;
typedef __uint32_t __uint_least32_t;
#define ___int_least32_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least32_t;
typedef __uint64_t __uint_least32_t;
#define ___int_least32_t_defined 1
#endif
#ifdef __INT_LEAST64_TYPE__
typedef __INT_LEAST64_TYPE__ __int_least64_t;
#ifdef __UINT_LEAST64_TYPE__
typedef __UINT_LEAST64_TYPE__ __uint_least64_t;
#else
typedef unsigned __INT_LEAST64_TYPE__ __uint_least64_t;
#endif
#define ___int_least64_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least64_t;
typedef __uint64_t __uint_least64_t;
#define ___int_least64_t_defined 1
#endif
#if defined(__INTMAX_TYPE__)
typedef __INTMAX_TYPE__ __intmax_t;
#elif __have_longlong64
typedef signed long long __intmax_t;
#else
typedef signed long __intmax_t;
#endif
#if defined(__UINTMAX_TYPE__)
typedef __UINTMAX_TYPE__ __uintmax_t;
#elif __have_longlong64
typedef unsigned long long __uintmax_t;
#else
typedef unsigned long __uintmax_t;
#endif
#ifdef __INTPTR_TYPE__
typedef __INTPTR_TYPE__ __intptr_t;
#ifdef __UINTPTR_TYPE__
typedef __UINTPTR_TYPE__ __uintptr_t;
#else
typedef unsigned __INTPTR_TYPE__ __uintptr_t;
#endif
#elif defined(__PTRDIFF_TYPE__)
typedef __PTRDIFF_TYPE__ __intptr_t;
typedef unsigned __PTRDIFF_TYPE__ __uintptr_t;
#else
typedef long __intptr_t;
typedef unsigned long __uintptr_t;
#endif
#ifdef __SIZE_TYPE__
typedef __SIZE_TYPE__ __size_t;
#else
typedef unsigned long long __size_t;
#endif
typedef __int8_t __int_fast8_t;
typedef __uint8_t __uint_fast8_t;
typedef __int16_t __int_fast16_t;
typedef __uint16_t __uint_fast16_t;
typedef __int32_t __int_fast32_t;
typedef __uint32_t __uint_fast32_t;
typedef __int64_t __int_fast64_t;
typedef __uint64_t __uint_fast64_t;
#undef __EXP
#if defined(__cplusplus)
}
#endif /* defined(__cplusplus) */
#endif /* _MACHINE__STDINT_H */

20
libc/include/stdarg.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef STDARG_H
#define STDARG_H
//typedef struct __va_list_tag *va_list;
typedef __builtin_va_list va_list;
# if defined(__GNUC__) && __GNUC__ >= 3
#define va_start(ap, arg) __builtin_va_start((ap), (arg))
#define va_arg __builtin_va_arg
#define va_copy __builtin_va_copy
#define va_end(ap) __builtin_va_end((ap))
#else
#error Unsupported compiler
#define va_start(ap, arg) ((ap) = ((va_list)&(arg)) + ((sizeof(long) > sizeof(arg)) ? sizeof(long) : sizeof(arg)))
#define va_arg(ap, type) *(type *)(ap), ((ap) += ((sizeof(long) > sizeof(type)) ? sizeof(long) : sizeof(type)))
#define va_copy(copy, arg) ((copy) = (arg))
#define va_end(ap)
#endif
#endif

8
libc/include/stdbool.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef STDBOOL_H_
#define STDBOOL_H_
#define bool _Bool
#define true 1
#define false 0
#endif

27
libc/include/stddef.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef STDDEF_H_
#define STDDEF_H_
#include "machine/_stdint.h"
#define NULL ((void *)0)
#define offsetof(t, m) ((size_t)&(((t *)0)->m))
#if defined(__cplusplus)
extern "C" {
#endif /* defined(__cplusplus) */
#ifndef __ptrdiff_t_defined
#define __ptrdiff_t_defined
typedef __intptr_t ptrdiff_t;
#endif
#ifndef __size_t_defined
#define __size_t_defined
typedef __size_t size_t;
#endif
#if defined(__cplusplus)
}
#endif /* defined(__cplusplus) */
#endif /* STDDEF_H_ */

48
libc/include/stdint.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef STDINT_H_
#define STDINT_H_
#include <machine/_stdint.h>
typedef __int8_t int8_t;
typedef __uint8_t uint8_t;
typedef __int16_t int16_t;
typedef __uint16_t uint16_t;
typedef __int32_t int32_t;
typedef __uint32_t uint32_t;
typedef __int64_t int64_t;
typedef __uint64_t uint64_t;
typedef __intptr_t intptr_t;
typedef __uintptr_t uintptr_t;
typedef __int_least8_t int_least8_t;
typedef __uint_least8_t uint_least8_t;
typedef __int_least16_t int_least16_t;
typedef __uint_least16_t uint_least16_t;
typedef __int_least32_t int_least32_t;
typedef __uint_least32_t uint_least32_t;
typedef __int_least64_t int_least64_t;
typedef __uint_least64_t uint_least64_t;
typedef __int_fast8_t int_fast8_t;
typedef __uint_fast8_t uint_fast8_t;
typedef __int_fast16_t int_fast16_t;
typedef __uint_fast16_t uint_fast16_t;
typedef __int_fast32_t int_fast32_t;
typedef __uint_fast32_t uint_fast32_t;
typedef __int_fast64_t int_fast64_t;
typedef __uint_fast64_t uint_fast64_t;
typedef __intmax_t intmax_t;
typedef __uintmax_t uintmax_t;
#endif /* STDINT_H_ */

67
libc/include/stdio.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef STDIO_H_
#define STDIO_H_
#include <stdarg.h>
#include <stddef.h>
#include <sys/_fconst.h>
#if defined(__FILENAME_MAX)
#define FILENAME_MAX __FILENAME_MAX
#else
#define FILENAME_MAX 1024
#endif
#define BUFSIZ __FIO_BUFSZ
#define SEEK_SET __SEEK_SET
#define SEEK_CUR __SEEK_CUR
#define SEEK_END __SEEK_END
#define EOF -1
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct __io_file FILE;
extern FILE *__get_stdio_file(int);
#define stdin (__get_stdio_file(0))
#define stdout (__get_stdio_file(1))
#define stderr (__get_stdio_file(2))
extern FILE *fopen(const char *path, const char *mode);
extern FILE *freopen(const char *path, const char *mode, FILE *fp);
extern FILE *fdopen(int fd, const char *mode);
extern int fclose(FILE *fp);
extern int fflush(FILE *fp);
extern size_t fread(void *ptr, size_t size, size_t count, FILE *fp);
extern size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp);
extern int fileno(FILE *fp);
extern int fputs(const char *str, FILE *fp);
extern int fputc(int c, FILE *fp);
extern int fgetc(FILE *fp);
extern char *fgets(char *restrict str, int count, FILE *restrict fp);
extern int putchar(int c);
extern int ungetc(int c, FILE *fp);
extern int printf(const char *restrict format, ...);
extern int fprintf(FILE *fp, const char *restrict format, ...);
extern int sprintf(char *buf, const char *restrict format, ...);
extern int snprintf(char *buf, size_t sz, const char *restrict format, ...);
extern int vprintf(const char *restrict format, va_list arg);
extern int vfprintf(FILE *fp, const char *restrict format, va_list arg);
extern int vsprintf(char *buf, const char *restrict format, va_list arg);
extern int vsnprintf(char *buf, size_t sz, const char *restrict format, va_list arg);
extern void perror(const char *s);
#if defined(__cplusplus)
}
#endif
#endif

34
libc/include/stdlib.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef STDLIB_H_
#define STDLIB_H_
#include <stddef.h>
#if defined(__cplusplus)
extern "C" {
#endif
extern _Noreturn void abort(void);
extern _Noreturn void exit(int code);
extern void *malloc(size_t sz);
extern void *realloc(void *ptr, size_t sz);
extern void *calloc(size_t n, size_t sz);
extern void free(void *ptr);
extern int rand(void);
extern void srand(unsigned int seed);
extern int atoi(const char *str);
extern double atof(const char *str);
extern long strtol(const char *str, char **endptr, int base);
extern unsigned long strtoul(const char *str, char **endptr, int base);
extern float strtof(const char *str, char **endptr);
extern double strtod(const char *str, char **endptr);
extern char *getenv(const char *name);
extern int atexit(void(*fn)(void));
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif

39
libc/include/string.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef STRING_H_
#define STRING_H_
#include <stddef.h>
#if defined(__cplusplus)
extern "C" {
#endif
extern void *memcpy(void *dest, const void *src, size_t sz);
extern int memcmp(const void *a, const void *b, size_t sz);
extern void *memmove(void *dest, const void *src, size_t sz);
extern void *memset(void *ptr, int value, size_t sz);
extern char *strcat(char *dest, const char *src);
extern size_t strlen(const char *str);
extern int strcmp(const char *a, const char *b);
extern int strncmp(const char *a, const char *b, size_t sz);
extern char *strcpy(char *dest, const char *src);
extern char *strncpy(char *dest, const char *src, size_t sz);
extern char *strchr(const char *str, int ch);
extern char *strrchr(const char *s, int c);
extern size_t strcspn(const char *str1, const char *str2);
extern char *strdup(const char *s);
extern char *strtok(char *s, const char *delim);
extern char *strtok_r(char *s, const char *delim, char **sp);
extern char *strerror(int errnum);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif

46
libc/include/time.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef TIME_H_
#define TIME_H_
#include <stddef.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/_time.h>
#define CLOCKS_PER_SEC __SYS_CLOCKS_PER_SEC
#define CLOCK_REALTIME __SYS_CLOCK_REALTIME
#define CLOCK_MONOTONIC __SYS_CLOCK_MONOTONIC
struct timespec {
time_t tv_sec;
long tv_nsec;
};
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
extern clock_t clock(void);
extern time_t time(time_t *p);
extern int nanosleep(const struct timespec *req, struct timespec *rem);
extern struct tm *gmtime(const time_t *timer);
extern struct tm *localtime(const time_t *timer);
extern time_t mktime(struct tm *timeptr);
extern size_t strftime(char *str, size_t max, const char *format, const struct tm *timeptr);
extern void tzset(void);
extern int clock_getres(clockid_t clk_id, struct timespec *res);
extern int clock_gettime(clockid_t clk_id, struct timespec *tp);
extern int clock_settime(clockid_t clk_id, const struct timespec *tp);
#endif

14
libc/include/wchar.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef WCHAR_H_
#define WCHAR_H_
#include <stdio.h>
#include <stdarg.h>
typedef unsigned int wchar_t;
extern int fwide(FILE *fp, int mode);
extern int vfwprintf(FILE *stream, const wchar_t *format, va_list arg);
extern int vswprintf(wchar_t *buf, size_t len, const wchar_t *format, va_list arg);
#endif

View File

@@ -0,0 +1,8 @@
#include <stdio.h>
#include <stdlib.h>
_Noreturn void __stack_chk_fail(void)
{
fprintf(stderr, "Stack smashing detected!\n");
abort();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,679 @@
/*
Default header file for malloc-2.7.2, written by Doug Lea
and released to the public domain. Use, modify, and redistribute
this code without permission or acknowledgement in any way you wish.
Send questions, comments, complaints, performance data, etc to
dl@cs.oswego.edu.
last update: Sun Feb 25 18:38:11 2001 Doug Lea (dl at gee)
This header is for ANSI C/C++ only. You can set either of
the following #defines before including:
* If USE_DL_PREFIX is defined, it is assumed that malloc.c
was also compiled with this option, so all routines
have names starting with "dl".
* If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
file will be #included AFTER <malloc.h>. This is needed only if
your system defines a struct mallinfo that is incompatible with the
standard one declared here. Otherwise, you can include this file
INSTEAD of your system system <malloc.h>. At least on ANSI, all
declarations should be compatible with system versions
*/
#ifndef MALLOC_270_H
#define MALLOC_270_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h> /* for size_t */
/*
malloc(size_t n)
Returns a pointer to a newly allocated chunk of at least n bytes, or
null if no space is available. Additionally, on failure, errno is
set to ENOMEM on ANSI C systems.
If n is zero, malloc returns a minimum-sized chunk. The minimum size
is 16 bytes on most 32bit systems, and either 24 or 32 bytes on
64bit systems, depending on internal size and alignment restrictions.
On most systems, size_t is an unsigned type. Calls with values of n
that appear "negative" when signed are interpreted as requests for
huge amounts of space, which will most often fail.
The maximum allowed value of n differs across systems, but is in all
cases less (typically by 8K) than the maximum representable value of
a size_t. Requests greater than this value result in failure.
*/
#ifndef USE_DL_PREFIX
void* malloc(size_t);
#else
void* dlmalloc(size_t);
#endif
/*
free(void* p)
Releases the chunk of memory pointed to by p, that had been previously
allocated using malloc or a related routine such as realloc.
It has no effect if p is null. It can have arbitrary (and bad!)
effects if p has already been freed or was not obtained via malloc.
Unless disabled using mallopt, freeing very large spaces will,
when possible, automatically trigger operations that give
back unused memory to the system, thus reducing program footprint.
*/
#ifndef USE_DL_PREFIX
void free(void*);
#else
void dlfree(void*);
#endif
/*
calloc(size_t n_elements, size_t element_size);
Returns a pointer to n_elements * element_size bytes, with all locations
set to zero.
*/
#ifndef USE_DL_PREFIX
void* calloc(size_t, size_t);
#else
void* dlcalloc(size_t, size_t);
#endif
/*
realloc(void* p, size_t n)
Returns a pointer to a chunk of size n that contains the same data
as does chunk p up to the minimum of (n, p's size) bytes.
The returned pointer may or may not be the same as p. The algorithm
prefers extending p when possible, otherwise it employs the
equivalent of a malloc-copy-free sequence.
If p is null, realloc is equivalent to malloc.
If space is not available, realloc returns null, errno is set (if on
ANSI) and p is NOT freed.
if n is for fewer bytes than already held by p, the newly unused
space is lopped off and freed if possible. Unless the #define
REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of
zero (re)allocates a minimum-sized chunk.
Large chunks that were internally obtained via mmap will always
be reallocated using malloc-copy-free sequences unless
the system supports MREMAP (currently only linux).
The old unix realloc convention of allowing the last-free'd chunk
to be used as an argument to realloc is not supported.
*/
#ifndef USE_DL_PREFIX
void* realloc(void*, size_t);
#else
void* dlrealloc(void*, size_t);
#endif
/*
memalign(size_t alignment, size_t n);
Returns a pointer to a newly allocated chunk of n bytes, aligned
in accord with the alignment argument.
The alignment argument should be a power of two. If the argument is
not a power of two, the nearest greater power is used.
8-byte alignment is guaranteed by normal malloc calls, so don't
bother calling memalign with an argument of 8 or less.
Overreliance on memalign is a sure way to fragment space.
*/
#ifndef USE_DL_PREFIX
void* memalign(size_t, size_t);
#else
void* dlmemalign(size_t, size_t);
#endif
/*
valloc(size_t n);
Allocates a page-aligned chunk of at least n bytes.
Equivalent to memalign(pagesize, n), where pagesize is the page
size of the system. If the pagesize is unknown, 4096 is used.
*/
#ifndef USE_DL_PREFIX
void* valloc(size_t);
#else
void* dlvalloc(size_t);
#endif
/*
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
independent_calloc is similar to calloc, but instead of returning a
single cleared space, it returns an array of pointers to n_elements
independent elements, each of which can hold contents of size
elem_size. Each element starts out cleared, and can be
independently freed, realloc'ed etc. The elements are guaranteed to
be adjacently allocated (this is not guaranteed to occur with
multiple callocs or mallocs), which may also improve cache locality
in some applications.
The "chunks" argument is optional (i.e., may be null, which is
probably the most typical usage). If it is null, the returned array
is itself dynamically allocated and should also be freed when it is
no longer needed. Otherwise, the chunks array must be of at least
n_elements in length. It is filled in with the pointers to the
chunks.
In either case, independent_calloc returns this pointer array, or
null if the allocation failed. If n_elements is zero and "chunks"
is null, it returns a chunk representing an array with zero elements
(which should be freed if not wanted).
Each element must be individually freed when it is no longer
needed. If you'd like to instead be able to free all at once, you
should instead use regular calloc and assign pointers into this
space to represent elements. (In this case though, you cannot
independently free elements.)
independent_calloc simplifies and speeds up implementations of many
kinds of pools. It may also be useful when constructing large data
structures that initially have a fixed number of fixed-sized nodes,
but the number is not known at compile time, and some of the nodes
may later need to be freed. For example:
struct Node { int item; struct Node* next; };
struct Node* build_list() {
struct Node** pool;
int n = read_number_of_nodes_needed();
if (n <= 0) return 0;
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
if (pool == 0) return 0; // failure
// organize into a linked list...
struct Node* first = pool[0];
for (i = 0; i < n-1; ++i)
pool[i]->next = pool[i+1];
free(pool); // Can now free the array (or not, if it is needed later)
return first;
}
*/
#ifndef USE_DL_PREFIX
void** independent_calloc(size_t, size_t, void**);
#else
void** dlindependent_calloc(size_t, size_t, void**);
#endif
/*
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
independent_comalloc allocates, all at once, a set of n_elements
chunks with sizes indicated in the "sizes" array. It returns
an array of pointers to these elements, each of which can be
independently freed, realloc'ed etc. The elements are guaranteed to
be adjacently allocated (this is not guaranteed to occur with
multiple callocs or mallocs), which may also improve cache locality
in some applications.
The "chunks" argument is optional (i.e., may be null). If it is null
the returned array is itself dynamically allocated and should also
be freed when it is no longer needed. Otherwise, the chunks array
must be of at least n_elements in length. It is filled in with the
pointers to the chunks.
In either case, independent_comalloc returns this pointer array, or
null if the allocation failed. If n_elements is zero and chunks is
null, it returns a chunk representing an array with zero elements
(which should be freed if not wanted).
Each element must be individually freed when it is no longer
needed. If you'd like to instead be able to free all at once, you
should instead use a single regular malloc, and assign pointers at
particular offsets in the aggregate space. (In this case though, you
cannot independently free elements.)
independent_comallac differs from independent_calloc in that each
element may have a different size, and also that it does not
automatically clear elements.
independent_comalloc can be used to speed up allocation in cases
where several structs or objects must always be allocated at the
same time. For example:
struct Head { ... }
struct Foot { ... }
void send_message(char* msg) {
int msglen = strlen(msg);
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
void* chunks[3];
if (independent_comalloc(3, sizes, chunks) == 0)
die();
struct Head* head = (struct Head*)(chunks[0]);
char* body = (char*)(chunks[1]);
struct Foot* foot = (struct Foot*)(chunks[2]);
// ...
}
In general though, independent_comalloc is worth using only for
larger values of n_elements. For small values, you probably won't
detect enough difference from series of malloc calls to bother.
Overuse of independent_comalloc can increase overall memory usage,
since it cannot reuse existing noncontiguous small chunks that
might be available for some of the elements.
*/
#ifndef USE_DL_PREFIX
void** independent_comalloc(size_t, size_t*, void**);
#else
void** dlindependent_comalloc(size_t, size_t*, void**);
#endif
/*
pvalloc(size_t n);
Equivalent to valloc(minimum-page-that-holds(n)), that is,
round up n to nearest pagesize.
*/
#ifndef USE_DL_PREFIX
void* pvalloc(size_t);
#else
void* dlpvalloc(size_t);
#endif
/*
cfree(void* p);
Equivalent to free(p).
cfree is needed/defined on some systems that pair it with calloc,
for odd historical reasons (such as: cfree is used in example
code in the first edition of K&R).
*/
#ifndef USE_DL_PREFIX
void cfree(void*);
#else
void dlcfree(void*);
#endif
/*
malloc_trim(size_t pad);
If possible, gives memory back to the system (via negative
arguments to sbrk) if there is unused memory at the `high' end of
the malloc pool. You can call this after freeing large blocks of
memory to potentially reduce the system-level memory requirements
of a program. However, it cannot guarantee to reduce memory. Under
some allocation patterns, some large free blocks of memory will be
locked between two used chunks, so they cannot be given back to
the system.
The `pad' argument to malloc_trim represents the amount of free
trailing space to leave untrimmed. If this argument is zero,
only the minimum amount of memory to maintain internal data
structures will be left (one page or less). Non-zero arguments
can be supplied to maintain enough trailing space to service
future expected allocations without having to re-obtain memory
from the system.
Malloc_trim returns 1 if it actually released any memory, else 0.
On systems that do not support "negative sbrks", it will always
return 0.
*/
#ifndef USE_DL_PREFIX
int malloc_trim(size_t);
#else
int dlmalloc_trim(size_t);
#endif
/*
malloc_usable_size(void* p);
Returns the number of bytes you can actually use in an allocated
chunk, which may be more than you requested (although often not) due
to alignment and minimum size constraints. You can use this many
bytes without worrying about overwriting other allocated
objects. This is not a particularly great programming practice. But
malloc_usable_size can be more useful in debugging and assertions,
for example:
p = malloc(n);
assert(malloc_usable_size(p) >= 256);
*/
#ifndef USE_DL_PREFIX
size_t malloc_usable_size(void*);
#else
size_t dlmalloc_usable_size(void*);
#endif
/*
malloc_stats();
Prints on stderr the amount of space obtained from the system (both
via sbrk and mmap), the maximum amount (which may be more than
current if malloc_trim and/or munmap got called), and the current
number of bytes allocated via malloc (or realloc, etc) but not yet
freed. Note that this is the number of bytes allocated, not the
number requested. It will be larger than the number requested
because of alignment and bookkeeping overhead. Because it includes
alignment wastage as being in use, this figure may be greater than
zero even when no user-level chunks are allocated.
The reported current and maximum system memory can be inaccurate if
a program makes other calls to system memory allocation functions
(normally sbrk) outside of malloc.
malloc_stats prints only the most commonly interesting statistics.
More information can be obtained by calling mallinfo.
*/
#ifndef USE_DL_PREFIX
void malloc_stats(void);
#else
void dlmalloc_stats(void);
#endif
/*
mallinfo()
Returns (by copy) a struct containing various summary statistics:
arena: current total non-mmapped bytes allocated from system
ordblks: the number of free chunks
smblks: the number of fastbin blocks (i.e., small chunks that
have been freed but not use resused or consolidated)
hblks: current number of mmapped regions
hblkhd: total bytes held in mmapped regions
usmblks: the maximum total allocated space. This will be greater
than current total if trimming has occurred.
fsmblks: total bytes held in fastbin blocks
uordblks: current total allocated space (normal or mmapped)
fordblks: total free space
keepcost: the maximum number of bytes that could ideally be released
back to system via malloc_trim. ("ideally" means that
it ignores page restrictions etc.)
The names of some of these fields don't bear much relation with
their contents because this struct was defined as standard in
SVID/XPG so reflects the malloc implementation that was then used
in SystemV Unix.
The original SVID version of this struct, defined on most systems
with mallinfo, declares all fields as ints. But some others define
as unsigned long. If your system defines the fields using a type of
different width than listed here, you should #include your system
version before including this file. The struct declaration is
suppressed if _MALLOC_H is defined (which is done in most system
malloc.h files). You can also suppress it by defining
HAVE_USR_INCLUDE_MALLOC_H.
Because these fields are ints, but internal bookkeeping is done with
unsigned longs, the reported values may appear as negative, and may
wrap around zero and thus be inaccurate.
*/
#ifndef HAVE_USR_INCLUDE_MALLOC_H
#ifndef _MALLOC_H
struct mallinfo {
int arena;
int ordblks;
int smblks;
int hblks;
int hblkhd;
int usmblks;
int fsmblks;
int uordblks;
int fordblks;
int keepcost;
};
#endif
#endif
#ifndef USE_DL_PREFIX
struct mallinfo mallinfo(void);
#else
struct mallinfo mallinfo(void);
#endif
/*
mallopt(int parameter_number, int parameter_value)
Sets tunable parameters The format is to provide a
(parameter-number, parameter-value) pair. mallopt then sets the
corresponding parameter to the argument value if it can (i.e., so
long as the value is meaningful), and returns 1 if successful else
0. SVID/XPG defines four standard param numbers for mallopt,
normally defined in malloc.h. Only one of these (M_MXFAST) is used
in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
so setting them has no effect. But this malloc also supports four
other options in mallopt. See below for details. Briefly, supported
parameters are as follows (listed defaults are for "typical"
configurations).
Symbol param # default allowed param values
M_MXFAST 1 64 0-80 (0 disables fastbins)
M_TRIM_THRESHOLD -1 128*1024 any (-1U disables trimming)
M_TOP_PAD -2 0 any
M_MMAP_THRESHOLD -3 128*1024 any (or 0 if no MMAP support)
M_MMAP_MAX -4 65536 any (0 disables use of mmap)
*/
#ifndef USE_DL_PREFIX
int mallopt(int, int);
#else
int dlmallopt(int, int);
#endif
/* Descriptions of tuning options */
/*
M_MXFAST is the maximum request size used for "fastbins", special bins
that hold returned chunks without consolidating their spaces. This
enables future requests for chunks of the same size to be handled
very quickly, but can increase fragmentation, and thus increase the
overall memory footprint of a program.
This malloc manages fastbins very conservatively yet still
efficiently, so fragmentation is rarely a problem for values less
than or equal to the default. The maximum supported value of MXFAST
is 80. You wouldn't want it any higher than this anyway. Fastbins
are designed especially for use with many small structs, objects or
strings -- the default handles structs/objects/arrays with sizes up
to 8 4byte fields, or small strings representing words, tokens,
etc. Using fastbins for larger objects normally worsens
fragmentation without improving speed.
You can reduce M_MXFAST to 0 to disable all use of fastbins. This
causes the malloc algorithm to be a closer approximation of
fifo-best-fit in all cases, not just for larger requests, but will
generally cause it to be slower.
*/
#ifndef M_MXFAST
#define M_MXFAST 1
#endif
/*
M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
to keep before releasing via malloc_trim in free().
Automatic trimming is mainly useful in long-lived programs.
Because trimming via sbrk can be slow on some systems, and can
sometimes be wasteful (in cases where programs immediately
afterward allocate more large chunks) the value should be high
enough so that your overall system performance would improve by
releasing this much memory.
The trim threshold and the mmap control parameters (see below)
can be traded off with one another. Trimming and mmapping are
two different ways of releasing unused memory back to the
system. Between these two, it is often possible to keep
system-level demands of a long-lived program down to a bare
minimum. For example, in one test suite of sessions measuring
the XF86 X server on Linux, using a trim threshold of 128K and a
mmap threshold of 192K led to near-minimal long term resource
consumption.
If you are using this malloc in a long-lived program, it should
pay to experiment with these values. As a rough guide, you
might set to a value close to the average size of a process
(program) running on your system. Releasing this much memory
would allow such a process to run in memory. Generally, it's
worth it to tune for trimming rather tham memory mapping when a
program undergoes phases where several large chunks are
allocated and released in ways that can reuse each other's
storage, perhaps mixed with phases where there are no such
chunks at all. And in well-behaved long-lived programs,
controlling release of large blocks via trimming versus mapping
is usually faster.
However, in most programs, these parameters serve mainly as
protection against the system-level effects of carrying around
massive amounts of unneeded memory. Since frequent calls to
sbrk, mmap, and munmap otherwise degrade performance, the default
parameters are set to relatively high values that serve only as
safeguards.
The trim value It must be greater than page size to have any useful
effect. To disable trimming completely, you can set to
(unsigned long)(-1)
Trim settings interact with fastbin (MXFAST) settings: Unless
compiled with TRIM_FASTBINS defined, automatic trimming never takes
place upon freeing a chunk with size less than or equal to
MXFAST. Trimming is instead delayed until subsequent freeing of
larger chunks. However, you can still force an attempted trim by
calling malloc_trim.
Also, trimming is not generally possible in cases where
the main arena is obtained via mmap.
Note that the trick some people use of mallocing a huge space and
then freeing it at program startup, in an attempt to reserve system
memory, doesn't have the intended effect under automatic trimming,
since that memory will immediately be returned to the system.
*/
#define M_TRIM_THRESHOLD -1
/*
M_TOP_PAD is the amount of extra `padding' space to allocate or
retain whenever sbrk is called. It is used in two ways internally:
* When sbrk is called to extend the top of the arena to satisfy
a new malloc request, this much padding is added to the sbrk
request.
* When malloc_trim is called automatically from free(),
it is used as the `pad' argument.
In both cases, the actual amount of padding is rounded
so that the end of the arena is always a system page boundary.
The main reason for using padding is to avoid calling sbrk so
often. Having even a small pad greatly reduces the likelihood
that nearly every malloc request during program start-up (or
after trimming) will invoke sbrk, which needlessly wastes
time.
Automatic rounding-up to page-size units is normally sufficient
to avoid measurable overhead, so the default is 0. However, in
systems where sbrk is relatively slow, it can pay to increase
this value, at the expense of carrying around more memory than
the program needs.
*/
#define M_TOP_PAD -2
/*
M_MMAP_THRESHOLD is the request size threshold for using mmap()
to service a request. Requests of at least this size that cannot
be allocated using already-existing space will be serviced via mmap.
(If enough normal freed space already exists it is used instead.)
Using mmap segregates relatively large chunks of memory so that
they can be individually obtained and released from the host
system. A request serviced through mmap is never reused by any
other request (at least not directly; the system may just so
happen to remap successive requests to the same locations).
Segregating space in this way has the benefits that:
1. Mmapped space can ALWAYS be individually released back
to the system, which helps keep the system level memory
demands of a long-lived program low.
2. Mapped memory can never become `locked' between
other chunks, as can happen with normally allocated chunks, which
means that even trimming via malloc_trim would not release them.
3. On some systems with "holes" in address spaces, mmap can obtain
memory that sbrk cannot.
However, it has the disadvantages that:
1. The space cannot be reclaimed, consolidated, and then
used to service later requests, as happens with normal chunks.
2. It can lead to more wastage because of mmap page alignment
requirements
3. It causes malloc performance to be more dependent on host
system memory management support routines.
The advantages of mmap nearly always outweigh disadvantages for
"large" chunks, but the value of "large" varies across systems. The
default is an empirically derived value that works well in most
systems.
*/
#define M_MMAP_THRESHOLD -3
/*
M_MMAP_MAX is the maximum number of requests to simultaneously
service using mmap. This parameter exists because
some systems have a limited number of internal tables for
use by mmap, and using more than a few of them may degrade
performance.
The default is set to a value that serves only as a safeguard.
Setting to 0 disables use of mmap for servicing large requests. If
mmap is not supported on a system, the default value is 0, and
attempts to set it to non-zero values in mallopt will fail.
*/
#define M_MMAP_MAX -4
/* Unused SVID2/XPG mallopt options, listed for completeness */
#ifndef M_NBLKS
#define M_NLBLKS 2 /* UNUSED in this malloc */
#endif
#ifndef M_GRAIN
#define M_GRAIN 3 /* UNUSED in this malloc */
#endif
#ifndef M_KEEP
#define M_KEEP 4 /* UNUSED in this malloc */
#endif
/*
Some malloc.h's declare alloca, even though it is not part of malloc.
*/
#ifndef _ALLOCA_H
extern void* alloca(size_t);
#endif
#ifdef __cplusplus
}; /* end of extern "C" */
#endif
#endif /* MALLOC_270_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,679 @@
/*
Default header file for malloc-2.7.2, written by Doug Lea
and released to the public domain. Use, modify, and redistribute
this code without permission or acknowledgement in any way you wish.
Send questions, comments, complaints, performance data, etc to
dl@cs.oswego.edu.
last update: Sun Feb 25 18:38:11 2001 Doug Lea (dl at gee)
This header is for ANSI C/C++ only. You can set either of
the following #defines before including:
* If USE_DL_PREFIX is defined, it is assumed that malloc.c
was also compiled with this option, so all routines
have names starting with "dl".
* If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
file will be #included AFTER <malloc.h>. This is needed only if
your system defines a struct mallinfo that is incompatible with the
standard one declared here. Otherwise, you can include this file
INSTEAD of your system system <malloc.h>. At least on ANSI, all
declarations should be compatible with system versions
*/
#ifndef MALLOC_270_H
#define MALLOC_270_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h> /* for size_t */
/*
malloc(size_t n)
Returns a pointer to a newly allocated chunk of at least n bytes, or
null if no space is available. Additionally, on failure, errno is
set to ENOMEM on ANSI C systems.
If n is zero, malloc returns a minimum-sized chunk. The minimum size
is 16 bytes on most 32bit systems, and either 24 or 32 bytes on
64bit systems, depending on internal size and alignment restrictions.
On most systems, size_t is an unsigned type. Calls with values of n
that appear "negative" when signed are interpreted as requests for
huge amounts of space, which will most often fail.
The maximum allowed value of n differs across systems, but is in all
cases less (typically by 8K) than the maximum representable value of
a size_t. Requests greater than this value result in failure.
*/
#ifndef USE_DL_PREFIX
void* malloc(size_t);
#else
void* dlmalloc(size_t);
#endif
/*
free(void* p)
Releases the chunk of memory pointed to by p, that had been previously
allocated using malloc or a related routine such as realloc.
It has no effect if p is null. It can have arbitrary (and bad!)
effects if p has already been freed or was not obtained via malloc.
Unless disabled using mallopt, freeing very large spaces will,
when possible, automatically trigger operations that give
back unused memory to the system, thus reducing program footprint.
*/
#ifndef USE_DL_PREFIX
void free(void*);
#else
void dlfree(void*);
#endif
/*
calloc(size_t n_elements, size_t element_size);
Returns a pointer to n_elements * element_size bytes, with all locations
set to zero.
*/
#ifndef USE_DL_PREFIX
void* calloc(size_t, size_t);
#else
void* dlcalloc(size_t, size_t);
#endif
/*
realloc(void* p, size_t n)
Returns a pointer to a chunk of size n that contains the same data
as does chunk p up to the minimum of (n, p's size) bytes.
The returned pointer may or may not be the same as p. The algorithm
prefers extending p when possible, otherwise it employs the
equivalent of a malloc-copy-free sequence.
If p is null, realloc is equivalent to malloc.
If space is not available, realloc returns null, errno is set (if on
ANSI) and p is NOT freed.
if n is for fewer bytes than already held by p, the newly unused
space is lopped off and freed if possible. Unless the #define
REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of
zero (re)allocates a minimum-sized chunk.
Large chunks that were internally obtained via mmap will always
be reallocated using malloc-copy-free sequences unless
the system supports MREMAP (currently only linux).
The old unix realloc convention of allowing the last-free'd chunk
to be used as an argument to realloc is not supported.
*/
#ifndef USE_DL_PREFIX
void* realloc(void*, size_t);
#else
void* dlrealloc(void*, size_t);
#endif
/*
memalign(size_t alignment, size_t n);
Returns a pointer to a newly allocated chunk of n bytes, aligned
in accord with the alignment argument.
The alignment argument should be a power of two. If the argument is
not a power of two, the nearest greater power is used.
8-byte alignment is guaranteed by normal malloc calls, so don't
bother calling memalign with an argument of 8 or less.
Overreliance on memalign is a sure way to fragment space.
*/
#ifndef USE_DL_PREFIX
void* memalign(size_t, size_t);
#else
void* dlmemalign(size_t, size_t);
#endif
/*
valloc(size_t n);
Allocates a page-aligned chunk of at least n bytes.
Equivalent to memalign(pagesize, n), where pagesize is the page
size of the system. If the pagesize is unknown, 4096 is used.
*/
#ifndef USE_DL_PREFIX
void* valloc(size_t);
#else
void* dlvalloc(size_t);
#endif
/*
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
independent_calloc is similar to calloc, but instead of returning a
single cleared space, it returns an array of pointers to n_elements
independent elements, each of which can hold contents of size
elem_size. Each element starts out cleared, and can be
independently freed, realloc'ed etc. The elements are guaranteed to
be adjacently allocated (this is not guaranteed to occur with
multiple callocs or mallocs), which may also improve cache locality
in some applications.
The "chunks" argument is optional (i.e., may be null, which is
probably the most typical usage). If it is null, the returned array
is itself dynamically allocated and should also be freed when it is
no longer needed. Otherwise, the chunks array must be of at least
n_elements in length. It is filled in with the pointers to the
chunks.
In either case, independent_calloc returns this pointer array, or
null if the allocation failed. If n_elements is zero and "chunks"
is null, it returns a chunk representing an array with zero elements
(which should be freed if not wanted).
Each element must be individually freed when it is no longer
needed. If you'd like to instead be able to free all at once, you
should instead use regular calloc and assign pointers into this
space to represent elements. (In this case though, you cannot
independently free elements.)
independent_calloc simplifies and speeds up implementations of many
kinds of pools. It may also be useful when constructing large data
structures that initially have a fixed number of fixed-sized nodes,
but the number is not known at compile time, and some of the nodes
may later need to be freed. For example:
struct Node { int item; struct Node* next; };
struct Node* build_list() {
struct Node** pool;
int n = read_number_of_nodes_needed();
if (n <= 0) return 0;
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
if (pool == 0) return 0; // failure
// organize into a linked list...
struct Node* first = pool[0];
for (i = 0; i < n-1; ++i)
pool[i]->next = pool[i+1];
free(pool); // Can now free the array (or not, if it is needed later)
return first;
}
*/
#ifndef USE_DL_PREFIX
void** independent_calloc(size_t, size_t, void**);
#else
void** dlindependent_calloc(size_t, size_t, void**);
#endif
/*
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
independent_comalloc allocates, all at once, a set of n_elements
chunks with sizes indicated in the "sizes" array. It returns
an array of pointers to these elements, each of which can be
independently freed, realloc'ed etc. The elements are guaranteed to
be adjacently allocated (this is not guaranteed to occur with
multiple callocs or mallocs), which may also improve cache locality
in some applications.
The "chunks" argument is optional (i.e., may be null). If it is null
the returned array is itself dynamically allocated and should also
be freed when it is no longer needed. Otherwise, the chunks array
must be of at least n_elements in length. It is filled in with the
pointers to the chunks.
In either case, independent_comalloc returns this pointer array, or
null if the allocation failed. If n_elements is zero and chunks is
null, it returns a chunk representing an array with zero elements
(which should be freed if not wanted).
Each element must be individually freed when it is no longer
needed. If you'd like to instead be able to free all at once, you
should instead use a single regular malloc, and assign pointers at
particular offsets in the aggregate space. (In this case though, you
cannot independently free elements.)
independent_comallac differs from independent_calloc in that each
element may have a different size, and also that it does not
automatically clear elements.
independent_comalloc can be used to speed up allocation in cases
where several structs or objects must always be allocated at the
same time. For example:
struct Head { ... }
struct Foot { ... }
void send_message(char* msg) {
int msglen = strlen(msg);
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
void* chunks[3];
if (independent_comalloc(3, sizes, chunks) == 0)
die();
struct Head* head = (struct Head*)(chunks[0]);
char* body = (char*)(chunks[1]);
struct Foot* foot = (struct Foot*)(chunks[2]);
// ...
}
In general though, independent_comalloc is worth using only for
larger values of n_elements. For small values, you probably won't
detect enough difference from series of malloc calls to bother.
Overuse of independent_comalloc can increase overall memory usage,
since it cannot reuse existing noncontiguous small chunks that
might be available for some of the elements.
*/
#ifndef USE_DL_PREFIX
void** independent_comalloc(size_t, size_t*, void**);
#else
void** dlindependent_comalloc(size_t, size_t*, void**);
#endif
/*
pvalloc(size_t n);
Equivalent to valloc(minimum-page-that-holds(n)), that is,
round up n to nearest pagesize.
*/
#ifndef USE_DL_PREFIX
void* pvalloc(size_t);
#else
void* dlpvalloc(size_t);
#endif
/*
cfree(void* p);
Equivalent to free(p).
cfree is needed/defined on some systems that pair it with calloc,
for odd historical reasons (such as: cfree is used in example
code in the first edition of K&R).
*/
#ifndef USE_DL_PREFIX
void cfree(void*);
#else
void dlcfree(void*);
#endif
/*
malloc_trim(size_t pad);
If possible, gives memory back to the system (via negative
arguments to sbrk) if there is unused memory at the `high' end of
the malloc pool. You can call this after freeing large blocks of
memory to potentially reduce the system-level memory requirements
of a program. However, it cannot guarantee to reduce memory. Under
some allocation patterns, some large free blocks of memory will be
locked between two used chunks, so they cannot be given back to
the system.
The `pad' argument to malloc_trim represents the amount of free
trailing space to leave untrimmed. If this argument is zero,
only the minimum amount of memory to maintain internal data
structures will be left (one page or less). Non-zero arguments
can be supplied to maintain enough trailing space to service
future expected allocations without having to re-obtain memory
from the system.
Malloc_trim returns 1 if it actually released any memory, else 0.
On systems that do not support "negative sbrks", it will always
return 0.
*/
#ifndef USE_DL_PREFIX
int malloc_trim(size_t);
#else
int dlmalloc_trim(size_t);
#endif
/*
malloc_usable_size(void* p);
Returns the number of bytes you can actually use in an allocated
chunk, which may be more than you requested (although often not) due
to alignment and minimum size constraints. You can use this many
bytes without worrying about overwriting other allocated
objects. This is not a particularly great programming practice. But
malloc_usable_size can be more useful in debugging and assertions,
for example:
p = malloc(n);
assert(malloc_usable_size(p) >= 256);
*/
#ifndef USE_DL_PREFIX
size_t malloc_usable_size(void*);
#else
size_t dlmalloc_usable_size(void*);
#endif
/*
malloc_stats();
Prints on stderr the amount of space obtained from the system (both
via sbrk and mmap), the maximum amount (which may be more than
current if malloc_trim and/or munmap got called), and the current
number of bytes allocated via malloc (or realloc, etc) but not yet
freed. Note that this is the number of bytes allocated, not the
number requested. It will be larger than the number requested
because of alignment and bookkeeping overhead. Because it includes
alignment wastage as being in use, this figure may be greater than
zero even when no user-level chunks are allocated.
The reported current and maximum system memory can be inaccurate if
a program makes other calls to system memory allocation functions
(normally sbrk) outside of malloc.
malloc_stats prints only the most commonly interesting statistics.
More information can be obtained by calling mallinfo.
*/
#ifndef USE_DL_PREFIX
void malloc_stats(void);
#else
void dlmalloc_stats(void);
#endif
/*
mallinfo()
Returns (by copy) a struct containing various summary statistics:
arena: current total non-mmapped bytes allocated from system
ordblks: the number of free chunks
smblks: the number of fastbin blocks (i.e., small chunks that
have been freed but not use resused or consolidated)
hblks: current number of mmapped regions
hblkhd: total bytes held in mmapped regions
usmblks: the maximum total allocated space. This will be greater
than current total if trimming has occurred.
fsmblks: total bytes held in fastbin blocks
uordblks: current total allocated space (normal or mmapped)
fordblks: total free space
keepcost: the maximum number of bytes that could ideally be released
back to system via malloc_trim. ("ideally" means that
it ignores page restrictions etc.)
The names of some of these fields don't bear much relation with
their contents because this struct was defined as standard in
SVID/XPG so reflects the malloc implementation that was then used
in SystemV Unix.
The original SVID version of this struct, defined on most systems
with mallinfo, declares all fields as ints. But some others define
as unsigned long. If your system defines the fields using a type of
different width than listed here, you should #include your system
version before including this file. The struct declaration is
suppressed if _MALLOC_H is defined (which is done in most system
malloc.h files). You can also suppress it by defining
HAVE_USR_INCLUDE_MALLOC_H.
Because these fields are ints, but internal bookkeeping is done with
unsigned longs, the reported values may appear as negative, and may
wrap around zero and thus be inaccurate.
*/
#ifndef HAVE_USR_INCLUDE_MALLOC_H
#ifndef _MALLOC_H
struct mallinfo {
int arena;
int ordblks;
int smblks;
int hblks;
int hblkhd;
int usmblks;
int fsmblks;
int uordblks;
int fordblks;
int keepcost;
};
#endif
#endif
#ifndef USE_DL_PREFIX
struct mallinfo mallinfo(void);
#else
struct mallinfo mallinfo(void);
#endif
/*
mallopt(int parameter_number, int parameter_value)
Sets tunable parameters The format is to provide a
(parameter-number, parameter-value) pair. mallopt then sets the
corresponding parameter to the argument value if it can (i.e., so
long as the value is meaningful), and returns 1 if successful else
0. SVID/XPG defines four standard param numbers for mallopt,
normally defined in malloc.h. Only one of these (M_MXFAST) is used
in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
so setting them has no effect. But this malloc also supports four
other options in mallopt. See below for details. Briefly, supported
parameters are as follows (listed defaults are for "typical"
configurations).
Symbol param # default allowed param values
M_MXFAST 1 64 0-80 (0 disables fastbins)
M_TRIM_THRESHOLD -1 128*1024 any (-1U disables trimming)
M_TOP_PAD -2 0 any
M_MMAP_THRESHOLD -3 128*1024 any (or 0 if no MMAP support)
M_MMAP_MAX -4 65536 any (0 disables use of mmap)
*/
#ifndef USE_DL_PREFIX
int mallopt(int, int);
#else
int dlmallopt(int, int);
#endif
/* Descriptions of tuning options */
/*
M_MXFAST is the maximum request size used for "fastbins", special bins
that hold returned chunks without consolidating their spaces. This
enables future requests for chunks of the same size to be handled
very quickly, but can increase fragmentation, and thus increase the
overall memory footprint of a program.
This malloc manages fastbins very conservatively yet still
efficiently, so fragmentation is rarely a problem for values less
than or equal to the default. The maximum supported value of MXFAST
is 80. You wouldn't want it any higher than this anyway. Fastbins
are designed especially for use with many small structs, objects or
strings -- the default handles structs/objects/arrays with sizes up
to 8 4byte fields, or small strings representing words, tokens,
etc. Using fastbins for larger objects normally worsens
fragmentation without improving speed.
You can reduce M_MXFAST to 0 to disable all use of fastbins. This
causes the malloc algorithm to be a closer approximation of
fifo-best-fit in all cases, not just for larger requests, but will
generally cause it to be slower.
*/
#ifndef M_MXFAST
#define M_MXFAST 1
#endif
/*
M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
to keep before releasing via malloc_trim in free().
Automatic trimming is mainly useful in long-lived programs.
Because trimming via sbrk can be slow on some systems, and can
sometimes be wasteful (in cases where programs immediately
afterward allocate more large chunks) the value should be high
enough so that your overall system performance would improve by
releasing this much memory.
The trim threshold and the mmap control parameters (see below)
can be traded off with one another. Trimming and mmapping are
two different ways of releasing unused memory back to the
system. Between these two, it is often possible to keep
system-level demands of a long-lived program down to a bare
minimum. For example, in one test suite of sessions measuring
the XF86 X server on Linux, using a trim threshold of 128K and a
mmap threshold of 192K led to near-minimal long term resource
consumption.
If you are using this malloc in a long-lived program, it should
pay to experiment with these values. As a rough guide, you
might set to a value close to the average size of a process
(program) running on your system. Releasing this much memory
would allow such a process to run in memory. Generally, it's
worth it to tune for trimming rather tham memory mapping when a
program undergoes phases where several large chunks are
allocated and released in ways that can reuse each other's
storage, perhaps mixed with phases where there are no such
chunks at all. And in well-behaved long-lived programs,
controlling release of large blocks via trimming versus mapping
is usually faster.
However, in most programs, these parameters serve mainly as
protection against the system-level effects of carrying around
massive amounts of unneeded memory. Since frequent calls to
sbrk, mmap, and munmap otherwise degrade performance, the default
parameters are set to relatively high values that serve only as
safeguards.
The trim value It must be greater than page size to have any useful
effect. To disable trimming completely, you can set to
(unsigned long)(-1)
Trim settings interact with fastbin (MXFAST) settings: Unless
compiled with TRIM_FASTBINS defined, automatic trimming never takes
place upon freeing a chunk with size less than or equal to
MXFAST. Trimming is instead delayed until subsequent freeing of
larger chunks. However, you can still force an attempted trim by
calling malloc_trim.
Also, trimming is not generally possible in cases where
the main arena is obtained via mmap.
Note that the trick some people use of mallocing a huge space and
then freeing it at program startup, in an attempt to reserve system
memory, doesn't have the intended effect under automatic trimming,
since that memory will immediately be returned to the system.
*/
#define M_TRIM_THRESHOLD -1
/*
M_TOP_PAD is the amount of extra `padding' space to allocate or
retain whenever sbrk is called. It is used in two ways internally:
* When sbrk is called to extend the top of the arena to satisfy
a new malloc request, this much padding is added to the sbrk
request.
* When malloc_trim is called automatically from free(),
it is used as the `pad' argument.
In both cases, the actual amount of padding is rounded
so that the end of the arena is always a system page boundary.
The main reason for using padding is to avoid calling sbrk so
often. Having even a small pad greatly reduces the likelihood
that nearly every malloc request during program start-up (or
after trimming) will invoke sbrk, which needlessly wastes
time.
Automatic rounding-up to page-size units is normally sufficient
to avoid measurable overhead, so the default is 0. However, in
systems where sbrk is relatively slow, it can pay to increase
this value, at the expense of carrying around more memory than
the program needs.
*/
#define M_TOP_PAD -2
/*
M_MMAP_THRESHOLD is the request size threshold for using mmap()
to service a request. Requests of at least this size that cannot
be allocated using already-existing space will be serviced via mmap.
(If enough normal freed space already exists it is used instead.)
Using mmap segregates relatively large chunks of memory so that
they can be individually obtained and released from the host
system. A request serviced through mmap is never reused by any
other request (at least not directly; the system may just so
happen to remap successive requests to the same locations).
Segregating space in this way has the benefits that:
1. Mmapped space can ALWAYS be individually released back
to the system, which helps keep the system level memory
demands of a long-lived program low.
2. Mapped memory can never become `locked' between
other chunks, as can happen with normally allocated chunks, which
means that even trimming via malloc_trim would not release them.
3. On some systems with "holes" in address spaces, mmap can obtain
memory that sbrk cannot.
However, it has the disadvantages that:
1. The space cannot be reclaimed, consolidated, and then
used to service later requests, as happens with normal chunks.
2. It can lead to more wastage because of mmap page alignment
requirements
3. It causes malloc performance to be more dependent on host
system memory management support routines.
The advantages of mmap nearly always outweigh disadvantages for
"large" chunks, but the value of "large" varies across systems. The
default is an empirically derived value that works well in most
systems.
*/
#define M_MMAP_THRESHOLD -3
/*
M_MMAP_MAX is the maximum number of requests to simultaneously
service using mmap. This parameter exists because
some systems have a limited number of internal tables for
use by mmap, and using more than a few of them may degrade
performance.
The default is set to a value that serves only as a safeguard.
Setting to 0 disables use of mmap for servicing large requests. If
mmap is not supported on a system, the default value is 0, and
attempts to set it to non-zero values in mallopt will fail.
*/
#define M_MMAP_MAX -4
/* Unused SVID2/XPG mallopt options, listed for completeness */
#ifndef M_NBLKS
#define M_NLBLKS 2 /* UNUSED in this malloc */
#endif
#ifndef M_GRAIN
#define M_GRAIN 3 /* UNUSED in this malloc */
#endif
#ifndef M_KEEP
#define M_KEEP 4 /* UNUSED in this malloc */
#endif
/*
Some malloc.h's declare alloca, even though it is not part of malloc.
*/
#ifndef _ALLOCA_H
extern void* alloca(size_t);
#endif
#ifdef __cplusplus
}; /* end of extern "C" */
#endif
#endif /* MALLOC_270_H */

File diff suppressed because it is too large Load Diff

866
libc/stdio/__printf.c Normal file
View File

@@ -0,0 +1,866 @@
///////////////////////////////////////////////////////////////////////////////
// \author (c) Marco Paland (info@paland.com)
// 2014-2019, PALANDesign Hannover, Germany
//
// \license The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
// embedded systems with a very limited resources. These routines are thread
// safe and reentrant!
// Use this instead of the bloated standard/newlib printf cause these use
// malloc for printf (and may not be thread safe).
//
///////////////////////////////////////////////////////////////////////////////
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
#include "__printf.h"
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
// numeric number including padded zeros (dynamically created on stack)
// default: 32 byte
#ifndef PRINTF_NTOA_BUFFER_SIZE
#define PRINTF_NTOA_BUFFER_SIZE 32U
#endif
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
// float number including padded zeros (dynamically created on stack)
// default: 32 byte
#ifndef PRINTF_FTOA_BUFFER_SIZE
#define PRINTF_FTOA_BUFFER_SIZE 32U
#endif
// support for the floating point type (%f)
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
#define PRINTF_SUPPORT_FLOAT
#endif
// support for exponential floating point notation (%e/%g)
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
#define PRINTF_SUPPORT_EXPONENTIAL
#endif
// define the default floating point precision
// default: 6 digits
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
#endif
// define the largest float suitable to print with %f
// default: 1e9
#ifndef PRINTF_MAX_FLOAT
#define PRINTF_MAX_FLOAT 1e9
#endif
// support for the long long types (%llu or %p)
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
#define PRINTF_SUPPORT_LONG_LONG
#endif
// support for the ptrdiff_t type (%t)
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
// default: activated
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
#define PRINTF_SUPPORT_PTRDIFF_T
#endif
///////////////////////////////////////////////////////////////////////////////
// internal flag definitions
#define FLAGS_ZEROPAD (1U << 0U)
#define FLAGS_LEFT (1U << 1U)
#define FLAGS_PLUS (1U << 2U)
#define FLAGS_SPACE (1U << 3U)
#define FLAGS_HASH (1U << 4U)
#define FLAGS_UPPERCASE (1U << 5U)
#define FLAGS_CHAR (1U << 6U)
#define FLAGS_SHORT (1U << 7U)
#define FLAGS_LONG (1U << 8U)
#define FLAGS_LONG_LONG (1U << 9U)
#define FLAGS_PRECISION (1U << 10U)
#define FLAGS_ADAPT_EXP (1U << 11U)
// import float.h for DBL_MAX
#if defined(PRINTF_SUPPORT_FLOAT)
#include <float.h>
#endif
#if 0
// output function type
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
// wrapper (used as buffer) for output function type
typedef struct {
void (*fct)(char character, void* arg);
void* arg;
} out_fct_wrap_type;
// internal buffer output
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
{
if (idx < maxlen) {
((char*)buffer)[idx] = character;
}
}
// internal null output
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)character; (void)buffer; (void)idx; (void)maxlen;
}
// internal _putchar wrapper
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)buffer; (void)idx; (void)maxlen;
if (character) {
_putchar(character);
}
}
// internal output function wrapper
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)idx; (void)maxlen;
if (character) {
// buffer is the output fct pointer
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
}
}
#endif
// internal secure strlen
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
{
const char* s;
for (s = str; *s && maxsize--; ++s);
return (unsigned int)(s - str);
}
// internal test if char is a digit (0-9)
// \return true if char is a digit
static inline bool _is_digit(char ch)
{
return (ch >= '0') && (ch <= '9');
}
// internal ASCII string to unsigned int conversion
static unsigned int _atoi(const char** str)
{
unsigned int i = 0U;
while (_is_digit(**str)) {
i = i * 10U + (unsigned int)(*((*str)++) - '0');
}
return i;
}
// output the specified string in reverse, taking care of any zero-padding
static size_t _out_rev(struct __printf_backend *out, const char* buf,
size_t len, unsigned int width, unsigned int flags)
{
size_t idx = 0;
// pad spaces up to given width
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
for (size_t i = len; i < width; i++) {
out->out(out, ' ');
}
}
// reverse string
while (len) {
out->out(out, buf[--len]);
}
// append pad spaces up to given width
if (flags & FLAGS_LEFT) {
while (idx++ < width) {
out->out(out, ' ');
}
}
return idx;
}
// internal itoa format
static size_t _ntoa_format(struct __printf_backend *out, char* buf,
size_t len, bool negative, unsigned int base, unsigned int prec,
unsigned int width, unsigned int flags)
{
// pad leading zeros
if (!(flags & FLAGS_LEFT)) {
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
width--;
}
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = '0';
}
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = '0';
}
}
// handle hash
if (flags & FLAGS_HASH) {
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
len--;
if (len && (base == 16U)) {
len--;
}
}
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = 'x';
}
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = 'X';
}
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
buf[len++] = 'b';
}
if (len < PRINTF_NTOA_BUFFER_SIZE) {
buf[len++] = '0';
}
}
if (len < PRINTF_NTOA_BUFFER_SIZE) {
if (negative) {
buf[len++] = '-';
}
else if (flags & FLAGS_PLUS) {
buf[len++] = '+'; // ignore the space if the '+' exists
}
else if (flags & FLAGS_SPACE) {
buf[len++] = ' ';
}
}
return _out_rev(out, buf, len, width, flags);
}
// internal itoa for 'long' type
static size_t _ntoa_long(struct __printf_backend *out, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
{
char buf[PRINTF_NTOA_BUFFER_SIZE];
size_t len = 0U;
// no hash for 0 values
if (!value) {
flags &= ~FLAGS_HASH;
}
// write if precision != 0 and value is != 0
if (!(flags & FLAGS_PRECISION) || value) {
do {
const char digit = (char)(value % base);
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
value /= base;
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
}
return _ntoa_format(out, buf, len, negative, (unsigned int)base, prec, width, flags);
}
// internal itoa for 'long long' type
#if defined(PRINTF_SUPPORT_LONG_LONG)
static size_t _ntoa_long_long(struct __printf_backend *out,
unsigned long long value, bool negative, unsigned long long base,
unsigned int prec, unsigned int width, unsigned int flags)
{
char buf[PRINTF_NTOA_BUFFER_SIZE];
size_t len = 0U;
// no hash for 0 values
if (!value) {
flags &= ~FLAGS_HASH;
}
// write if precision != 0 and value is != 0
if (!(flags & FLAGS_PRECISION) || value) {
do {
const char digit = (char)(value % base);
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
value /= base;
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
}
return _ntoa_format(out, buf, len, negative, (unsigned int)base, prec, width, flags);
}
#endif // PRINTF_SUPPORT_LONG_LONG
#if defined(PRINTF_SUPPORT_FLOAT)
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
static size_t _etoa(struct __printf_backend *out, double value,
unsigned int prec, unsigned int width, unsigned int flags);
#endif
// internal ftoa for fixed decimal floating point
static size_t _ftoa(struct __printf_backend *out, double value,
unsigned int prec, unsigned int width, unsigned int flags)
{
char buf[PRINTF_FTOA_BUFFER_SIZE];
size_t len = 0U;
double diff = 0.0;
// powers of 10
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
// test for special values
if (value != value)
return _out_rev(out, "nan", 3, width, flags);
if (value < -DBL_MAX)
return _out_rev(out, "fni-", 4, width, flags);
if (value > DBL_MAX)
return _out_rev(out, (flags & FLAGS_PLUS) ? "fni+" : "fni",
(flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
// test for very large values
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
return _etoa(out, value, prec, width, flags);
#else
return 0U;
#endif
}
// test for negative
bool negative = false;
if (value < 0) {
negative = true;
value = 0 - value;
}
// set default precision, if not set explicitly
if (!(flags & FLAGS_PRECISION)) {
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
}
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
buf[len++] = '0';
prec--;
}
int whole = (int)value;
double tmp = (value - whole) * pow10[prec];
unsigned long frac = (unsigned long)tmp;
diff = tmp - frac;
if (diff > 0.5) {
++frac;
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
if (frac >= pow10[prec]) {
frac = 0;
++whole;
}
}
else if (diff < 0.5) {
}
else if ((frac == 0U) || (frac & 1U)) {
// if halfway, round up if odd OR if last digit is 0
++frac;
}
if (prec == 0U) {
diff = value - (double)whole;
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
// exactly 0.5 and ODD, then round up
// 1.5 -> 2, but 2.5 -> 2
++whole;
}
}
else {
unsigned int count = prec;
// now do fractional part, as an unsigned number
while (len < PRINTF_FTOA_BUFFER_SIZE) {
--count;
buf[len++] = (char)(48U + (frac % 10U));
if (!(frac /= 10U)) {
break;
}
}
// add extra 0s
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
buf[len++] = '0';
}
if (len < PRINTF_FTOA_BUFFER_SIZE) {
// add decimal
buf[len++] = '.';
}
}
// do whole part, number is reversed
while (len < PRINTF_FTOA_BUFFER_SIZE) {
buf[len++] = (char)(48 + (whole % 10));
if (!(whole /= 10)) {
break;
}
}
// pad leading zeros
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
width--;
}
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
buf[len++] = '0';
}
}
if (len < PRINTF_FTOA_BUFFER_SIZE) {
if (negative) {
buf[len++] = '-';
}
else if (flags & FLAGS_PLUS) {
buf[len++] = '+'; // ignore the space if the '+' exists
}
else if (flags & FLAGS_SPACE) {
buf[len++] = ' ';
}
}
return _out_rev(out, buf, len, width, flags);
}
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
static size_t _etoa(struct __printf_backend *out, double value,
unsigned int prec, unsigned int width, unsigned int flags)
{
// check for NaN and special values
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
return _ftoa(out, value, prec, width, flags);
}
// determine the sign
const bool negative = value < 0;
if (negative) {
value = -value;
}
// default precision
if (!(flags & FLAGS_PRECISION)) {
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
}
// determine the decimal exponent
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
union {
uint64_t U;
double F;
} conv;
conv.F = value;
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
// now we want to compute 10^expval but we want to be sure it won't overflow
exp2 = (int)(expval * 3.321928094887362 + 0.5);
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
const double z2 = z * z;
conv.U = (uint64_t)(exp2 + 1023) << 52U;
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
// correct for rounding errors
if (value < conv.F) {
expval--;
conv.F /= 10;
}
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
// in "%g" mode, "prec" is the number of *significant figures* not decimals
if (flags & FLAGS_ADAPT_EXP) {
// do we want to fall-back to "%f" mode?
if ((value >= 1e-4) && (value < 1e6)) {
if ((int)prec > expval) {
prec = (unsigned)((int)prec - expval - 1);
}
else {
prec = 0;
}
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
// no characters in exponent
minwidth = 0U;
expval = 0;
}
else {
// we use one sigfig for the whole part
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
--prec;
}
}
}
// will everything fit?
unsigned int fwidth = width;
if (width > minwidth) {
// we didn't fall-back so subtract the characters required for the exponent
fwidth -= minwidth;
} else {
// not enough characters, so go back to default sizing
fwidth = 0U;
}
if ((flags & FLAGS_LEFT) && minwidth) {
// if we're padding on the right, DON'T pad the floating part
fwidth = 0U;
}
// rescale the float value
if (expval) {
value /= conv.F;
}
// output the floating part
size_t idx = _ftoa(out, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
// output the exponent part
if (minwidth) {
// output the exponential symbol
out->out(out, (flags & FLAGS_UPPERCASE) ? 'E' : 'e');
// output the exponent value
idx += _ntoa_long(out, (expval < 0) ? -expval : expval, expval < 0,
10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
// might need to right-pad spaces
if (flags & FLAGS_LEFT) {
while (idx++ < width) out->out(out, ' ');
}
}
return idx;
}
#endif // PRINTF_SUPPORT_EXPONENTIAL
#endif // PRINTF_SUPPORT_FLOAT
// internal vsnprintf
int __xprintf(struct __printf_backend *bk, const char* format, va_list va)
{
unsigned int flags, width, precision, n;
size_t idx = 0U;
while (*format)
{
// format specifier? %[flags][width][.precision][length]
if (*format != '%') {
// no
bk->out(bk, *format);
format++;
continue;
}
else {
// yes, evaluate it
format++;
}
// evaluate flags
flags = 0U;
do {
switch (*format) {
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
default : n = 0U; break;
}
} while (n);
// evaluate width field
width = 0U;
if (_is_digit(*format)) {
width = _atoi(&format);
}
else if (*format == '*') {
const int w = va_arg(va, int);
if (w < 0) {
flags |= FLAGS_LEFT; // reverse padding
width = (unsigned int)-w;
}
else {
width = (unsigned int)w;
}
format++;
}
// evaluate precision field
precision = 0U;
if (*format == '.') {
flags |= FLAGS_PRECISION;
format++;
if (_is_digit(*format)) {
precision = _atoi(&format);
}
else if (*format == '*') {
const int prec = (int)va_arg(va, int);
precision = prec > 0 ? (unsigned int)prec : 0U;
format++;
}
}
// evaluate length field
switch (*format) {
case 'l' :
flags |= FLAGS_LONG;
format++;
if (*format == 'l') {
flags |= FLAGS_LONG_LONG;
format++;
}
break;
case 'h' :
flags |= FLAGS_SHORT;
format++;
if (*format == 'h') {
flags |= FLAGS_CHAR;
format++;
}
break;
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
case 't' :
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
format++;
break;
#endif
case 'j' :
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
format++;
break;
case 'z' :
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
format++;
break;
default :
break;
}
// evaluate specifier
switch (*format) {
case 'd' :
case 'i' :
case 'u' :
case 'x' :
case 'X' :
case 'o' :
case 'b' : {
// set the base
unsigned int base;
if (*format == 'x' || *format == 'X') {
base = 16U;
}
else if (*format == 'o') {
base = 8U;
}
else if (*format == 'b') {
base = 2U;
}
else {
base = 10U;
flags &= ~FLAGS_HASH; // no hash for dec format
}
// uppercase
if (*format == 'X') {
flags |= FLAGS_UPPERCASE;
}
// no plus or space flag for u, x, X, o, b
if ((*format != 'i') && (*format != 'd')) {
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
}
// ignore '0' flag when precision is given
if (flags & FLAGS_PRECISION) {
flags &= ~FLAGS_ZEROPAD;
}
// convert the integer
if ((*format == 'i') || (*format == 'd')) {
// signed
if (flags & FLAGS_LONG_LONG) {
#if defined(PRINTF_SUPPORT_LONG_LONG)
const long long value = va_arg(va, long long);
idx += _ntoa_long_long(bk, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
#endif
}
else if (flags & FLAGS_LONG) {
const long value = va_arg(va, long);
idx += _ntoa_long(bk, (unsigned long)(value > 0 ? value : 0 - value),
value < 0, base, precision, width, flags);
}
else {
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int)
: (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
idx += _ntoa_long(bk, (unsigned int)(value > 0 ? value : 0 - value),
value < 0, base, precision, width, flags);
}
}
else {
// unsigned
if (flags & FLAGS_LONG_LONG) {
#if defined(PRINTF_SUPPORT_LONG_LONG)
idx += _ntoa_long_long(bk, va_arg(va, unsigned long long),
false, base, precision, width, flags);
#endif
}
else if (flags & FLAGS_LONG) {
idx += _ntoa_long(bk, va_arg(va, unsigned long),
false, base, precision, width, flags);
}
else {
const unsigned int value = (flags & FLAGS_CHAR)
? (unsigned char)va_arg(va, unsigned int)
: (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int)
: va_arg(va, unsigned int);
idx += _ntoa_long(bk, value, false, base, precision, width, flags);
}
}
format++;
break;
}
#if defined(PRINTF_SUPPORT_FLOAT)
case 'f' :
case 'F' :
if (*format == 'F') flags |= FLAGS_UPPERCASE;
idx += _ftoa(bk, va_arg(va, double), precision, width, flags);
format++;
break;
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
case 'e':
case 'E':
case 'g':
case 'G':
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
idx += _etoa(bk, va_arg(va, double), precision, width, flags);
format++;
break;
#endif // PRINTF_SUPPORT_EXPONENTIAL
#endif // PRINTF_SUPPORT_FLOAT
case 'c' : {
unsigned int l = 1U;
// pre padding
if (!(flags & FLAGS_LEFT)) {
while (l++ < width) {
bk->out(bk, ' ');
}
}
// char output
bk->out(bk, (char)va_arg(va, int));
// post padding
if (flags & FLAGS_LEFT) {
while (l++ < width) {
bk->out(bk, ' ');
}
}
format++;
break;
}
case 's' : {
const char* p = va_arg(va, char*);
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
// pre padding
if (flags & FLAGS_PRECISION) {
l = (l < precision ? l : precision);
}
if (!(flags & FLAGS_LEFT)) {
while (l++ < width) {
bk->out(bk, ' ');
}
}
// string output
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
bk->out(bk, *(p++));
}
// post padding
if (flags & FLAGS_LEFT) {
while (l++ < width) {
bk->out(bk, ' ');
}
}
format++;
break;
}
case 'p' : {
width = sizeof(void*) * 2U;
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
#if defined(PRINTF_SUPPORT_LONG_LONG)
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
if (is_ll) {
idx += _ntoa_long_long(bk, (uintptr_t)va_arg(va, void*),
false, 16U, precision, width, flags);
}
else {
#endif
idx += _ntoa_long(bk,
(unsigned long)((uintptr_t)va_arg(va, void*)),
false, 16U, precision, width, flags);
#if defined(PRINTF_SUPPORT_LONG_LONG)
}
#endif
format++;
break;
}
case '%' :
bk->out(bk, '%');
format++;
break;
default :
bk->out(bk, *format);
format++;
break;
}
}
// termination
bk->out(bk, (char)0);
// return written chars without terminating \0
return (int)idx;
}

16
libc/stdio/__printf.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __PRINTF_H_
#define __PRINTF_H_
struct __printf_backend;
typedef void(*__printf_backend_fn)(struct __printf_backend *, char);
struct __printf_backend {
__printf_backend_fn out;
void *arg;
};
extern int __xprintf(struct __printf_backend *bk, const char *format,
va_list va);
#endif

15
libc/stdio/fclose.c Normal file
View File

@@ -0,0 +1,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <__fio.h>
int fclose(FILE *fp)
{
int res = __fio_fclose(fp);
if (res != 0) {
return EOF;
}
free(fp);
return 0;
}

18
libc/stdio/fdopen.c Normal file
View File

@@ -0,0 +1,18 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <__fio.h>
FILE *fdopen(int fd, const char *mode)
{
struct __io_file *fp = malloc(sizeof(*fp));
memset(fp, 0x0, sizeof(*fp));
int res = __fio_fdopen(fd, mode, fp);
if (res != 0) {
free(fp);
return NULL;
}
return fp;
}

7
libc/stdio/ferror.c Normal file
View File

@@ -0,0 +1,7 @@
#include <stdio.h>
#include <__fio.h>
int ferror(FILE *fp)
{
return __fio_error(fp);
}

13
libc/stdio/fflush.c Normal file
View File

@@ -0,0 +1,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <__fio.h>
int fflush(FILE *fp)
{
int res = __fio_flush(fp);
if (res != 0) {
return -1;
}
return 0;
}

13
libc/stdio/fgetc.c Normal file
View File

@@ -0,0 +1,13 @@
#include <stdio.h>
#include <__fio.h>
int fgetc(FILE *fp)
{
char ch = 0;
unsigned int r = __fio_read(fp, &ch, 1);
if (r == 0 || __fio_error(fp) || __fio_eof(fp)) {
return EOF;
}
return ch;
}

32
libc/stdio/fgets.c Normal file
View File

@@ -0,0 +1,32 @@
#include <stdio.h>
char *fgets(char *restrict str, int count, FILE *restrict fp)
{
if (count < 1) {
return NULL;
}
if (count == 1) {
str[0] = '\0';
return str;
}
int r = 0;
while (1) {
int c = fgetc(fp);
if (c == EOF) {
str[r] = '\0';
break;
}
str[r++] = c;
if (r == count - 1 || c == '\n') {
str[r] = '\0';
break;
}
}
return r > 0 ? str : NULL;
}

7
libc/stdio/fileno.c Normal file
View File

@@ -0,0 +1,7 @@
#include <__fio.h>
#include <stdio.h>
int fileno(FILE *f)
{
return __fileno(f);
}

18
libc/stdio/fopen.c Normal file
View File

@@ -0,0 +1,18 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <__fio.h>
FILE *fopen(const char *path, const char *mode)
{
struct __io_file *fp = malloc(sizeof(*fp));
memset(fp, 0x0, sizeof(*fp));
int res = __fio_fopen(path, mode, fp);
if (res != 0) {
free(fp);
return NULL;
}
return fp;
}

10
libc/stdio/fprintf.c Normal file
View File

@@ -0,0 +1,10 @@
#include <stdio.h>
int fprintf(FILE *fp, const char *restrict format, ...)
{
va_list arg;
va_start(arg, format);
int ret = vfprintf(fp, format, arg);
va_end(arg);
return ret;
}

13
libc/stdio/fputc.c Normal file
View File

@@ -0,0 +1,13 @@
#include <stdio.h>
#include <__fio.h>
int fputc(int c, FILE *fp)
{
char ch = c;
__fio_write(fp, &ch, 1);
if (__fio_error(fp)) {
return EOF;
}
return c;
}

14
libc/stdio/fputs.c Normal file
View File

@@ -0,0 +1,14 @@
#include <stdio.h>
#include <__fio.h>
int fputs(const char *str, FILE *fp)
{
while (*str) {
__fio_write(fp, str++, 1);
if (__fio_error(fp)) {
return EOF;
}
}
return 0;
}

16
libc/stdio/freopen.c Normal file
View File

@@ -0,0 +1,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <__fio.h>
FILE *freopen(const char *path, const char *mode, FILE *fp)
{
int res = __fio_fclose(fp);
res = __fio_fopen(path, mode, fp);
if (res != 0) {
free(fp);
return NULL;
}
return fp;
}

12
libc/stdio/fwrite.c Normal file
View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <__fio.h>
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp)
{
if (!size || !count) {
return 0;
}
unsigned int written = __fio_write(fp, ptr, size * count);
return written / size;
}

13
libc/stdio/perror.c Normal file
View File

@@ -0,0 +1,13 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
void perror(const char *s)
{
if (s) {
fprintf(stderr, "%s: %s\n", s, strerror(errno));
} else {
fputs(strerror(errno), stderr);
fputc('\n', stderr);
}
}

11
libc/stdio/printf.c Normal file
View File

@@ -0,0 +1,11 @@
#include <stdio.h>
#include "__printf.h"
int printf(const char *restrict format, ...)
{
va_list args;
va_start(args, format);
int len = vprintf(format, args);
va_end(args);
return len;
}

6
libc/stdio/putchar.c Normal file
View File

@@ -0,0 +1,6 @@
#include <stdio.h>
int putchar(int c)
{
return fputc(c, stdout);
}

11
libc/stdio/puts.c Normal file
View File

@@ -0,0 +1,11 @@
#include <stdio.h>
int puts(const char *str)
{
int r = fputs(str, stdout);
if (r != 0) {
return r;
}
return fputc('\n', stdout);
}

10
libc/stdio/snprintf.c Normal file
View File

@@ -0,0 +1,10 @@
#include <stdio.h>
int snprintf(char *buf, size_t sz, const char *restrict format, ...)
{
va_list arg;
va_start(arg, format);
int ret = vsnprintf(buf, sz, format, arg);
va_end(arg);
return ret;
}

11
libc/stdio/sprintf.c Normal file
View File

@@ -0,0 +1,11 @@
#include <stdio.h>
#include "__printf.h"
int sprintf(char *buf, const char *restrict format, ...)
{
va_list args;
va_start(args, format);
int len = vsprintf(buf, format, args);
va_end(args);
return len;
}

12
libc/stdio/ungetc.c Normal file
View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <__fio.h>
int ungetc(int c, FILE *fp)
{
if (c == EOF) {
return EOF;
}
int res = __fio_ungetc(fp, c);
return res == -1 ? EOF : c;
}

19
libc/stdio/vfprintf.c Normal file
View File

@@ -0,0 +1,19 @@
#include <stdio.h>
#include "__printf.h"
static void _out_file(struct __printf_backend *bk, char ch)
{
FILE *fp = bk->arg;
if (ch) {
fputc(ch, fp);
}
}
int vfprintf(FILE *fp, const char *restrict format, va_list arg)
{
struct __printf_backend bk = {};
bk.out = _out_file;
bk.arg = fp;
return __xprintf(&bk, format, arg);
}

7
libc/stdio/vprintf.c Normal file
View File

@@ -0,0 +1,7 @@
#include <stdio.h>
#include "__printf.h"
int vprintf(const char *restrict format, va_list arg)
{
return vfprintf(stdout, format, arg);
}

36
libc/stdio/vsnprintf.c Normal file
View File

@@ -0,0 +1,36 @@
#include <stdio.h>
#include "__printf.h"
struct __vsnprintf_arg {
char *buf;
size_t idx;
size_t max;
};
static void _out_buf(struct __printf_backend *bk, char ch)
{
struct __vsnprintf_arg *arg = bk->arg;
if (arg->idx < arg->max) {
arg->buf[arg->idx] = ch;
}
arg->idx++;
}
int vsnprintf(char *buf, size_t sz, const char *restrict format, va_list arg)
{
struct __vsnprintf_arg bk_arg = {};
bk_arg.buf = buf;
bk_arg.max = sz;
struct __printf_backend bk = {};
bk.out = _out_buf;
bk.arg = &bk_arg;
__xprintf(&bk, format, arg);
if (!bk_arg.idx) {
return 0;
}
return bk_arg.idx - 1;
}

6
libc/stdio/vsprintf.c Normal file
View File

@@ -0,0 +1,6 @@
#include <stdio.h>
int vsprintf(char *buf, const char *restrict format, va_list arg)
{
return vsnprintf(buf, (size_t)-1, format, arg);
}

16
libc/stdlib/abort.c Normal file
View File

@@ -0,0 +1,16 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
/* defined in dyld/main.c */
extern const char *dyld_exec_path(void);
_Noreturn void abort(void)
{
/* yes we're faking the job number shut up */
char header[64];
snprintf(header, sizeof header, "[1] %6d abort", getpid());
fprintf(stderr, "%-20s %s\n", header, dyld_exec_path());
exit(-1);
}

8
libc/stdlib/assert.c Normal file
View File

@@ -0,0 +1,8 @@
#include <stdlib.h>
#include <stdio.h>
extern void _Noreturn __assert_fail(const char *exp, const char *func, const char *file, int line)
{
printf("Assertion failed: (%s), function %s, file %s, line %d\n", exp, func, file, line);
abort();
}

21
libc/stdlib/atexit.c Normal file
View File

@@ -0,0 +1,21 @@
#define MAX_FN 32
static void(*atexit_fn[MAX_FN])(void);
static int atexit_fn_count = 0;
int atexit(void(*fn)(void))
{
if (atexit_fn_count == MAX_FN) {
return -1;
}
atexit_fn[atexit_fn_count++] = fn;
return 0;
}
void __crt_run_atexit()
{
for (int i = 0; i < atexit_fn_count; i++) {
atexit_fn[i]();
}
}

42
libc/stdlib/atof.c Normal file
View File

@@ -0,0 +1,42 @@
#include <ctype.h>
double atof(const char *s)
{
double a = 0.0;
int e = 0;
int c;
while ((c = *s++) != '\0' && isdigit(c)) {
a = a*10.0 + (c - '0');
}
if (c == '.') {
while ((c = *s++) != '\0' && isdigit(c)) {
a = a*10.0 + (c - '0');
e = e-1;
}
}
if (c == 'e' || c == 'E') {
int sign = 1;
int i = 0;
c = *s++;
if (c == '+')
c = *s++;
else if (c == '-') {
c = *s++;
sign = -1;
}
while (isdigit(c)) {
i = i*10 + (c - '0');
c = *s++;
}
e += i*sign;
}
while (e > 0) {
a *= 10.0;
e--;
}
while (e < 0) {
a *= 0.1;
e++;
}
return a;
}

0
libc/stdlib/atoi.c Normal file
View File

6
libc/stdlib/exit.c Normal file
View File

@@ -0,0 +1,6 @@
#include <__system.h>
_Noreturn void exit(int code)
{
__exit(code);
}

6
libc/stdlib/getenv.c Normal file
View File

@@ -0,0 +1,6 @@
extern char *__crt_sys_getenv(const char *name);
char *getenv(const char *name)
{
return __crt_sys_getenv(name);
}

31
libc/stdlib/rand.c Normal file
View File

@@ -0,0 +1,31 @@
#include <stddef.h>
static unsigned int seed = 0;
void srand(unsigned int _seed)
{
seed = _seed;
}
int rand(void)
{
int next = seed;
int result;
next *= 1103515245;
next += 12345;
result = (int)(next / 65536) % 2048;
next *= 1103515245;
next += 12345;
result <<= 10;
result ^= (int)(next / 65536) % 1024;
next *= 1103515245;
next += 12345;
result <<= 10;
result ^= (int)(next / 65536) % 1024;
seed = next;
return result;
}

91
libc/stdlib/strtod.c Normal file
View File

@@ -0,0 +1,91 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
double strtod(const char *str, char **ptr)
{
if (ptr == (char **)0) {
return atof(str);
}
size_t len = strlen(str);
char rstr[len + 1];
strcpy(rstr, str);
char *p = rstr;
while (isspace(*p)) {
++p;
}
if (*p == '+' || *p == '-') {
++p;
}
if ((p[0] == 'i' || p[0] == 'I')
&& (p[1] == 'n' || p[1] == 'N')
&& (p[2] == 'f' || p[2] == 'F')) {
if ((p[3] == 'i' || p[3] == 'I')
&& (p[4] == 'n' || p[4] == 'N')
&& (p[5] == 'i' || p[5] == 'I')
&& (p[6] == 't' || p[6] == 'T')
&& (p[7] == 'y' || p[7] == 'Y')) {
*ptr = p + 8;
return atof(str);
} else {
*ptr = p + 3;
return atof(str);
}
}
if ((p[0] == 'n' || p[0] == 'N')
&& (p[1] == 'a' || p[1] == 'A')
&& (p[2] == 'n' || p[2] == 'N')) {
p += 3;
if (*p == '(') {
++p;
while (*p != '\0' && *p != ')') {
++p;
}
if (*p == ')') {
++p;
}
}
*ptr = p;
return atof(str);
}
if (isdigit(*p) || *p == '.') {
int got_dot = 0;
while (isdigit(*p) || (!got_dot && *p == '.')) {
if (*p == '.')
got_dot = 1;
++p;
}
if (*p == 'e' || *p == 'E') {
int i;
i = 1;
if (p[i] == '+' || p[i] == '-') {
++i;
}
if (isdigit (p[i])) {
while (isdigit (p[i])) {
++i;
}
*ptr = p + i;
return atof(str);
}
}
*ptr = p;
return atof(str);
}
*ptr = (char *)str;
return 0.0;
}

33
libc/stdlib/strtof.c Normal file
View File

@@ -0,0 +1,33 @@
#include <ctype.h>
float strtof(const char *str, char **endptr)
{
float res = 0.0F;
char *ptr = (char*)str;
int after_dot = 0;
float div = 1;
while (*ptr != '\0') {
if (isdigit(*ptr)) {
if (!after_dot) {
res *= 10;
res += *ptr - '0';
} else {
div *= 10;
res += (float)(*ptr - '0') / div;
}
} else if (*ptr == '.') {
after_dot = 1;
} else {
break;
}
ptr++;
}
if (endptr) {
*endptr = ptr;
}
return res;
}

73
libc/stdlib/strtol.c Normal file
View File

@@ -0,0 +1,73 @@
#include <ctype.h>
#include <stdint.h>
#include <limits.h>
long strtol(const char *nptr, char **endptr, int base)
{
const char *s = nptr;
unsigned long acc;
int c;
unsigned long cutoff;
int neg = 0, any, cutlim;
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+') {
c = *s++;
} if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
} else if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0) {
base = c == '0' ? 8 : 10;
}
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c)) {
c -= '0';
} else if (isalpha(c)) {
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
} else {
break;
}
if (c >= base) {
break;
} if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) {
any = -1;
} else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
} else if (neg) {
acc = -acc;
}
if (endptr != 0) {
*endptr = (char *)(any ? s - 1 : nptr);
}
return acc;
}

74
libc/stdlib/strtoul.c Normal file
View File

@@ -0,0 +1,74 @@
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
unsigned long strtoul(const char *nptr, char **endptr, int base)
{
const char *s = nptr;
unsigned long acc;
int c;
unsigned long cutoff;
int neg = 0, any, cutlim;
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+') {
c = *s++;
} if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
} else if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0) {
base = c == '0' ? 8 : 10;
}
cutoff = ULONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c)) {
c -= '0';
} else if (isalpha(c)) {
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
} else {
break;
}
if (c >= base) {
break;
} if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) {
any = -1;
} else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
} else if (neg) {
acc = -acc;
}
if (endptr != 0) {
*endptr = (char *)(any ? s - 1 : nptr);
}
return acc;
}

12
libc/string/fread.c Normal file
View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <__fio.h>
size_t fread(void *ptr, size_t size, size_t count, FILE *fp)
{
if (!size || !count) {
return 0;
}
unsigned int written = __fio_read(fp, ptr, size * count);
return written / size;
}

0
libc/string/fwrite.c Normal file
View File

14
libc/string/memcmp.c Normal file
View File

@@ -0,0 +1,14 @@
#include <stddef.h>
int memcmp(const void *a, const void *b, size_t n)
{
const unsigned char *s1 = a, *s2 = b;
for (size_t i = 0; i < n; i++) {
if (s1[i] != s2[i]) {
return ((s1[i] < s2[i]) ? -1 : 1);
}
}
return 0;
}

43
libc/string/memcpy.c Normal file
View File

@@ -0,0 +1,43 @@
#include <stddef.h>
#define ALIGNED(p) (!((long)p & (sizeof(long) - 1)))
#define QUADBLOCKSIZE (sizeof(long) << 2)
#define BLOCKSIZE (sizeof(long))
void *memcpy(void *dest, const void *src, size_t sz)
{
/* Only try word-writing if the pointers are aligned and
* the buffer is big enough */
if (sz >= BLOCKSIZE && ALIGNED(dest) && ALIGNED(src)) {
long *dest_word = dest;
const long *src_word = src;
/* First try copying 4x blocks per iteration */
while (sz >= QUADBLOCKSIZE) {
*dest_word++ = *src_word++;
*dest_word++ = *src_word++;
*dest_word++ = *src_word++;
*dest_word++ = *src_word++;
sz -= QUADBLOCKSIZE;
}
/* Then try copying 1x words per iteration */
while (sz >= BLOCKSIZE) {
*dest_word++ = *src_word++;
sz -= BLOCKSIZE;
}
/* Then go back to the byte-level copying */
dest = dest_word;
src = src_word;
}
char *dest0 = dest;
const char *src0 = src;
while (sz-- > 0) {
*dest0++ = *src0++;
}
return dest;
}

27
libc/string/memmove.c Normal file
View File

@@ -0,0 +1,27 @@
#include <string.h>
#define ALIGNED(p) (!((long)p & (sizeof(long) - 1)))
#define QUADBLOCKSIZE (sizeof(long) << 2)
#define BLOCKSIZE (sizeof(long))
static void *memcpy_r(void *dest, const void *src, size_t sz)
{
unsigned char *d = dest;
const unsigned char *s = src;
for (size_t i = 0; i < sz; i++) {
size_t b = sz - i - 1;
d[b] = s[b];
}
return dest;
}
void *memmove(void *dest, const void *src, size_t n)
{
if (dest < src) {
return memcpy(dest, src, n);
} else {
return memcpy_r(dest, src, n);
}
}

28
libc/string/memset.c Normal file
View File

@@ -0,0 +1,28 @@
#include <stddef.h>
void *memset(void *ptr, int value, size_t sz)
{
value = (unsigned char)value;
unsigned int realval =
value |
(value << 8) |
(value << 16) |
(value << 24);
unsigned char *buf = ptr;
size_t i = 0;
for (i = 0; i < sz; i += sizeof(unsigned int)) {
unsigned int *t = (unsigned int *)&buf[i];
*t = realval;
}
if (sz % sizeof(unsigned int)) {
i -= sizeof(unsigned int);
while (i < sz) {
buf[i++] = value;
}
}
return ptr;
}

8
libc/string/strcat.c Normal file
View File

@@ -0,0 +1,8 @@
#include <string.h>
char *strcat(char *dest, const char *src)
{
size_t len = strlen(dest);
strcpy(dest + len, src);
return dest;
}

14
libc/string/strchr.c Normal file
View File

@@ -0,0 +1,14 @@
#include <string.h>
char *strchr(const char *str, int ch)
{
char c = ch;
for (size_t i = 0; str[i]; i++) {
if (str[i] == c) {
return (char *)&str[i];
}
}
return NULL;
}

25
libc/string/strcmp.c Normal file
View File

@@ -0,0 +1,25 @@
#include <stddef.h>
int strcmp(const char *s1, const char *s2)
{
int i;
for (i = 0; s1[i] == s2[i]; i++) {
if (s1[i] == '\0') {
return 0;
}
}
return s1[i] - s2[i];
}
int strncmp(const char *s1, const char *s2, size_t n)
{
for (; n > 0; s1++, s2++, --n) {
if (*s1 != *s2) {
return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : 1);
} else if (*s1 == '\0') {
return 0;
}
}
return 0;
}

26
libc/string/strcpy.c Normal file
View File

@@ -0,0 +1,26 @@
char *strcpy(char *output, const char *input)
{
unsigned int i;
for (i = 0; input[i] != 0; i++) {
output[i] = input[i];
}
output[i] = '\0';
return output;
}
char *strncpy(char *output, const char *input, unsigned int count)
{
unsigned int size = count;
unsigned int i;
for (i = 0; i < size; i++) {
output[i] = input[i];
if (input[i] == 0) {
break;
}
}
output[i] = '\0';
return output;
}

15
libc/string/strcspn.c Normal file
View File

@@ -0,0 +1,15 @@
#include <stddef.h>
size_t strcspn(const char *str1, const char *str2)
{
size_t i;
for (i = 0; str1[i]; i++) {
for (size_t ii = 0; str2[ii]; ii++) {
if (str1[i] == str2[ii]) {
return i;
}
}
}
return i;
}

11
libc/string/strdup.c Normal file
View File

@@ -0,0 +1,11 @@
#include <string.h>
#include <stdlib.h>
char *strdup(const char *str)
{
size_t len = strlen(str);
char *out = malloc(len + 1);
memcpy(out, str, len);
out[len] = 0;
return out;
}

152
libc/string/strerror.c Normal file
View File

@@ -0,0 +1,152 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
static const char *sys_errlist[] = {
[EPERM] = "Operation not permitted",
[ENOENT] = "No such file or directory",
[ESRCH] = "No such process",
[EINTR] = "Interrupted system call",
[EIO] = "Input/output error",
[ENXIO] = "No such device or address",
[E2BIG] = "Argument list too long",
[ENOEXEC] = "Exec format error",
[EBADF] = "Bad file descriptor",
[ECHILD] = "No child processes",
[EAGAIN] = "Resource temporarily unavailable",
[ENOMEM] = "Cannot allocate memory",
[EACCES] = "Permission denied",
[EFAULT] = "Bad address",
[ENOTBLK] = "Block device required",
[EBUSY] = "Device or resource busy",
[EEXIST] = "File exists",
[EXDEV] = "Invalid cross-device link",
[ENODEV] = "No such device",
[ENOTDIR] = "Not a directory",
[EISDIR] = "Is a directory",
[EINVAL] = "Invalid argument",
[ENFILE] = "Too many open files in system",
[EMFILE] = "Too many open files",
[ENOTTY] = "Inappropriate ioctl for device",
[ETXTBSY] = "Text file busy",
[EFBIG] = "File too large",
[ENOSPC] = "No space left on device",
[ESPIPE] = "Illegal seek",
[EROFS] = "Read-only file system",
[EMLINK] = "Too many links",
[EPIPE] = "Broken pipe",
[EDOM] = "Numerical argument out of domain",
[ERANGE] = "Numerical result out of range",
[EDEADLK] = "Resource deadlock avoided",
[ENAMETOOLONG] = "File name too long",
[ENOLCK] = "No locks available",
[ENOSYS] = "Function not implemented",
[ENOTEMPTY] = "Directory not empty",
[ELOOP] = "Too many levels of symbolic links",
[ENOMSG] = "No message of desired type",
[EIDRM] = "Identifier removed",
[ECHRNG] = "Channel number out of range",
[EL2NSYNC] = "Level 2 not synchronized",
[EL3HLT] = "Level 3 halted",
[EL3RST] = "Level 3 reset",
[ELNRNG] = "Link number out of range",
[EUNATCH] = "Protocol driver not attached",
[ENOCSI] = "No CSI structure available",
[EL2HLT] = "Level 2 halted",
[EBADE] = "Invalid exchange",
[EBADR] = "Invalid request descriptor",
[EXFULL] = "Exchange full",
[ENOANO] = "No anode",
[EBADRQC] = "Invalid request code",
[EBADSLT] = "Invalid slot",
[EBFONT] = "Bad font file format",
[ENOSTR] = "Device not a stream",
[ENODATA] = "No data available",
[ETIME] = "Timer expired",
[ENOSR] = "Out of streams resources",
[ENONET] = "Machine is not on the network",
[ENOPKG] = "Package not installed",
[EREMOTE] = "Object is remote",
[ENOLINK] = "Link has been severed",
[EADV] = "Advertise error",
[ESRMNT] = "Srmount error",
[ECOMM] = "Communication error on send",
[EPROTO] = "Protocol error",
[EMULTIHOP] = "Multihop attempted",
[EDOTDOT] = "RFS specific error",
[EBADMSG] = "Bad message",
[EOVERFLOW] = "Value too large for defined data type",
[ENOTUNIQ] = "Name not unique on network",
[EBADFD] = "File descriptor in bad state",
[EREMCHG] = "Remote address changed",
[ELIBACC] = "Can not access a needed shared library",
[ELIBBAD] = "Accessing a corrupted shared library",
[ELIBSCN] = ".lib section in a.out corrupted",
[ELIBMAX] = "Attempting to link in too many shared libraries",
[ELIBEXEC] = "Cannot exec a shared library directly",
[EILSEQ] = "Invalid or incomplete multibyte or wide character",
[ERESTART] = "Interrupted system call should be restarted",
[ESTRPIPE] = "Streams pipe error",
[EUSERS] = "Too many users",
[ENOTSOCK] = "Socket operation on non-socket",
[EDESTADDRREQ] = "Destination address required",
[EMSGSIZE] = "Message too long",
[EPROTOTYPE] = "Protocol wrong type for socket",
[ENOPROTOOPT] = "Protocol not available",
[EPROTONOSUPPORT] = "Protocol not supported",
[ESOCKTNOSUPPORT] = "Socket type not supported",
[ENOTSUP] = "Operation not supported",
[EPFNOSUPPORT] = "Protocol family not supported",
[EAFNOSUPPORT] = "Address family not supported by protocol",
[EADDRINUSE] = "Address already in use",
[EADDRNOTAVAIL] = "Cannot assign requested address",
[ENETDOWN] = "Network is down",
[ENETUNREACH] = "Network is unreachable",
[ENETRESET] = "Network dropped connection on reset",
[ECONNABORTED] = "Software caused connection abort",
[ECONNRESET] = "Connection reset by peer",
[ENOBUFS] = "No buffer space available",
[EISCONN] = "Transport endpoint is already connected",
[ENOTCONN] = "Transport endpoint is not connected",
[ESHUTDOWN] = "Cannot send after transport endpoint shutdown",
[ETOOMANYREFS] = "Too many references: cannot splice",
[ETIMEDOUT] = "Connection timed out",
[ECONNREFUSED] = "Connection refused",
[EHOSTDOWN] = "Host is down",
[EHOSTUNREACH] = "No route to host",
[EALREADY] = "Operation already in progress",
[EINPROGRESS] = "Operation now in progress",
[ESTALE] = "Stale file handle",
[EUCLEAN] = "Structure needs cleaning",
[ENOTNAM] = "Not a XENIX named type file",
[ENAVAIL] = "No XENIX semaphores available",
[EISNAM] = "Is a named type file",
[EREMOTEIO] = "Remote I/O error",
[EDQUOT] = "Disk quota exceeded",
[ENOMEDIUM] = "No medium found",
[EMEDIUMTYPE] = "Wrong medium type",
[ECANCELED] = "Operation canceled",
[ENOKEY] = "Required key not available",
[EKEYEXPIRED] = "Key has expired",
[EKEYREVOKED] = "Key has been revoked",
[EKEYREJECTED] = "Key was rejected by service",
[EOWNERDEAD] = "Owner died",
[ENOTRECOVERABLE] = "State not recoverable",
[ERFKILL] = "Operation not possible due to RF-kill",
[EHWPOISON] = "Memory page has hardware error",
};
static int n_sys_errlist = sizeof sys_errlist / sizeof sys_errlist[0];
static char g_msg_buf[128];
char *strerror(int errnum)
{
if (errnum <= 0 || errnum >= n_sys_errlist) {
snprintf(g_msg_buf, sizeof g_msg_buf, "Unknown error: %d", errnum);
} else {
strncpy(g_msg_buf, sys_errlist[errnum], sizeof g_msg_buf - 1);
g_msg_buf[sizeof g_msg_buf - 1] = '\0';
}
return g_msg_buf;
}

11
libc/string/strlen.c Normal file
View File

@@ -0,0 +1,11 @@
#include <string.h>
size_t strlen(const char *str)
{
const char *start = str;
while (*str) {
str++;
}
return str - start;
}

15
libc/string/strrchr.c Normal file
View File

@@ -0,0 +1,15 @@
#include <string.h>
char *strrchr(const char *s, int c)
{
/* include null term */
long sz = strlen(s) + 1;
for (long i = sz; i >= 0; i--) {
if (s[i] == c) {
return (char *)(s + i);
}
}
return NULL;
}

62
libc/string/strtok.c Normal file
View File

@@ -0,0 +1,62 @@
#include <string.h>
static char *global_sp = NULL;
char *strtok(char *str, const char *delim)
{
return strtok_r(str, delim, &global_sp);
}
char *strtok_r(char *str, const char *delim, char **sp)
{
int i = 0;
int len = strlen(delim);
if (len == 0) {
return NULL;
}
if (!str && !sp) {
return NULL;
}
if (str) {
*sp = str;
}
char *p_start = *sp;
while (1) {
for (i = 0; i < len; i++) {
if (*p_start == delim[i]) {
p_start++;
break;
}
}
if (i == len) {
*sp = p_start;
break;
}
}
if (**sp == '\0') {
*sp = NULL;
return *sp;
}
while (**sp != '\0') {
for (i = 0; i < len; i++) {
if (**sp == delim[i]) {
**sp = '\0';
break;
}
}
(*sp)++;
if (i < len) {
break;
}
}
return p_start;
}

323
libc/sys/horizon/__elf.h Normal file
View File

@@ -0,0 +1,323 @@
#ifndef SYS_HORIZON_SYS___ELF_H_
#define SYS_HORIZON_SYS___ELF_H_
#include <magenta/types.h>
#include <stdint.h>
#define ELF_LOAD_ERR -1
#define ELF_LOADED_EXEC 0
#define ELF_LOADED_INTERP 1
#define ELF_MAG0 0x7f
#define ELF_MAG1 'E'
#define ELF_MAG2 'L'
#define ELF_MAG3 'F'
#define ELF_NIDENT 16
#define SHT_NONE 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_DYNAMIC 6
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_DYNSYM 11
/** Little endian. */
#define ELFDATA2LSB (1)
/** 64-bit. */
#define ELFCLASS64 (2)
/** x86_64 machine type. */
#define EM_X86_64 (62)
/** ELF current version. */
#define EV_CURRENT (1)
/** Dynamic section tags. */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_JMPREL 23
#define DT_GNU_HASH 0x6ffffef5
#define DT_AUXILIARY 0x7ffffffd
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GOT32 3
#define R_386_PLT32 4
#define R_386_GOTOFF 9
#define R_386_GOTPC 10
#define R_386_GOT32X 43
#define R_X86_64_64 1
#define R_X86_64_PC32 2
#define R_X86_64_GOT32 3
#define R_X86_64_PLT32 4
#define R_X86_64_COPY 5
#define R_X86_64_GLOB_DAT 6
#define R_X86_64_JUMP_SLOT 7
#define R_X86_64_RELATIVE 8
#define R_X86_64_GOTPCREL 9
#define R_X86_64_32 10
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
/* Section flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHN_UNDEF 0
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((elf_word_t)(i))
#define ELF64_ST_BIND(i) ((i) >> 4)
#define ELF64_ST_TYPE(i) ((i)&0xf)
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_NUM 3
typedef uint64_t elf_addr_t;
typedef uint64_t elf_off_t;
typedef uint16_t elf_half_t;
typedef uint32_t elf_word_t;
typedef int32_t elf_sword_t;
typedef uint64_t elf_xword_t;
typedef int64_t elf_sxword_t;
/**
* ELF file header.
*/
typedef struct {
uint8_t e_ident[ELF_NIDENT];
elf_half_t e_type;
elf_half_t e_machine;
elf_word_t e_version;
elf_addr_t e_entry;
elf_off_t e_phoff;
elf_off_t e_shoff;
elf_word_t e_flags;
elf_half_t e_ehsize;
elf_half_t e_phentsize;
elf_half_t e_phnum;
elf_half_t e_shentsize;
elf_half_t e_shnum;
elf_half_t e_shstrndx;
} elf_ehdr_t;
/**
* ELF section header.
*/
typedef struct {
elf_word_t sh_name;
elf_word_t sh_type;
elf_xword_t sh_flags;
elf_addr_t sh_addr;
elf_off_t sh_offset;
elf_xword_t sh_size;
elf_word_t sh_link;
elf_word_t sh_info;
elf_xword_t sh_addralign;
elf_xword_t sh_entsize;
} elf_shdr_t;
/**
* ELF symbol.
*/
typedef struct {
elf_word_t st_name;
unsigned char st_info;
unsigned char st_other;
elf_half_t st_shndx;
elf_addr_t st_value;
elf_xword_t st_size;
} elf_sym_t;
/**
* ELF program header.
*/
typedef struct {
elf_word_t p_type;
elf_word_t p_flags;
elf_off_t p_offset;
elf_addr_t p_vaddr;
elf_addr_t p_paddr;
elf_xword_t p_filesz;
elf_xword_t p_memsz;
elf_xword_t p_align;
} elf_phdr_t;
/**
* Extended ELF relocation information.
*/
typedef struct {
elf_addr_t r_offset;
elf_xword_t r_info;
elf_sxword_t r_addend;
} elf_rela_t;
/**
* Dynamic section entries
*/
typedef struct {
elf_sxword_t d_tag;
union {
elf_xword_t d_val;
elf_addr_t d_ptr;
} d_un;
} elf_dyn_t;
/**
* Section header types.
*/
enum elf_stype {
ST_NONE = 0,
ST_PROGBITS = 1,
ST_SYMTAB = 2,
ST_STRTAB = 3,
ST_NOBITS = 8,
ST_REL = 9
};
/**
* Program header types.
*/
enum elf_ptype {
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6
};
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
/**
* ELF identification byte locations.
*/
enum elf_ident {
EI_MAG0 = 0,
EI_MAG1 = 1,
EI_MAG2 = 2,
EI_MAG3 = 3,
EI_CLASS = 4,
EI_DATA = 5,
EI_VERSION = 6,
EI_OSABI = 7,
EI_ABIVERSION = 8,
EI_PAD = 9
};
enum elf_type {
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
};
#define AT_NULL 0
#define AT_IGNORE 1
#define AT_EXECFD 2
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_ENTRY 9
#define AT_NOTELF 10
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_CLKTCK 17
#define AT_PLATFORM 15
#define AT_HWCAP 16
#define AT_FPUCW 18
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
#define AT_IGNOREPPC 22
#define AT_SECURE 23
#define AT_BASE_PLATFORM 24
#define AT_RANDOM 25
#define AT_HWCAP2 26
#define AT_EXECFN 31
#define AT_SYSINFO 32
#define AT_SYSINFO_EHDR 33
#define AT_L1I_CACHESHAPE 34
#define AT_L1D_CACHESHAPE 35
#define AT_L2_CACHESHAPE 36
#define AT_L3_CACHESHAPE 37
#define AT_ENTRY_COUNT 38
struct bootdata;
struct bootfs_file;
struct elf_image {
mx_handle_t image_vmo, rw_vmo;
mx_vaddr_t local_base_addr, remote_base_addr;
mx_handle_t local_root_vmar, local_exec_vmar;
mx_handle_t remote_root_vmar, remote_exec_vmar;
size_t exec_vmar_size;
elf_ehdr_t hdr;
uintptr_t dynstr_offset;
size_t dynstr_len;
uintptr_t dynsym_offset;
size_t dynsym_len, dynsym_entsz;
elf_phdr_t dynamic;
enum { NO_HASH, REG_HASH, GNU_HASH } hash_type;
uintptr_t hash_offset;
};
extern void __elf_image_init(mx_handle_t local_vmar, mx_handle_t remote_vmar, struct elf_image *out);
extern int __elf_image_load_image(struct elf_image *image, mx_handle_t image_vmo);
extern int __elf_get_interp_path(mx_handle_t exec_vmo, char *out, size_t max);
extern int __elf_check_dependencies(struct elf_image *image);
extern mx_vaddr_t __elf_image_get_symbol(struct elf_image *image, const char *name);
extern int __elf_image_link(struct elf_image *exec, struct elf_image *vdso);
extern mx_vaddr_t __elf_image_entry_point(struct elf_image *image);
extern void __elf_image_cleanup(struct elf_image *image);
#endif

36
libc/sys/horizon/__fio.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef SYS_HORIZON___FIO_H_
#define SYS_HORIZON___FIO_H_
#define __FIO_BUFSZ 512
#if defined(__cplusplus)
extern "C" {
#endif
struct __io_file {
char in_buf[__FIO_BUFSZ];
char out_buf[__FIO_BUFSZ];
unsigned long in_buf_ptr, in_buf_len;
unsigned long out_buf_len;
int fd, unget;
char err, eof;
};
extern int __fileno(struct __io_file *f);
extern void __fio_init(int in, int out, int err);
extern unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz);
extern unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz);
extern unsigned int __fio_flush(struct __io_file *f);
extern int __fio_error(struct __io_file *f);
extern int __fio_eof(struct __io_file *f);
extern int __fio_ungetc(struct __io_file *f, char c);
extern int __fio_fopen(const char *path, const char *mode, struct __io_file *out);
extern int __fio_fclose(struct __io_file *in);
extern int __fio_fdopen(int fd, const char *mode, struct __io_file *out);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,8 @@
#ifndef SYS_HORIZON_HEAP_H_
#define SYS_HORIZON_HEAP_H_
#include "__init.h"
extern int __heap_init();
#endif

View File

@@ -0,0 +1,4 @@
#ifndef SYS_HORIZON_INIT_H_
#define SYS_HORIZON_INIT_H_
#endif

View File

@@ -0,0 +1,14 @@
#ifndef SYS_LINUX___SYSTEM_H_
#define SYS_LINUX___SYSTEM_H_
#if defined(__cplusplus)
extern "C" {
#endif
extern _Noreturn void __exit(int code);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,6 @@
#ifndef SYS_HORIZON___TIME_H_
#define SYS_HORIZON___TIME_H_
#include <time.h>
#endif

View File

157
libc/sys/horizon/dirent.c Normal file
View File

@@ -0,0 +1,157 @@
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <mio/fs.h>
#include <mio/dirent.h>
DIR *opendir(const char *path)
{
int fd = open(path, O_DIRECTORY);
if (fd < 0) {
return NULL;
}
DIR *out = malloc(sizeof(*out));
if (!out) {
__set_errno(ENOMEM);
return NULL;
}
memset(out, 0x0, sizeof(*out));
out->fd = fd;
return out;
}
int closedir(DIR *d)
{
close(d->fd);
for (int i = 0; i < d->cache_size; i++) {
if (d->dent_cache[i].d_namep) {
free(d->dent_cache[i].d_namep);
}
}
free(d);
return 0;
}
static void clear_cache(DIR *d)
{
for (int i = 0; i < d->cache_size; i++) {
if (d->dent_cache[i].d_namep) {
free(d->dent_cache[i].d_namep);
}
d->dent_cache[i].d_namep = NULL;
}
d->cache_size = d->cache_idx = 0;
}
static int refill(DIR *d)
{
clear_cache(d);
for (int i = 0; i < d->cache_size; i++) {
free(d->dent_cache[i].d_namep);
d->dent_cache[i].d_namep = NULL;
}
d->cache_size = d->cache_idx = 0;
mio_dirent dent[__SYS_DENT_CACHE_SZ];
int r = mio_getdents(d->fd, dent, __SYS_DENT_CACHE_SZ);
if (r < 0) {
__set_errno(-r);
return -1;
}
for (int i = 0; i < r; i++) {
struct __dentcache *cache_ent = &d->dent_cache[i];
cache_ent->d_ino = dent[i].d_ino;
cache_ent->d_type = dent[i].d_type;
cache_ent->d_namep = strdup(dent[i].d_name);
}
d->cache_idx = 0;
d->cache_size = r;
return 0;
}
static void fill_dirent(DIR *d, struct dirent *out)
{
if (d->cache_idx >= d->cache_size) {
return;
}
struct __dentcache *cache_ent = &d->dent_cache[d->cache_idx];
out->d_ino = cache_ent->d_ino;
out->d_type = cache_ent->d_type;
if (cache_ent->d_namep) {
strncpy(out->d_name, cache_ent->d_namep, sizeof out->d_name - 1);
out->d_name[sizeof out->d_name - 1] = '\0';
}
}
struct dirent *readdir(DIR *d)
{
if (d->cache_idx == d->cache_size) {
if (refill(d) != 0 || !d->cache_size) {
return NULL;
}
}
fill_dirent(d, &d->cdent);
d->cache_idx++;
d->seek++;
return &d->cdent;
}
int readdir_r(DIR *d, struct dirent *entry, struct dirent **result)
{
if (d->cache_idx == d->cache_size) {
if (refill(d) != 0) {
return 1;
}
if (d->cache_size == 0) {
if (result) {
*result = NULL;
}
return 0;
}
}
fill_dirent(d, entry);
d->seek++;
if (result) {
*result = entry;
}
return 0;
}
void rewinddir(DIR *d)
{
d->seek = mio_seek(d->fd, 0, SEEK_SET);
clear_cache(d);
}
void seekdir(DIR *d, long int off)
{
d->seek = mio_seek(d->fd, off, SEEK_SET);
clear_cache(d);
}
long int telldir(DIR *d)
{
return d->seek;
}

56
libc/sys/horizon/dlfcn.c Normal file
View File

@@ -0,0 +1,56 @@
#include <magenta/types.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <mio/fs.h>
__attribute__((weak)) void *dyld_load_object(const char *path, mx_handle_t handle, int mode) { return NULL; }
__attribute__((weak)) void *dyld_get_symbol(void *handle, const char *name) { return NULL; }
__attribute__((weak)) int dyld_close_object(void *handle) { return 0; }
__attribute__((weak)) char *dyld_get_error(void) { return NULL; }
static char dl_error[512] = {};
void *dlopen(const char *path, int mode)
{
/* TODO include error message from errno */
int fd = open(path, O_RDONLY);
if (fd == -1) {
snprintf(dl_error, sizeof dl_error, "cannot open '%s'", path);
return NULL;
}
mx_handle_t image_vmo = MX_NULL_HANDLE;
int err = mio_map_file(fd, &image_vmo);
close(fd);
if (err != 0) {
snprintf(dl_error, sizeof dl_error, "cannot load '%s'", path);
return NULL;
}
dl_error[0] = '\0';
return dyld_load_object(path, image_vmo, mode);
}
void *dlsym(void *handle, const char *name)
{
return dyld_get_symbol(handle, name);
}
int dlclose(void *handle)
{
return dyld_close_object(handle);
}
char *dlerror(void)
{
if (dl_error[0] != '\0') {
return dl_error;
}
return dyld_get_error();
}

673
libc/sys/horizon/elf.c Normal file
View File

@@ -0,0 +1,673 @@
#include <magenta/misc.h>
#include <magenta/errors.h>
#include <magenta/handle.h>
#include <magenta/vmo.h>
#include <magenta/vmar.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "__elf.h"
#define HIDDEN __attribute__((visibility("hidden")))
#define VDSO_SONAME "mx.dylib"
#define NEEDS_NOTHING 0
#define NEEDS_VDSO 1
#define NEEDS_MORE 2
#define ACL (PF_R | PF_W | PF_X)
#define ACCESS(x) ((x) & ACL)
/* TODO in case we ever support ELF32 images */
#define elf_class_bits(x) (64)
#define PAGE_OFFSET(v) ((v) & (MX_PAGE_SIZE - 1))
#define PAGE_ALIGN_DOWN(v) (v) &= ~(MX_PAGE_SIZE - 1)
#define PAGE_ALIGN_UP(v) \
do { \
if ((v) & (MX_PAGE_SIZE - 1)) { \
v &= ~(MX_PAGE_SIZE - 1); \
v += MX_PAGE_SIZE; \
} \
} while (0)
#undef DEBUG_LOG
HIDDEN void __elf_image_init(mx_handle_t local_vmar, mx_handle_t remote_vmar, struct elf_image *out)
{
memset(out, 0x0, sizeof(*out));
out->local_root_vmar = local_vmar;
out->remote_root_vmar = remote_vmar;
}
static int elf_validate_ehdr(elf_ehdr_t *hdr)
{
if (hdr->e_ident[EI_MAG0] != ELF_MAG0) {
return -1;
}
if (hdr->e_ident[EI_MAG1] != ELF_MAG1) {
return -1;
}
if (hdr->e_ident[EI_MAG2] != ELF_MAG2) {
return -1;
}
if (hdr->e_ident[EI_MAG3] != ELF_MAG3) {
return -1;
}
if (hdr->e_ident[EI_CLASS] != ELFCLASS64) {
return -1;
}
if (hdr->e_machine != EM_X86_64) {
return -1;
}
if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
return -1;
}
if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
return -1;
}
return 0;
}
static int read_header(struct elf_image *image)
{
mx_status_t err = mx_vmo_read(image->image_vmo, (uint8_t *)&image->hdr, sizeof(image->hdr), 0);
if (err != MX_OK) {
printf("vmo_read %x error %s\n", image->image_vmo, mx_status_to_string(err));
return -1;
}
return elf_validate_ehdr(&image->hdr);
}
static mx_status_t allocate_vmar(struct elf_image *image, size_t size)
{
mx_status_t err = mx_vmar_allocate(image->local_root_vmar,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE |
MX_VM_CAN_MAP_EXEC | MX_VM_CAN_MAP_SPECIFIC,
0, size, &image->local_exec_vmar, &image->local_base_addr);
if (err != MX_OK) {
return err;
}
err = mx_vmar_allocate(image->remote_root_vmar,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE |
MX_VM_CAN_MAP_EXEC | MX_VM_CAN_MAP_SPECIFIC,
0, size, &image->remote_exec_vmar, &image->remote_base_addr);
image->exec_vmar_size = size;
return err;
}
static void deduce_dynsym_count(struct elf_image *image)
{
if (image->hash_type == REG_HASH) {
image->dynsym_len = *(((uint32_t *)image->hash_offset) + 1);
} else {
/* We don't need to know the symbol count to use DT_GNU_HASH
* (which is good because calculating it is a pain) */
image->dynsym_len = 0;
}
}
static void read_dynamic_segment(struct elf_image *image)
{
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
for (int i = 0;; i++) {
elf_dyn_t *dyn = &dyn_array[i];
if (dyn->d_tag == DT_NULL) {
break;
}
switch (dyn->d_tag) {
case DT_STRTAB:
image->dynstr_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
case DT_STRSZ:
image->dynstr_len = dyn->d_un.d_val;
break;
case DT_SYMTAB:
image->dynsym_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
case DT_SYMENT:
image->dynsym_entsz = dyn->d_un.d_val;
break;
case DT_HASH:
/* prefer the GNU hash table */
if (image->hash_type == GNU_HASH) {
continue;
}
image->hash_type = REG_HASH;
image->hash_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
case DT_GNU_HASH:
image->hash_type = GNU_HASH;
image->hash_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
default:
break;
}
}
}
static void get_memory_requirements(void *phdr_buf, int entsize, int nr_phdr,
size_t *out_vmem, size_t *out_rw)
{
size_t vmem_max = 0;
size_t rw_max = 0;
for (int i = 0; i < nr_phdr; i++) {
elf_phdr_t *phdr = (elf_phdr_t *)((char *)phdr_buf + (i * entsize));
if (phdr->p_type != PT_LOAD) {
continue;
}
size_t foffset = phdr->p_offset;
size_t voffset = phdr->p_vaddr;
PAGE_ALIGN_DOWN(foffset);
PAGE_ALIGN_DOWN(voffset);
size_t vend = phdr->p_vaddr + phdr->p_memsz;
PAGE_ALIGN_UP(vend);
size_t fsize = phdr->p_filesz;
size_t vsize = vend - voffset;
PAGE_ALIGN_UP(fsize);
if (phdr->p_flags & PF_W) {
rw_max += vsize;
}
if (vend > vmem_max) {
vmem_max = vend;
}
}
*out_rw = rw_max;
*out_vmem = vmem_max;
}
static mx_status_t map_memory(struct elf_image *image,
mx_off_t voffset, mx_off_t foffset, size_t sz, int flags, void **out_buf)
{
mx_status_t err = MX_OK;
mx_flags_t options = MX_VM_SPECIFIC;
mx_handle_t vmo = image->image_vmo;
if (flags & PF_R) {
options |= MX_VM_PERM_READ;
}
if (flags & PF_W) {
options |= MX_VM_PERM_WRITE;
vmo = image->rw_vmo;
}
if (flags & PF_X) {
options |= MX_VM_PERM_EXEC;
}
mx_vaddr_t local_addr = 0, remote_addr = 0;
*out_buf = NULL;
err = mx_vmar_map(image->local_exec_vmar, options, voffset, vmo, foffset, sz, &local_addr);
if (err != MX_OK) {
return err;
}
err = mx_vmar_map(image->remote_exec_vmar, options, voffset, vmo, foffset, sz, &remote_addr);
if (err != MX_OK) {
return err;
}
*out_buf = (void *)local_addr;
return MX_OK;
}
static mx_status_t map_image(struct elf_image *image,
void *phdr_buf, int phdr_entsize, int phdr_num)
{
size_t rw_offset = 0;
mx_status_t err = MX_OK;
for (int i = 0; i < phdr_num; i++) {
elf_phdr_t *phdr = (elf_phdr_t *)((char *)phdr_buf + (i * phdr_entsize));
if (phdr->p_type == PT_DYNAMIC) {
image->dynamic = *phdr;
}
if (phdr->p_type != PT_LOAD) {
continue;
}
size_t foffset = phdr->p_offset;
size_t voffset = phdr->p_vaddr;
PAGE_ALIGN_DOWN(foffset);
PAGE_ALIGN_DOWN(voffset);
size_t vend = phdr->p_vaddr + phdr->p_memsz;
PAGE_ALIGN_UP(vend);
size_t fsize = phdr->p_filesz;
size_t vsize = vend - voffset;
PAGE_ALIGN_UP(fsize);
if (phdr->p_flags & PF_W) {
size_t rw_vmo_offset = rw_offset;
size_t rw_vmo_size = vsize;
size_t bss_offset = phdr->p_vaddr + phdr->p_filesz;
size_t bss_size = phdr->p_memsz - phdr->p_filesz;
void *segment_buf = NULL;
err = map_memory(image, voffset, rw_vmo_offset, vsize, phdr->p_flags, &segment_buf);
if (err != MX_OK) {
return err;
}
void *file_dest = (char *)image->local_base_addr + phdr->p_vaddr;
void *bss_dest = (char *)image->local_base_addr + bss_offset;
mx_vmo_read(image->image_vmo, file_dest, phdr->p_filesz, phdr->p_offset);
if (bss_size) {
memset(bss_dest, 0x0, bss_size);
}
rw_offset += rw_vmo_size;
} else {
void *segment_buf = NULL;
err = map_memory(image, voffset, foffset, vsize, phdr->p_flags, &segment_buf);
if (err != MX_OK) {
return err;
}
}
}
return MX_OK;
}
HIDDEN int __elf_image_load_image(struct elf_image *image, mx_handle_t image_vmo)
{
image->image_vmo = image_vmo;
int status = read_header(image);
if (status != 0) {
printf("read_header error\n");
return status;
}
size_t phdr_bufsz = image->hdr.e_phentsize * image->hdr.e_phnum;
unsigned char phdr_buf[phdr_bufsz];
mx_vmo_read(image_vmo, phdr_buf, phdr_bufsz, image->hdr.e_phoff);
size_t rw_size, vmem_size;
get_memory_requirements(phdr_buf, image->hdr.e_phentsize, image->hdr.e_phnum, &vmem_size, &rw_size);
if (allocate_vmar(image, vmem_size) != MX_OK) {
printf("allocate_vmar error\n");
return -1;
}
if (rw_size) {
mx_vmo_create(rw_size, MX_VM_PERM_READ | MX_VM_PERM_WRITE, &image->rw_vmo);
}
mx_status_t err = map_image(image, phdr_buf, image->hdr.e_phentsize, image->hdr.e_phnum);
if (err != MX_OK) {
printf("map_image error\n");
return -1;
}
read_dynamic_segment(image);
return 0;
}
HIDDEN int __elf_get_interp_path(mx_handle_t image_vmo, char *out, size_t max)
{
elf_ehdr_t hdr;
mx_vmo_read(image_vmo, (uint8_t *)&hdr, sizeof(hdr), 0);
if (elf_validate_ehdr(&hdr) != 0) {
return -1;
}
unsigned char phdr_buf[hdr.e_phentsize * hdr.e_phnum];
mx_vmo_read(image_vmo, phdr_buf, hdr.e_phentsize * hdr.e_phnum, hdr.e_phoff);
uintptr_t dynamic_offset = 0, interp_offset = 0;
size_t dynamic_sz = 0, interp_sz = 0;
for (size_t i = 0; i < hdr.e_phnum; i++) {
elf_phdr_t *phdr = (elf_phdr_t *)(phdr_buf + i * hdr.e_phentsize);
switch (phdr->p_type) {
case PT_DYNAMIC:
dynamic_offset = phdr->p_offset;
dynamic_sz = phdr->p_filesz;
break;
case PT_INTERP:
interp_offset = phdr->p_offset;
interp_sz = phdr->p_filesz;
break;
default:
break;
}
}
if (!dynamic_sz || !interp_offset) {
return 0;
}
if (max > interp_sz) {
max = interp_sz;
}
mx_vmo_read(image_vmo, (uint8_t *)out, max, interp_offset);
return 1;
}
HIDDEN int __elf_check_dependencies(struct elf_image *image)
{
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
for (int i = 0;; i++) {
elf_dyn_t *dyn = &dyn_array[i];
if (dyn->d_tag == DT_NULL) {
break;
}
if (dyn->d_tag != DT_NEEDED) {
continue;
}
const char *lib_name = (const char *)(image->local_base_addr + image->dynstr_offset + dyn->d_un.d_ptr);
if (strcmp(lib_name, VDSO_SONAME) != 0) {
/* We can't load executables that link to libraries other than
* libmx */
return -1;
}
}
return 0;
}
static elf_sym_t *get_dynsym_entry(struct elf_image *image, unsigned int idx)
{
return (elf_sym_t *)(image->local_base_addr + image->dynsym_offset + idx * image->dynsym_entsz);
}
static const char *get_dynstr(struct elf_image *image, unsigned int idx)
{
return (const char *)(image->local_base_addr + image->dynstr_offset + idx);
}
static int do_rela(struct elf_image *image, struct elf_image *lib, uintptr_t ptr, size_t sz, size_t entsz)
{
size_t entries = sz / entsz;
for (size_t i = 0; i < entries; i++) {
elf_rela_t *rela = (elf_rela_t *)(image->local_base_addr + ptr + i * entsz);
int sym_idx = ELF64_R_SYM(rela->r_info);
int type = ELF64_R_TYPE(rela->r_info);
mx_vaddr_t sym_val = 0;
if (type != R_X86_64_RELATIVE) {
elf_sym_t *dynsym = get_dynsym_entry(image, sym_idx);
const char *name = get_dynstr(image, dynsym->st_name);
sym_val = __elf_image_get_symbol(image, name);
if (!sym_val && lib) {
sym_val = __elf_image_get_symbol(lib, name);
}
if (!sym_val) {
return -1;
}
}
int ok = 1;
mx_status_t status = MX_OK;
switch (type) {
case R_X86_64_GLOB_DAT: {
elf_xword_t val = sym_val;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} case R_X86_64_64: {
elf_xword_t val = sym_val + rela->r_addend;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} case R_X86_64_JUMP_SLOT: {
elf_xword_t val = sym_val;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} case R_X86_64_RELATIVE: {
elf_xword_t val = image->remote_base_addr + rela->r_addend;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} default:
ok = 0;
break;
}
if (!ok || status != MX_OK) {
return -1;
}
}
return 0;
}
static int relocate(struct elf_image *image, struct elf_image *lib)
{
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
int result = 0;
uintptr_t rel_addr = 0, rela_addr = 0, plt_addr = 0;
size_t rel_sz = 0, rel_entsz = 0;
size_t rela_sz = 0, rela_entsz = 0;
size_t plt_sz = 0, plt_entsz = 0;
int plt_enttype;
for (int i = 0;; i++) {
elf_dyn_t *dyn = &dyn_array[i];
if (dyn->d_tag == DT_NULL) {
break;
}
switch (dyn->d_tag) {
case DT_REL:
rel_addr = dyn->d_un.d_ptr;
break;
case DT_RELSZ:
rel_sz = dyn->d_un.d_val;
break;
case DT_RELENT:
rel_entsz = dyn->d_un.d_val;
break;
case DT_RELA:
rela_addr = dyn->d_un.d_ptr;
break;
case DT_RELASZ:
rela_sz = dyn->d_un.d_val;
break;
case DT_RELAENT:
rela_entsz = dyn->d_un.d_val;
break;
case DT_PLTRELSZ:
plt_sz = dyn->d_un.d_val;
break;
case DT_JMPREL:
plt_addr = dyn->d_un.d_ptr;
break;
case DT_PLTREL:
plt_enttype = dyn->d_un.d_ptr;
break;
default:
break;
}
if (dyn->d_tag != DT_NEEDED) {
continue;
}
}
if (rel_sz) {
/* DT_REL is not supported */
return -1;
}
if (plt_enttype == DT_RELA) {
plt_entsz = rela_entsz ? rela_entsz : sizeof(elf_rela_t);
} else if (plt_enttype == DT_REL) {
return -1;
}
int r;
if (rela_sz) {
r = do_rela(image, lib, rela_addr, rela_sz, rela_entsz);
if (r != 0) {
return r;
}
}
if (plt_sz) {
r = do_rela(image, lib, plt_addr, plt_sz, plt_entsz);
if (r != 0) {
return r;
}
}
return 0;
}
HIDDEN int __elf_image_link(struct elf_image *exec, struct elf_image *vdso)
{
int status = relocate(vdso, NULL);
if (status != 0) {
return status;
}
return relocate(exec, vdso);
}
HIDDEN mx_vaddr_t __elf_image_entry_point(struct elf_image *image)
{
return image->remote_base_addr + image->hdr.e_entry;
}
static uint32_t gnu_hash(const char *name)
{
uint32_t h = 5381;
for (; *name; name++) {
h = (h << 5) + h + *name;
}
return h;
}
static mx_vaddr_t sym_gnu_hash_search(struct elf_image *image, const char *name)
{
uint32_t hash = gnu_hash(name);
uint32_t *hashtab = (uint32_t *)(image->local_base_addr + image->hash_offset);
uint32_t nbuckets = hashtab[0];
uint32_t symoffset = hashtab[1];
uint32_t bloom_size = hashtab[2];
uint32_t bloom_shift = hashtab[3];
uint64_t *bloom = (uint64_t *)&hashtab[4];
uint32_t *buckets = (uint32_t *)&bloom[bloom_size];
uint32_t *chain = &buckets[nbuckets];
uint64_t bloom_word =
bloom[(hash / elf_class_bits(image)) % bloom_size];
uint64_t bloom_mask =
((uint64_t)1 << (hash % elf_class_bits(image))) |
((uint64_t)1 << ((hash >> bloom_shift) % elf_class_bits(image)));
if ((bloom_word & bloom_mask) != bloom_mask) {
return 0;
}
uint32_t symix = buckets[hash % nbuckets];
if (symix < symoffset) {
return 0;
}
const char *strtab = (const char *)(image->local_base_addr + image->dynstr_offset);
elf_sym_t *symtab = (elf_sym_t *)(image->local_base_addr + image->dynsym_offset);
while (1) {
const char *symname = strtab + symtab[symix].st_name;
uint32_t symhash = chain[symix - symoffset];
if ((symhash | 1) == (hash | 1) && !strcmp(symname, name)) {
return image->remote_base_addr + symtab[symix].st_value;
}
if (symhash & 1) {
break;
}
symix++;
}
return 0;
}
HIDDEN mx_vaddr_t __elf_image_get_symbol(struct elf_image *image, const char *name)
{
switch (image->hash_type) {
case GNU_HASH:
return sym_gnu_hash_search(image, name);
default:
return 0;
}
}
HIDDEN void __elf_image_cleanup(struct elf_image *image)
{
if (image->local_exec_vmar) {
mx_vmar_unmap(image->local_exec_vmar, 0, image->exec_vmar_size);
mx_vmar_destroy(image->local_exec_vmar);
mx_handle_close(image->local_exec_vmar);
image->local_exec_vmar = MX_NULL_HANDLE;
}
if (image->remote_exec_vmar) {
mx_handle_close(image->remote_exec_vmar);
image->remote_exec_vmar = MX_NULL_HANDLE;
}
if (image->rw_vmo) {
mx_handle_close(image->rw_vmo);
image->rw_vmo = MX_NULL_HANDLE;
}
}

View File

@@ -0,0 +1,35 @@
#include <stddef.h>
#include <string.h>
extern const char **__crt_environ();
char *__crt_sys_getenv(const char *name)
{
const char **envp = __crt_environ();
for (int i = 0; envp[i] != NULL; i++) {
int equal = -1;
const char *env = envp[i];
for (int ii = 0; env[ii] != '\0'; ii++) {
if (env[ii] == '=') {
equal = ii;
break;
}
}
if (equal == -1) {
continue;
}
char env_name[equal + 1];
memcpy(env_name, env, equal);
env_name[equal] = '\0';
if (!strcmp(env_name, name)) {
return (char *)(env + equal + 1);
}
}
return NULL;
}

31
libc/sys/horizon/fcntl.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef SYS_HORIZON_FCNTL_H_
#define SYS_HORIZON_FCNTL_H_
#include <sys/types.h>
#define O_ACCMODE 0003
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#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_NDELAY O_NONBLOCK
#define O_SYNC 04010000
#define O_FSYNC O_SYNC
#define O_ASYNC 020000
#define O_LARGEFILE 0100000
#define O_DIRECTORY 0200000
#define O_NOFOLLOW 0400000
#define O_CLOEXEC 02000000
#define O_DIRECT 040000
#define O_NOATIME 01000000
#define O_PATH 010000000
#define O_DSYNC 010000
#define O_TMPFILE (020000000 | __O_DIRECTORY)
#endif

202
libc/sys/horizon/fio.c Normal file
View File

@@ -0,0 +1,202 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "sys/types.h"
#include "__fio.h"
static struct __io_file __stdin = {};
static struct __io_file __stdout = {};
static struct __io_file __stderr = {};
static int flags_from_mode(const char *r)
{
return 0;
}
static int refill(struct __io_file *fp)
{
ssize_t err = read(fp->fd, fp->in_buf, sizeof fp->in_buf);
if (err < 0) {
fp->err = 1;
return 0;
}
fp->in_buf_ptr = 0;
fp->in_buf_len = err;
return err;
}
FILE *__get_stdio_file(int i)
{
switch (i) {
case 0:
return &__stdin;
case 1:
return &__stdout;
case 2:
return &__stderr;
default:
return NULL;
}
}
void __fio_init(int in, int out, int err)
{
__stdin.fd = in;
__stdout.fd = out;
__stderr.fd = err;
}
int __fio_fopen(const char *path, const char *mode, struct __io_file *fp)
{
/* TODO */
int fd = open(path, 0);
if (fd == -1) {
return -1;
}
fp->fd = fd;
return 0;
}
int __fio_fclose(struct __io_file *fp)
{
if (fp->fd == -1) {
return -1;
}
close(fp->fd);
fp->fd = -1;
return 0;
}
int __fio_fdopen(int fd, const char *mode, struct __io_file *fp)
{
if (fd == -1) {
return -1;
}
fp->fd = fd;
return 0;
}
int __fileno(struct __io_file *f)
{
return (int)f->fd;
}
unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz)
{
if (sz == 0) {
return 0;
}
size_t r = 0;
char *out = buf;
if (f->unget) {
*out++ = f->unget;
f->unget = 0;
r++;
sz--;
}
size_t available = f->in_buf_len - f->in_buf_ptr;
size_t bufread = sz;
if (bufread > available) {
bufread = available;
}
memcpy(out, f->in_buf + f->in_buf_ptr, bufread);
f->in_buf_ptr += bufread;
out += bufread;
sz -= bufread;
r += bufread;
if (sz == 0) {
return r;
}
while (1) {
refill(f);
available = f->in_buf_len - f->in_buf_ptr;
if (available == 0) {
f->eof = 1;
break;
}
bufread = sz;
if (bufread > available) {
bufread = available;
}
memcpy(out, f->in_buf + f->in_buf_ptr, bufread);
f->in_buf_ptr += bufread;
out += bufread;
sz -= bufread;
r += bufread;
if (sz == 0 || f->err || f->eof) {
break;
}
}
if (sz > 0) {
f->eof = 1;
}
return r;
}
unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz)
{
for (unsigned int i = 0; i < sz; i++) {
if (f->out_buf_len >= __FIO_BUFSZ) {
__fio_flush(f);
}
f->out_buf[f->out_buf_len++] = buf[i];
if (buf[i] == '\n') {
__fio_flush(f);
}
}
return sz;
}
int __fio_ungetc(struct __io_file *f, char c)
{
if (f->unget) {
return -1;
}
f->unget = c;
return 0;
}
unsigned int __fio_flush(struct __io_file *f)
{
ssize_t res = write(f->fd, f->out_buf, f->out_buf_len);
if (res != f->out_buf_len) {
f->err = 1;
}
size_t flushed = f->out_buf_len;
f->out_buf_len = 0;
return flushed;
}
int __fio_error(struct __io_file *f)
{
return f->err != 0;
}
int __fio_eof(struct __io_file *f)
{
return f->eof != 0;
}

101
libc/sys/horizon/heap.c Normal file
View File

@@ -0,0 +1,101 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <magenta/vmo.h>
#include <magenta/bootstrap.h>
#include <magenta/errors.h>
#include <magenta/misc.h>
#include <magenta/vmar.h>
/* 1 GiB */
#define HEAP_REGION_SZ 0x40000000
#define ROUND_UP(x, b) x += (b) - ((x) % (b))
static uintptr_t heap_start = 0;
static uintptr_t heap_end = 0;
static uintptr_t heap_alloc_point = 0;
static size_t heap_sz = 0;
static mx_handle_t heap_vmo = MX_NULL_HANDLE;
static mx_handle_t heap_vmar = MX_NULL_HANDLE;
void __crt_heap_init(size_t sz)
{
mx_handle_t root_vmar = mx_bootstrap_handle_get(MX_B_VMAR_ROOT);
mx_vaddr_t heap = 0;
mx_status_t status = mx_vmar_allocate(root_vmar,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE | MX_VM_CAN_MAP_SPECIFIC,
0, HEAP_REGION_SZ, &heap_vmar, &heap);
if (status != MX_OK) {
fprintf(stderr, "fatal: cannot allocate heap virtual region (%s)\n", mx_status_to_string(status));
abort();
}
status = mx_vmo_create(
sz,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE | MX_VM_CAN_MAP_SPECIFIC,
&heap_vmo);
if (status != MX_OK) {
fprintf(stderr, "fatal: cannot allocate heap (%s)\n", mx_status_to_string(status));
abort();
}
status = mx_vmar_map(heap_vmar,
MX_VM_PERM_READ | MX_VM_PERM_WRITE | MX_VM_SPECIFIC,
0, heap_vmo, 0, sz,
&heap);
if (status != MX_OK) {
fprintf(stderr, "fatal: cannot map heap (%s)\n", mx_status_to_string(status));
abort();
}
heap_sz = sz;
heap_start = heap;
heap_end = heap + heap_sz;
heap_alloc_point = heap_start;
memset((void *)heap, 0x0, heap_sz);
}
void *__crt_heap_extend(size_t sz)
{
if (sz % MX_PAGE_SIZE) {
sz &= (MX_PAGE_SIZE - 1);
sz += MX_PAGE_SIZE;
}
if (!sz) {
return (void *)heap_end;
}
if (!heap_start) {
__crt_heap_init(sz);
return (void *)heap_start;
}
mx_vmo_set_size(heap_vmo, heap_sz + sz);
mx_vaddr_t vmar_base, alloc_base;
mx_vmar_bounds(heap_vmar, &vmar_base, NULL);
size_t offset = heap_end - vmar_base;
mx_status_t err = mx_vmar_map(heap_vmar,
MX_VM_PERM_READ | MX_VM_PERM_WRITE | MX_VM_SPECIFIC,
offset, heap_vmo, heap_sz, sz, &alloc_base);
if (err != MX_OK) {
fprintf(stderr, "fatal: cannot map extended heap (%s)\n", mx_status_to_string(err));
abort();
}
heap_sz += sz;
void *out = (void *)heap_end;
memset(out, 0x0, sz);
heap_end += sz;
return out;
}

378
libc/sys/horizon/init.c Normal file
View File

@@ -0,0 +1,378 @@
#include <magenta/task.h>
#include <magenta/tunnel.h>
#include <magenta/bootstrap.h>
#include <magenta/signals.h>
#include <magenta/errors.h>
#include <magenta/handle.h>
#include <magenta/misc.h>
#include <magenta/object.h>
#include <mio/object.h>
#include <mio/fd.h>
#include <mio/fs.h>
#include <mio/namespace.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "__init.h"
#include "__heap.h"
#include "__fio.h"
/* maximum of 32 handles can be received sent as arguments */
#define MAX_HANDLE_ARGS 32
/* maximum size of bootstrap message that can be received */
#define MAX_MSG_SIZE 0x2000
#if 1
#define dbg_log(...)
#else
static void dbg_log(const char *format, ...)
{
char buf[1024];
va_list arg;
va_start(arg, format);
int r = vsnprintf(buf, sizeof buf, format, arg);
va_end(arg);
mx_console_write(buf, r);
}
#endif
#ifdef DYLD_PARENT_IMAGE
extern mx_vaddr_t dyld_load_exec(int argc, const char **argv);
#endif
static const char **environ = NULL;
static char arg_msg_buf[MAX_MSG_SIZE];
static mx_bootstrap_handle_t arg_handles[MAX_HANDLE_ARGS];
const char **__crt_environ()
{
return environ;
}
extern int main(int, const char **);
extern void __crt_run_atexit();
static void extract_arg_handles(mx_bootstrap_msg_t *args,
mx_handle_t *handles, int hndc, mx_bootstrap_handle_t *out)
{
uint32_t *hent = (uint32_t *)((char *)args + args->handle_info_off);
for (int i = 0; i < hndc; i++) {
out[i].info = hent[i];
out[i].handle = handles[i];
}
}
static void parse_args(mx_bootstrap_msg_t *args,
const char **argv, const char **envp, const char **namep)
{
if (args->args_num > 0) {
char *arg_buf = (char *)args + args->args_off;
int arg_i = 0;
int arg_off = 0;
for (int i = 0; ; i++) {
if (arg_buf[i] == '\0') {
argv[arg_i++] = arg_buf + arg_off;
arg_off = i + 1;
}
if (arg_i == (int)args->args_num) {
break;
}
}
}
if (args->environ_num > 0) {
char *env_buf = (char *)args + args->environ_off;
int env_i = 0;
int env_off = 0;
for (int i = 0; ; i++) {
if (env_buf[i] == '\0') {
envp[env_i++] = env_buf + env_off;
env_off = i + 1;
}
if (env_i == (int)args->environ_num) {
break;
}
}
}
if (args->names_num) {
char *name_buf = (char *)args + args->names_off;
int name_i = 0;
int name_off = 0;
for (int i = 0; ; i++) {
if (name_buf[i] == '\0') {
namep[name_i++] = name_buf + name_off;
name_off = i + 1;
}
if (name_i == (int)args->names_num) {
break;
}
}
}
}
static void hang()
{
while (1) {
mx_nanosleep(mx_deadline_after(MX_SEC(1)));
}
}
static void init_stdio_fd(int fd, mx_handle_t *handles, size_t nhandles)
{
if (handles[0] == MX_NULL_HANDLE) {
dbg_log("** photon: FD %d is closed\n", fd);
return;
}
mx_info_basic_t handle0_info;
mx_status_t err = mx_object_get_info(handles[0], MX_INFO_HANDLE_BASIC, &handle0_info, sizeof(handle0_info));
if (err != MX_OK) {
/* bad handle. TODO report error somehow */
return;
}
mio_object *obj = NULL;
if (handle0_info.type == MX_OBJECT_PIPE) {
obj = mio_pipe_create(handles[0]);
dbg_log("** photon: FD %d is a pipe\n", fd);
} else {
/* just assume all other stdio handles implement the file protocol over a tunnel */
obj = mio_file_create(handles[0]);
dbg_log("** photon: FD %d is a file\n", fd);
}
mio_fd_list_alloc_at(mio_global_fd_list(), obj, fd);
}
static void init_stdio(mx_bootstrap_handle_t *handles, size_t nhandles)
{
dbg_log("** photon: initialising stdio\n");
bool no_fds = true;
int max_fd = 0;
for (size_t i = 0; i < nhandles; i++) {
uint32_t info = handles[i].info;
if (MX_B_HND_TYPE(info) != MX_B_FD) {
continue;
}
no_fds = false;
int fd = MX_B_HND_ARG(info);
if (fd > max_fd) {
max_fd = fd;
}
}
if (no_fds) {
dbg_log("** photon: we've been given no FDs\n");
return;
}
int nfds = max_fd + 1;
dbg_log("** photon: we've been given up to %d FDs\n", nfds);
/* Supports up to two handles per FD */
mx_handle_t fd_handles[nfds][2];
memset(fd_handles, 0x0, sizeof(mx_handle_t) * 2 * nfds);
for (size_t i = 0; i < nhandles; i++) {
uint32_t info = handles[i].info;
if (MX_B_HND_TYPE(info) != MX_B_FD) {
continue;
}
int fd = MX_B_HND_ARG(info);
mx_handle_t *this_fd_handles = fd_handles[fd];
if (this_fd_handles[0] != MX_NULL_HANDLE) {
this_fd_handles[1] = handles[i].handle;
} else {
this_fd_handles[0] = handles[i].handle;
}
}
for (int i = 0; i < nfds; i++) {
size_t n = 1;
if (fd_handles[i][1] != MX_NULL_HANDLE) {
n++;
}
//dbg_log("** photon: handles for FD %d = { %x, %x }\n", i, fd_handles[i][0], fd_handles[i][1]);
init_stdio_fd(i, fd_handles[i], n);
}
__fio_init(0, 1, 2);
dbg_log("** photon: stdio init finished\n");
}
static int do_init(mx_handle_t bootstrap, bool enable_fs, bool enable_stdio, int *out_argc, const char ***out_argv)
{
dbg_log("reading bootstrap message from %x\n", bootstrap);
mx_signals_t sig = 0;
mx_object_wait(bootstrap, MX_TUNNEL_READABLE, 0, &sig);
if (!(sig & MX_TUNNEL_READABLE)) {
dbg_log("no bootstrap message!\n");
return -1;
}
size_t msg_size = 0;
size_t nr_handles = 0;
mx_handle_t handles[MAX_HANDLE_ARGS + 1];
dbg_log("receiving message from handle %lx\n", bootstrap);
mx_status_t err = mx_tunnel_read(bootstrap,
arg_msg_buf, MAX_MSG_SIZE,
handles, MAX_HANDLE_ARGS,
&msg_size, &nr_handles);
if (err != MX_OK) {
dbg_log("error: cannot read bootstrap message from handle %lx (error %d)\n",
bootstrap, err);
return -1;
}
mx_bootstrap_msg_t *msg = (mx_bootstrap_msg_t *)arg_msg_buf;
dbg_log("extracting handles\n");
extract_arg_handles(msg, handles, nr_handles, arg_handles);
#if 0
arg_handles[nr_handles].handle = bootstrap;
arg_handles[nr_handles].info = MX_B_HND(MX_B_TUNNEL_BTSTP, 0);
nr_handles++;
#endif
dbg_log("extracted %zu handles\n", nr_handles);
mx_bootstrap_handle_init(arg_handles, nr_handles);
const char **argv = NULL, **envp = NULL, **namep = NULL;
dbg_log("allocating buffers (%u, %u, %u)\n", msg->args_num, msg->environ_num, msg->names_num);
argv = calloc(sizeof *argv, msg->args_num + 1);
envp = calloc(sizeof *envp, msg->environ_num + 1);
namep = calloc(sizeof *namep, msg->names_num + 1);
environ = envp;
parse_args(msg, argv, envp, namep);
*out_argc = msg->args_num;
*out_argv = argv;
if (enable_stdio) {
init_stdio(arg_handles, nr_handles);
} else {
__fio_init(-1, -1, -1);
}
if (!enable_fs) {
return 0;
}
mio_namespace *ns = mio_namespace_create();
dbg_log("received %u names/%zu handles\n", msg->names_num, nr_handles);
if (msg->names_num > 0) {
for (size_t i = 0; i < nr_handles; i++) {
int type = MX_B_HND_TYPE(arg_handles[i].info);
int arg = MX_B_HND_ARG(arg_handles[i].info);
if (type != MX_B_NS_DIR && type != MX_B_TUNNEL_CWD) {
dbg_log(" * wrong type %x\n", type);
continue;
}
const char *path = namep[arg];
dbg_log(" * %s = %x\n", path, arg_handles[i].handle);
if (type == MX_B_TUNNEL_CWD) {
mio_set_cwd(arg_handles[i].handle, path);
} else {
mio_namespace_add_entry(ns, path, arg_handles[i].handle);
}
}
}
mio_set_global_namespace(ns);
return 0;
}
static int do_run(mx_handle_t bootstrap)
{
int argc;
const char **argv;
int err = do_init(bootstrap, true, true, &argc, &argv);
if (err != 0) {
return err;
}
return main(argc, argv);
}
#ifdef DYLD_PARENT_IMAGE
static int do_load_and_run(mx_handle_t bootstrap)
{
int argc;
const char **argv;
int err = do_init(bootstrap, false, true, &argc, &argv);
if (err != 0) {
return err;
}
mx_vaddr_t main_ptr = dyld_load_exec(argc, argv);
if (!main_ptr) {
return -1;
}
mx_bootstrap_handle_cleanup();
err = do_init(bootstrap, true, true, &argc, &argv);
if (err != 0) {
return err;
}
int(*main_func)(int, const char **) = (int(*)(int, const char **))main_ptr;
if (!main_func) {
return -1;
}
return main_func(argc, argv);
}
#endif
int __crt_init(mx_handle_t bootstrap, mx_vaddr_t arg2)
{
#ifndef DYLD_PARENT_IMAGE
int ret = do_run(bootstrap);
#else
int ret = do_load_and_run(bootstrap);
#endif
fflush(stdout);
fflush(stderr);
__crt_run_atexit();
mio_fd_cleanup();
mio_fs_cleanup();
mx_task_kill(mx_bootstrap_handle_get(MX_B_TASK_SELF), ret);
/* unreachable */
hang();
return 0;
}

1225
libc/sys/horizon/launch.c Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,18 @@
.global _start
.type _start, @function
.extern __crt_init
.type __crt_init, @function
.extern main
.type main, @function
_start:
# Magenta aligns the stack to a page boundry and subtracts 8.
# Add 8 to restore 16-byte alignment
add $8, %rsp
call __crt_init
# unreachable; __crt_init() will call mx_task_kill()
.loop:
jmp .loop

View File

@@ -0,0 +1,11 @@
.global __pthread_self
.type __pthread_self, @function
__pthread_self:
push %rbp
mov %rsp, %rbp
mov %fs:0, %rax
pop %rbp
ret

View File

@@ -0,0 +1,29 @@
#ifndef SYS_HORIZON_SYS__DIRENT_H_
#define SYS_HORIZON_SYS__DIRENT_H_
#include <sys/types.h>
#include <limits.h>
#define __SYS_DENT_CACHE_SZ 4
struct __dentcache {
ino_t d_ino;
unsigned char d_type;
char *d_namep;
};
struct dirent {
ino_t d_ino;
unsigned char d_type;
char d_name[NAME_MAX + 1];
};
typedef struct {
int fd;
long seek;
unsigned char cache_idx, cache_size;
struct __dentcache dent_cache[__SYS_DENT_CACHE_SZ];
struct dirent cdent;
} DIR;
#endif

Some files were not shown because too many files have changed in this diff Show More