From 5a05da89e94baed7a94baa4de38e3b1bda295f22 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 22 Jul 2020 14:30:46 +0300 Subject: [PATCH] Add stubs and functions neccessary to build Lua --- Makefile | 11 ++--- include/locale.h | 41 +++++++++++++++++ include/math.h | 6 +++ include/setjmp.h | 8 ++++ include/stdlib.h | 5 +++ include/time.h | 6 +++ src/locale/localeconv.c | 32 ++++++++++++++ src/locale/setlocale.c | 7 +++ src/math/log.c | 98 +++++++++++++++++++++++++++++++++++++++++ src/stdio/fclose.c | 5 ++- src/stdio/pclose.c | 6 +++ src/stdio/popen.c | 9 ++++ src/stdio/tmpfile.c | 38 ++++++++++++++++ src/stdlib/abort.c | 10 +++++ src/stdlib/strtod.c | 7 +++ src/stdlib/system.c | 52 ++++++++++++++++++++++ src/string/strstr.c | 2 +- src/time/clock.c | 5 +++ src/time/difftime.c | 5 +++ src/time/localtime_r.c | 10 +++++ src/time/mktime.c | 45 +++++++++++++++++++ src/time/time.c | 10 +++++ 22 files changed, 411 insertions(+), 7 deletions(-) create mode 100644 include/locale.h create mode 100644 include/math.h create mode 100644 include/setjmp.h create mode 100644 src/locale/localeconv.c create mode 100644 src/locale/setlocale.c create mode 100644 src/math/log.c create mode 100644 src/stdio/pclose.c create mode 100644 src/stdio/popen.c create mode 100644 src/stdio/tmpfile.c create mode 100644 src/stdlib/abort.c create mode 100644 src/stdlib/strtod.c create mode 100644 src/stdlib/system.c create mode 100644 src/time/clock.c create mode 100644 src/time/difftime.c create mode 100644 src/time/localtime_r.c create mode 100644 src/time/mktime.c create mode 100644 src/time/time.c diff --git a/Makefile b/Makefile index 2e78b93..34a89f0 100644 --- a/Makefile +++ b/Makefile @@ -3,17 +3,15 @@ HEADERS=$(shell find include -type f -name "*.h") INSTALL_HEADERS=$(filter-out include/_libc/%,$(HEADERS)) OBJ_CRT=$(O)/obj/crt0.o SRC_LIBC=$(shell find src -type f -name "*.c") -OBJ_LIBC=$(SRC_LIBC:src/%.c=$(O)/libc/%.o) +AS_SRC_LIBC=$(shell find src -type f -name "*.S") +OBJ_LIBC=$(SRC_LIBC:src/%.c=$(O)/libc/%.o) $(AS_SRC_LIBC:src/%.S=$(O)/libc/%.o) SRC_DIR_LIBC=$(shell find src/* -type d) DIR_LIBC=$(SRC_DIR_LIBC:src/%=$(O)/libc/%) STATIC_LIBS=$(O)/lib/libc.a SHARED_LIBS= # Build -CFLAGS=-mno-sse \ - -mno-sse2 \ - -mno-mmx \ - -I include \ +CFLAGS=-I include \ -ffreestanding \ -Wall \ -Wextra \ @@ -70,3 +68,6 @@ $(O)/lib/libc.a: $(OBJ_LIBC) $(O)/libc/%.o: src/%.c $(HEADERS) $(CC) $(CFLAGS) -c -o $@ $< + +$(O)/libc/%.o: src/%.S $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/include/locale.h b/include/locale.h new file mode 100644 index 0000000..25ef686 --- /dev/null +++ b/include/locale.h @@ -0,0 +1,41 @@ +#pragma once + +struct lconv { + char *currency_symbol; + char *decimal_point; + char frac_digits; + char *grouping; + char *int_curr_symbol; + char int_frac_digits; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_p_sign_posn; + char *mon_decimal_point; + char *mon_grouping; + char *mon_thousands_sep; + char *negative_sign; + char n_cs_precedes; + char n_sep_by_space; + char n_sign_posn; + char *positive_sign; + char p_cs_precedes; + char p_sep_by_space; + char p_sign_posn; + char *thousands_sep; +}; + +#define LC_ALL 1 +#define LC_COLLATE 2 +#define LC_CTYPE 3 +#define LC_MESSAGES 4 +#define LC_MONETARY 5 +#define LC_NUMERIC 6 +#define LC_TIME 7 + +typedef struct __locale *locale_t; + +char *setlocale(int cat, const char *loc); +struct lconv *localeconv(void); diff --git a/include/math.h b/include/math.h new file mode 100644 index 0000000..fbffb58 --- /dev/null +++ b/include/math.h @@ -0,0 +1,6 @@ +#pragma once + +#define HUGE_VAL (__builtin_huge_val()) + +double log10(double f); +double log(double f); diff --git a/include/setjmp.h b/include/setjmp.h new file mode 100644 index 0000000..ab18099 --- /dev/null +++ b/include/setjmp.h @@ -0,0 +1,8 @@ +#pragma once + +typedef struct { + unsigned long _v[8]; +} jmp_buf[1]; + +int setjmp(jmp_buf env); +void longjmp(jmp_buf env, int val); diff --git a/include/stdlib.h b/include/stdlib.h index 6bd12eb..a771d9b 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -2,6 +2,11 @@ #include #include +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +double strtod(const char *nptr, char **endptr); + __Malloc void *malloc(size_t size); void *realloc(void *p, size_t newsz); void free(void *ptr); diff --git a/include/time.h b/include/time.h index 16f33d5..c28c435 100644 --- a/include/time.h +++ b/include/time.h @@ -2,6 +2,8 @@ #include #include +#define CLOCKS_PER_SEC 1000000 + struct tm { int tm_sec; int tm_min; @@ -16,5 +18,9 @@ struct tm { int nanosleep(const struct timespec *restrict ts, struct timespec *restrict rem); +clock_t clock(void); +time_t time(time_t *t); +double difftime(time_t t1, time_t t0); + struct tm *gmtime_r(const time_t *restrict timep, struct tm *restrict res); size_t strftime(char *restrict buf, size_t lim, const char *restrict fmt, const struct tm *restrict tm); diff --git a/src/locale/localeconv.c b/src/locale/localeconv.c new file mode 100644 index 0000000..89dd980 --- /dev/null +++ b/src/locale/localeconv.c @@ -0,0 +1,32 @@ +#include + +static const struct lconv generic = { + .currency_symbol = "", + .decimal_point = "", + .frac_digits = -1, + .grouping = "", + .int_curr_symbol = "", + .int_frac_digits = -1, + .int_n_cs_precedes = -1, + .int_n_sep_by_space = -1, + .int_n_sign_posn = -1, + .int_p_cs_precedes = -1, + .int_p_sep_by_space = -1, + .int_p_sign_posn = -1, + .mon_decimal_point = "", + .mon_grouping = "", + .mon_thousands_sep = "", + .negative_sign = "", + .n_cs_precedes = -1, + .n_sep_by_space = -1, + .n_sign_posn = -1, + .positive_sign = "", + .p_cs_precedes = -1, + .p_sep_by_space = -1, + .p_sign_posn = -1, + .thousands_sep = "" +}; + +struct lconv *localeconv(void) { + return (struct lconv *) &generic; +} diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c new file mode 100644 index 0000000..debf0b9 --- /dev/null +++ b/src/locale/setlocale.c @@ -0,0 +1,7 @@ +#include + +char *setlocale(int cat, const char *locale) { + (void) cat; + (void) locale; + return 0; +} diff --git a/src/math/log.c b/src/math/log.c new file mode 100644 index 0000000..46bc8df --- /dev/null +++ b/src/math/log.c @@ -0,0 +1,98 @@ +#include + +// TODO: actual implementation + +double asin(double x) { + (void) x; + return 0; +} + +double acos(double x) { + (void) x; + return 0; +} + +double sin(double x) { + (void) x; + return 0; +} + +double cos(double x) { + (void) x; + return 0; +} + +double tan(double x) { + (void) x; + return 0; +} + +double sinh(double x) { + (void) x; + return 0; +} + +double cosh(double x) { + (void) x; + return 0; +} + +double tanh(double x) { + (void) x; + return 0; +} + +double sqrt(double x) { + (void) x; + return 0; +} + +double pow(double x, double y) { + (void) x; + (void) y; + return 0; +} + +double atan2(double x, double y) { + (void) x; + (void) y; + return 0; +} + +double ldexp(double x, int exp) { + (void) x; + (void) exp; + return 0; +} + +double exp(double f) { + (void) f; + return 0; +} + +double frexp(double x, int *exp) { + (void) x; + *exp = 0; + return 0; +} + +double log(double f) { + (void) f; + return 0; +} + +double log2(double f) { + (void) f; + return 0; +} + +double log10(double f) { + (void) f; + return 0; +} + +double fmod(double x, double y) { + (void) x; + (void) y; + return 0; +} diff --git a/src/stdio/fclose.c b/src/stdio/fclose.c index e04c542..3d3d63c 100644 --- a/src/stdio/fclose.c +++ b/src/stdio/fclose.c @@ -5,7 +5,10 @@ int fclose(FILE *fp) { __libc_file_flush_write(fp); __libc_file_flush_read(fp); - int r = fp->close(fp->ctx); + int r = 0; + if (fp->close) { + r = fp->close(fp->ctx); + } fp->free(fp->ctx, fp); diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c new file mode 100644 index 0000000..04d6d8f --- /dev/null +++ b/src/stdio/pclose.c @@ -0,0 +1,6 @@ +#include + +int pclose(FILE *fp) { + (void) fp; + return 0; +} diff --git a/src/stdio/popen.c b/src/stdio/popen.c new file mode 100644 index 0000000..ba4762b --- /dev/null +++ b/src/stdio/popen.c @@ -0,0 +1,9 @@ +#include +#include + +FILE *popen(const char *command, const char *mode) { + (void) command; + (void) mode; + errno = EINVAL; + return NULL; +} diff --git a/src/stdio/tmpfile.c b/src/stdio/tmpfile.c new file mode 100644 index 0000000..5693cef --- /dev/null +++ b/src/stdio/tmpfile.c @@ -0,0 +1,38 @@ +#include +#include +#include + +// TODO: rewrite this crap +struct xorshift32_state { + uint32_t a; +}; + +static uint32_t xorshift32(struct xorshift32_state *state) { + uint32_t x = state->a; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return state->a = x; +} + +static int initialized = 0; +static struct xorshift32_state state; + +FILE *tmpfile(void) { + // TODO: make this atomic? + char name[32]; + + if (!initialized) { + time_t t = time(NULL); + state.a = t + 1237617; + initialized = 1; + } + + uint32_t rnd = xorshift32(&state); + snprintf(name, sizeof(name), "/tmp/%u", rnd); + + // TODO: actually support this mode + // TODO: delete-on-close flag + FILE *fp = fopen(name, "w+b"); + return fp; +} diff --git a/src/stdlib/abort.c b/src/stdlib/abort.c new file mode 100644 index 0000000..6984d4a --- /dev/null +++ b/src/stdlib/abort.c @@ -0,0 +1,10 @@ +#include +#include + +_Noreturn void abort(void) { + kill(0, SIGABRT); + // Still alive + signal(SIGABRT, SIG_DFL); + kill(0, SIGABRT); + while (1); +} diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c new file mode 100644 index 0000000..d911baa --- /dev/null +++ b/src/stdlib/strtod.c @@ -0,0 +1,7 @@ +#include + +double strtod(const char *nptr, char **endptr) { + (void) nptr; + *endptr = NULL; + return 0; +} diff --git a/src/stdlib/system.c b/src/stdlib/system.c new file mode 100644 index 0000000..7a29566 --- /dev/null +++ b/src/stdlib/system.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +static int system_execute(char *const *argv) { + int pid = fork(); + + if (pid < 0) { + return -1; + } + + if (pid == 0) { + _exit(execve(argv[0], argv, environ)); + } else { + int status; + waitpid(pid, &status, 0); + return status; + } +} + +int system(const char *command) { + char *s = strdup(command); + size_t argc = 2; // "sh" "-c" + size_t argc_cap = 32; + char *argv[32]; + argv[0] = "/bin/sh"; + argv[1] = "-c"; + char *token; + char *saveptr = NULL; + while (1) { + token = strtok_r(s, " ", &saveptr); + if (!token) { + break; + } + if (argc == argc_cap) { + // TODO: extend the buffer + free(s); + return -1; + } + argv[argc++] = token; + s = NULL; + } + argv[argc] = NULL; + + int r = system_execute(argv); + + free(s); + + return r; +} diff --git a/src/string/strstr.c b/src/string/strstr.c index 55586dd..931a666 100644 --- a/src/string/strstr.c +++ b/src/string/strstr.c @@ -1,6 +1,6 @@ #include -char *_strstr(const char *haystack, const char *needle) { +char *strstr(const char *haystack, const char *needle) { // TODO: maybe use KMP algorithm for small needle sizes size_t n = strlen(needle); if (!*needle && !*haystack) { diff --git a/src/time/clock.c b/src/time/clock.c new file mode 100644 index 0000000..eb9c98a --- /dev/null +++ b/src/time/clock.c @@ -0,0 +1,5 @@ +#include + +clock_t clock(void) { + return -1; +} diff --git a/src/time/difftime.c b/src/time/difftime.c new file mode 100644 index 0000000..d78ac33 --- /dev/null +++ b/src/time/difftime.c @@ -0,0 +1,5 @@ +#include + +double difftime(time_t t1, time_t t0) { + return t1 - t0; +} diff --git a/src/time/localtime_r.c b/src/time/localtime_r.c new file mode 100644 index 0000000..552a31d --- /dev/null +++ b/src/time/localtime_r.c @@ -0,0 +1,10 @@ +#include + +struct tm *localtime_r(const time_t *time_ptr, struct tm *ret) { + struct tm tm; + if (!gmtime_r(time_ptr, &tm)) { + return NULL; + } + *ret = tm; + return ret; +} diff --git a/src/time/mktime.c b/src/time/mktime.c new file mode 100644 index 0000000..ae2ddb0 --- /dev/null +++ b/src/time/mktime.c @@ -0,0 +1,45 @@ +#include + +#define leap_days_to_1970 477 + +static const int days_to_month365[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +}; + +static const int days_to_month366[] = { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 +}; + +static inline int is_leap(int year) { + return (year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0))); +} + +static int tm_check(const struct tm *tm) { + return tm->tm_mday < 0 || tm->tm_mday > 31 || + tm->tm_mon < 0 || tm->tm_mon > 12 || + tm->tm_year < 1970 || tm->tm_year > 2500 || + tm->tm_hour < 0 || tm->tm_hour > 23 || + tm->tm_min < 0 || tm->tm_min > 59 || + tm->tm_sec < 0 || tm->tm_sec > 59; +} + +time_t mktime(struct tm *tm) { + if (tm_check(tm) != 0) { + return 0; + } + + // Calculate year day when month starts + int month_startd = (is_leap(tm->tm_year) ? days_to_month366 : days_to_month365)[tm->tm_mon - 1]; + + // Calculate number of days from epoch to year start + int prev_year = tm->tm_year; + int days_before = ((prev_year - 1970) * 365) + (prev_year) / 4 - (prev_year) / 100 + (prev_year / 400) - leap_days_to_1970; + + // Add number of seconds in epoch days + time_t result = days_before + month_startd + tm->tm_mday - 2; + result *= 86400; + + result += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; + + return result; +} diff --git a/src/time/time.c b/src/time/time.c new file mode 100644 index 0000000..71013c0 --- /dev/null +++ b/src/time/time.c @@ -0,0 +1,10 @@ +#include +#include + +time_t time(time_t *t) { + struct timeval now; + if (gettimeofday(&now, NULL) != 0) { + return -1; + } + return t ? *t = now.tv_sec : now.tv_sec; +}