Implement alloca for x86 (grischka case_8).
This implements alloca() on x86, at least for non-Windows.
Unlike the grischka version, this patch handles both the bounded and
non-bounded cases (when bounded, the alloca'd memory is covered), and
when asked to allocate with 0 size, it returns 0 without any allocation.
Modify the assembly files to adjust the amount of padding (the unused space
after an allocation); this must be at least 1 for bounds-checking.  It's
recommended that the padding be identical for unchecked and bounded cases,
because otherwise turning on bound-checking might change errors to non-errors.

diff -ur --unidirectional-new-file tinycc-rl-1.0.0/alloca86.S tinycc-alloca/alloca86.S
--- tinycc-rl-1.0.0/alloca86.S	1969-12-31 19:00:00.000000000 -0500
+++ tinycc-alloca/alloca86.S	2007-05-09 14:42:23.000000000 -0400
@@ -0,0 +1,41 @@
+/* Implementation of alloca() for tinycc (tcc) on x86.
+ * Based on grischka case_8, modified by David A. Wheeler 2007-05-09.
+ * Plays games with stack, so it omits the usual prologue and epilogue.
+ * We use the normal cdecl calling convention to reduce the risk of error. */
+
+
+/* alloca_padding is the minimum number of unused bytes AFTER the allocation.
+ * It must be at LEAST 1 for bound-checking to work, 4 if you want
+ * off-by-one word-writes to not overwrite something important, and 0
+ * if stack space is an absolute premium */
+alloca_padding=4
+
+/* Alignment: usually 4, 8, or 16. Power of 2. Result % alignment == 0. */
+alloca_alignment=4
+
+.globl _alloca_tcc
+_alloca_tcc:
+    pop    %edx        /* yank return address from stack */
+    pop    %ecx        /* Get parameter (which is size). */
+
+    /* See if we got 0, and if so, handle specially. */
+    or     $0,%ecx
+    jz     alloc_zero
+
+    /* Allocate memory on the stack */
+    mov    %ecx,%eax
+    add    $(alloca_padding+alloca_alignment-1),%eax
+    and    $(-alloca_alignment),%eax
+    sub    %eax,%esp   /* Allocate!  MODIFIES STACK POINTER HERE */
+
+    mov    %esp,%eax   /* Return beginning of allocated area to caller */
+    push   %edx        /* Re-allocate param space for the caller to remove */
+    push   %edx        /* Restore return address to return to. */
+    ret
+
+alloc_zero:
+    mov    %ecx,%eax   /* Return NULL */
+    push   %eax        /* Re-allocate param space for the caller to remove */
+    push   %edx        /* Restore return address to return to. */
+    ret
+
diff -ur --unidirectional-new-file tinycc-rl-1.0.0/bound-alloca86.S tinycc-alloca/bound-alloca86.S
--- tinycc-rl-1.0.0/bound-alloca86.S	1969-12-31 19:00:00.000000000 -0500
+++ tinycc-alloca/bound-alloca86.S	2007-05-09 14:41:58.000000000 -0400
@@ -0,0 +1,50 @@
+/* Implementation of alloca() for tinycc (tcc) on x86, bound-checking.
+ * See alloca86.S */
+
+/* alloca_padding is the minimum number of bytes AFTER the allocation that will
+ * be unused.  Must be at LEAST 1 for bound-checking to work, 4 if you want
+ * off-by-one word-writes to not overwrite something important, and 0
+ * if stack space is an absolute premium. Often wise to keep bounded and
+ * unbounded values the same. */
+bounded_alloca_padding=4
+
+/* Alignment: usually 4, 8, or 16. Power of 2. Result % alignment == 0. */
+bounded_alloca_alignment=4
+
+.globl __bound__alloca_tcc
+__bound__alloca_tcc:
+    pop    %edx        /* yank return address from stack */
+    pop    %ecx        /* Get parameter (which is size). */
+
+    /* See if we got 0, and if so, handle specially. */
+    or     $0,%ecx
+    jz     bound_alloc_zero
+
+    /* Allocate memory on the stack */
+    mov    %ecx,%eax
+    add    $(bounded_alloca_padding+bounded_alloca_alignment-1),%eax
+    and    $(-bounded_alloca_alignment),%eax
+    sub    %eax,%esp   /* Allocate!  MODIFIES STACK POINTER HERE */
+
+/* Call __bound_new_region(void *p, unsigned long size)
+ * if doing bound checks, where *p is %esp, and size is size (NOT size+1).
+ * For maximum efficiency could merge this with the code afterwards, but
+ * it's easier to see what it does this way. */
+    mov    %esp,%eax
+    push   %edx
+    push   %ecx
+    push   %eax
+    call   __bound_new_region
+    add    $8, %esp
+    pop    %edx
+
+    mov    %esp,%eax   /* Return beginning of allocated area to caller */
+    push   %edx        /* Re-allocate param space for the caller to remove */
+    push   %edx        /* Restore return address to return to. */
+    ret
+
+bound_alloc_zero:
+    mov    %ecx,%eax   /* Return NULL */
+    push   %eax        /* Re-allocate param space for the caller to remove */
+    push   %edx        /* Restore return address to return to. */
+    ret
+
diff -ur --unidirectional-new-file tinycc-rl-1.0.0/config.mak tinycc-alloca/config.mak
--- tinycc-rl-1.0.0/config.mak	2007-05-09 11:59:02.000000000 -0400
+++ tinycc-alloca/config.mak	2007-05-09 14:20:15.000000000 -0400
@@ -18,4 +18,4 @@
 EXESUF=
 ARCH=i386
 VERSION=0.9.23
-SRC_PATH=/home/dwheeler/temp/tinycc-rl-1.0.0
+SRC_PATH=/home/dwheeler/temp/tinycc-alloca
diff -ur --unidirectional-new-file tinycc-rl-1.0.0/include/alloca.h tinycc-alloca/include/alloca.h
--- tinycc-rl-1.0.0/include/alloca.h	1969-12-31 19:00:00.000000000 -0500
+++ tinycc-alloca/include/alloca.h	2007-05-09 09:56:24.000000000 -0400
@@ -0,0 +1,16 @@
+
+#ifndef _ALLOCA_H
+#define _ALLOCA_H
+
+#ifdef __TINYC__
+#define alloca(x) _alloca_tcc(x)
+
+extern void * _alloca_tcc(unsigned x);
+extern void * __bound__alloca_tcc(unsigned x);
+
+#else
+extern void * alloca(unsigned x);
+#endif
+
+#endif
+
diff -ur --unidirectional-new-file tinycc-rl-1.0.0/Makefile tinycc-alloca/Makefile
--- tinycc-rl-1.0.0/Makefile	2007-04-18 14:52:22.000000000 -0400
+++ tinycc-alloca/Makefile	2007-05-09 10:52:29.000000000 -0400
@@ -46,7 +46,7 @@
 endif
 
 # run local version of tcc with local libraries and includes
-TCC=./tcc -B. -I.
+TCC=./tcc -B. -I./include -I.
 
 all: $(PROGS) libtcc1.a $(BCHECK_O) libtcc.a libtcc_test$(EXESUF) \
      tcc-doc.html tcc.1
@@ -173,6 +173,9 @@
 LIBTCC1_CC=./tcc.exe -Bwin32
 else
 LIBTCC1_OBJS=libtcc1.o
+ifeq ($(ARCH),i386)
+LIBTCC1_OBJS+=alloca86.o bound-alloca86.o
+endif
 LIBTCC1_CC=$(CC)
 endif
 
diff -ur --unidirectional-new-file tinycc-rl-1.0.0/tcc.c tinycc-alloca/tcc.c
--- tinycc-rl-1.0.0/tcc.c	2007-04-18 14:52:22.000000000 -0400
+++ tinycc-alloca/tcc.c	2007-05-09 09:56:24.000000000 -0400
@@ -450,6 +450,7 @@
             case TOK_memset:
             case TOK_strlen:
             case TOK_strcpy:
+            case TOK_alloca:
                 strcpy(buf, "__bound_");
                 strcat(buf, name);
                 name = buf;
diff -ur --unidirectional-new-file tinycc-rl-1.0.0/tcctok.h tinycc-alloca/tcctok.h
--- tinycc-rl-1.0.0/tcctok.h	2007-04-18 14:52:22.000000000 -0400
+++ tinycc-alloca/tcctok.h	2007-05-09 09:56:24.000000000 -0400
@@ -130,7 +130,7 @@
      DEF(TOK_memcpy, "memcpy")
      DEF(TOK_memset, "memset")
 #endif
-     DEF(TOK_alloca, "alloca")
+     DEF(TOK_alloca, "_alloca_tcc")
      DEF(TOK___divdi3, "__divdi3")
      DEF(TOK___moddi3, "__moddi3")
      DEF(TOK___udivdi3, "__udivdi3")
diff -ur --unidirectional-new-file tinycc-rl-1.0.0/tests/tcctest.c tinycc-alloca/tests/tcctest.c
--- tinycc-rl-1.0.0/tests/tcctest.c	2007-04-18 14:52:22.000000000 -0400
+++ tinycc-alloca/tests/tcctest.c	2007-05-09 12:01:42.000000000 -0400
@@ -2,6 +2,8 @@
  * TCC auto test program
  */
 #include "config.h"
+#include <alloca.h>
+
 
 #if GCC_MAJOR >= 3
 
@@ -74,6 +76,7 @@
 void whitespace_test(void);
 void relocation_test(void);
 void old_style_function(void);
+void alloca_test(void);
 void sizeof_test(void);
 void typeof_test(void);
 void local_label_test(void);
@@ -526,6 +529,7 @@
     whitespace_test();
     relocation_test();
     old_style_function();
+    alloca_test();
     sizeof_test();
     typeof_test();
     statement_expr_test();
@@ -1772,6 +1776,37 @@
     decl_func2(NULL);
 }
 
+
+void alloca_test1()
+{
+ char *p = alloca(1);
+ *p = 0;
+}
+
+void alloca_test2()
+{
+ char *p = alloca(2000);
+ p += 2000;
+ p--;
+ *p = 0;
+}
+
+void alloca_test()
+{
+  char *p = alloca(16);
+  strcpy(p,"123456789012345");
+  printf("p is %s\n", p);
+
+  char *demo = "This is a test.  This is only a test.\n";
+
+  /* Test alloca embedded in a larger expression */
+  printf("Test: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
+
+  alloca_test2();
+  alloca_test1();
+}
+
+
 void sizeof_test(void)
 {
     int a;
