From f4616dfef148684e8efb1e4e371c504579dd74c4 Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Wed, 6 Jun 2018 19:44:29 +0200 Subject: [PATCH] mescc: Support gcc-3.4.0: alloca. * lib/alloca.c: New file. * AUTHORS: Mention it. * lib/libc+gnu.c: Add it. * include/stdlib.h: Declare alloca. --- AUTHORS | 4 ++ include/stdlib.h | 8 ++++ lib/alloca.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/libc+gnu.c | 1 + lib/m4.c | 2 +- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 lib/alloca.c diff --git a/AUTHORS b/AUTHORS index ea7de2fb..3686cbb5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -8,8 +8,12 @@ lib/libc.c (fopen) Han-Wen Nienhuys lib/libc+tcc.c (_memmem, memmem) + List of imported files +D A Gwyn +lib/alloca.c + Based on Guile ECMAScript module/language/c/lexer.mes diff --git a/include/stdlib.h b/include/stdlib.h index 36c21d8d..230291f2 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -34,6 +34,11 @@ typedef unsigned long size_t; #endif +#if _ALLOCA_UNSIGNED +void * alloca (unsigned size); +#else +void * alloca (size_t size); +#endif int atoi (char const *s); void * calloc (size_t nmemb, size_t size); void exit (int); @@ -55,6 +60,9 @@ unsigned long long strtoull (char const *nptr, char **endptr, int base); #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 +#ifndef NULL +#define NULL 0 +#endif #if __MESC__ typedef int (*comparison_fn_t) (void const *, void const *); diff --git a/lib/alloca.c b/lib/alloca.c new file mode 100644 index 00000000..53dbdc8a --- /dev/null +++ b/lib/alloca.c @@ -0,0 +1,98 @@ +/* alloca.c -- allocate automatically reclaimed memory + (Mostly) portable public-domain implementation -- D A Gwyn + + This implementation of the PWB library alloca function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + + There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. */ + +#include + +#define ALIGN_SIZE 4 +#define ADDRESS_FUNCTION(arg) &(arg) +#define STACK_DIR -1 + +union alloca_header +{ + char align[ALIGN_SIZE]; /* To force sizeof(union alloca_header). */ + struct + { + union alloca_header *next; /* For chaining headers. */ + char *deep; /* For stack depth measure. */ + } h; +}; + +static union alloca_header *last_alloca_header = NULL; /* -> last alloca header. */ + +/* Return a void * to at least SIZE bytes of storage, + which will be automatically reclaimed upon exit from + the procedure that called alloca. Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. */ + +void * +alloca (size_t size) +{ + char probe; /* Probes stack depth: */ + char *depth = ADDRESS_FUNCTION (probe); + + /* Reclaim garbage, defined as all alloca'd storage that + was allocated from deeper in the stack than currently. */ + + { + union alloca_header *hp; /* Traverses linked list. */ + + for (hp = last_alloca_header; hp != NULL;) + if ((STACK_DIR > 0 && hp->h.deep > depth) + || (STACK_DIR < 0 && hp->h.deep < depth)) + { + union alloca_header *np = hp->h.next; + + free ((void *) hp); /* Collect garbage. */ + + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + last_alloca_header = hp; /* -> last valid storage. */ + + } + + if (size == 0) + return NULL; /* No allocation required. */ + + /* Allocate combined header + user data storage. */ + + { + void * new = malloc (sizeof (union alloca_header) + size); + /* Address of header. */ + + if (new == 0) + abort(); + + ((union alloca_header *) new)->h.next = last_alloca_header; + ((union alloca_header *) new)->h.deep = depth; + + last_alloca_header = (union alloca_header *) new; + + /* User storage begins just after header. */ + + return (void *) ((char *) new + sizeof (union alloca_header)); + } +} diff --git a/lib/libc+gnu.c b/lib/libc+gnu.c index 5cd48c23..abdedd34 100644 --- a/lib/libc+gnu.c +++ b/lib/libc+gnu.c @@ -23,4 +23,5 @@ #include #include #include +#include #include diff --git a/lib/m4.c b/lib/m4.c index f1e4ae7d..b4ff9c2e 100644 --- a/lib/m4.c +++ b/lib/m4.c @@ -19,7 +19,7 @@ */ int -abort (int x) +abort () { eputs ("abort stub\n"); return 0;