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