Annotation of researchv10no/cmd/cfront/libC/task/fudge.c.3b, revision 1.1.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.