*BSD News Article 49372


Return to BSD News archive

Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!simtel!swidir.switch.ch!newsfeed.ACO.net!Austria.EU.net!EU.net!newsfeed.internetmci.com!usenet.eel.ufl.edu!willow!amigagod
From: Out of his mind <amigagod@grove.ufl.edu>
Newsgroups: comp.unix.bsd.netbsd.misc
Subject: m68k alloca.S replacement
Date: Fri, 11 Aug 1995 16:59:17 -0400
Lines: 191
Message-ID: <Pine.ULT.3.91.950811162941.17184D-100000@willow>
NNTP-Posting-Host: grove.ufl.edu
Mime-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
X-Sender: amigagod@willow
X-URL: http://grove.ufl.edu/~amigagod/


While resuming work on AmiNIX (after months of financial difficulty), I've
been reworking a couple of the NetBSD libc sources in assembly, and found
the alloca.S supplied for m68k to not only be lacking but quite unstable.
(To see what I mean, read the source and ask yourself what a calling
function will find if it tries to access a stack argument after calling
alloca().)

Attached below are the as (I think it's fully as compliant; please correct
me if not--it translates to Metacomco correctly), and Metacomco format
sources for an alloca replacement that is very compact. It acts much like
the GNU alloca; it doesn't use the stack for storage and allows an
alloca(0) call to do garbage collection now and then. It *should* work on
just about any m68k-based OS that has the ANSI C functions malloc, free,
and realloc. And no, this doesn't free() before realloc()ing (who ever
allowed that horrid situation in the first place?).

Feel free to give this a lookthrough; I haven't gotten the code to screw
up yet. I'd be curious, though, to see if it passes the GNU autoconf
alloca() tests.

===== alloca.S =====

/*
 * alloca.S - alloca(), properly implemented for m68k
 *
 * Behaves much like GNU alloca, but with far less overhead
 * (doesn't actually use the stack, and supports alloca(0) flush call)
 *
 * Author: Todd Vierling
 * Version: @AmiNIX: src/lib/libc/stdlib/alloca.S 0.9.1 95.08.11@
 */

#include <machine/asm.h>

	.globl	_malloc
	.globl	_free
	.globl	_realloc

ENTRY(alloca)
	movml	d2/a2,sp@-		| save d2,a2
	movl	allocstack,a2		| get current allocstack
startflush:
	movl	a2,d1			| test register (68000 ok)
	beq	getnew			| if 0, assume flushed and get new
	cmpl	a2@(4),sp		| compare stackpointers
	beq	flushed			| equal, assume flushed
	bgt	getnew			| greater, assume flushed and get new
flush:
	movl	a2,sp@-			| save a2
	movl	a2@(8),a2		| get first entry
floop:
	movl	a2,d1			| test block address (68000 ok)
	beq	endfloop		| if 0, done flushing
	movl	a2,sp@-			| push memptr
	movl	a2@,a2			| get address of next block
	jbsr	_free			| free memptr
	lea	sp@(4),sp		| ignore memptr
	bra	floop			| try again
endfloop:
	movl	sp@,a2			| pop and repush a2
	movl	a2@,a2			| get new struct pointer
	jbsr	_free			| free old struct
	lea	sp@(4),sp		| ignore saved a2
	bra	startflush		| try to flush again
getnew:
	movl	sp@(12),d0		| alloca(0)? (flush only)
	beq	quit			| yes, skip allocation
	moveq	#12,d0			| size of struct
	movl	d0,sp@-			| push as argument to malloc()
	jbsr	_malloc			| get memory
	lea	sp@(4),sp		| ignore 12
	tstl	d0			| is memory full?
	beq	quit			| yes, skip everything
	movl	d0,a0			| make it an a-register (no test)
	movl	a2,a0@+			| save old allocstack
	movl	sp,a0@+			| shove in the stackpointer
	clrl	a0@			| start entry at 0
	lea	a0@(-8),a2		| new allocstack
flushed:
	movl	sp@(12),d0		| alloca(0)? (flush only)
	beq	quit			| yes, skip allocation
	addql	#4,d0			| add 4 for pointer
	movl	d0,sp@-			| allocation bytes
	jbsr	_malloc			| try to allocate them
	lea	sp@(4),sp		| ignore argument
	movl	d0,d2			| did we get it?
	beq	quit			| no, return 0
	movl	a2@(8),a1		| get first block
	exg	a1,d2			| swap first block/new block
	movl	d2,a1@			| insert first block in new block
	movl	a1,a2@(8)		| put new block in struct
	movl	a1,d0			| prepare return value
	addql	#4,d0			| skip over list pointer
quit:
	movl	a2,allocstack		| put (possibly new) allocstack back
	movml	sp@+,d2/a2		| pop d2,a2
	rts				| return

/*
 * The allocstack structure has the following format:
 * struct allocstack {
 *	struct allocstack *next;	* next higher level
 *	u_int32_t stackptr;		* sp for which this reflects
 *	void *memfirst;			* the entries themselves, linked list
 * };
 */

	.data
allocstack:
	.long	0

===== alloca.asm

	machine	68000
	public	_malloc
	public	_free
	public	_realloc
	cseg
	even
	public	_alloca
_alloca:
	movem.l	d2/a2,-(sp)		
	move.l	allocstack,a2		
startflush:
	move.l	a2,d1			
	beq	getnew			
	cmp.l	4(a2),sp		
	beq	flushed			
	bgt	getnew			
flush:
	move.l	a2,-(sp)			
	move.l	8(a2),a2		
floop:
	move.l	a2,d1			
	beq	endfloop		
	move.l	a2,-(sp)			
	move.l	(a2),a2			
	jsr	_free			
	lea	4(sp),sp		
	bra	floop			
endfloop:
	move.l	(sp),a2			
	move.l	(a2),a2			
	jsr	_free			
	lea	4(sp),sp		
	bra	startflush		
getnew:
	move.l	12(sp),d0		
	beq	quit			
	moveq	#12,d0			
	move.l	d0,-(sp)			
	jsr	_malloc			
	lea	4(sp),sp		
	tst.l	d0			
	beq	quit			
	move.l	d0,a0			
	move.l	a2,(a0)+			
	move.l	sp,(a0)+			
	clr.l	(a0)			
	lea	-8(a0),a2		
flushed:
	move.l	12(sp),d0		
	beq	quit			
	addq.l	#4,d0			
	move.l	d0,-(sp)			
	jsr	_malloc			
	lea	4(sp),sp		
	move.l	d0,d2			
	beq	quit			
	move.l	8(a2),a1		
	exg	a1,d2			
	move.l	d2,(a1)			
	move.l	a1,8(a2)		
	move.l	a1,d0			
	addq.l	#4,d0			
quit:
	move.l	a2,allocstack		
	movem.l	(sp)+,d2/a2		
	rts				

	dseg
allocstack:
	dc.l	0

=====
=== Todd Vierling (amigagod@grove.ufl.edu): Finger for PGP 2.6 public key ===
=== I remember the hopes, the fears, the successes, and the failures that ===
== brought us to the pinnacles of achievement today. -- essay "I Remember" ==
=== Vierling's Law: The revolution won't be televised; it will be posted. ===