[comp.sys.mac.programmer] alloca; *almost* working...

morten@cs.qmw.ac.uk (Morten Ronseth) (03/19/90)

(A lat desperate attempt to make 'alloca' work on the mac...)

This is the assembly for my `alloca' routine, a rewrite of the 
one used in GNU Emacs.
Now, the `alloca' works fine in all of my own code, both using MPW 
and LightspeedC. I thought I had it all figured out, until I linked
it into gcc (as in the actual GNU code), using MPW C, and found I 
was wrong. The preprocessor cc1 just falls over on this code, and as 
the stackpointer gets garbled I can't do a stack-trace. When I use 
`malloc' instead of `alloca', everything is fine (but don't tell me
to use `malloc' instead and just forget about the whole thing!) 
Can somebody please tell me what is wrong?

				Morten.



Strategy:
Because one can never predict how many registers (if any)
are saved  at function entry, (movem.l <registers>,-(sp)), 
assume worst case and copy ALL registers to TOS where they 
are expected to be found at return-time.



	CASE OBJ
		
alloca PROC EXPORT
		movea.l	(sp)+,a0	; pop return addr from tos
		move.l	(sp)+,d0	; pop size in bytes from tos
		move.l	sp,a1		; save old sp for register copy
		move.l	sp,d1		; compute new sp
		sub.l	d0,d1		; allocate requested space on stack
		and.l	#-4,d1		; round down to longword
		sub.l	#16 * 4,d1	; space for saving registers
		move.l	d1,sp		; save new value of sp
		move.w	#16 - 1,d0	; loop counter...
@loop
		move.l	(a1)+,(sp)+	; copy the register to top of stack
		dbra	d0,@loop	; loop...
		move.l	sp,d0		; return value
		move.l	d1,sp		; load new value for sp
		jmp	(a0)		; rts
		ENDPROC

		END

(If I remeber correctly, MPW C defers the pop'ing, `addq.l #n,sp',
 of params after the return of a 'jsr', i.e. relying on an `unlk' to
 adjust the stack. Hence I do not need a `subq.l #4,sp' in my 'alloca'
 to fix the stack. But what, do I hear you ask, if the calling function
 doesn't take any params nor uses any local vars? Well, I'm compiling 
 with `-g' so the compiler should generate a `link' and an `unlk' no matter
 what...shouldn't it?) 

	The LightspeedC version looks like this (pretty much the same, huh?):

#define MAXREG	16

long alloca ()
{

	asm{
		movea.l	(sp)+,a0	; pop return addr from tos
		move.l	(sp)+,d0	; pop size in bytes from tos
		move.l	sp,a1		; save old sp for register copy
		move.l	sp,d1		; compute new sp
		sub.l	d0,d1		; allocate requested space on stack
		and.l	#-4,d1		; round down to longword
		sub.l	#MAXREG * 4,d1	; space for saving registers
		move.l	d1,sp		; save new value of sp
		move.w	#MAXREG - 1,d0	; loop counter...
loop:
		move.l	(a1)+,(sp)+	; copy the register to top of stack
		dbra	d0,@loop	; loop...
		move.l	sp,d0		; return value
		move.l	d1,sp		; load new value for sp
		subq.l	#4,sp		; caller will do `addq.l #4,sp'
		jmp	(a0)		; rts
	}
}
(No optimization here, lets fix the stack right away, we've got all the
 time in the world, right?)
-- 
==============================================================================
Morten Lerskau Ronseth

UUCP:     morten@qmw-cs.uucp       	   or ...seismo!mcvax!ukc!qmw-cs!morten
JANET:    morten@uk.ac.qmw.cs 	       Post:  Dept of Computer Science 
ARPA:     morten%qmw.cs@ucl-cs.arpa    		  Queen Mary and Westfield College 
Easylink: 19019285                     		  University of London
Telex:    893750 QMCUOL                		  Mile End Road
Fax:      +44 1 981 7517               		  London E1 4NS
Phone:    +44 1 975 5220               		  England

brecher@well.sf.ca.us (Steve Brecher) (03/21/90)

In article <1801@sequent.cs.qmw.ac.uk>, morten@cs.qmw.ac.uk (Morten Ronseth)
writes:

> This is the assembly for my `alloca' routine, a rewrite of the 
> one used in GNU Emacs.
> ...
>       movea.l (sp)+,a0        ; pop return addr from tos
>       move.l  (sp)+,d0        ; pop size in bytes from tos
>       move.l  sp,a1           ; save old sp for register copy
>       move.l  sp,d1           ; compute new sp
>       sub.l   d0,d1           ; allocate requested space on stack
>       and.l   #-4,d1          ; round down to longword
>       sub.l   #16 * 4,d1      ; space for saving registers
>       move.l  d1,sp           ; save new value of sp
>       move.w  #16 - 1,d0      ; loop counter...
> @loop
>       move.l  (a1)+,(sp)+     ; copy the register to top of stack
>       dbra    d0,@loop        ; loop...
>       move.l  sp,d0           ; return value
>       move.l  d1,sp           ; load new value for sp
>       jmp     (a0)            ; rts

Unfortunately I don't know what "alloca" is or what it's supposed to do;
but I know the above code is wrong, because (SP)+ never makes sense as
the destination of a move, unless maybe to make sure some data on the
stack is overwritten (say, a password) for security reasons.  The stack
is used by asynchronous processes such as interrupt handlers and hence
any data immediately below SP is subject to destruction at any time.

I infer that what is wanted is something like this:

On entry--

        stuff[15] ("stuff" = saved register value?)
        ...
        stuff[0]
        size of desired stack allocation
SP->    return address

On exit--
        stuff[15]
        ...
        stuff[0]
        end of allocated stack area
        ...
 D0->   start of allocated stack area
        copy of stuff[15]
        ...
 SP->   copy of stuff[0]

If I infer correctly, then:

        Move.L  (SP)+,A0        ;return address
        MoveQ   #-4,D0          ;truncation mask
        And.L   (SP)+,D0        ;size of allocated area, truncated
        Lea     4*16(SP),A1     ;point beyond end of stuff to be copied
        Sub.L   D0,SP           ;allocate the area
        Move.L  SP,D0           ;return value
        MoveQ   #16-1,D1        ;Dbra count
@0      Move.L  -(A1),-(SP)     ;copy a longword of stuff
        Dbra    D1,@0
        Jmp     (A0)            ;return

> (If I remeber correctly, MPW C defers the pop'ing, `addq.l #n,sp',
>  of params after the return of a 'jsr', i.e. relying on an `unlk' to
>  adjust the stack. Hence I do not need a `subq.l #4,sp' in my 'alloca'
>  to fix the stack. But what, do I hear you ask, if the calling function
>  doesn't take any params nor uses any local vars? Well, I'm compiling
>  with `-g' so the compiler should generate a `link' and an `unlk' no
>  matter what...shouldn't it?)

MPW C does not necessarily depend on a final UNLK to fix the stack; it
may deallocate the parameters to a called routine, or re-use the
allocated stack space, at any time after the call.  So if the above is
to be an MPW C function, you should indeed fix the stack by inserting
SubQ #4,SP before the final Jmp.  Whether the assumption that there are
saved registers (and not some transient temporaries) on the stack
immediately above the parameter is valid I cannot say, but in the
general case of a function called from an arbitrary point in another,
the assumption would NOT be warranted.

-- 

brecher@well.sf.ca.us (Steve Brecher)