Annotation of researchv10no/cmd/cfront/libC/task/fudge.c.386, 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 "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.