Annotation of researchv10no/cmd/cfront/libC/task/fudge.c.386, 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 "hw_stack.h"
        !            14: 
        !            15: // Intel 386 frame fudger
        !            16: 
        !            17: /* careful -- stack frame not self-describing */
        !            18: // STACK GROWS DOWN
        !            19: 
        !            20: // We define a mask in which FrameLayout can record which regs are saved.
        !            21: // We only care about the non-scratch regs edi, esi, ebx.
        !            22: const short REG_EDI    = 0x1;
        !            23: const short REG_ESI    = 0x2;
        !            24: const short REG_EBX    = 0x4;
        !            25: #define        ALL_REGS_SAVED(m)       ((short)(m) == 0x0007)
        !            26: 
        !            27: const int              OPCODE_SIZE     = 1;
        !            28: const MACHINE_BYTE     CALL_INSTR      = 0xe8;
        !            29: const int              CALL_SIZE       = 5;
        !            30: const MACHINE_BYTE     JMP_SHORT       = 0xeb;
        !            31: const MACHINE_BYTE     JMP_DISPL       = 0xe9;
        !            32: // assumes we don't need to worry about jump near indirect (0xff)
        !            33: 
        !            34: #define IS_JMP_INSTR(instr)                                    \
        !            35:        ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)JMP_SHORT ||    \
        !            36:         (MACHINE_BYTE)(instr) == (MACHINE_BYTE)JMP_DISPL)
        !            37: const MACHINE_BYTE     PUSH_EBP_INSTR = 0x55;
        !            38: const int              PUSH_SIZE = 1;
        !            39: const MACHINE_BYTE     MOV_INSTR = 0x8b;
        !            40: const int              MOV_SIZE = 2;
        !            41: const MACHINE_BYTE     SUB_INSTR = 0x83;
        !            42: const int              SUB_SIZE = 3;
        !            43: const MACHINE_BYTE     PUSH_EDI_INSTR = 0x57;
        !            44: const MACHINE_BYTE     PUSH_ESI_INSTR = 0x56;
        !            45: const MACHINE_BYTE     PUSH_EBX_INSTR = 0x53;
        !            46: #define        IS_PUSH_REG_INSTR(instp)                \
        !            47:        ((*((MACHINE_BYTE*)(instp)) & 0xf0) == 0x50)
        !            48: #define IS_SET_EBP_INSTR(instp)                        \
        !            49:        (((*(instp)) == MOV_INSTR) && (*((MACHINE_BYTE*)(instp) + 1) == 0xec))
        !            50: #define        IS_SUB_ESP_INSTR(instp)                         \
        !            51:        ((*((MACHINE_BYTE*)(instp)) == SUB_INSTR)       \
        !            52:        && (*((MACHINE_BYTE*)(instp) + 1) == 0xec))
        !            53: 
        !            54: 
        !            55: int*   Skip_pc_p;      // global to hold fudged return pc.
        !            56:                        // See comments in hw_stack.c.
        !            57: 
        !            58: /* Given a pointer to a call instruction, yield a pointer to
        !            59:  * the called function */
        !            60: unsigned int
        !            61: call_dst_ptr(MACHINE_BYTE* callp)
        !            62: {
        !            63:        /*
        !            64:         * On the Intel 386, the call instruction is: call displ
        !            65:         * where the displacement is always relative to the pc.
        !            66:         */
        !            67:        MACHINE_BYTE* dst_op_p = callp + OPCODE_SIZE;
        !            68:        int offset = 0;
        !            69:        // bytes are in reverse order, must flip positions
        !            70:        offset = dst_op_p[0]       |
        !            71:                 dst_op_p[1] <<  8 |
        !            72:                 dst_op_p[2] << 16 |
        !            73:                 dst_op_p[3] << 24;
        !            74:        return (unsigned int)(callp + CALL_SIZE + offset);
        !            75: }
        !            76: 
        !            77: FrameLayout::FrameLayout(int* fp)
        !            78: {
        !            79:        mask = 0;
        !            80:        unsigned int*   return_pc = (unsigned int*)OLD_PC(fp);
        !            81:        /*
        !            82:         * find the starting address of the function.  The idea is that the
        !            83:         * instruction immediately before the return address must be the
        !            84:         * function call.
        !            85:         */
        !            86:        MACHINE_BYTE*   callp = (MACHINE_BYTE*)return_pc - CALL_SIZE;
        !            87:        if (*callp != CALL_INSTR)
        !            88:                object::task_error(E_FUNCS, (object*)0);
        !            89:        MACHINE_BYTE* func_addr = (MACHINE_BYTE*) call_dst_ptr(callp);
        !            90: 
        !            91:        /* If first instruction is jmp (-O not used), add displacement to pc
        !            92:         * to get to function prologue.
        !            93:         * Function prologue should be:
        !            94:         *      pushl   %ebp
        !            95:         *      movl    %esp,%ebp
        !            96:         *      subl    XXX,%esp        / XXX is the offset we want
        !            97:         *      pushl   %eXX            / a push instruction for each saved reg
        !            98:         *                              / (sometimes first push is of scratch
        !            99:         *                              / reg, and then that is the offset)
        !           100:         *      / stop when no more push instructions, or have saved all regs
        !           101:         */
        !           102:        if (IS_JMP_INSTR(*func_addr)) {
        !           103:                int displ;
        !           104:                if (*func_addr == JMP_SHORT) {  // 1 byte displacement
        !           105:                        displ = func_addr[1];
        !           106:                        func_addr += 2;         // next instruction
        !           107:                } else {        // JMP_DISPL, 4 byte displacement
        !           108:                                // bytes reversed
        !           109:                        displ = func_addr[1]       |
        !           110:                                func_addr[2] <<  8 |
        !           111:                                func_addr[3] << 16 |
        !           112:                                func_addr[4] << 24;
        !           113:                        func_addr += 5;         // next instruction
        !           114:                }
        !           115:                func_addr += displ;     // jmp destination
        !           116:        }
        !           117:        if ((*func_addr == PUSH_EBP_INSTR)
        !           118:            && (IS_SET_EBP_INSTR(func_addr + PUSH_SIZE))) {
        !           119:                func_addr += MOV_SIZE + PUSH_SIZE;
        !           120:                if (IS_SUB_ESP_INSTR(func_addr)) {
        !           121:                        offset = func_addr[2] / 4;
        !           122:                        func_addr += SUB_SIZE;
        !           123:                } else {        // assume no automatics to be allocated
        !           124:                        offset = 0;
        !           125:                }
        !           126:        } else {
        !           127:                object::task_error(E_FUNCS, (object*)0);
        !           128:        }
        !           129:        while (IS_PUSH_REG_INSTR(func_addr) && (! ALL_REGS_SAVED(mask))) {
        !           130:                if (*func_addr == PUSH_EDI_INSTR) {
        !           131:                        mask |= REG_EDI;
        !           132:                        func_addr += PUSH_SIZE;
        !           133:                } else if (*func_addr == PUSH_ESI_INSTR) {
        !           134:                        mask |= REG_ESI;
        !           135:                        func_addr += PUSH_SIZE;
        !           136:                } else if (*func_addr == PUSH_EBX_INSTR) {
        !           137:                        mask |= REG_EBX;
        !           138:                        func_addr += PUSH_SIZE;
        !           139:                } else  {
        !           140:                        // Compiler might push a scratch reg before any non-
        !           141:                        // scratch regs to reserve space for automatics.
        !           142:                        if (mask != 0) {
        !           143:                                // if non-scratch regs already saved,
        !           144:                                // then this is not an offset
        !           145:                                break;
        !           146:                        } else {
        !           147:                                offset += 1;
        !           148:                                func_addr += PUSH_SIZE;
        !           149:                        }
        !           150:                }
        !           151: 
        !           152:        }       
        !           153: }
        !           154: 
        !           155: /*
        !           156:  * Fudge frame of function-defined-by-f_fp (called "f" below)
        !           157:  * so that that function returns to its grandparent,
        !           158:  * in particular, so a parent task returns to the function that
        !           159:  * called the derived constructor, skipping the derived constructor;
        !           160:  * the child will return to the derived constructor, which is its "main."
        !           161:  * To do this we will overwrite the old fp and pc (those saved by
        !           162:  * f) with the old-old ones (those saved by f's caller),
        !           163:  * and we will overwrite the register save area with registers saved by 
        !           164:  * f's caller (referred to as "skip" below).
        !           165:  *
        !           166:  * There are 2 register-save cases to deal with:
        !           167:  *     1. skip_n_saved <= f_n_saved
        !           168:  *     3. skip_n_saved >  f_n_saved
        !           169:  *
        !           170:  * These are handled as follows:
        !           171:  *     1. copy the saved skip_regs over the corresponding f_regs,
        !           172:  *        leaving any additional saved f_regs intact.
        !           173:  *        f's epilogue instructions will be correct.
        !           174:  *     2. f's epilogue instructions will restore too few regs,
        !           175:  *       must take special care to see that the extras are restored properly.
        !           176:  *       -Copy saved skip_regs over any corresponding f_regs,
        !           177:  *       -If fudge_return saved more regs than f did, then
        !           178:  *        copy saved extra saved skip_regs over any corresponding fudge_regs,
        !           179:  *       -If more extra skip_regs (not saved by either f or fudge_return,
        !           180:  *        and therefore not used by either) remain, restore them explicitly.
        !           181:  *        They will not be disturbed by the return from fudge_return or f.
        !           182:  */
        !           183: void
        !           184: task::fudge_return(int* f_fp)
        !           185: {
        !           186:        register int*   fp = f_fp;              // fp of frame-to-be-fudged
        !           187:        FrameLayout     lo(fp);                 // frame to be fudged
        !           188:        register int*   skip_fp = (int*)OLD_FP(fp); // fp for f's caller (skip)
        !           189:        FrameLayout     skip_lo(skip_fp);       // frame for skip
        !           190:        register int*   fr_fp = FP();           // fp for fudge_return
        !           191:        FrameLayout     fr_lo(fr_fp);           // frame for fudge_return
        !           192: 
        !           193:        OLD_PC(fp) = (int)&fudge_sp;    // task::task will return through
        !           194:                                        // fudge_sp, which will reset the sp
        !           195:                                        // to point at the return-pc in
        !           196:                                        // skip's frame
        !           197:        // copy old fp
        !           198:        OLD_FP(fp) = OLD_FP(skip_fp);
        !           199: 
        !           200:        // now copy saved registers
        !           201:        // copy any saved skip regs over corresponding f regs; if there isn't
        !           202:        // a corresponding f reg, copy over corresponding fudge_return reg;
        !           203:        // if there isn't a corresponding fr_reg, restore it explicitly.
        !           204:        register int*   to = FIRST_SAVED_REG_P(fp, lo.offset);
        !           205:        register int*   from = FIRST_SAVED_REG_P(skip_fp, skip_lo.offset);
        !           206:        register int*   fr_to = FIRST_SAVED_REG_P(fr_fp, fr_lo.offset);
        !           207:        for (register short m = 1; m != 0x08; m <<=1) {
        !           208:                if (m & lo.mask) {
        !           209:                        if (m & skip_lo.mask) {
        !           210:                                *to-- = *from--;
        !           211:                                if (m & fr_lo.mask) fr_to--;
        !           212:                        } else {  // nothing to copy
        !           213:                                to--;
        !           214:                                if (m & fr_lo.mask) fr_to--;
        !           215:                        }
        !           216:                } else if (m & skip_lo.mask) {
        !           217:                        // No slot for *from in f's frame
        !           218:                        if (m & fr_lo.mask) {  // copy to fudge_return's frame
        !           219:                                *fr_to-- = *from--;
        !           220:                        } else {
        !           221:                                // Not used in f or fudge_return;
        !           222:                                // restore explicitly
        !           223:                                switch(m)       {
        !           224:                                case REG_EDI:
        !           225:                                        set_edi(from--);
        !           226:                                        break;
        !           227:                                case REG_ESI:
        !           228:                                        set_esi(from--);
        !           229:                                        break;
        !           230:                                case REG_EBX:
        !           231:                                        set_ebx(from--);
        !           232:                                        break;
        !           233:                                default:
        !           234:                                        // Oops--don't expect other regs
        !           235:                                        // to be saved
        !           236:                                        from--;
        !           237:                                        task_error(E_REGMASK, this);
        !           238:                                        break;
        !           239:                                }
        !           240:                        }
        !           241:                }
        !           242:        }
        !           243: }
        !           244: 

unix.superglobalmegacorp.com

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