Here's "version 3" of my alloca patch.
As Rob requested, the amount of padding is now configurable. I only made it
configurable in the sense that it's now an easily-edited constant at the
beginning of the file; you still need to assemble it to make it take effect. I
don't think we need anything more than that. I made alignment configurable the
same way.
If the biggest thing Rob and I argue about is alloca padding, things are going
really well :-).
--- David A. Wheeler
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;
_______________________________________________
Tinycc-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/tinycc-devel