ssuhook@rosemary.cs.reading.ac.uk (Roger Neil Hook) (08/18/90)
I am trying to compile GNU bison version 1.10 on a PC running DOS 3.3, using Turbo C v2.0. The source references a function called 'alloca' to allocate memory off the stack which is automatically freed when the function calling it returns. 'alloca' is not included in the TurboC library, and is anyway not standard C. I have come across two sets of assembly sources for a __680x0__ version, but do not understand precisely how they function, not having much experience in assembly. Turbo C describes two methods of calling C functions which it calls 'cdecl' and 'pascal' conventions. I have been trying to work out how to write an 80x86 assembly version of alloca to work with Turbo C. The problems I have encountered relate to not understanding what the conventions for calling a function are, and also confusion arising from trying to work out what the stack pointer is doing. To whit: I assume it is possible for a C compiler (on a PC but not necessarily TurboC) to have a function, say A(), which does some stuff which ends up with data stored on the stack. Then it calls alloca() which I assume modifies the stack pointer to hide the alloca'd block. 1) This being the case, how does A find it's stacked data? 2) Also how does the memory get freed? 3) How can I write a version of alloca in 8086 assembly for the PC, and TurboC in particular? 4) Finally, could someone please explain what alloca _should_ do, and also what the version below (extracted from a GNU library for the Atari GCC) does, especially the last op: .text .even .globl _alloca _alloca: movel sp@+,a0 ;get return addr movel sp@+,d0 ;get size -- assist in bug fix, add 4 to sp addql #1,d0 ;ensure address even andl #0xFFFFFFFE,d0 ;lop off extra bits subl d0,sp ;increase stack frame size by that much movel sp,d0 ;set up to return it lea sp@(-4),sp ;new top of stack (real bug fix here) jmp a0@ ;return by jumping via saved addr In summary, I am mainly interested in finding out how to get an alloca() for the PC for Turbo C, and also what it is that alloca() actually does. My apologies in advance if bits of this aren't relevant to any particular group. Please email me, and I will endeavour to summarize to the net if there is enough interest. Thanks, Alias JANET: ssuhook@susssys1.rdg.ac.uk
vu0310@bingvaxu.cc.binghamton.edu (R. Kym Horsell) (08/18/90)
In article <2745@onion.reading.ac.uk> ssuhook@susssys1.cs.reading.ac.uk writes: \\\ >In summary, I am mainly interested in finding out how to get an alloca() for >the PC for Turbo C, and also what it is that alloca() actually does. \\\ Alloca does something *like* char *alloca(n) { n = /* round up to words */; ((char*)SP) += n; /* bump up the stack ptr */ return (char*)SP-n; /* return address of stuff on stack */ } I.e. it just bumps up the stack by n bytes (usually word alignining the result) and returns the address of the new stack section. Since the SP is restore by C exit stuff from a `frame ptr register' (typically, anyway) this memory is deallocated at the end of the function. Note I've assumed the stack grows up (not a normal thing these days). Also we can't *actually* write alloca() as above even when you can refer to the SP directly since its exit will deallocate the space just allocated -- you should think of alloca() as written above as a macro. To solve your problem with proting Bison -- why not use (a) malloc/alloc and just forget deallocating it, or (b) malloc/alloc and use an explicit free at the end of the function its used it (might as well catch *all* returns from the function while you're about it). Ive written a fairly complete Yacc/Lex for AT's and didn't both about memory leakage. After a PDP-11 there was more memory than I new what to do with (ahhh...many years ago now). Hope this's been some help, -Kym Horsell
trier@cwlim.CWRU.EDU (Stephen C. Trier) (08/22/90)
Here's a version of alloca I use. It's my clone of a version from some piece of PD software I saw a year or two ago. #define alloca(A) ((_SP -= ((A)+1) & 0xFFFE), (void far *)(((unsigned long)_SS << 16) | _SP)) The idea is to subtract the size A from the stack pointer, making sure it's word-aligned. (This is the (_SP -= ((A)+1) & 0xFFFE) part.) Then, since alloca returns a pointer to the allocated space, the macro must kludge together a far pointer from the stack segment and stack pointer. I should add the disclaimer that I'm not entirely sure that this works. It's my own version of someone else's, but I changed it a bit. (I don't remember what the original looked like.) Hope this helps! -- Stephen Trier Case Western Reserve University Home: sct@seldon.clv.oh.us Information Network Services Work: trier@cwlim.ins.cwru.edu I may work for the University, but that doesn't mean I speak for them.
sidney@saturn.ucsc.edu (Sidney Markowitz ) (08/23/90)
trier@po.CWRU.Edu writes: >Here's a version of alloca I use. It's my clone of a version from some >piece of PD software I saw a year or two ago. [For anyone who still hasn't gotten the idea, alloca is supposed to allocate storage (like malloc) which is automatically freed upon exit from the calling procedure (as if they are on the stack like local variables).] I haven't checked it out thoroughly in TC 2.0, but in TC++ nothing that actually puts the alloca'd storage on the stack is going to work. For one thing, the compiler may save a value on the stack before the call to alloca, then try to pop it after the call, not realizing that alloca has changed the stack. Also, if you look at the assembler code generated for a function that has 0, 1 or 2 words of local variables, you will see that no stack space is reserved for them (SI and DI registers are used instead) and the compiler assumes that it doesn't need a mov sp,bp instruction to restore the stack on exit. This assumption is not true if alloca has pushed stuff on the stack expecting it to be cleaned up on exit. Basically, you can't have a real alloca without support from the compiler. There's a portable alloca written in C that I've seen with some FSF software. It simulates the effect of alloca by calling malloc and maintaining a linked list of pointers to the allocated blocks, along with the value of SP at the time of each allocation. Whenever alloca is called, it goes through the linked list, freeing all blocks for which the saved SP is smaller (deeper in the stack) than the current one. So alloca'd storage is not freed at once upon exit from the routine that is calling alloca, but instead is freed approximately the next time alloca is called. If there is interest, I can post the code. But I suggest rewriting the program to use malloc and free instead of alloca. -- sidney markowitz <sidney@saturn.ucsc.edu>
dale@NCoast.ORG (Dale Smith) (08/23/90)
In article <1990Aug22.032243.18214@usenet.ins.cwru.edu> trier@po.CWRU.Edu writes: >Here's a version of alloca I use. It's my clone of a version from some >piece of PD software I saw a year or two ago. > > #define alloca(A) ((_SP -= ((A)+1) & 0xFFFE), (void far *)(((unsigned long)_SS << 16) | _SP)) > >The idea is to subtract the size A from the stack pointer, making sure >it's word-aligned. (This is the (_SP -= ((A)+1) & 0xFFFE) part.) Then, >since alloca returns a pointer to the allocated space, the macro must >kludge together a far pointer from the stack segment and stack pointer. > >I should add the disclaimer that I'm not entirely sure that this works. >It's my own version of someone else's, but I changed it a bit. (I don't >remember what the original looked like.) > >Hope this helps! > >-- >Stephen Trier Case Western Reserve University >Home: sct@seldon.clv.oh.us Information Network Services >Work: trier@cwlim.ins.cwru.edu > I may work for the University, but that doesn't mean I speak for them. I believe I saw something like that in an early port of bison. It's really cute but will trash register variables. Someone posted an alloca for the 386 which I hacked to fit Turbo C. I also took a peek at a disassembly of the Microsoft C 5.1 alloca(). Here it is, have fun. ------ Snip it or somethin' ------------------------------ ; alloca.asm ; Allocate from the stack for Turbo C 2.0 ; I have not tried this this TC++ 1.0 ; void *alloca(size_t size); ; Beware of using alloca in functions without arguments ; and -k- in tiny, small, and medium models. The stack has a ; possibility of growing. ifdef __TINY__ .model tiny elseifdef __SMALL__ .model small elseifdef __MEDIUM__ .model medium elseifdef __COMPACT__ .model compact elseifdef __LARGE__ .model large elseifdef __HUGE__ .model huge else .model small endif if @DataSize EQ 0 .data extrn ___brklvl:word endif .code public _alloca _alloca proc ;; Pop return address into (es:) cx and size into ax pop cx ; return address if @CodeSize pop es ; return segment endif pop ax ; size ;; Make sure that ax is greater than zero, and is a multiple of two. cmp ax,0 jl error inc ax and ax,not 1 ;; Figure new stack pointer, check for negative and less than brk. mov bx,sp sub bx,ax jb error ; below zero if @DataSize EQ 0 ; tiny, small, medium cmp bx,___brklvl jb error ; below the brk endif xchg sp,bx mov ax,sp ;; Copy the (hypothetical) register variables. ifdef __MEDIUM__ push ss:6[bx] ; return segment(medium) endif push ss:4[bx] ; return offset(med,sm,tiny) or ds(huge) push ss:2[bx] ; di (all) push ss:[bx] ; si (all) if @DataSize mov dx,ss endif exit: ;; Put something on the stack so that our caller can pop it off. push ax ;; Return to the the caller. if @CodeSize push es push cx ret else jmp cx endif error: xor ax,ax if @DataSize cwd endif jmp exit endp end -------------- Ok, that's it ----------------------------------------- dale -- Dale P. Smith dale@ncoast.org uunet!usenet.ins.cwru.edu!ncoast!dale
pruss@ria.ccs.uwo.ca (Alex Pruss) (08/28/90)
In article <1990Aug22.032243.18214@usenet.ins.cwru.edu> trier@po.CWRU.Edu writes: >Here's a version of alloca I use. It's my clone of a version from some >piece of PD software I saw a year or two ago. > > #define alloca(A) ((_SP -= ((A)+1) & 0xFFFE), (void far *)(((unsigned long)_SS << 16) | _SP)) This looks surprisingly like the original of my alloca(). Unfortunately it doesn't work. (Not at all!--my version didn't either--it took many hours of painful debugging to find what was wrong.) You see it returns SS:SP. However, next time a function call, push, or interrupt comes along, a word gets stored at SS:SP which is part of the allocated area. Thus a minimal fix is to change it to: #define alloca(A) ((_SP -= ((A)+1) & 0xFFFE), (void far *)(((unsigned long)_SS << 16) | _SP+2)) Unfortunately this fails in the case that the function has stored DS/SI/DI on the stack. Furthermore one must beware that the calling function may not have a proper stack frame. >I should add the disclaimer that I'm not entirely sure that this works. >It's my own version of someone else's, but I changed it a bit. (I don't >remember what the original looked like.) It was less elegant in the forcing of A to be even, and it too didn't work. It included also a { char dummy; dummy=dummy; } type of thing to force a stack frame. Anyways, the latest WORKING (I hope... I tested it...) version I've just posted to alt.sources. (The whole thing with docs and uuencoded object files is 13Kb, so I didn't want to post it here). pruss@uwo.ca // internet pruss@uwovax // bitnet pruss@ria // uucp //\\ The SCHSPH Guy //\\