|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.