File:  [Research Unix] / researchv10no / cmd / cfront / libC / otask / fudge.c.68k
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:35 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

#include "task.h"

// MC68000 frame fudger

/* careful -- stack frame not self-describing */
// STACK GROWS DOWN
#define FP(p)		( (int*)(&p+1) )
#define AP()		0	/* unnecessary on mc68000 */
#define OLD_AP(fp)	0	/* unnecessary on mc68000 */
#define OLD_FP(fp)	(*fp)

struct FrameLayout {
	short	offset; // of top of frame from fp (size of locals + regs)
	unsigned short	mask;   // of registers saved in frame
		FrameLayout(int*);  // called with frame pointer
};

/*
 * This code figures out the layout of the frame of the user's constructor.  Note
 * the user's class is directly derived from class task and the call to the
 * constructor is automatically generated.
 */
FrameLayout::FrameLayout(int* fp)
{
	unsigned short*	ret_addr = (unsigned short*)*(fp+1);
/*
 * find the starting address of the function.  The idea is that the instruction
 * immediately before the return address must be the function call.  Only works
 * if the function was called by name.
 */
/*
 * On the 68000, the four forms of function call generated by the compiler are
 *	047271	jsr	followed by the function address (long)
 *	060777	bsrl	followed by the function offset (long) (68020 only)
 *	060400	bsr	followed by the function offset (short)
 *	0x61NN	bsrb	low order byte is the offset (not actually seen or tested)
 */
	unsigned short*	func_addr = 	
		(ret_addr[-3] == 047271) ?
			(unsigned short*)*(int*)(ret_addr-2) :
		(ret_addr[-3] == 060777) ? 
			(unsigned short*) ((char*)(ret_addr-2) + *(int*)(ret_addr-2)) :
		(ret_addr[-2] == 060400) ?
			(unsigned short*) ((char*)(ret_addr-1) + *(short*)(ret_addr-1)) :
		(*(char*)(ret_addr-1) == 0x61) ?
			(unsigned short*) ((char*)ret_addr + *((char*)ret_addr-1)) :
			(unsigned short*)((object*)0)->task_error(E_FUNCS);
/*
 * the first instruction in the function is linkw a6,xxx
 * if -O was used, xxx is the frame size in bytes, otherwise
 * xxx is 0 and the next instruction is addl #yyy, sp
 * where yyy is the frame size
 */
	if (*func_addr == 047126) { // linkw instruction
		if ((offset = (short)*++func_addr / 4) == 0)
			if (*++func_addr == 0157774)  // addl
				offset = (short)*(func_addr += 2) / 4;
	} else ((object*)0)->task_error(E_FRAMES);
/*
 * The next instruction saves the registers in the frame.  The possibilities are
 *	movem	mask,@sp	| save the register specified by the mask word
 *	movl	a5,@sp		| just save a5
 *	movl	d7,@sp		| just save d7
 * The mask uses the standard 68000 layout
 */
	switch (*++func_addr) {
	case 027215:			// movl a5,sp@
		mask = 020000;		//  just a5
		break;
	case 044327:			// movem mask,@sp
		mask = *++func_addr;	//  mask word
		break;
	case 027207:			// movl d7,sp@
		mask = 0200;		//  just d7
		break;
	default:			// no saved registers is also possible
		mask = 0;
		break;
	}
}

/*
 * fix a frame so that it returns like the arg
 * The idea is that task_fp points to the task::task() stack frame which
 * contains all the saved registers.  t_framep points to the stack frame
 * that contains the return address and old fp (and perhaps some registers).
 * fill the frame pointed to by t_framep with the registers from task_fp.
 */
void
task::fudge_return(int* task_fp, int offset, task* next)
{
	int*	fp = t_framep + offset;
	task_fp += offset;		// in case this is SHARED
	FrameLayout	this_lo(fp);
	FrameLayout	task_lo(task_fp);
	// copy any saved registers from this to task frame
	register int*	task_rp = task_fp + task_lo.offset;
	register int*	this_rp = fp + this_lo.offset;
	register int	reg_count = 0;
	for (register mask = 1; mask != 0x10000; mask <<= 1) {
		if (mask & task_lo.mask) {
			reg_count++;
			if (mask & this_lo.mask)
				*task_rp++ = *this_rp++;
			else task_rp++;
		} else if (mask & this_lo.mask)
			task_error(E_FUDGE);
	}
	// next copy all the registers from the task frame to this (using task offset)
	task_rp = task_fp + task_lo.offset + reg_count;
	this_rp = fp + task_lo.offset + reg_count;
	while (reg_count--)
		*--this_rp = *--task_rp;
	if (next) next->restore();
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.