Annotation of researchv10no/cmd/cfront/libC/otask/fudge.c.3b, revision 1.1.1.1

1.1       root        1: #include "task.h"
                      2: #include <assert.h>
                      3: #include <stdio.h>
                      4: 
                      5: // 3B frame fudger
                      6: 
                      7: //Frames not self-describing!
                      8: //STACK GROWS UP
                      9: 
                     10: typedef unsigned char MACHINE_BYTE;
                     11: 
                     12: #ifdef u3b
                     13: 
                     14: #define OLD_FP(fp)     ( *( (int*)(fp) - 11 ) )
                     15: #define OLD_AP(fp)     ( *( (int*)(fp) - 12 ) )
                     16: #define OLD_PC(fp)     ( *( (int*)(fp) - 13 ) )
                     17: #define FIRST_SAVED_REG_P(fp)  ( (int*)(fp) - 6 )
                     18: 
                     19: const CALL_OPCODE = ((MACHINE_BYTE)0x78);
                     20:                        /* SAK:  really: 0x78 | 0x79 | 0xB9 | 0x77 */
                     21: const SAVE_OPCODE = ((MACHINE_BYTE)0x7A);
                     22: const BYTE_DISPL       = 0xC0; /* SAK: WRONG for u3b! */
                     23: const HALFWORD_DISPL   = 0xA0; /* SAK: WRONG for u3b! */
                     24: const WORD_DISPL       = 0x80; /* SAK: WRONG for u3b! */
                     25: const ABSOLUTE         = 0x70; /* SAK: WRONG for u3b! */
                     26: 
                     27: const N_CALL_INSTR_SIZES = 6;  /* SAK: WRONG for u3b! */
                     28: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11};     /* SAK: WRONG for u3b! */
                     29: 
                     30: /* SAK: SAVE_OPERAND(instr) not needed for u3b */
                     31: 
                     32: /* Given a pointer to a save instruction, yield the number of registers saved */
                     33: #define N_SAVED_REGS(instr)    (((char *)(instr))[1] >> 4)
                     34: 
                     35: /* CALL's src operand descriptor needed to determine size of src operand */
                     36: #define SRC_OP_DESC(instr)     (((char *)(instr))[1] & 0xf0)
                     37: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\
                     38:        (((desc) == BYTE_DISPL)         ? 2 :   \
                     39:         ((desc) == HALFWORD_DISPL)     ? 3 :   \
                     40:         ((desc) == WORD_DISPL)         ? 5 :   \
                     41:         ((((object*)0)->task_error(E_FRAMES)))         \
                     42:        )
                     43: const  OPCODE_SIZE = 1;
                     44: const  DESC_SIZE = 1;
                     45: 
                     46: /* SAK:  WRONG for u3b! */
                     47: #define        DST_OP_DESC(instr)      \
                     48:        (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0)
                     49: 
                     50: /* SAK:  WRONG for u3b! */
                     51: #define IS_LEGAL_SRC_OP(desc)                  \
                     52:        (((desc) == BYTE_DISPL)         ||      \
                     53:         ((desc) == HALFWORD_DISPL)     ||      \
                     54:         ((desc) == WORD_DISPL)                 \
                     55:        )
                     56: /* SAK:  WRONG for u3b! */
                     57: #define IS_LEGAL_DST_OP(desc)                  \
                     58:        (((desc) == BYTE_DISPL)         ||      \
                     59:         ((desc) == HALFWORD_DISPL)     ||      \
                     60:         ((desc) == WORD_DISPL)         ||      \
                     61:         ((desc) == ABSOLUTE)                   \
                     62:        )
                     63: 
                     64: 
                     65: #else  /* m32:  u3b2, u3b5, u3b15 */
                     66: #define OLD_FP(fp)     ( *( (int*)(fp) - 7 ) )
                     67: #define OLD_AP(fp)     ( *( (int*)(fp) - 8 ) )
                     68: #define OLD_PC(fp)     ( *( (int*)(fp) - 9 ) ) 
                     69: #define FIRST_SAVED_REG_P(fp)  ( (int*)(fp) - 6 )
                     70:     /*
                     71:      * On the 3B2, the call instruction is CALL src,dst
                     72:      * where src is the address of the new ap (where the args were
                     73:      * already pushed on the stack) and dst is the address of the
                     74:      * called function.  src and dst can be various lengths:
                     75:      * src will be a byte, halfword, or word displacement
                     76:      * and dst will be absolute, or be a byte, halfword, or word displacement.
                     77:      * Byte displacement = 2 bytes, halfword = 3, word = 5; the opcode = 1 byte;
                     78:      * absolute = 5 bytes--12 possible combinations and 6 possible instr lengths.
                     79:      */
                     80: 
                     81: 
                     82: const CALL_OPCODE = ((MACHINE_BYTE)0x2c);
                     83: const SAVE_OPCODE = ((MACHINE_BYTE)0x10);
                     84: const BYTE_DISPL       = 0xC0;
                     85: const HALFWORD_DISPL   = 0xA0;
                     86: const WORD_DISPL       = 0x80;
                     87: const ABSOLUTE         = 0x70;
                     88: 
                     89: const N_CALL_INSTR_SIZES = 6;
                     90: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11};
                     91: 
                     92: #define SAVE_OPERAND(instr)    (((char *)(instr))[1] & 0xf)
                     93: 
                     94: /* Given a pointer to a save instruction, yield the number of registers saved */
                     95: #define N_SAVED_REGS(instr)    (8 - SAVE_OPERAND(instr) + 1)
                     96: 
                     97: /* CALL's src operand descriptor needed to determine size of src operand */
                     98: #define SRC_OP_DESC(instr)     (((char *)(instr))[1] & 0xf0)
                     99: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\
                    100:        (((desc) == BYTE_DISPL)         ? 2 :   \
                    101:         ((desc) == HALFWORD_DISPL)     ? 3 :   \
                    102:         ((desc) == WORD_DISPL)         ? 5 :   \
                    103:         ((((object*)0)->task_error(E_FRAMES)))         \
                    104:        )
                    105: const  OPCODE_SIZE = 1;
                    106: const  DESC_SIZE = 1;
                    107: 
                    108: #define        DST_OP_DESC(instr)      \
                    109:        (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0)
                    110: 
                    111: #define IS_LEGAL_SRC_OP(desc)                  \
                    112:        (((desc) == BYTE_DISPL)         ||      \
                    113:         ((desc) == HALFWORD_DISPL)     ||      \
                    114:         ((desc) == WORD_DISPL)                 \
                    115:        )
                    116: #define IS_LEGAL_DST_OP(desc)                  \
                    117:        (((desc) == BYTE_DISPL)         ||      \
                    118:         ((desc) == HALFWORD_DISPL)     ||      \
                    119:         ((desc) == WORD_DISPL)         ||      \
                    120:         ((desc) == ABSOLUTE)                   \
                    121:        )
                    122: 
                    123: /* Given a pointer to a call instruction, yield a pointer to the called function */
                    124: unsigned int
                    125: call_dst_ptr(unsigned char* callp)
                    126: {
                    127:     int sop_size = SRC_OP_SIZE(SRC_OP_DESC(callp));
                    128:     unsigned char* dst_op_p = /* points past the dst desc, to addr or offset */
                    129:        callp + OPCODE_SIZE + sop_size + DESC_SIZE;
                    130:     int offset;                // offset for displacement modes
                    131:     switch(DST_OP_DESC(callp)) {
                    132:     case BYTE_DISPL:
                    133:        offset = dst_op_p[0];
                    134:        if(*dst_op_p & 0x80) {  /* negative--do sign extension for offset */
                    135:            offset |= 0xffffff00;
                    136:        }
                    137:        return (unsigned int)(callp + offset);
                    138:     case HALFWORD_DISPL:
                    139:        // bytes are in reverse order, must flip positions
                    140:        offset = dst_op_p[0] | dst_op_p[1] << 8;
                    141:        if(dst_op_p[1] & 0x80) {        /* negative--do sign extension for offset */
                    142:            offset |= 0xffff0000;
                    143:        }
                    144:        return (unsigned int)(callp + offset);
                    145:     case WORD_DISPL:
                    146:        // bytes are in reverse order, must flip positions
                    147:        offset = dst_op_p[0]       |
                    148:                 dst_op_p[1] <<  8 |
                    149:                 dst_op_p[2] << 16 |
                    150:                 dst_op_p[3] << 24;
                    151:        /* don't need sign extension */
                    152:        return (unsigned int)(callp + offset);
                    153:     case ABSOLUTE:
                    154:        return
                    155:            dst_op_p[0]       |
                    156:            dst_op_p[1] <<  8 |
                    157:            dst_op_p[2] << 16 |
                    158:            dst_op_p[3] << 24;
                    159:     default:
                    160:        ((object*)0)->task_error(E_FRAMES);
                    161:     }
                    162: }
                    163: 
                    164: 
                    165: #endif
                    166: 
                    167: 
                    168: struct FrameLayout {
                    169:     short   n_saved;   // number of registers saved in this frame.
                    170:                        // (3B's don't have masks of regs saved)
                    171:            FrameLayout(int*);  // called with frame pointer
                    172: };
                    173: 
                    174: FrameLayout::FrameLayout(int* fp)
                    175: {
                    176:     /*
                    177:      * Given a frame pointer, find the number of regs saved in the frame.
                    178:      * The idea is that the instruction immediately before the return pc
                    179:      * is the function call, and contains a pointer to the first instruction
                    180:      * in the function denoted by the fp, which will be a save instruction.
                    181:      * We can decode the save instruction to find how many registers
                    182:      * were saved.
                    183:      */
                    184: 
                    185:     int*   return_pc = (int*)OLD_PC(fp);
                    186: 
                    187:     char* callp = NULL;
                    188:     /* Because this method is nondeterministic, try all combinations
                    189:        instead of stopping when one fits */
                    190:     for(int i = 0; i < N_CALL_INSTR_SIZES; i++) {
                    191:         char* poss_callp = (char *)return_pc - call_size[i];
                    192:        if ((*poss_callp == CALL_OPCODE)
                    193:             && IS_LEGAL_SRC_OP((SRC_OP_DESC(poss_callp)))
                    194:             && IS_LEGAL_DST_OP((DST_OP_DESC(poss_callp)))) {
                    195:            if(!callp) callp = poss_callp;
                    196:            else ((object*)0)->task_error(E_FRAMES);    //ambiguous; can't tell which
                    197:                                                //is real call.
                    198:        }
                    199:     }
                    200:     if (callp == NULL) ((object*)0)->task_error(E_FRAMES);     //No match!
                    201:     assert( *(char *)(call_dst_ptr(callp)) == SAVE_OPCODE);
                    202:     n_saved = N_SAVED_REGS(call_dst_ptr(callp));
                    203: }
                    204: 
                    205: /*
                    206:  * fix a frame so that it returns like the arg
                    207:  * The idea is that task_fp points to the task::task() stack frame which
                    208:  * contains all the saved registers.  t_framep points to the stack frame
                    209:  * that contains the return address and old fp (and perhaps some registers).
                    210:  * fill the frame pointed to by t_framep with the registers from task_fp.
                    211:  */
                    212: void
                    213: task::fudge_return(int* task_fp, int offset, task* next)
                    214: {
                    215:        int*    fp = t_framep + offset;
                    216:        task_fp += offset;              // in case this is SHARED
                    217:        FrameLayout     this_lo(fp);
                    218:        FrameLayout     task_lo(task_fp);
                    219:        if (task_lo.n_saved != 6)       // task::task() saves all regs
                    220:                task_error(E_FUDGE);
                    221:        // copy any saved registers from this to task frame
                    222:        register int*   task_rp = FIRST_SAVED_REG_P(task_fp) +
                    223:                        task_lo.n_saved - this_lo.n_saved;
                    224:        register int*   this_rp = FIRST_SAVED_REG_P(fp);
                    225:        register int    count;
                    226:        for (count = this_lo.n_saved; count--; )
                    227:                *task_rp++ = *this_rp++;
                    228:        // next copy all the registers from the task frame to this
                    229:        task_rp = FIRST_SAVED_REG_P(task_fp);
                    230:        this_rp = FIRST_SAVED_REG_P(fp);
                    231:        for (count = task_lo.n_saved; count--; )
                    232:                *this_rp++ = *task_rp++;
                    233:        if (next) next->restore();
                    234: }
                    235: 
                    236: 

unix.superglobalmegacorp.com

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