mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-21 03:51:47 -08:00
202 lines
5.4 KiB
C
202 lines
5.4 KiB
C
/* -*- mode: c; c-basic-offset: 8 -*- */
|
|
/*
|
|
cs.h -- C stack manipulation.
|
|
*/
|
|
/*
|
|
Copyright (c) 1990, Giuseppe Attardi.
|
|
|
|
ECoLisp is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
See file '../Copyright' for full details.
|
|
*/
|
|
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
* Low level stack manipulation macros
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
#define asm __asm__
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
* Stack of predefined size
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
#define cl_nextarg(arg) va_arg((arg),cl_object)
|
|
|
|
#define CSTACK(size) register cl_object *_stack_top; \
|
|
cl_object _stack_bot[size]; \
|
|
_stack_top = _stack_bot /* __GNUC__ */
|
|
#define CPUSH(val) *_stack_top++ = (val);
|
|
|
|
#define CSTACK_BOT _stack_bot
|
|
#define CSTACK_TOP _stack_top
|
|
|
|
/*---------------------------------------------------------------------- */
|
|
|
|
#if defined(__i386__) && 0
|
|
/* Stack usage:
|
|
|
|
sp | lclm |
|
|
| ... |
|
|
| lcl1 |
|
|
bp | obp |
|
|
| ret? |
|
|
| arg1 |
|
|
| ... |
|
|
osp | argn |
|
|
| ... |
|
|
obp | |
|
|
|
|
Caller pushes args and pops them after return. Result in ax.
|
|
*/
|
|
|
|
#ifdef __GO32__ /* DJGPP */
|
|
typedef char * caddr_t;
|
|
#endif
|
|
|
|
#define GET_CURRENT_FRAME(frame) asm("movl (%%ebp),%0" : "=r" (frame))
|
|
#define FRAME_CHAIN(frame) ((char **)frame)[0]
|
|
#define FRAME_SAVED_PC(frame) ((char **)frame)[1]
|
|
|
|
#define PC_INDEX 8
|
|
|
|
#if 0
|
|
#define TRANSFER_CALL(fun) asm("leave"); goto *(fun) /* __GNUC__ */
|
|
#endif
|
|
|
|
#define CCALL(narg,fun) ({register cl_object eax asm("%eax"); \
|
|
asm("push %0" :: "g" (narg)); \
|
|
asm("call %0" :: "g" (fun) : "eax"); \
|
|
asm("addl $4, %%esp" :: ); eax;})
|
|
|
|
#if !defined(__linux__) && !defined(__FreeBSD__)
|
|
#define ARGCALL CCALL
|
|
#define ARGSTACK(size) CSTACK(size)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------- */
|
|
|
|
#ifdef __mips
|
|
|
|
/* stack usage:
|
|
|
|
sp | |
|
|
| ... |
|
|
| save $31 | \ return pointer
|
|
| save regs | > frame offset
|
|
| locals | /
|
|
fp | arg1 | first arg of this function
|
|
| ... |
|
|
| argn |
|
|
| ... |
|
|
| |
|
|
|
|
*/
|
|
/* Unfortunately MIPS stacks do not have enough information to chain through
|
|
them. FP is virtual, has no allocated register. We might reconstruct
|
|
framesize and frameoffset from first two instructions of procedure:
|
|
|
|
subu $sp, framesize
|
|
sw $ra, framesize+frameoffset($sp)
|
|
|
|
However we have no way to find the entry to a function given a PC.
|
|
GDB uses symbol information from the function to determine FP.
|
|
*/
|
|
|
|
#define ARGSTACK(size) register cl_object *_stack_top; \
|
|
cl_object _stack_bot[size+1]; \
|
|
_stack_top = _stack_bot /* __GNUC__ */
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------- */
|
|
|
|
#if defined(sparc) && 0
|
|
|
|
/*
|
|
#define JB_SP 1
|
|
#define JB_PC 2
|
|
#define JB_FP 3
|
|
#define JB_NPC 4
|
|
#define JB_PSR 5
|
|
*/
|
|
|
|
/*
|
|
* Got this info from gdb (config/sparc/tm-sparc.h and sparc-tdep.c)
|
|
*/
|
|
|
|
#define GET_CURRENT_FRAME(frame) asm("mov %%fp,%0" : "=r" (frame))
|
|
#define FRAME_CHAIN(frame) ((caddr_t *)frame)[14]
|
|
#define FRAME_SAVED_PC(frame) ((caddr_t *)frame)[15]
|
|
|
|
|
|
/* GCC reserves 6 words for saving registers o0-05, but never does that */
|
|
|
|
#define ARGSTACK(size) register volatile cl_object *_stack_top; \
|
|
cl_object _stack_bot[size+1]; \
|
|
_stack_top = _stack_bot-6 /* __GNUC__ */
|
|
|
|
#define ARGCALL(narg, fun) ({ register cl_object _res asm("%o0"); \
|
|
asm("mov %0,%%o0" :: "r" (narg) : "%o0"); \
|
|
asm("ld [%%sp+72],%%o1" ::: "%o1"); \
|
|
asm("ld [%%sp+76],%%o2" ::: "%o2"); \
|
|
asm("ld [%%sp+80],%%o3" ::: "%o3"); \
|
|
asm("ld [%%sp+84],%%o4" ::: "%o4"); \
|
|
asm("ld [%%sp+88],%%o5" ::: "%o5"); \
|
|
asm("call %0,0" : : "r" (fun) ); \
|
|
asm("nop"); _res;})
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------- */
|
|
|
|
#if defined(vax) && 0
|
|
#define PC_INDEX 0
|
|
#define TRANSFER(buf, addr) buf[PC_INDEX] = (int)addr+((((int *)addr)[0] >> 19) & 4)+4; \
|
|
ecl_longjmp(buf)
|
|
#define TRANSFER_CALL(fun) REG = (cl_object)fun; \
|
|
asm(" ashl $-19,(r11),r0"); \
|
|
asm(" bicl2 $-5,r0"); \
|
|
asm(" addl2 r11,r0"); \
|
|
asm(" addl2 $4,r0"); \
|
|
asm(" jmp (r0)")
|
|
#define CSTACK(size) register cl_object REG
|
|
#define CPUSH(val) (REG = (cl_object)(val), \
|
|
asm(" pushl r11"))
|
|
#define CPOP (asm(" movl (sp)+,r11"), REG)
|
|
|
|
/* Reverse arguments on the stack, push narg, and then call.
|
|
narg (r11), up (r9), dn (r8)
|
|
for (dn = sp, up = sp+narg-1; dn < up; ) {
|
|
tmp = *dn; *dn++ = *up; *up-- = tmp;
|
|
}
|
|
*/
|
|
#define CCALL(narg, fun) (REG = (cl_object)(narg), \
|
|
asm(" movl sp,r8"), \
|
|
asm(" ashl $2,r11,r0"), \
|
|
asm(" addl3 r0,sp,r9"), \
|
|
asm(" subl2 $4,r9"), \
|
|
asm("1: cmpl r8,r9"), \
|
|
asm(" jgeq 2f"), \
|
|
asm(" movl (r8),r7"), \
|
|
asm(" movl (r9),(r8)+"), \
|
|
asm(" movl r7,(r9)"), \
|
|
asm(" subl2 $4,r9"), \
|
|
asm(" jbr 1b"), \
|
|
asm("2: pushl r11"), \
|
|
asm(" addl3 $1,r11,r0"), \
|
|
REG = (cl_object)(fun), \
|
|
asm(" calls r0,(r11)"), \
|
|
asm(" movl r0,r11"), (int)REG)
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------- */
|