meta: move photon/libc to root
This commit is contained in:
46
libc/ctype/ctype.c
Normal file
46
libc/ctype/ctype.c
Normal 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
9
libc/errno/errno.c
Normal 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
8
libc/include/assert.h
Normal 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
27
libc/include/ctype.h
Normal 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
14
libc/include/dirent.h
Normal 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
14
libc/include/dlfcn.h
Normal 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
19
libc/include/errno.h
Normal 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
195
libc/include/inttypes.h
Normal 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
37
libc/include/limits.h
Normal 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
4
libc/include/locale.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifndef LOCALE_H_
|
||||
#define LOCALE_H_
|
||||
|
||||
#endif
|
||||
249
libc/include/machine/_stdint.h
Normal file
249
libc/include/machine/_stdint.h
Normal 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
20
libc/include/stdarg.h
Normal 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
8
libc/include/stdbool.h
Normal 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
27
libc/include/stddef.h
Normal 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
48
libc/include/stdint.h
Normal 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
67
libc/include/stdio.h
Normal 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
34
libc/include/stdlib.h
Normal 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
39
libc/include/string.h
Normal 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
46
libc/include/time.h
Normal 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
14
libc/include/wchar.h
Normal 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
|
||||
8
libc/internal/stack_chk_fail.c
Normal file
8
libc/internal/stack_chk_fail.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
_Noreturn void __stack_chk_fail(void)
|
||||
{
|
||||
fprintf(stderr, "Stack smashing detected!\n");
|
||||
abort();
|
||||
}
|
||||
5596
libc/malloc/dlmalloc-legacy/malloc.c
Normal file
5596
libc/malloc/dlmalloc-legacy/malloc.c
Normal file
File diff suppressed because it is too large
Load Diff
679
libc/malloc/dlmalloc-legacy/malloc.h
Normal file
679
libc/malloc/dlmalloc-legacy/malloc.h
Normal 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 */
|
||||
6309
libc/malloc/dlmalloc/malloc.c
Normal file
6309
libc/malloc/dlmalloc/malloc.c
Normal file
File diff suppressed because it is too large
Load Diff
679
libc/malloc/dlmalloc/malloc.h
Normal file
679
libc/malloc/dlmalloc/malloc.h
Normal 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 */
|
||||
5596
libc/malloc/dlmalloc/malloc.old
Normal file
5596
libc/malloc/dlmalloc/malloc.old
Normal file
File diff suppressed because it is too large
Load Diff
866
libc/stdio/__printf.c
Normal file
866
libc/stdio/__printf.c
Normal 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
16
libc/stdio/__printf.h
Normal 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
15
libc/stdio/fclose.c
Normal 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
18
libc/stdio/fdopen.c
Normal 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
7
libc/stdio/ferror.c
Normal 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
13
libc/stdio/fflush.c
Normal 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
13
libc/stdio/fgetc.c
Normal 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
32
libc/stdio/fgets.c
Normal 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
7
libc/stdio/fileno.c
Normal 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
18
libc/stdio/fopen.c
Normal 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
10
libc/stdio/fprintf.c
Normal 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
13
libc/stdio/fputc.c
Normal 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
14
libc/stdio/fputs.c
Normal 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
16
libc/stdio/freopen.c
Normal 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
12
libc/stdio/fwrite.c
Normal 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
13
libc/stdio/perror.c
Normal 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
11
libc/stdio/printf.c
Normal 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
6
libc/stdio/putchar.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int putchar(int c)
|
||||
{
|
||||
return fputc(c, stdout);
|
||||
}
|
||||
11
libc/stdio/puts.c
Normal file
11
libc/stdio/puts.c
Normal 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
10
libc/stdio/snprintf.c
Normal 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
11
libc/stdio/sprintf.c
Normal 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
12
libc/stdio/ungetc.c
Normal 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
19
libc/stdio/vfprintf.c
Normal 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
7
libc/stdio/vprintf.c
Normal 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
36
libc/stdio/vsnprintf.c
Normal 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
6
libc/stdio/vsprintf.c
Normal 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
16
libc/stdlib/abort.c
Normal 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
8
libc/stdlib/assert.c
Normal 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
21
libc/stdlib/atexit.c
Normal 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
42
libc/stdlib/atof.c
Normal 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
0
libc/stdlib/atoi.c
Normal file
6
libc/stdlib/exit.c
Normal file
6
libc/stdlib/exit.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <__system.h>
|
||||
|
||||
_Noreturn void exit(int code)
|
||||
{
|
||||
__exit(code);
|
||||
}
|
||||
6
libc/stdlib/getenv.c
Normal file
6
libc/stdlib/getenv.c
Normal 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
31
libc/stdlib/rand.c
Normal 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
91
libc/stdlib/strtod.c
Normal 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
33
libc/stdlib/strtof.c
Normal 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
73
libc/stdlib/strtol.c
Normal 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
74
libc/stdlib/strtoul.c
Normal 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
12
libc/string/fread.c
Normal 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
0
libc/string/fwrite.c
Normal file
14
libc/string/memcmp.c
Normal file
14
libc/string/memcmp.c
Normal 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
43
libc/string/memcpy.c
Normal 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
27
libc/string/memmove.c
Normal 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
28
libc/string/memset.c
Normal 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
8
libc/string/strcat.c
Normal 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
14
libc/string/strchr.c
Normal 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
25
libc/string/strcmp.c
Normal 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
26
libc/string/strcpy.c
Normal 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
15
libc/string/strcspn.c
Normal 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
11
libc/string/strdup.c
Normal 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
152
libc/string/strerror.c
Normal 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
11
libc/string/strlen.c
Normal 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
15
libc/string/strrchr.c
Normal 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
62
libc/string/strtok.c
Normal 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
323
libc/sys/horizon/__elf.h
Normal 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
36
libc/sys/horizon/__fio.h
Normal 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
|
||||
8
libc/sys/horizon/__heap.h
Normal file
8
libc/sys/horizon/__heap.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef SYS_HORIZON_HEAP_H_
|
||||
#define SYS_HORIZON_HEAP_H_
|
||||
|
||||
#include "__init.h"
|
||||
|
||||
extern int __heap_init();
|
||||
|
||||
#endif
|
||||
4
libc/sys/horizon/__init.h
Normal file
4
libc/sys/horizon/__init.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifndef SYS_HORIZON_INIT_H_
|
||||
#define SYS_HORIZON_INIT_H_
|
||||
|
||||
#endif
|
||||
14
libc/sys/horizon/__system.h
Normal file
14
libc/sys/horizon/__system.h
Normal 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
|
||||
6
libc/sys/horizon/__time.h
Normal file
6
libc/sys/horizon/__time.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef SYS_HORIZON___TIME_H_
|
||||
#define SYS_HORIZON___TIME_H_
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#endif
|
||||
0
libc/sys/horizon/config.cmake
Normal file
0
libc/sys/horizon/config.cmake
Normal file
157
libc/sys/horizon/dirent.c
Normal file
157
libc/sys/horizon/dirent.c
Normal 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
56
libc/sys/horizon/dlfcn.c
Normal 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
673
libc/sys/horizon/elf.c
Normal 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;
|
||||
}
|
||||
}
|
||||
35
libc/sys/horizon/environ.c
Normal file
35
libc/sys/horizon/environ.c
Normal 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
31
libc/sys/horizon/fcntl.h
Normal 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
202
libc/sys/horizon/fio.c
Normal 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
101
libc/sys/horizon/heap.c
Normal 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
378
libc/sys/horizon/init.c
Normal 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
1225
libc/sys/horizon/launch.c
Normal file
File diff suppressed because it is too large
Load Diff
BIN
libc/sys/horizon/launch.tar.xz
Normal file
BIN
libc/sys/horizon/launch.tar.xz
Normal file
Binary file not shown.
18
libc/sys/horizon/machine/x86_64/crt0.s
Normal file
18
libc/sys/horizon/machine/x86_64/crt0.s
Normal 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
|
||||
11
libc/sys/horizon/machine/x86_64/pthread.s
Normal file
11
libc/sys/horizon/machine/x86_64/pthread.s
Normal 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
|
||||
29
libc/sys/horizon/sys/_dirent.h
Normal file
29
libc/sys/horizon/sys/_dirent.h
Normal 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
Reference in New Issue
Block a user