Annotation of researchv10no/cmd/cfront/libC/otask/fudge.c.3b, revision 1.1

1.1     ! root        1: #include "task.h"
        !             2: #include <assert.h>
        !             3: #include <stdio.h>
        !             4: 
        !             5: // 3B frame fudger
        !             6: 
        !             7: //Frames not self-describing!
        !             8: //STACK GROWS UP
        !             9: 
        !            10: typedef unsigned char MACHINE_BYTE;
        !            11: 
        !            12: #ifdef u3b
        !            13: 
        !            14: #define OLD_FP(fp)     ( *( (int*)(fp) - 11 ) )
        !            15: #define OLD_AP(fp)     ( *( (int*)(fp) - 12 ) )
        !            16: #define OLD_PC(fp)     ( *( (int*)(fp) - 13 ) )
        !            17: #define FIRST_SAVED_REG_P(fp)  ( (int*)(fp) - 6 )
        !            18: 
        !            19: const CALL_OPCODE = ((MACHINE_BYTE)0x78);
        !            20:                        /* SAK:  really: 0x78 | 0x79 | 0xB9 | 0x77 */
        !            21: const SAVE_OPCODE = ((MACHINE_BYTE)0x7A);
        !            22: const BYTE_DISPL       = 0xC0; /* SAK: WRONG for u3b! */
        !            23: const HALFWORD_DISPL   = 0xA0; /* SAK: WRONG for u3b! */
        !            24: const WORD_DISPL       = 0x80; /* SAK: WRONG for u3b! */
        !            25: const ABSOLUTE         = 0x70; /* SAK: WRONG for u3b! */
        !            26: 
        !            27: const N_CALL_INSTR_SIZES = 6;  /* SAK: WRONG for u3b! */
        !            28: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11};     /* SAK: WRONG for u3b! */
        !            29: 
        !            30: /* SAK: SAVE_OPERAND(instr) not needed for u3b */
        !            31: 
        !            32: /* Given a pointer to a save instruction, yield the number of registers saved */
        !            33: #define N_SAVED_REGS(instr)    (((char *)(instr))[1] >> 4)
        !            34: 
        !            35: /* CALL's src operand descriptor needed to determine size of src operand */
        !            36: #define SRC_OP_DESC(instr)     (((char *)(instr))[1] & 0xf0)
        !            37: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\
        !            38:        (((desc) == BYTE_DISPL)         ? 2 :   \
        !            39:         ((desc) == HALFWORD_DISPL)     ? 3 :   \
        !            40:         ((desc) == WORD_DISPL)         ? 5 :   \
        !            41:         ((((object*)0)->task_error(E_FRAMES)))         \
        !            42:        )
        !            43: const  OPCODE_SIZE = 1;
        !            44: const  DESC_SIZE = 1;
        !            45: 
        !            46: /* SAK:  WRONG for u3b! */
        !            47: #define        DST_OP_DESC(instr)      \
        !            48:        (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0)
        !            49: 
        !            50: /* SAK:  WRONG for u3b! */
        !            51: #define IS_LEGAL_SRC_OP(desc)                  \
        !            52:        (((desc) == BYTE_DISPL)         ||      \
        !            53:         ((desc) == HALFWORD_DISPL)     ||      \
        !            54:         ((desc) == WORD_DISPL)                 \
        !            55:        )
        !            56: /* SAK:  WRONG for u3b! */
        !            57: #define IS_LEGAL_DST_OP(desc)                  \
        !            58:        (((desc) == BYTE_DISPL)         ||      \
        !            59:         ((desc) == HALFWORD_DISPL)     ||      \
        !            60:         ((desc) == WORD_DISPL)         ||      \
        !            61:         ((desc) == ABSOLUTE)                   \
        !            62:        )
        !            63: 
        !            64: 
        !            65: #else  /* m32:  u3b2, u3b5, u3b15 */
        !            66: #define OLD_FP(fp)     ( *( (int*)(fp) - 7 ) )
        !            67: #define OLD_AP(fp)     ( *( (int*)(fp) - 8 ) )
        !            68: #define OLD_PC(fp)     ( *( (int*)(fp) - 9 ) ) 
        !            69: #define FIRST_SAVED_REG_P(fp)  ( (int*)(fp) - 6 )
        !            70:     /*
        !            71:      * On the 3B2, the call instruction is CALL src,dst
        !            72:      * where src is the address of the new ap (where the args were
        !            73:      * already pushed on the stack) and dst is the address of the
        !            74:      * called function.  src and dst can be various lengths:
        !            75:      * src will be a byte, halfword, or word displacement
        !            76:      * and dst will be absolute, or be a byte, halfword, or word displacement.
        !            77:      * Byte displacement = 2 bytes, halfword = 3, word = 5; the opcode = 1 byte;
        !            78:      * absolute = 5 bytes--12 possible combinations and 6 possible instr lengths.
        !            79:      */
        !            80: 
        !            81: 
        !            82: const CALL_OPCODE = ((MACHINE_BYTE)0x2c);
        !            83: const SAVE_OPCODE = ((MACHINE_BYTE)0x10);
        !            84: const BYTE_DISPL       = 0xC0;
        !            85: const HALFWORD_DISPL   = 0xA0;
        !            86: const WORD_DISPL       = 0x80;
        !            87: const ABSOLUTE         = 0x70;
        !            88: 
        !            89: const N_CALL_INSTR_SIZES = 6;
        !            90: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11};
        !            91: 
        !            92: #define SAVE_OPERAND(instr)    (((char *)(instr))[1] & 0xf)
        !            93: 
        !            94: /* Given a pointer to a save instruction, yield the number of registers saved */
        !            95: #define N_SAVED_REGS(instr)    (8 - SAVE_OPERAND(instr) + 1)
        !            96: 
        !            97: /* CALL's src operand descriptor needed to determine size of src operand */
        !            98: #define SRC_OP_DESC(instr)     (((char *)(instr))[1] & 0xf0)
        !            99: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\
        !           100:        (((desc) == BYTE_DISPL)         ? 2 :   \
        !           101:         ((desc) == HALFWORD_DISPL)     ? 3 :   \
        !           102:         ((desc) == WORD_DISPL)         ? 5 :   \
        !           103:         ((((object*)0)->task_error(E_FRAMES)))         \
        !           104:        )
        !           105: const  OPCODE_SIZE = 1;
        !           106: const  DESC_SIZE = 1;
        !           107: 
        !           108: #define        DST_OP_DESC(instr)      \
        !           109:        (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0)
        !           110: 
        !           111: #define IS_LEGAL_SRC_OP(desc)                  \
        !           112:        (((desc) == BYTE_DISPL)         ||      \
        !           113:         ((desc) == HALFWORD_DISPL)     ||      \
        !           114:         ((desc) == WORD_DISPL)                 \
        !           115:        )
        !           116: #define IS_LEGAL_DST_OP(desc)                  \
        !           117:        (((desc) == BYTE_DISPL)         ||      \
        !           118:         ((desc) == HALFWORD_DISPL)     ||      \
        !           119:         ((desc) == WORD_DISPL)         ||      \
        !           120:         ((desc) == ABSOLUTE)                   \
        !           121:        )
        !           122: 
        !           123: /* Given a pointer to a call instruction, yield a pointer to the called function */
        !           124: unsigned int
        !           125: call_dst_ptr(unsigned char* callp)
        !           126: {
        !           127:     int sop_size = SRC_OP_SIZE(SRC_OP_DESC(callp));
        !           128:     unsigned char* dst_op_p = /* points past the dst desc, to addr or offset */
        !           129:        callp + OPCODE_SIZE + sop_size + DESC_SIZE;
        !           130:     int offset;                // offset for displacement modes
        !           131:     switch(DST_OP_DESC(callp)) {
        !           132:     case BYTE_DISPL:
        !           133:        offset = dst_op_p[0];
        !           134:        if(*dst_op_p & 0x80) {  /* negative--do sign extension for offset */
        !           135:            offset |= 0xffffff00;
        !           136:        }
        !           137:        return (unsigned int)(callp + offset);
        !           138:     case HALFWORD_DISPL:
        !           139:        // bytes are in reverse order, must flip positions
        !           140:        offset = dst_op_p[0] | dst_op_p[1] << 8;
        !           141:        if(dst_op_p[1] & 0x80) {        /* negative--do sign extension for offset */
        !           142:            offset |= 0xffff0000;
        !           143:        }
        !           144:        return (unsigned int)(callp + offset);
        !           145:     case WORD_DISPL:
        !           146:        // bytes are in reverse order, must flip positions
        !           147:        offset = dst_op_p[0]       |
        !           148:                 dst_op_p[1] <<  8 |
        !           149:                 dst_op_p[2] << 16 |
        !           150:                 dst_op_p[3] << 24;
        !           151:        /* don't need sign extension */
        !           152:        return (unsigned int)(callp + offset);
        !           153:     case ABSOLUTE:
        !           154:        return
        !           155:            dst_op_p[0]       |
        !           156:            dst_op_p[1] <<  8 |
        !           157:            dst_op_p[2] << 16 |
        !           158:            dst_op_p[3] << 24;
        !           159:     default:
        !           160:        ((object*)0)->task_error(E_FRAMES);
        !           161:     }
        !           162: }
        !           163: 
        !           164: 
        !           165: #endif
        !           166: 
        !           167: 
        !           168: struct FrameLayout {
        !           169:     short   n_saved;   // number of registers saved in this frame.
        !           170:                        // (3B's don't have masks of regs saved)
        !           171:            FrameLayout(int*);  // called with frame pointer
        !           172: };
        !           173: 
        !           174: FrameLayout::FrameLayout(int* fp)
        !           175: {
        !           176:     /*
        !           177:      * Given a frame pointer, find the number of regs saved in the frame.
        !           178:      * The idea is that the instruction immediately before the return pc
        !           179:      * is the function call, and contains a pointer to the first instruction
        !           180:      * in the function denoted by the fp, which will be a save instruction.
        !           181:      * We can decode the save instruction to find how many registers
        !           182:      * were saved.
        !           183:      */
        !           184: 
        !           185:     int*   return_pc = (int*)OLD_PC(fp);
        !           186: 
        !           187:     char* callp = NULL;
        !           188:     /* Because this method is nondeterministic, try all combinations
        !           189:        instead of stopping when one fits */
        !           190:     for(int i = 0; i < N_CALL_INSTR_SIZES; i++) {
        !           191:         char* poss_callp = (char *)return_pc - call_size[i];
        !           192:        if ((*poss_callp == CALL_OPCODE)
        !           193:             && IS_LEGAL_SRC_OP((SRC_OP_DESC(poss_callp)))
        !           194:             && IS_LEGAL_DST_OP((DST_OP_DESC(poss_callp)))) {
        !           195:            if(!callp) callp = poss_callp;
        !           196:            else ((object*)0)->task_error(E_FRAMES);    //ambiguous; can't tell which
        !           197:                                                //is real call.
        !           198:        }
        !           199:     }
        !           200:     if (callp == NULL) ((object*)0)->task_error(E_FRAMES);     //No match!
        !           201:     assert( *(char *)(call_dst_ptr(callp)) == SAVE_OPCODE);
        !           202:     n_saved = N_SAVED_REGS(call_dst_ptr(callp));
        !           203: }
        !           204: 
        !           205: /*
        !           206:  * fix a frame so that it returns like the arg
        !           207:  * The idea is that task_fp points to the task::task() stack frame which
        !           208:  * contains all the saved registers.  t_framep points to the stack frame
        !           209:  * that contains the return address and old fp (and perhaps some registers).
        !           210:  * fill the frame pointed to by t_framep with the registers from task_fp.
        !           211:  */
        !           212: void
        !           213: task::fudge_return(int* task_fp, int offset, task* next)
        !           214: {
        !           215:        int*    fp = t_framep + offset;
        !           216:        task_fp += offset;              // in case this is SHARED
        !           217:        FrameLayout     this_lo(fp);
        !           218:        FrameLayout     task_lo(task_fp);
        !           219:        if (task_lo.n_saved != 6)       // task::task() saves all regs
        !           220:                task_error(E_FUDGE);
        !           221:        // copy any saved registers from this to task frame
        !           222:        register int*   task_rp = FIRST_SAVED_REG_P(task_fp) +
        !           223:                        task_lo.n_saved - this_lo.n_saved;
        !           224:        register int*   this_rp = FIRST_SAVED_REG_P(fp);
        !           225:        register int    count;
        !           226:        for (count = this_lo.n_saved; count--; )
        !           227:                *task_rp++ = *this_rp++;
        !           228:        // next copy all the registers from the task frame to this
        !           229:        task_rp = FIRST_SAVED_REG_P(task_fp);
        !           230:        this_rp = FIRST_SAVED_REG_P(fp);
        !           231:        for (count = task_lo.n_saved; count--; )
        !           232:                *this_rp++ = *task_rp++;
        !           233:        if (next) next->restore();
        !           234: }
        !           235: 
        !           236: 

unix.superglobalmegacorp.com

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