Annotation of coherent/b/bin/as/build.c.sav, revision 1.1.1.1

1.1       root        1: /*
                      2:  * 80386 Assembler Build output code.
                      3:  */
                      4: #include <asm.h>
                      5: #include <asflags.h>
                      6: #include <y_tab.h>
                      7: #include <symtab.h>
                      8: 
                      9: static symt *st;
                     10: static struct expr *opList[3];
                     11: static int ct;
                     12: 
                     13: /* as checkop runs it sets the following fields */
                     14: static expr *addr, *displ, *immed, *immedx;
                     15: static char mod, rm, reg, scale, index, base, immed8;
                     16: 
                     17: static unsigned long uflags;
                     18: #define U_REL8 1       /* relative 8  bit operand */
                     19: #define U_REL16        2       /* relative 16 bit operand */
                     20: #define U_RELI 3       /* we get to choose 8 0r 16 bit */
                     21: #define U_REL_MASK 3
                     22: 
                     23: #define U_RMS   0x04   /* mod/rm .16 */
                     24: #define U_RML   0x08   /* mod/rm .32 */
                     25: #define U_IMM8  0x10   /* 8  bit immediate field */
                     26: #define U_IMM16         0x20   /* 16 bit immediate field */
                     27: #define U_IMM16X 0x40  /* 16 bit second immediate field */
                     28: #define U_IMM32         0x80   /* 32 bit immediate field */
                     29: #define U_IMM32X 0x100 /* 32 bit second immediate field */
                     30: #define U_ADR16  0x200 /* 16 bit direct address */
                     31: #define U_ADR32  0x400 /* 32 bit direct address */
                     32: #define U_DSP8  0x800  /* 8 bit displacment with mod/rm */
                     33: #define U_DSP    0x1000        /* 16 or 32 bit displacment with mod/rm */
                     34: #define U_CTL   0x2000 /* control register */
                     35: 
                     36: /*
                     37:  * Build indefinate opcode. On 80386 thats everything.
                     38:  * First try all instrs not in the wrong mode.
                     39:  * Then try the instrs in the wrong mode.
                     40:  */
                     41: buildind(label, op, oper)
                     42: parm *label;
                     43: register opc *op;
                     44: register expr *oper;
                     45: {
                     46:        int i;
                     47:        unsigned short wrongMode;
                     48: 
                     49:        buildlab(label);
                     50: 
                     51:        ct = countList((parm *)oper);
                     52: 
                     53:        if (ct > 3) {
                     54:                yyerror("Too many operands");
                     55:                /* No 386 opcode has more than three operands. */
                     56:                return (1);
                     57:        }
                     58: 
                     59:        if (fswitch)    /* reverse operand order */
                     60:                for (i = ct; i--; oper = oper->next)
                     61:                        opList[i] = oper;
                     62:        else            /* normal operand order */
                     63:                for (i = 0; i < ct; i++, oper = oper->next)
                     64:                        opList[i] = oper;
                     65: 
                     66:        /* try the stuff not in the wrong mode */
                     67:        wrongMode = longMode ? WORD_MODE : LONG_MODE;
                     68:        for (i = 0; i < choices; i++) {
                     69:                st = typTab + op[i].kind;
                     70:                if (!(st->bldr & wrongMode) && !buildop(op + i))
                     71:                        return(0);
                     72:        }
                     73: 
                     74:        /* now try the wrong mode choices */
                     75:        for (i = 0; i < choices; i++) {
                     76:                st = typTab + op[i].kind;
                     77:                if ((st->bldr & wrongMode) && !buildop(op + i))
                     78:                        return(0);
                     79:        }
                     80: 
                     81:        yyerror("Illegal combination of opcode and operands");
                     82:        /* Although the opcode is valid and the operands are valid,
                     83:         * there is no form of this opcode which takes this combination
                     84:         * of operands in this order. */
                     85:        return(1);
                     86: }
                     87: 
                     88: /*
                     89:  * Check if operator validly fits mode.
                     90:  * return 1 for false zero for true.
                     91:  */
                     92: static
                     93: checkop(this, type)
                     94: register expr *this;
                     95: unsigned short type;
                     96: {
                     97:        register sym *r1;
                     98:        long d;
                     99:        int  regsz;
                    100: 
                    101:        r1 = this->r1;
                    102: 
                    103:        switch (type) {
                    104:        case m8:
                    105:        case m16:
                    106:        case m32:
                    107:        case m64:
                    108:        case m80:
                    109:                regsz = -1;     /* can't be a register */
                    110:                break;
                    111: 
                    112:        case rm8:
                    113:                regsz = 1;      /* reg must be 1 long */
                    114:                break;
                    115: 
                    116:        case rm16:
                    117:                regsz = 2;      /* reg must be 2 long */
                    118:                break;
                    119: 
                    120:        case rm32:
                    121:                regsz = 4;      /* reg must be 4 long */
                    122:                break;
                    123: 
                    124:        case reli:      /* near branch */
                    125:                if (!(lflags & A_INDIR)) {
                    126:                        uflags = U_RELI;
                    127:                        return (T_D != this->mode);
                    128:                }
                    129:                regsz = longMode ? 4 : 2;
                    130:                break;
                    131: 
                    132:        case rel8:      /* near branch */
                    133:                uflags = U_REL8;
                    134:                return (T_D != this->mode);
                    135:                    
                    136:        case rel16:     /* medium or long branch */
                    137:                uflags = U_REL16;
                    138:                return (T_D != this->mode);
                    139:                    
                    140:        case mem32:     /* 32 bit simple address */
                    141:                uflags |= U_ADR32;
                    142:                rm = 5;
                    143:                return (T_D != (addr = this)->mode);
                    144: 
                    145:        case mem16:     /* 16 bit simple address */
                    146:                uflags |= U_ADR16;
                    147:                rm = 6;
                    148:                return (T_D != (addr = this)->mode);
                    149: 
                    150: 
                    151:        case imm8:
                    152:                uflags |= U_IMM8;
                    153:                immed8 = this->exp;
                    154:                return (this->ref != NULL ||
                    155:                        this->mode != T_IMM ||
                    156:                        this->exp < -128 ||
                    157:                        this->exp > 255);
                    158: 
                    159:        case imm8s:
                    160:                uflags |= U_IMM8;
                    161:                immed8 = this->exp;
                    162:                return (this->ref != NULL ||
                    163:                        this->mode != T_IMM ||
                    164:                        this->exp < -128 ||
                    165:                        this->exp > 127);
                    166: 
                    167:        case imm16x:
                    168:                uflags |= U_IMM16X;
                    169:                d = (immedx = this)->exp;
                    170:                return (this->mode != T_IMM ||
                    171:                        d < -32768L ||
                    172:                        d > 65535L);
                    173: 
                    174:        case imm16:
                    175:                uflags |= U_IMM16;
                    176:                d = (immed = this)->exp;
                    177:                return (this->mode != T_IMM ||
                    178:                        d < -32768L ||
                    179:                        d > 65535L);
                    180: 
                    181:        case imm32x:
                    182:                uflags |= U_IMM32X;
                    183:                immedx = this;
                    184:                return (this->mode != T_IMM);
                    185: 
                    186:        case moffs:
                    187:                uflags |= U_IMM32;
                    188:                immed = this;
                    189:                return (this->mode != T_D);
                    190: 
                    191:        case imm32:
                    192:                uflags |= U_IMM32;
                    193:                immed = this;
                    194:                return (this->mode != T_IMM);
                    195: 
                    196:        case con1:
                    197:                return (this->mode != T_IMM ||
                    198:                        this->exp != 1);
                    199: 
                    200:        case con3:
                    201:                return (this->mode != T_IMM ||
                    202:                        this->exp != 3);
                    203: 
                    204:        case al:
                    205:                return (this->mode != T_R ||
                    206:                        r1->flag != ORD_REG ||
                    207:                        r1->size != 1 ||
                    208:                        r1->loc != 0);
                    209: 
                    210:        case ax:
                    211:                return (this->mode != T_R ||
                    212:                        r1->flag != ORD_REG ||
                    213:                        r1->size != 2 ||
                    214:                        r1->loc != 0);
                    215: 
                    216:        case eax:
                    217:                return (this->mode != T_R ||
                    218:                        r1->flag != ORD_REG ||
                    219:                        r1->size != 4 ||
                    220:                        r1->loc != 0);
                    221: 
                    222:        case r16:
                    223:                if (this->mode != T_R || r1->flag != ORD_REG || r1->size != 2)
                    224:                        return (1);
                    225:                reg = r1->loc;
                    226:                return (0);
                    227: 
                    228:        case atdx:
                    229:                if (this->mode != T_RI || r1->flag != ORD_REG ||
                    230:                    r1->size != 2 || r1->loc != 2)
                    231:                        return(1);
                    232:                lflags &= ~A_SHORT;
                    233:                return(0);
                    234: 
                    235:        case cl:
                    236:                return (this->mode != T_R ||
                    237:                        r1->flag != ORD_REG ||
                    238:                        r1->size != 1 ||
                    239:                        r1->loc != 1);
                    240: 
                    241:        case ds:
                    242:                return (this->mode != T_R ||
                    243:                        r1->flag != SEG_REG ||
                    244:                        r1->loc != 3);
                    245: 
                    246:        case es:
                    247:                return (this->mode != T_R ||
                    248:                        r1->flag != SEG_REG ||
                    249:                        r1->loc != 0);
                    250: 
                    251:        case ss:
                    252:                return (this->mode != T_R ||
                    253:                        r1->flag != SEG_REG ||
                    254:                        r1->loc != 2);
                    255: 
                    256:        case fs:
                    257:                return (this->mode != T_R ||
                    258:                        r1->flag != SEG_REG ||
                    259:                        r1->loc != 4);
                    260: 
                    261:        case gs:
                    262:                return (this->mode != T_R ||
                    263:                        r1->flag != SEG_REG ||
                    264:                        r1->loc != 5);
                    265: 
                    266:        case cs:
                    267:                return (this->mode != T_R ||
                    268:                        r1->flag != SEG_REG ||
                    269:                        r1->loc != 1);
                    270: 
                    271:        case sreg:
                    272:                if (this->mode != T_R || r1->flag != SEG_REG)
                    273:                        return (1);
                    274:                reg = r1->loc;
                    275:                return (0);
                    276: 
                    277:        case st0:
                    278:                if (this->mode != T_FP || this->exp)
                    279:                        return (1);
                    280:                return (0);
                    281: 
                    282:        case fpreg:
                    283:                if (this->mode != T_FP)
                    284:                        return (1);
                    285:                reg = this->exp;
                    286:                return (0);
                    287: 
                    288:        case ctlreg:
                    289:                if (this->mode != T_R || r1->flag != CTL_REG)
                    290:                        return (1);
                    291:                uflags |= U_CTL;
                    292:                rm = r1->loc;
                    293:                return (0);
                    294: 
                    295:        case dbreg:
                    296:                if (this->mode != T_R || r1->flag != DEB_REG)
                    297:                        return (1);
                    298:                uflags |= U_CTL;
                    299:                rm = r1->loc;
                    300:                return (0);
                    301: 
                    302:        case treg:
                    303:                if (this->mode != T_R || r1->flag != TST_REG)
                    304:                        return (1);
                    305:                uflags |= U_CTL;
                    306:                rm = r1->loc;
                    307:                return (0);
                    308: 
                    309:        case r32:
                    310:                if (this->mode != T_R || r1->flag != ORD_REG || r1->size != 4)
                    311:                        return (1);
                    312:                reg = r1->loc;
                    313:                return (0);
                    314: 
                    315:        case r8:
                    316:                if (this->mode != T_R || r1->flag != ORD_REG || r1->size != 1)
                    317:                        return (1);
                    318:                reg = r1->loc;
                    319:                return (0);
                    320:        }
                    321: 
                    322:        /*
                    323:         * If we get to here the mode must be rm16 or rm32.
                    324:         * The table mode has been used to decide the proper
                    325:         * size for registers. Decide which is the real mode.
                    326:         */
                    327:        if (longMode)
                    328:                if (lflags & A_SHORT)
                    329:                        type = rm16;
                    330:                else
                    331:                        type = rm32;
                    332:        else
                    333:                if (lflags & A_LONG)
                    334:                        type = rm32;
                    335:                else
                    336:                        type = rm16;
                    337: 
                    338:        switch(type) {
                    339:        case rm32:      /* r/m 32 See Tables 17-3 and 17-4 */
                    340:                uflags |= U_RML;
                    341:                switch (this->mode) {
                    342:                case T_D:       /* all 32 bit disp must be good */
                    343:                        mod = 0;
                    344:                        rm = 5;
                    345:                        uflags |= U_DSP;
                    346:                        displ = this;
                    347:                        return (0);
                    348: 
                    349:                case T_RID:
                    350:                        if ((NULL != this->ref) ||
                    351:                            (d = this->exp) < -128 || d > 127) {
                    352:                                uflags |= U_DSP;
                    353:                                mod = 2;
                    354:                        }
                    355:                        else {
                    356:                                uflags |= U_DSP8;
                    357:                                mod = 1;
                    358:                        }
                    359: 
                    360:                        if (4 == (rm = r1->loc)) { /* disp (%esp) */
                    361:                                base = 4;       /* base = %esp */
                    362:                                index = 4;      /* no index */
                    363:                        }
                    364:                        displ = this;
                    365:                        return (0);
                    366: 
                    367:                case T_R:       /* eax | ecx || edx || ebx || esi || edi */
                    368:                        if ((r1->size != regsz) || (r1->flag != ORD_REG))
                    369:                                return (1);
                    370:                        rm  = r1->loc;
                    371:                        mod = 3;
                    372:                        return(0);
                    373: 
                    374:                case T_RI:
                    375:                        switch (rm = r1->loc) {
                    376:                        case 5: /* ( %ebp ) */
                    377:                                mod = 1;        /* 0 ( %ebp ) */
                    378:                                uflags |= U_DSP8; /* force displacment 0 */
                    379:                                displ = this;
                    380:                                break;
                    381:                        case 4: /* ( %esp ) */
                    382:                                base = 4;       /* %sp */
                    383:                                index = 4;      /* no index */
                    384:                        default: /* (eax | ecx | edx | ebx | esi | edi) */
                    385:                                mod = 0;
                    386:                        }
                    387: 
                    388:                        return (0);
                    389: 
                    390:                case T_RIS:
                    391:                        if (4 == (index = r1->loc)) /* can't index %esp */
                    392:                                return (1);
                    393: 
                    394:                        rm = 4;         /* use sib */
                    395:                        mod = 0;        /* no disp */
                    396:                        base = 5;       /* no base */
                    397:                        uflags |= U_DSP;
                    398:                        scale = this->scale;
                    399:                        index = r1->loc;
                    400:                        displ = this;
                    401:                        return (0);
                    402: 
                    403:                case T_RIX:             
                    404:                case T_RIXS:
                    405:                        /* can't index esp */
                    406:                        if (4 == (index = this->r2->loc))
                    407:                                return(1);
                    408: 
                    409:                        if (5 != (base = r1->loc)) {
                    410:                                mod = 0;
                    411:                                rm = 4;
                    412:                                scale = this->scale;
                    413:                                return (0);
                    414:                        } /* if base %ebp use T_RIXDS */
                    415: 
                    416:                case T_RIXD:
                    417:                case T_RIXDS:
                    418:                        /* can't index esp */
                    419:                        if (4 == (index = this->r2->loc))
                    420:                                return (1);
                    421: 
                    422:                        base = r1->loc;
                    423:                        if ((NULL != this->ref) ||
                    424:                            (d = this->exp) < -128 || d > 127) {
                    425:                                uflags |= U_DSP;
                    426:                                mod = 2;
                    427:                        }
                    428:                        else {
                    429:                                uflags |= U_DSP8;
                    430:                                mod = 1;
                    431:                        }
                    432: 
                    433:                        rm = 4;
                    434:                        scale = this->scale;
                    435:                        displ = this;
                    436:                        return (0);
                    437: 
                    438:                case T_RIDS:
                    439:                        if (4 == (index = r1->loc))     /* can't index sp */
                    440:                                return (1);
                    441: 
                    442:                        mod = 0;
                    443:                        uflags |= U_DSP;
                    444:                        scale = this->scale;
                    445:                        rm = 4;
                    446:                        base = 5;
                    447:                        displ = this;
                    448:                        return (0);
                    449:                }
                    450:                return (1);
                    451: 
                    452:        case rm16:      /* r/m 16 */
                    453:                uflags |= U_RMS;
                    454:                switch (this->mode) {
                    455:                case T_RI:      /* register indirect */
                    456:                        switch ((int)r1->loc) {
                    457:                        case 6: /* (%si) */
                    458:                                rm = 4; break;
                    459:                        case 7: /* (%di) */
                    460:                                rm = 5; break;
                    461:                        case 3: /* (%bx) */
                    462:                                rm = 7; break;
                    463:                        default:
                    464:                                return (1);
                    465:                        }
                    466:                        mod = 0;
                    467:                        return (0);
                    468: 
                    469:                case T_R:       /* register */
                    470:                        if ((r1->size != regsz) || (r1->flag != ORD_REG))
                    471:                                return (1);
                    472:                        rm = r1->loc;
                    473:                        mod = 3;
                    474:                        return (0);
                    475:                        
                    476:                case T_D:       /* displacment */
                    477:                        if (this->exp < -32768L || this->exp > 65535L)
                    478:                                return(1);
                    479: 
                    480:                        mod = 0;
                    481:                        rm  = 6;
                    482:                        uflags |= U_DSP;
                    483:                        displ = this;
                    484:                        return (0);
                    485: 
                    486:                case T_RID:     /* register indirect displacment */
                    487:                        if (this->exp < -32768L || this->exp > 65535L)
                    488:                                return(1);
                    489: 
                    490:                        switch ((int)r1->loc) {
                    491:                        case 6: /* (%si) */
                    492:                                rm = 4; break;
                    493:                        case 7: /* (%di) */
                    494:                                rm = 5; break;
                    495:                        case 5: /* (%bp) */
                    496:                                rm = 6; break;
                    497:                        case 3: /* (%bx) */
                    498:                                rm = 7; break;
                    499:                        default:
                    500:                                return (1);
                    501:                        }
                    502: 
                    503:                        if ((NULL != this->ref) ||
                    504:                            (d = this->exp) < -128 || d > 127) {
                    505:                                uflags |= U_DSP;
                    506:                                mod = 2;
                    507:                        }
                    508:                        else {
                    509:                                uflags |= U_DSP8;
                    510:                                mod = 1;
                    511:                        }
                    512:                        displ = this;
                    513:                        return (0);
                    514: 
                    515:                case T_RIXD:    /* register index displacment */
                    516:                        if ((NULL != this->ref) ||
                    517:                            (d = this->exp) < -128 || d > 127) {
                    518:                                uflags |= U_DSP;
                    519:                                mod = 2;
                    520:                        }
                    521:                        else {
                    522:                                uflags |= U_DSP8;
                    523:                                mod = 1;
                    524:                        }
                    525:                        /* fall through */
                    526:                        displ = this;
                    527: 
                    528:                case T_RIX:     /* register index */
                    529:                        if (T_RIX == this->mode)
                    530:                                mod = 0;
                    531: 
                    532:                        switch ((int)r1->loc) {
                    533:                        case 3: /* %bx */
                    534:                                switch ((int)this->r2->loc) {
                    535:                                case 6: /* %si */
                    536:                                        rm = 0; break;
                    537:                                case 7: /* %di */
                    538:                                        rm = 1; break;
                    539:                                default:
                    540:                                        return (1);
                    541:                                }
                    542:                                break;
                    543:                        case 5: /* bp */
                    544:                                switch ((int)this->r2->loc) {
                    545:                                case 6: /* %si */
                    546:                                        rm = 2; break;
                    547:                                case 7: /* %di */
                    548:                                        rm = 3; break;
                    549:                                default:
                    550:                                        return (1);
                    551:                                }
                    552:                                break;
                    553:                        default:
                    554:                                return (1);
                    555:                        }
                    556:                        return (0);
                    557:                }
                    558:                return (1);
                    559:        }
                    560: }
                    561: 
                    562: /*
                    563:  * Chip errata message.
                    564:  */
                    565: errata(opcode)
                    566: {
                    567:        if (opcode && !nswitch)
                    568:                outab(opcode);
                    569:        else
                    570:                yywarn("This code may not work the same way on all chips");
                    571:                /* Some chips may not execute this code as expected. */
                    572: }
                    573: 
                    574: /*
                    575:  * Try to build an opcode.
                    576:  */
                    577: static
                    578: buildop(op)
                    579: opc *op;
                    580: {
                    581:        register unsigned short i, j;
                    582:        static short postSw = 0;
                    583:        static short lastOp = 0;
                    584:        static short lastFlags = 0;
                    585: 
                    586:        /* First check if everything is ok */
                    587:        if (st->operands != ct)
                    588:                return(1);
                    589: 
                    590:        uflags = base = mod = rm = reg = scale = index = 0;
                    591:        for (i = 0; i < ct; i++)
                    592:                if (checkop(opList[i], (unsigned short)(st->ap[i])))
                    593:                        return(1);
                    594: 
                    595:        /* deal with unusual stuff */
                    596:        if (st->bldr & (AMBIG_MATCH | TWO_OP_MULT | XTENDS)) {
                    597:                if (st->bldr & AMBIG_MATCH)
                    598:                        yywarn("Ambiguous operand length, %d bytes selected", 
                    599:                           (MOV_BYTE == op->code) ? 1 : (longMode ? 4 : 2));
                    600:                        /* The assembler cannot tell the operand length by
                    601:                         * looking at the opcode and the operands.
                    602:                         * You may want to do something like change
                    603:                         * \fBmov\fR to \fBmovl\fR. */
                    604: 
                    605:                /* 2 operand form of 3 operand multiply */
                    606:                if (st->bldr & TWO_OP_MULT) {
                    607:                        mod = 3;
                    608:                        rm  = opList[1]->r1->loc;
                    609:                }
                    610: 
                    611:                /* movsx and movzx have mixed 16 and 32 bit stuff */
                    612:                if (st->bldr & XTENDS)
                    613:                        lflags &= ~(O_LONG|O_SHORT);
                    614:        }
                    615: 
                    616:        /*
                    617:         * Only a few instructions are defined after a rep  or lock
                    618:         * Instructions valid after lock are marked but are
                    619:         * only valid if a memory location is accessed. This is
                    620:         * checked by excluding (mod == 3) which is rm is register.
                    621:         */
                    622:        if (postSw) {
                    623:                if (postSw & REP_INSTR)
                    624:                        if (!(st->bldr & AFTER_REP))
                    625:                                yywarn("Improper instruction following rep");
                    626:                                /* Only a few instructions
                    627:                                 * are valid after a rep instruction.
                    628:                                 * See your machine documentation for details.*/
                    629:                        else if (op->code == INSB || op->code == INSW)
                    630:                                errata(0);
                    631: 
                    632:                if ((postSw & LOCK_OP) &&
                    633:                    (!(st->bldr & AFTER_LOCK) || (3 == mod)))
                    634:                        yywarn("Improper instruction following lock");
                    635:                        /* Only a few instructions
                    636:                         * are valid after a lock instruction.
                    637:                         * See your machine documentation for details. */
                    638:        }
                    639:        postSw = st->bldr & (LOCK_OP | REP_INSTR);
                    640: 
                    641:        /* 
                    642:         * check for various chip errata
                    643:         * sometimes wave a dead chicken over your head to make things work
                    644:         */
                    645: #if 0
                    646:        /* See Intel chip errata for 80386-B1 17.
                    647:         * Coprocessor instruction crossing segment boundaries may hang chip.
                    648:         * Assume any 4's boundary is a potential boundary. */
                    649:        if ((st->bldr & FLOAT_ESC) &&
                    650:            (((st->bldr & FLOAT_PFX) ? 2 : 3) == (dot.loc % 4)))
                    651:                errata(NOP);
                    652: #endif
                    653: 
                    654:        /* See Intel chip errata for 80386-B1 23. */
                    655:        if (((lastOp == POPA) && (uflags & U_RML) && (mod != 3)) &&
                    656:                /* determine longmode of popa */
                    657:            ((longMode ? !(lastFlags & 2) : (lastFlags & 4)) ?
                    658:                /* longmode then if base index and either not %eax */
                    659:             ((rm == 4) && (index || base)) :
                    660:                /* not longmode any index was %eax */
                    661:             (!rm || ((rm == 4) && (!index || !base)))))
                    662:                errata(NOP);
                    663: 
                    664:        if (POP_MEM == op->code) {
                    665:                /* pop  %cs:mem */
                    666:                if (opList[0]->sg == 1)
                    667:                        errata(0);
                    668: 
                    669:                /* pop  n(%esp)  */
                    670:                if ((uflags & U_RML) && base == 4 && rm == 4 && mod)
                    671:                        errata(0);
                    672:        }
                    673:        
                    674:        /*
                    675:         * aam must be preceeded with special stuff on 80486
                    676:         * The idea is that there must be an xchg with a non 1 value.
                    677:         */
                    678:        if (op->code == AAM) {
                    679:                static char seq[8] = {
                    680:                        0x51,           /* push         %ecx */
                    681:                        0x33, 0xC9,     /* xor          %ecx, %ecx */
                    682:                        0x87, 0xC9,     /* xchg         %ecx, %ecx */
                    683:                        0xD4, 0x0A,     /* aam */
                    684:                        0x59            /* pop          %ecx */
                    685:                };
                    686: 
                    687:                if (nswitch)
                    688:                        errata(0);
                    689:                else {
                    690:                        for (i = 0; i < 8; i++)
                    691:                                outab(seq[i]);
                    692:                        return (0);
                    693:                }
                    694:        }
                    695:                        
                    696:        lastFlags = st->bldr;
                    697:        lastOp = op->code;
                    698: 
                    699:        if (lflags & A_INDIR) {
                    700:                lastFlags = (longMode ? LONG_MODE : WORD_MODE) | MODRM_BYTE;
                    701:                switch (lastOp) {
                    702:                case JMP_NEAR:
                    703:                        lastOp = JMP_INDIR;     break;
                    704:                case CALL_NEAR:
                    705:                        lastOp = CALL_INDIR;    break;
                    706:                default:
                    707:                        yyerror("Indirect mode on invalid instruction");
                    708:                        /* Indirection is only allowed on call and jump near
                    709:                         * instructions. */
                    710:                }
                    711:        }
                    712: 
                    713:        if (longMode) {
                    714:                if (lflags & A_SHORT) {
                    715:                        yywarn("16 bit addressing mode used in 32 bit code");
                    716:                        /* You probably don't want to do this.
                    717:                         * For example, you may want to say \fB(%esi)\fR, not
                    718:                         * \fB(%si)\fR. */
                    719:                        outab(PREFIX_AD);       /* address size prefix */
                    720:                }
                    721:                else
                    722:                        lflags |= A_LONG;
                    723: 
                    724:                if (lastFlags & WORD_MODE)
                    725:                        outab(PREFIX_OP);       /* operand size prefix */
                    726:        }
                    727:        else {
                    728:                if (lflags & A_LONG) {
                    729:                        yywarn("32 bit addressing mode used in 16 bit code");
                    730:                        /* You probably don't want to do this.
                    731:                         * For example, you may want to say \fB(%si)\fR, not
                    732:                         * \fB(%esi)\fR. */
                    733:                        outab(PREFIX_AD);       /* address size prefix */
                    734:                }
                    735:                else
                    736:                        lflags |= A_SHORT;
                    737: 
                    738:                if (lastFlags & LONG_MODE)
                    739:                        outab(PREFIX_OP); /* operand size prefix */
                    740:        }
                    741: 
                    742: #define ck(x, y) if (j & x) break; j |= x; outab(y); break;
                    743: 
                    744:        /* Put out nessisary prefix bytes */
                    745:        for (j = i = 0; i < ct; i++) {
                    746:                switch (opList[i]->sg) {
                    747:                case 0: /* es: */
                    748:                        ck(1, PREFIX_ES);
                    749:                case 1: /* cs: */
                    750:                        ck(2, PREFIX_CS);
                    751:                case 2: /* ss: */
                    752:                        ck(4, PREFIX_SS);
                    753:                case 3: /* ds: */
                    754:                        ck(8, PREFIX_DS);
                    755:                case 4: /* fs: */
                    756:                        ck(16, PREFIX_FS);
                    757:                case 5: /* gs: */
                    758:                        ck(32, PREFIX_GS);
                    759:                }
                    760:        }
                    761: 
                    762: #undef ck
                    763: 
                    764:        /* Then build the op code */
                    765: 
                    766:        /* Test for relative jump first */
                    767:        switch ((int)(uflags & U_REL_MASK)) {
                    768:        case U_REL16:   /* 16 or 32 bit branch */
                    769:                indBra(lastOp, NON_OP, opList[0]);
                    770:                return(0);
                    771: 
                    772:        case U_REL8:    /* 8 bit branch */
                    773:                indBra(NON_OP, lastOp, opList[0]);
                    774:                return(0);
                    775: 
                    776:        case U_RELI:    /* may become 8, 16 or 32 bit branch */
                    777:                switch (lastOp) {
                    778:                case JMP_NEAR:
                    779:                        indBra(lastOp, JMP_SHORT, opList[0]);
                    780:                        break;
                    781:                case CALL_NEAR:
                    782:                        indBra(lastOp, NON_OP, opList[0]);
                    783:                        break;
                    784:                default:        /* conditional jump */
                    785:                        indBra(lastOp + JCC_NEAR,
                    786:                               lastOp + JCC_SHORT, opList[0]);
                    787:                }
                    788:                return(0);
                    789:        }
                    790: 
                    791:        if (lastFlags & PFX_0F)
                    792:                outab(0x0F);
                    793: 
                    794:        if (lastFlags & FLOAT_PFX)
                    795:                outab(0x9B);
                    796: 
                    797:        if (lastFlags & MODRM_BYTE ||
                    798:            lastOp & 0xFF00)
                    799:                outab(lastOp >> 8);
                    800: 
                    801:        j = lastOp & 0xFF;
                    802: 
                    803:        if (lastFlags & ADD_REG)
                    804:                j += reg;
                    805: 
                    806:        if (lastFlags & MODRM_BYTE)
                    807:                reg = j;
                    808:        else
                    809:                outab(j);
                    810: 
                    811:        if (uflags & (U_RML|U_CTL))
                    812:                outrm32();
                    813:        else if (uflags & U_RMS)
                    814:                outrm16();
                    815: 
                    816:        if (uflags & U_IMM16)
                    817:                outrw(immed, 0);
                    818: 
                    819:        if (uflags & U_IMM32)
                    820:                outrl(immed, 0);
                    821: 
                    822:        if (uflags & U_IMM8)
                    823:                outab(immed8);
                    824: 
                    825:        if (uflags & U_IMM16X)
                    826:                outrw(immedx, 0);
                    827: 
                    828:        if (uflags & U_IMM32X)
                    829:                outrl(immedx, 0);
                    830: 
                    831:        if (uflags & U_ADR16)
                    832:                outrw(addr, 0);
                    833: 
                    834:        if (uflags & U_ADR32)
                    835:                outrl(addr, 0);
                    836: 
                    837:        return(0);
                    838: }
                    839: 
                    840: /*
                    841:  * Output mod/rm byte and maybe sib
                    842:  */
                    843: static
                    844: outrm32()
                    845: {
                    846:        short modrm, sib;
                    847: 
                    848:        if (uflags & U_CTL)     /* Special register used */
                    849:                modrm = (3 << 6) | (rm << 3) | reg;
                    850:        else
                    851:                modrm = (mod << 6) | (reg << 3) | rm;
                    852: 
                    853:        outab(modrm);
                    854:        if (4 == rm && 3 != mod) {
                    855:                sib = (scale << 6) | (index << 3) | base;
                    856:                outab(sib);
                    857:        }
                    858: 
                    859:        if (uflags & U_DSP8)
                    860:                outrb(displ, 0);
                    861: 
                    862:        else if (uflags & U_DSP)
                    863:                outrl(displ, 0);
                    864: }
                    865: 
                    866: /*
                    867:  * Output mod/rm byte
                    868:  */
                    869: static
                    870: outrm16()
                    871: {
                    872:        short modrm;
                    873: 
                    874:        modrm = (mod << 6) | (reg << 3) | rm;
                    875:        outab(modrm);
                    876: 
                    877:        if (uflags & U_DSP8)
                    878:                outrb(displ, 0);
                    879: 
                    880:        else if (uflags & U_DSP)
                    881:                outrw(displ, 0);
                    882: }
                    883: 
                    884: /*
                    885:  * Code for relative branches.
                    886:  * Save type of all branch operators on a list assuming shortest feasable.
                    887:  * If a type changes set xpass = 1.
                    888:  *
                    889:  * Pass logic in newPass goes to 2 only if xpass == 0 else it goes to 1
                    890:  *
                    891:  * There is an elegant algorithm for fixing up jumps between passes by
                    892:  * tree manipulation, this would reduce this to a two pass assembler.
                    893:  * Sadly it won't work. It assumes smooth code, that is if I change a
                    894:  * byte jump to a near jump the following addresses will change by addition.
                    895:  * In assembly language people can insert things like .align or .org which
                    896:  * break that assumption, the GNU compiler does this every few lines.
                    897:  *
                    898:  * Once the smooth code assumption is broken we no longer know that the
                    899:  * tree algorithm terminates at all, a byte jump can go to a longer jump
                    900:  * and back again in the next pass. To guarantee termination we start at
                    901:  * byte jumps and only go to longer jumps when we know it is forced. Once
                    902:  * we go to longer jump we never go back. This speeds the assembly of GNU
                    903:  * output by about 10 times.
                    904:  */
                    905: static unsigned braCt;         /* count of branches */
                    906: 
                    907: #define BYTE_J 0       /* byte jump length */
                    908: #define NEAR_J 1       /* int  jump length */
                    909: #define EXT_J  2       /* jump around sequence */
                    910: 
                    911: /*
                    912:  * Called at new pass or init. Returns 1 if another pass required.
                    913:  */
                    914: indPass()
                    915: {
                    916:        braCt = 0;              /* so far no branches */
                    917:        if (xpass) {
                    918:                xpass = 0;
                    919:                return (1);
                    920:        }
                    921:        return (0);
                    922: }
                    923: 
                    924: /*
                    925:  * Put out op code.
                    926:  */
                    927: static void
                    928: putOp(opCode)
                    929: register unsigned short opCode;
                    930: {
                    931:        if (opCode & 0xFF00) {
                    932:                outab(opCode >> 8);
                    933:                outab(opCode & 0xff);
                    934:        }
                    935:        else
                    936:                outab(opCode);
                    937: }
                    938: 
                    939: /*
                    940:  * Called for each relative branch.
                    941:  * Calculates branch size. Forces another pass if a branch expands.
                    942:  */
                    943: void
                    944: indBra(nearOp, byteOp, op)
                    945: unsigned short nearOp, byteOp;
                    946: register expr *op;
                    947: {
                    948:        static char *list;              /* one for each relative branch */
                    949:        static unsigned max;            /* size of list */
                    950:        char size;                      /* BYTE_J NEAR_J EXT_J */
                    951:        long d;                         /* displacment */
                    952:        short  flag, exref;
                    953:        char *old;
                    954: 
                    955:        /* insure space for branch data */
                    956:        if (max <= ++braCt)
                    957:                expand(&list, &max, 64, sizeof(char));
                    958: 
                    959:        old = list + (braCt - 1);
                    960:        /* assume size from last pass or shortest size for this jump. */
                    961:        size = pass ? *old : ((byteOp == NON_OP) ? NEAR_J : BYTE_J);
                    962: 
                    963:        if (NULL == op->ref)
                    964:                fatal("NULL address in relative branch"); /* TECH */
                    965: 
                    966:        flag = op->ref->flag;
                    967:        exref = 0; 
                    968: 
                    969:        if (flag & S_UNDEF) {   /* undefined symbol */
                    970:                if (pass)
                    971:                        size = NEAR_J;  /* known near */
                    972:                else if (BYTE_J == size)
                    973:                        xpass = 1;
                    974: 
                    975:                if (gswitch)    /* -g turns undefined to global */
                    976:                        exref = 1;
                    977:        }
                    978: 
                    979:        else if ((flag & S_EXREF) || (dot.sg != op->ref->sg)) {
                    980:                exref = 1;
                    981:                size = NEAR_J;          /* known near */
                    982:        }
                    983: 
                    984:        else if (BYTE_J == size) {
                    985:                /* Calculate displacment from end of byte instr */
                    986:                d = op->exp - (dot.loc + ((byteOp & 0xFF00) ? 3 : 2));
                    987: 
                    988:                if ((d < -128) || (d > 127))    /* near limits */
                    989:                        size = NEAR_J;
                    990:        }
                    991: 
                    992:        /* near branch and none available build jumpover */
                    993:        if ((NEAR_J == size) && (NON_OP == nearOp))
                    994:                size = EXT_J;
                    995: 
                    996:        /* How does this compare to the last time? */
                    997:        if (*old != size) {
                    998:                switch(pass) {
                    999:                case 1:
                   1000:                        if (*old > size)        /* never shrink */
                   1001:                                break;
                   1002:                        xpass = 1;              /* take one more pass */
                   1003:                case 0:
                   1004:                        *old = size;            /* take new size */
                   1005:                        break;
                   1006:                default:
                   1007:                        if (*old < size)        /* too late for changes */
                   1008:                                fatal("Internal error relative branch logic");
                   1009:                                 /* TECH */
                   1010:                }
                   1011:        }
                   1012: 
                   1013:        /* output code */
                   1014:        switch(*old) {
                   1015:        case BYTE_J:    /* short op */
                   1016:                putOp(byteOp);
                   1017:                if (exref)
                   1018:                        outrb(op, 1);
                   1019:                else
                   1020:                        outab((int)d);
                   1021:                break;
                   1022: 
                   1023:        case EXT_J:     /* jump around sequence */
                   1024:                putOp(byteOp);          /* caller's jump over byte jump */
                   1025:                outab(2);
                   1026: 
                   1027:                outab(JMP_SHORT);       /* byte jump over near jump */
                   1028:                outab(longMode ? 0x05 : 0x03);
                   1029: 
                   1030:                nearOp = JMP_NEAR;      /* near jump to caller's destination */
                   1031: 
                   1032:        case NEAR_J:    /* near jumps */
                   1033:                putOp(nearOp);
                   1034:                if (longMode)
                   1035:                        if (exref)
                   1036:                                outrl(op, 1);
                   1037:                        else    /* displacement from end of address */
                   1038:                                outal(op->exp - (dot.loc + 4));
                   1039:                else
                   1040:                        if (exref)
                   1041:                                outrw(op, 1);
                   1042:                        else    /* displacement from end of address */
                   1043:                                outaw((int)(op->exp - (dot.loc + 2)));
                   1044:        }
                   1045: }

unix.superglobalmegacorp.com

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