[alt.sources] alloca

pruss@ria.ccs.uwo.ca (Alex Pruss) (08/28/90)

Here are two versions of alloca() for Turbo C.  They haven't been tested
as thoroughly as I would have liked, but here they are.  If you have any
comments feel free to write me (pruss@uwo.ca).  As usual, this is provided
with no warranties of any kind.  Not only are there no valid implied warranties,
but I explicitly state that under many circumstance this program will not work
(and may crash the system).  USE WITH CARE and READ THE DOCUMENTATION!
Be careful when using not on Turbo C 2.0 or 1.0++.

UUE binaries included for the object files (if you don't have a86).

Please send me any modifications you make that you think may be useful
generally.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	alloca.8
#	alloca.doc
#	alloca.h
#	obc.uue
#	obl.uue
#	obm.uue
#	obs.uue
# This archive created: Mon Aug 27 13:08:27 1990
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
Xalloca() for Turbo C and Turbo C++.  See alloca.doc for more information.
SHAR_EOF
fi # end of overwriting check
if test -f 'alloca.8'
then
	echo shar: will not over-write existing file "'alloca.8'"
else
sed 's/^X//' << \SHAR_EOF > 'alloca.8'
X;
X; alloca.8 begins
X; source for a86 assembler
X; released into the public domain with the restriction that the
X; acknowledgement below be preserved:
X;   ...  This alloca() for Turbo C is by Alexander Pruss  ...
X;
X; Assemble via:
X;  A86 +oc =__<MODEL-IDENTIFIER>__ alloca.8
X; Note that the HUGE alloca = LARGE alloca and that TINY alloca = SMALL alloca
X;
X#if __MEDIUM__
XL_CODE = 1
X#elseif __COMPACT__
XL_DATA = 1
X#elseif __LARGE__
XL_DATA = 1
XL_CODE = 1
X#elseif __HUGE__
XL_DATA = 1
XL_CODE = 1
X#endif
X
X#if L_CODE
XALLOCA_TEXT     segment byte public 'CODE'
X#else
XTEXT            segment byte public 'CODE'
X#endif
X
X@alloca_buffer dw ?
X
Xpublic __alloca
X;; void *_alloca(unsigned size) ;;
X__alloca:
X        pop      bx                     ; Return address
X#if L_CODE
X        pop      es                     ; into [ES:]BX
X#endif
X        pop      cx                     ; Data size.  (Argument to alloca)
X
X        pop      dx                      ; Store some
X        pop      ax
X#if L_DATA
X        pop      cs:@alloca_buffer       ; data from caller's stack
X        push     cs:@alloca_buffer       ; (DS,SI,DI--some may not be necessary)
X#endif                                   ; DS unnecessary for small data models
X        push     ax                      ; we put it back after reading
X        push     dx
X        inc      cx                     ; Round CX to even.  (SP must be even,
X                                        ; else performance degrades)
X        shr      cx,1
X 	shl	 cx,1     
X        sub      sp,cx                  ; Allocate the space
X
X#if L_DATA
X        push     cs:@alloca_buffer      ; make a copy of the possible data
X#endif
X        push     ax                     ; (DS,SI,DI) on the caller's stack
X        push     dx
X
X        mov      ax,sp                  ; Return value.
X#if L_DATA
X        add      ax,8                   ; remember we put 3 words on the stack
X                                        ; and the stack points to a free word
X#else
X        add      ax,6                   ; 2 words for small data models only
X#endif
X        push     cx                     ; put the size back on the stack
X#if L_CODE
X        push     es                     ; high order return address
X#endif
X        push     bx                     ; low order return address
X#if L_DATA
X        mov      dx,ss                  ; high order return value
X#endif
X#if L_CODE
X        retf                            ; out we go!
X#else
X        ret
X#endif
X
XALLOCA_TEXT     ends
X	end
SHAR_EOF
fi # end of overwriting check
if test -f 'alloca.doc'
then
	echo shar: will not over-write existing file "'alloca.doc'"
else
sed 's/^X//' << \SHAR_EOF > 'alloca.doc'
Xalloca() by Alexander Pruss for Turbo C
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
X
Xemail: pruss@uwo.ca  // internet
X       pruss@uwovax  // bitnet
X       pruss@ria     // uucp
X
XReleased into the public domain with the restriction that the acknowledgements
Xto Alexander Pruss are preserved.
X
X
XWarranty: NONE!  This has undergone considerable testing, but it is likely
X          not to work in many cases.  It may cause damage to your system if
X          it fails in a particularly nasty way.  USE AT YOUR OWN RISK!
X
X
XA few words about stack frames.
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Xalloca() needs a real stack frame in the function that calls it.
XThis means that the function must begin with an ENTER (or push bp; mov bp,sp)
Xand end with a LEAVE (or mov sp,bp; pop bp).  Just setting the compiler -k
X(standard frame) switch is not enough as the LEAVE is then changed into a
Xstraight pop bp.
X
XThe correct stack frame will be inserted provided the compiler cannot
Xmake all the local variables into registers.  Thus if the calling function
Xhas more than two integer auto variables or it has a noninteger and nonfloat
Xauto variable (a near pointer we consider an integer, but not a far pointer)
Xthen it will have a stack frame.
X
XI.e. the functions below have a stack frame:
Xf(a)  { int x; int y; int z; ... }  /* 3 integer vars */
Xg(a)  { char x; ... }               /* noninteger var */
Xh(a)  { char far *x; ... }          /* far pointer    */
Xi(a)  { { char dummy; dummy=dummy; } }  /* more about this later on */
X
Xand the functions below may or may not have a proper stack frame:
XF(a)  { int x; int y; ... }
XG(a)  { int x; ... }
XH(a)  { char near *x; int y; ... }
XI(a)  { float x; double y; ... }    /* floats might go on 8087 stack */
X
XYou can force a stack frame by inserting somewhere in the function, where
Xthe flow of execution will reach it, the line:
X  { char dummy; dummy=dummy; }
X
X
XHow to use alloca().
X~~~~~~~~~~~~~~~~~~~~
X#include "alloca.h"
X
Xnow you can use alloca() as:
X        void *alloca(unsigned size);
X
Xalloca() is a replacement for malloc() which allocates space which will
Xbe deallocated upon return from the calling routine.
X
XYou must link in the appropriate version unless you are using INLINE_ALLOCA
X(see below):
X
Xmemory model      object file
X~~~~~~~~~~~~      ~~~~~~~~~~~
Xtiny, small       alloca.obs
Xmedium            alloca.obm
Xcompact           alloca.obc
Xlarge, huge       alloca.obl
X
XOptions:
X If you insert #define INLINE_ALLOCA before #include'ing alloca.h, then you
X will have a much faster (but larger) inline version.  You need no longer
X link in the object file.
X
X If you insert #define FORCE_STACK, then a stack frame is forced onto the
X function automatically.  This is done as alloca() is defined to be
X alloca(); { char dummy; dummy=dummy; }
X This means, however, that lexically all calls to alloca() must be of the
X following form:
X  xxx alloca(yyy);
X where xxx and yyy are arbitrary things (conforming to C syntax).  Thus,
X  x = 3+(char *)alloca(y); is allowed, while
X  x = (char *)alloca(y) + 3; is illegal.  (And will likely produce a
X compiler error.)
X
XCompiler
X~~~~~~~~
XTested under Turbo C 2.0.
X
XBugs
X~~~~
XIf the alloca()'d pointer is assigned to z and z is unitialized, the compiler
Xmay generate a `possible use before definition' error for z.  Ignore this
Xerror.  I have yet to find out what causes it, but the assembly output is
XO.K. even if the error occurs.
X
XThe function must have a proper stack frame.  (See above).
X
Xalloca() in FORCE_STACK mode must be called lexically as xxx alloca(yyy);
X(see above)
X
Xalloca() will not work in a long and complicated expression or in the middle
Xof a function call as at that time the stack may be screwed up.  It is safe
Xto use alloca() as the last argument to a function call, so:
X z=f(alpha,alloca(100)); is O.K. (unless in FORCE_STACK mode), while:
X z=F(alloca(100),alpha); is illegal and will likely crash.  (compiler error
Xis generated in FORCE_STACK mode).
XLong arithmetic expressions may save intermediate results on the stack.  This
Xwill cause alloca() to screw up, so do not do more than a few simple operations
Xon the return value.  You should use alloca() mainly as z=alloca(y); which will
Xwork unless y is a long and complex expression.
XIn FORCE_STACK mode some long arithmetic expressions may generate compiler errors
Xbut normally if alloca() screws up the compiling will be O.K., just the
Xprogram will crash.
X
XStack overflow is not checked, so alloca() will always work.
X
XI haven't time to test as thoroughly as I wish to.
X
XNews!
X~~~~~
XI got it to work with TC++ 1.00.  I had to change the FORCE_STACK method.
XChars can now be made into register variables, so g() and i() defined above
Xin the stack frame section do not have stack frames.  Now the stack is forced
Xby using a long.  See alloca.h for more information.
SHAR_EOF
fi # end of overwriting check
if test -f 'alloca.h'
then
	echo shar: will not over-write existing file "'alloca.h'"
else
sed 's/^X//' << \SHAR_EOF > 'alloca.h'
X/* alloca for Turbo C
X* public domain with the restriction that the following line is always retained:
X* ... alloca() written by Alexander Pruss ...
X* Options:
X** INLINE_ALLOCA -- sets up an inline equivalent to the assembly version.
X**                  equivalent in all respects but it is macro.
X** FORCE_STACK   -- forces a stack frame for each function.  This will increase
X**                  the stack frame for each function that already has a frame
X**                  and calls alloca() by 2 bytes.  If it is activated, the
X**                  alloca call MUST be of the form:  xxx=yyy alloca(zzz);
X**                  where yyy and xxx are anything valid.
X*/
X
X#ifndef alloca
X
X#ifndef __TURBOC__
X#error Turbo C is required for alloca.h.  Sorry.
X#endif
X
X#ifdef INLINE_ALLOCA
Xvoid __emit__();
X
X#define MAKE_FAR_PTR(seg,off) \
X (void far *) ( ( (unsigned long)(seg) << 16 ) | ( (unsigned int)(off) ) )
X
X#define MAKE_EVEN(x)   ( ( ((x)+1)>>1 ) <<1 )
X
X#if sizeof(void *)==4
X#define _alloca(space) (void *) \
X	 ( __emit__(0x07, 0x5B, 0x59, 0x51, 0x53, 0x06), \
X    _SP-=MAKE_EVEN((space)), __emit__(0x51,0x53,0x06), MAKE_FAR_PTR(_SS,_SP+8))
X#else
X#define _alloca(space) (void *) \
X         ( __emit__(0x5B, 0x59, 0x51, 0x53), \
X    _SP-=MAKE_EVEN((space)), __emit__(0x51,0x53), MAKE_FAR_PTR(_SS,_SP+6))
X#endif
X
X/* this is equivalent in operation to the assembly language version.
XThe emits are: es bx cx
X   pop es  (only if large data)
X   pop bx
X   pop cx
X   push cx
X   push bx
X   push es   (to save the (DS,SI,DI), or (SI,DI) in small data)
X  followed by
X   push cx
X   push bx
X   push es   (to make a copy of (DS,SI,DI))
X*/
X#else
X
Xvoid *_alloca(unsigned length);
X
X#endif  /* INLINE */
X
X#ifdef FORCE_STACK
X# if __TURBOC__ > 0x200
X  static long __global_long_dummy__;
X# define alloca(x) _alloca((x)); { long z; __global_long_dummy__=z; };
X#else
X# define alloca(x) _alloca((x)); { char z; z=z; };
X#endif
X
X#else
X#define alloca(x) _alloca((x))
X#endif
X
X#endif /* def alloca */
SHAR_EOF
fi # end of overwriting check
if test -f 'obc.uue'
then
	echo shar: will not over-write existing file "'obc.uue'"
else
sed 's/^X//' << \SHAR_EOF > 'obc.uue'
Xsection 1 of uuencode 4.02 of file alloca.obc    by R.E.M.
X
Xbegin 644 alloca.obc
XM@`@`!D%,3$]#0<:6#```!%1%6%0$0T]$1?:8!P`H*@`"`P$)D`\```$(7U]AV
XM;&QO8V$"```LH"P``0(`6UE:6"Z/!@``+O\V``!04D'1Z='A*<PN_S8``%!2Q
X@B>`%"`!14XS2PR&<#0#$!U0!Q`Q4`<0:5`'?B@(``'0`G
X``
Xend
Xsum -r/size 35747/201 section (from "begin" to "end")
Xsum -r/size 30608/122 entire input file
SHAR_EOF
fi # end of overwriting check
if test -f 'obl.uue'
then
	echo shar: will not over-write existing file "'obl.uue'"
else
sed 's/^X//' << \SHAR_EOF > 'obl.uue'
Xsection 1 of uuencode 4.02 of file alloca.obl    by R.E.M.
X
Xbegin 644 alloca.obl
XM@`@`!D%,3$]#0<:6$P``"T%,3$]#05]415A4!$-/1$7=F`<`*"P``@,!!Y`/J
XM```!"%]?86QL;V-A`@``+*`P``$`````6P=96E@NCP8``"[_-@``4%)!T>G1=
XKX2G,+O\V``!04HG@!0@`4093C-++"IP-`,0*5`'$#U0!Q!U4`=:*`@``=```T
X``
Xend
Xsum -r/size 53963/217 section (from "begin" to "end")
Xsum -r/size 6431/133 entire input file
SHAR_EOF
fi # end of overwriting check
if test -f 'obm.uue'
then
	echo shar: will not over-write existing file "'obm.uue'"
else
sed 's/^X//' << \SHAR_EOF > 'obm.uue'
Xsection 1 of uuencode 4.02 of file alloca.obm    by R.E.M.
X
Xbegin 644 alloca.obm
XM@`@`!D%,3$]#0<:6$P``"T%,3$]#05]415A4!$-/1$7=F`<`*!L``@,!&)`/Z
XM```!"%]?86QL;V-A`@``+*`?``$`````6P=96EA04D'1Z='A*<Q04HG@!08`0
X*4093RP2*`@``=```+
X``
Xend
Xsum -r/size 59505/173 section (from "begin" to "end")
Xsum -r/size 64567/100 entire input file
SHAR_EOF
fi # end of overwriting check
if test -f 'obs.uue'
then
	echo shar: will not over-write existing file "'obs.uue'"
else
sed 's/^X//' << \SHAR_EOF > 'obs.uue'
Xsection 1 of uuencode 4.02 of file alloca.obs    by R.E.M.
X
Xbegin 644 alloca.obs
XM@`@`!D%,3$]#0<:6#```!%1%6%0$0T]$1?:8!P`H&0`"`P$:D`\```$(7U]AS
XL;&QO8V$"```LH!L``0(`6UE:6%!20='IT>$IS%!2B>`%!@!14\,;B@(``'0`=
X``
Xend
Xsum -r/size 55189/154 section (from "begin" to "end")
Xsum -r/size 37941/89 entire input file
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0