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

1.1     ! root        1: /*ident        "%W%" */
        !             2: /**************************************************************************
        !             3:                        Copyright (c) 1984 AT&T
        !             4:                          All Rights Reserved   
        !             5: 
        !             6:        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
        !             7:        
        !             8:        The copyright notice above does not evidence any        
        !             9:        actual or intended publication of such source code.
        !            10: 
        !            11: *****************************************************************************/
        !            12: #include <task.h>
        !            13: #include <stdio.h>
        !            14: #include "hw_stack.h"
        !            15: 
        !            16: // 3B frame fudger
        !            17: 
        !            18: //Frames not self-describing!
        !            19: //STACK GROWS UP
        !            20: 
        !            21: #ifdef u3b
        !            22:        /*
        !            23:         * On the 3B20, the call instruction is call num,dst
        !            24:         * where num is the number of arguments to the function
        !            25:         * and dst is the address of the called function.
        !            26:         * There are 4 possible opcodes for the call instruction:
        !            27:         * 3 are optimizations possible when num can be represented in 4 bits
        !            28:         * (the usual case), and further depend on the addressing mode used.
        !            29:         * This code assumes that destination addresses will only be 
        !            30:         * pc-relative, absolute, or absolute deferred.
        !            31:         */
        !            32: 
        !            33: const GEN_CALL         = 0x78;
        !            34: const OPT_GEN_CALL     = 0x79;
        !            35: const PC_REL_CALL      = 0x77;
        !            36: const IMM_CALL         = 0xB9;
        !            37: 
        !            38: const ABSOLUTE_DESC    = 0x08;
        !            39: const PC_REL_DESC      = 0x06;
        !            40: const ABSOLUTE_DEF_DESC        = 0x09;
        !            41: 
        !            42: #define IS_CALL_OPCODE(instr)                                          \
        !            43:        (((MACHINE_BYTE)(instr) == (MACHINE_BYTE)GEN_CALL)      ||      \
        !            44:         ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)OPT_GEN_CALL)  ||      \
        !            45:         ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)PC_REL_CALL)   ||      \
        !            46:         ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)IMM_CALL))
        !            47: 
        !            48: const N_CALL_INSTR_SIZES = 3;
        !            49: short call_size[N_CALL_INSTR_SIZES] = {4, 6, 7};
        !            50: 
        !            51: #undef SAVE_OPERAND    /* not needed for u3b */
        !            52: 
        !            53: /* src op is not important in decoding the call instruction on u3b */
        !            54: #define        SRC_OP_DESC(instr)              /* not needed for u3b */
        !            55: #define        IS_LEGAL_SRC_OP()       1
        !            56: #undef SRC_OP_SIZE     /* not needed for u3b */
        !            57: const  OPCODE_SIZE = 1;
        !            58: const  OPERAND1_SIZE = 1;
        !            59: 
        !            60: #define        DST_OP_DESC(instr)      \
        !            61:        (((unsigned char *)(instr))[OPCODE_SIZE] & 0x0f)
        !            62: 
        !            63: #define IS_LEGAL_DST_OP(desc)                  \
        !            64:        (((desc) == ABSOLUTE_DESC)      ||      \
        !            65:         ((desc) == PC_REL_DESC)        ||      \
        !            66:         ((desc) == ABSOLUTE_DEF_DESC)          \
        !            67:        )
        !            68: #define        HAS_LEGAL_OPERANDS(call_instr)                  \
        !            69:        (IS_LEGAL_DST_OP((DST_OP_DESC(poss_callp))) ||  \
        !            70:         (call_instr[0] == PC_REL_CALL))
        !            71: 
        !            72: 
        !            73: /* Given a pointer to a call instruction,
        !            74:  * yield a pointer to the called function */
        !            75: unsigned int
        !            76: call_dst_ptr(unsigned char* callp)
        !            77: {
        !            78:        int offset = 0;
        !            79:        // points past operand1 and/or descriptor to address or offset
        !            80:        unsigned char* dst_op_p = callp + OPCODE_SIZE + OPERAND1_SIZE;
        !            81:        switch(*callp)  {
        !            82:        case PC_REL_CALL:                       // 16-bit pc-relative address
        !            83:                offset = dst_op_p[0] << 8 | dst_op_p[1];
        !            84:                if (callp[1] & 0x80)            // negative offset
        !            85:                        offset = -(offset);
        !            86:                unsigned char* next_pc = callp + 4;     // relative to NEXT pc
        !            87:                return (unsigned int)((short*)next_pc + offset);
        !            88:        case GEN_CALL:
        !            89:        case OPT_GEN_CALL:
        !            90:                switch(DST_OP_DESC(callp))      {
        !            91:                case ABSOLUTE_DESC:     // 24-bit absolute address
        !            92:                        return  (dst_op_p[0] << 20 |
        !            93:                                 dst_op_p[1] << 12 |
        !            94:                                 dst_op_p[2] <<  4 |
        !            95:                                 dst_op_p[3] >>  4 ) & 0x00ffffff;
        !            96:                case ABSOLUTE_DEF_DESC: // 24-bit absolute deferred address
        !            97:                        int* addr_p =
        !            98:                                (int*) ((dst_op_p[0] << 20 |
        !            99:                                         dst_op_p[1] << 12 |
        !           100:                                         dst_op_p[2] <<  4 |
        !           101:                                         dst_op_p[3] >>  4 ) & 0x00ffffff);
        !           102:                        return (unsigned int)(*addr_p);
        !           103:                case PC_REL_DESC:       // 24-bit pc-relative address
        !           104:                        offset = (dst_op_p[0] << 20 |
        !           105:                                  dst_op_p[1] << 12 |
        !           106:                                  dst_op_p[2] <<  4 |
        !           107:                                  dst_op_p[3] >>  4 );
        !           108:                        if (dst_op_p[0] & 0x08) // negative offset
        !           109:                                offset |= 0xff000000;
        !           110:                        else                    // positive offset
        !           111:                                offset &= 0x00ffffff;
        !           112:                        return (unsigned int)(callp + offset);
        !           113:                default:                        // illegal descriptor
        !           114:                        object::task_error(E_FUNCS, (object*)0);
        !           115:                }
        !           116:        case IMM_CALL:                          // 24-bit immediate address
        !           117:                return  (dst_op_p[0] << 20 |
        !           118:                         dst_op_p[1] << 12 |
        !           119:                         dst_op_p[2] <<  4 |
        !           120:                         dst_op_p[3] >>  4 ) & 0x00ffffff;
        !           121:        default:                                // illegal call instruction
        !           122:                object::task_error(E_FUNCS, (object*)0);
        !           123:        }
        !           124: }      /* call_dst_ptr */
        !           125: 
        !           126: 
        !           127: #else  /* m32:  u3b2, u3b5, u3b15 */
        !           128: 
        !           129: /*
        !           130:  * On the 3B2, the call instruction is CALL src,dst
        !           131:  * where src is the address of the new ap (where the args were
        !           132:  * already pushed on the stack) and dst is the address of the
        !           133:  * called function.  src and dst can be various lengths:
        !           134:  * src will be a byte, halfword, or word displacement
        !           135:  * and dst will be absolute, or be a byte, halfword, or word displacement.
        !           136:  * Byte displacement = 2 bytes, halfword = 3, word = 5;
        !           137:  * the opcode = 1 byte; absolute = 5 bytes--12 possible combinations
        !           138:  * and 6 possible instr lengths.
        !           139:  */
        !           140: 
        !           141: 
        !           142: #define IS_CALL_OPCODE(instr) ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)0x2c)
        !           143: 
        !           144: const BYTE_DISPL       = 0xC0;
        !           145: const HALFWORD_DISPL   = 0xA0;
        !           146: const WORD_DISPL       = 0x80;
        !           147: const ABSOLUTE         = 0x70;
        !           148: const REG_SP           = 0x0C;
        !           149: const REG_PC           = 0x0F;
        !           150: 
        !           151: const N_CALL_INSTR_SIZES = 6;
        !           152: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11};
        !           153: 
        !           154: /* CALL's src operand descriptor needed to determine size of src operand */
        !           155: #define SRC_OP_DESC(instr)     (((unsigned char *)(instr))[1])
        !           156: #define SRC_OP_SIZE(desc)                              \
        !           157:        ((MODE_FIELD(desc) == BYTE_DISPL)       ? 2 :   \
        !           158:         (MODE_FIELD(desc) == HALFWORD_DISPL)   ? 3 :   \
        !           159:         (MODE_FIELD(desc) == WORD_DISPL)       ? 5 :   \
        !           160:         ((object::task_error(E_FUNCS, (object*)0)))            \
        !           161:        )
        !           162: const  OPCODE_SIZE = 1;
        !           163: const  DESC_SIZE = 1;
        !           164: 
        !           165: #define        DST_OP_DESC(instr)              \
        !           166:        (((unsigned char *)(instr))     \
        !           167:                [OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))])
        !           168: #define        MODE_FIELD(desc)        ((desc) & 0xf0)
        !           169: #define        REG_FIELD(desc)         ((desc) & 0x0f)
        !           170: 
        !           171: #define IS_LEGAL_SRC_OP(desc)  /* assumes sp-relative displ */ \
        !           172:        (((MODE_FIELD(desc) == BYTE_DISPL)              ||      \
        !           173:          (MODE_FIELD(desc) == HALFWORD_DISPL)          ||      \
        !           174:          (MODE_FIELD(desc) == WORD_DISPL)                      \
        !           175:         ) && (REG_FIELD(desc) == REG_SP)                       \
        !           176:        )
        !           177: /* destination displacement is probably pc-relative, but we don't
        !           178:  * make that assumption.  It could be a call through a function pointer.
        !           179:  */
        !           180: #define IS_LEGAL_DST_OP(desc)                                          \
        !           181:        ((MODE_FIELD(desc) == BYTE_DISPL)               ||              \
        !           182:         (MODE_FIELD(desc) == HALFWORD_DISPL)           ||              \
        !           183:         (MODE_FIELD(desc) == WORD_DISPL)               ||              \
        !           184:         ((MODE_FIELD(desc) == ABSOLUTE) && (REG_FIELD(desc) == REG_PC))\
        !           185:        )
        !           186: #define        HAS_LEGAL_OPERANDS(call_instr)                  \
        !           187:        (IS_LEGAL_SRC_OP((SRC_OP_DESC(call_instr)))     \
        !           188:        && IS_LEGAL_DST_OP((DST_OP_DESC(call_instr))))
        !           189: 
        !           190: 
        !           191: /* Given a pointer to a call instruction, yield a pointer to
        !           192:  * the called function */
        !           193: unsigned int
        !           194: call_dst_ptr(unsigned char* callp)
        !           195: {
        !           196:        int sop_size = SRC_OP_SIZE(SRC_OP_DESC(callp));
        !           197:        unsigned char* dst_op_p =
        !           198:                /* points past the dst desc, to addr or offset */
        !           199:                callp + OPCODE_SIZE + sop_size + DESC_SIZE;
        !           200:        int offset = 0;         // offset for displacement modes
        !           201:        switch(MODE_FIELD(DST_OP_DESC(callp))) {
        !           202:        case BYTE_DISPL:
        !           203:                offset = dst_op_p[0];
        !           204:                if(*dst_op_p & 0x80) {
        !           205:                        /* negative--do sign extension for offset */
        !           206:                        offset |= 0xffffff00;
        !           207:                }
        !           208:                return (unsigned int)(callp + offset);
        !           209:        case HALFWORD_DISPL:
        !           210:                // bytes are in reverse order, must flip positions
        !           211:                offset = dst_op_p[0] | dst_op_p[1] << 8;
        !           212:                if(dst_op_p[1] & 0x80) {
        !           213:                        /* negative--do sign extension for offset */
        !           214:                        offset |= 0xffff0000;
        !           215:                }
        !           216:                return (unsigned int)(callp + offset);
        !           217:        case WORD_DISPL:
        !           218:                // bytes are in reverse order, must flip positions
        !           219:                offset = dst_op_p[0]       |
        !           220:                         dst_op_p[1] <<  8 |
        !           221:                         dst_op_p[2] << 16 |
        !           222:                         dst_op_p[3] << 24;
        !           223:                /* don't need sign extension */
        !           224:                return (unsigned int)(callp + offset);
        !           225:        case ABSOLUTE:
        !           226:                return
        !           227:                        dst_op_p[0]       |
        !           228:                        dst_op_p[1] <<  8 |
        !           229:                        dst_op_p[2] << 16 |
        !           230:                        dst_op_p[3] << 24;
        !           231:        default:
        !           232:                object::task_error(E_FUNCS, (object*)0);
        !           233:        }
        !           234: }      /* call_dst_ptr */
        !           235: 
        !           236: #endif /* m32:  u3b2, u3b5, u3b15 */
        !           237: 
        !           238: FrameLayout::FrameLayout(int* fp)
        !           239: {
        !           240:        /*
        !           241:         * Given a frame pointer, find the number of regs saved in the frame.
        !           242:         * The idea is that the instruction immediately before the return pc
        !           243:         * is the function call, and contains a pointer to the first
        !           244:         * instruction in the function denoted by the fp, which will be a save
        !           245:         * instruction. We can decode the save instruction to find how many
        !           246:         * registers were saved.
        !           247:         */
        !           248: 
        !           249:        int*   return_pc = (int*)OLD_PC(fp);
        !           250: 
        !           251:        unsigned char* callp = NULL;
        !           252:        /* Because this method is nondeterministic, try all combinations
        !           253:           instead of stopping when one fits */
        !           254:        for(int i = 0; i < N_CALL_INSTR_SIZES; i++) {
        !           255:                unsigned char* poss_callp =
        !           256:                        (unsigned char *)return_pc - call_size[i];
        !           257:                if ((IS_CALL_OPCODE(*poss_callp))
        !           258:                     && HAS_LEGAL_OPERANDS(poss_callp)) {
        !           259:                        if(!callp) callp = poss_callp;
        !           260:                        else {  // try some heuristics to disambiguate
        !           261:                                // (Don't try to dereference dst ptr
        !           262:                                // until sure, or necessary to disambiguate,
        !           263:                                // to avoid unnecessary core dumps.)
        !           264:                                // If first callp dst points to a save,
        !           265:                                // assume that is the instruction we want.
        !           266:                                if (!IS_SAVE_OPCODE(
        !           267:                                     *(unsigned char *)(call_dst_ptr(callp))) ) {
        !           268:                                        if (IS_SAVE_OPCODE(
        !           269:                                            *(unsigned char *)(call_dst_ptr(poss_callp))) ) {
        !           270:                                                callp = poss_callp;
        !           271:                                        } else {
        !           272:                                                // neither is right, go on
        !           273:                                                callp = 0;
        !           274:                                        }
        !           275:                                        
        !           276:                                }
        !           277:                        }
        !           278:                }
        !           279:        }
        !           280:        if (callp == NULL) object::task_error(E_FUNCS, (object*)0);     //No match!
        !           281:        unsigned int func_addr = call_dst_ptr(callp);
        !           282:        if (!(IS_SAVE_OPCODE( *(unsigned char *)func_addr) ))
        !           283:                object::task_error(E_FUNCS, (object*)0);
        !           284:        n_saved = N_SAVED_REGS(func_addr);
        !           285: }
        !           286: 
        !           287: /*
        !           288:  * Fudge frame of function-defined-by-f_fp (called "f" below)
        !           289:  * so that that function returns to its grandparent,
        !           290:  * in particular, so a parent task returns to the function that
        !           291:  * called the derived constructor (de_ctor), skipping de_ctor;
        !           292:  * the child will return to the derived constructor, which is its "main."
        !           293:  * To do this we will overwrite the old fp, ap, and pc (those saved by
        !           294:  * f) with the old-old ones (those saved by f's caller),
        !           295:  * and we will overwrite the register save area with registers saved by 
        !           296:  * f's caller (referred to as "skip" below).
        !           297:  *
        !           298:  * There are 2 register-save cases to deal with:
        !           299:  *     1. skip_n_saved <= f_n_saved
        !           300:  *     2. skip_n_saved >  f_n_saved
        !           301:  *
        !           302:  * These are handled as follows:
        !           303:  *     1. copy the saved skip_regs over the corresponding f_regs,
        !           304:  *        leaving any additional saved f_regs intact.
        !           305:  *        f's restore instruction will be correct.
        !           306:  *     2. f's restore instruction will restore too few regs, must take special
        !           307:  *       care to see that the extras are restored properly.
        !           308:  *       -Copy saved skip_regs over any corresponding f_regs,
        !           309:  *       -If fudge_return saved more regs than f did, then
        !           310:  *        copy saved extra saved skip_regs over any corresponding fudge_regs,
        !           311:  *       -If more extra skip_regs (not saved by either f or fudge_return,
        !           312:  *        and therefore not used by either) remain, restore them explicitly.
        !           313:  *        They will not be disturbed by the return from fudge_return or f,
        !           314:  */
        !           315: void
        !           316: task::fudge_return(int* f_fp)
        !           317: {
        !           318:        register int*   fp = f_fp;              // fp of frame-to-be-fudged
        !           319:        FrameLayout     lo(fp);                 // frame to be fudged
        !           320:        register int*   skip_fp = (int*)OLD_FP(fp); // fp for f's caller (skip)
        !           321:        FrameLayout     skip_lo(skip_fp);       // frame for skip
        !           322: 
        !           323:        OLD_PC(fp) = OLD_PC(skip_fp);
        !           324:        OLD_AP(fp) = OLD_AP(skip_fp);
        !           325:        OLD_FP(fp) = OLD_FP(skip_fp);
        !           326: 
        !           327:        // finally copy saved regs
        !           328:        register int* from = LAST_SAVED_REG_P(skip_fp, skip_lo.n_saved);
        !           329:        register int* to   = LAST_SAVED_REG_P(fp, lo.n_saved);
        !           330:        register int i;
        !           331:        if(lo.n_saved >= skip_lo.n_saved) {
        !           332:                // copy the saved skip regs over the corresponding f regs,
        !           333:                // leaving any additional saved f regs intact.
        !           334:                for(i = skip_lo.n_saved; i > 0; i--) {
        !           335:                        *to-- = *from--;
        !           336:                }
        !           337:        } else  {       // lo.n_saved < skip_lo.n_saved--take care!
        !           338:                // copy the saved skip regs over any corresponding
        !           339:                // f regs.
        !           340:                for(i = lo.n_saved; i > 0; i--) {
        !           341:                        *to-- = *from--;
        !           342:                }
        !           343:                int extra = skip_lo.n_saved - lo.n_saved;
        !           344:                // If fudge_return saved more regs than f, extra skip_regs
        !           345:                // should be copied over any corresponding fudge_return regs.
        !           346:                int*    fr_fp = FP();           // fp for fudge_return
        !           347:                FrameLayout     fr_lo(fr_fp);   // frame for fudge_return
        !           348:                if (fr_lo.n_saved >= lo.n_saved) {
        !           349:                        to = LAST_SAVED_REG_P(fr_fp, fr_lo.n_saved) - lo.n_saved;
        !           350:                        int n;
        !           351:                        int d = fr_lo.n_saved - lo.n_saved;
        !           352:                        if (d >= extra) {       // room for all extra skip_regs
        !           353:                                n = extra;
        !           354:                        } else {
        !           355:                                n = d;
        !           356:                        }
        !           357:                        for(i = n; i > 0; i--) {
        !           358:                                *to-- = *from--;
        !           359:                                extra--;
        !           360:                        }
        !           361:                }
        !           362:                if (extra) { // Remaining skip regs must be explicitly restored.
        !           363:                        int r = skip_lo.n_saved - extra + 1;
        !           364:                        for (i = extra; i > 0; i--) {
        !           365:                                switch (r++) {
        !           366:                                case 6:
        !           367:                                        set_r3(from);
        !           368:                                        from--;
        !           369:                                        break;
        !           370:                                case 5:
        !           371:                                        set_r4(from);
        !           372:                                        from--;
        !           373:                                        break;
        !           374:                                case 4:
        !           375:                                        set_r5(from);
        !           376:                                        from--;
        !           377:                                        break;
        !           378:                                case 3:
        !           379:                                        set_r6(from);
        !           380:                                        from--;
        !           381:                                        break;
        !           382:                                case 2:
        !           383:                                        set_r7(from);
        !           384:                                        from--;
        !           385:                                        break;
        !           386:                                case 1:
        !           387:                                        set_r8(from);
        !           388:                                        from--;
        !           389:                                        break;
        !           390:                                }
        !           391:                        }
        !           392:                }
        !           393:        }
        !           394: }

unix.superglobalmegacorp.com

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