|
|
1.1 root 1: /*
2: * n2/i386/asm.c
3: * The routines in this file assemble buffered code
4: * and write the code to the output file.
5: * i386.
6: */
7:
8: #ifdef vax
9: #include "INC$LIB:cc2.h"
10: #else
11: #include "cc2.h"
12: #endif
13:
14: #define W 0x01 /* W (word) bit */
15: #define D 0x02 /* D (direction) bit */
16: #define ESC_2B 0x0F /* Two-byte op escape */
17: #define ESC 0xD8 /* Escape */
18: #define WAIT 0x9B /* Wait */
19:
20: static ADDRESS pc; /* Current assembly pc */
21: static ADDRESS pcdot[NSEG]; /* Working copy of seg '.' fields */
22: static int pcseg; /* Current segment */
23: static int pass; /* Pass flag; only 1 emits code */
24:
25: extern int hasfloat; /* function uses floating point */
26:
27: /*
28: * Driving routine.
29: * Run pass 0 of the assembly to get sizes.
30: * All jumps are assumed to be short.
31: * Fix up any that don't reach.
32: * Run the second assembly pass to generate the final code.
33: */
34: genfunc()
35: {
36: register INS *ip1, *ip2;
37: register int i;
38:
39: pc = dot;
40: pass = 0;
41: pcseg = dotseg;
42: for (i = 0; i < NSEG; ++i)
43: pcdot[i] = seg[i].s_dot;
44: ip1 = ins.i_fp;
45: while (ip1 != &ins) {
46: assemble(ip1);
47: ip1 = ip1->i_fp;
48: }
49: sdi();
50: pc = dot;
51: pass = 1;
52: pcseg = dotseg;
53: for (i = 0; i < NSEG; ++i)
54: pcdot[i] = seg[i].s_dot;
55: ip1 = ins.i_fp;
56: while (ip1 != &ins) {
57: asmdbgt(ip1);
58: if (isvariant(VASM))
59: unassemble(ip1);
60: else
61: assemble(ip1);
62: ip2 = ip1->i_fp;
63: free((char *) ip1);
64: ip1 = ip2;
65: }
66: asmdbgt(&ins);
67: }
68:
69: /*
70: * Generate code for a single instruction.
71: * Used to compile external data definitions, etc.
72: */
73: genins(ip) register INS *ip;
74: {
75: register int i;
76:
77: for (pass=0; pass!=2; ++pass) {
78: pc = dot;
79: pcseg = dotseg;
80: for (i = 0; i < NSEG; ++i)
81: pcdot[i] = seg[i].s_dot;
82: if (isvariant(VASM) && pass != 0) {
83: if (ip->i_type != LINE
84: || isvariant(VLINES))
85: unassemble(ip);
86: } else
87: assemble(ip);
88: }
89: }
90:
91: /*
92: * This function fixes up the span dependent instructions.
93: * The only case on the iAPX-86 is the jump, which has limited range.
94: * There is nothing to be done with the adjustable displacements,
95: * bacause these are always absolute and do not change.
96: * For the moment,
97: * unconditional JMP gets bumped from JMP i8 to JMP i32 (2 bytes -> 5);
98: * conditional Jcc gets bumped from Jcc i8 to Jcc i32 (2 -> 6).
99: * The 16-bit forms using operand escape prefix are probably better.
100: */
101: sdi()
102: {
103: register INS *ip1, *ip2;
104: register SYM *sp;
105: register int bump, changes;
106: SIGNEDADDRESS disp;
107:
108: do {
109: changes = 0;
110: ip1 = ins.i_fp;
111: while (ip1 != &ins) {
112: if (isoptjump(ip1)) {
113: if ((sp=ip1->i_sp) == NULL)
114: cbotch("sdi");
115: if (ip1->i_pcseg != sp->s_seg)
116: cbotch("x seg #1");
117: disp = sp->s_value-ip1->i_pc-2;
118: if (disp < -128 || disp > 127) {
119: ip1->i_long = 1;
120: changes = 1;
121: bump = 3;
122: if (ip1->i_rel != ZJMP)
123: bump = 4;
124: ip2 = ip1->i_fp;
125: while (ip2 != &ins) {
126: sdibump(ip1, ip2, bump);
127: ip2 = ip2->i_fp;
128: }
129: }
130: }
131: ip1 = ip1->i_fp;
132: }
133: } while (changes);
134: }
135:
136: /*
137: * This routine performs the nitty gritty
138: * of bumping an instruction to a higher address because
139: * an sdi changed from short to long.
140: * The 'ip1' argument is a pointer to the INS of the jump.
141: * The 'ip2' argument is the node to be bumped by 'bump' bytes.
142: * Only labels and code in the same segment as the 'ip1' node are adjusted.
143: */
144: sdibump(ip1, ip2, bump) register INS *ip1, *ip2; int bump;
145: {
146: register int type;
147: register SYM *sp;
148:
149: if ((type=ip2->i_type) == LLABEL) {
150: if ((sp=ip2->i_sp) == NULL)
151: cbotch("sdibump");
152: if (sp->s_seg == ip1->i_pcseg)
153: sp->s_value += bump;
154: } else if (type==JUMP || type==CODE) {
155: if (ip2->i_pcseg == ip1->i_pcseg)
156: ip2->i_pc += bump;
157: }
158: }
159:
160: /*
161: * This routine checks if a node is an optimizable short jump.
162: * The node must be a jump,
163: * it must be short and it must either be the unconditional
164: * jump or one of the jumps that has a reverse.
165: */
166: isoptjump(ip1) register INS *ip1;
167: {
168: register int rel;
169:
170: if (ip1->i_type==JUMP && ip1->i_long==0) {
171: rel = ip1->i_rel;
172: if (rel!=ZJCXZ && rel!=ZLOOP && rel!=ZLOOPE && rel!=ZLOOPNE)
173: return 1;
174: }
175: return 0;
176: }
177:
178: /*
179: * Assemble a line.
180: * If pass 1 the binary goes straight out.
181: * The ip1 argument points to the INS node that is to be assembled.
182: */
183: assemble(ip1) register INS *ip1;
184: {
185: SIGNEDADDRESS disp;
186: int opbits, opcode, ostyle, prefix, m1, m2, m3, regm, rn, shortflag;
187: int align, count;
188: sizeof_t length;
189: OPINFO *opinfop;
190: SYM *sp;
191: AFIELD a1;
192: int is16bit; /* Current op needs 16-bit prefix */
193:
194: switch (ip1->i_type) {
195:
196: case ENTER:
197: pcdot[pcseg] = pc;
198: pcseg = ip1->i_seg;
199: pc = pcdot[pcseg];
200: if (pass != 0)
201: genseg(pcseg);
202: break;
203:
204: case BLOCK:
205: if ((length=ip1->i_len) != 0) {
206: if (pcseg == SBSS) {
207: pc += length;
208: if (pass != 0)
209: dot += length;
210: } else if (pass != 0)
211: outnzb(length, 0);
212: }
213: break;
214:
215: case ALIGN:
216: if ((align = ip1->i_align) != 0 && (pc & (align-1)) != 0) {
217: count = align - (pc & (align-1));
218: if (pcseg == SBSS) {
219: pc += count;
220: if (pass != 0)
221: dot += count;
222: } else {
223: while (count--)
224: asmab(0);
225: }
226: }
227: break;
228:
229: case JUMP:
230: ip1->i_pc = pc;
231: ip1->i_pcseg = pcseg;
232: if ((sp=ip1->i_sp) == NULL) {
233: sp = llookup(ip1->i_labno, 0);
234: ip1->i_sp = sp;
235: }
236: if (pass != 0) {
237: if (sp==NULL || (sp->s_flag&S_DEF)==0)
238: cbotch("undef");
239: if (ip1->i_long == 0) {
240: if (sp->s_seg != ip1->i_pcseg)
241: cbotch("x seg #2");
242: disp = sp->s_value - pc - 2;
243: if (disp < -128 || disp > 127)
244: cbotch("reach, disp=%d", disp);
245: }
246: }
247: opbits = opinfo[ip1->i_rel].op_opcode;
248: if (ip1->i_long == 0) {
249: /* Short JMP or Jcc, i8 displacement. */
250: asmab(opbits);
251: asmab(disp);
252: } else {
253: /* Long jumps, see comments on sdi() above. */
254: if (ip1->i_rel != ZJMP) {
255: /* Jcc i8 becomes Jcc i32. */
256: disp = sp->s_value - pc - 6;
257: asmab(ESC_2B); /* 2-byte escape */
258: asmab(opbits+0x10); /* 7x becomes 8x */
259: asmal(disp);
260: break;
261: }
262: disp = sp->s_value - pc - 5;
263: asmab(0xE9); /* Jump i32 */
264: asmal(disp);
265: }
266: break;
267:
268: case LLABEL:
269: if ((sp=ip1->i_sp) == NULL) {
270: sp = llookup(ip1->i_labno, 1);
271: ip1->i_sp = sp;
272: }
273: sp->s_seg = pcseg;
274: sp->s_value = pc;
275: break;
276:
277: case LLLINK:
278: if ((sp=ip1->i_sp) == NULL) {
279: sp = llookup(ip1->i_labno, 0);
280: ip1->i_sp = sp;
281: }
282: if (pass!=0 && (sp==NULL || (sp->s_flag&S_DEF)==0))
283: cbotch("undef");
284: a1.a_mode = A_DIR;
285: a1.a_sp = sp;
286: a1.a_value = 0;
287: asmxl(&a1, 0);
288: break;
289:
290: case CODE:
291: ip1->i_pc = pc;
292: ip1->i_pcseg = pcseg;
293: opcode = ip1->i_op;
294: opinfop = &opinfo[opcode];
295: opbits = opinfop->op_opcode;
296: if (opinfop->op_flag & OP_WORD) {
297: is16bit = 1;
298: asmab(0x66); /* 16-bit operand prefix */
299: } else
300: is16bit = 0;
301: switch (ostyle = opinfop->op_style) {
302:
303: case OF_INH2:
304: asmab(opbits);
305: asmab(0x0A);
306: break;
307:
308: case OF_INH:
309: asmab(opbits);
310: break;
311:
312: case OF_PUSH:
313: case OF_POP:
314: m1 = MOD(af_p(ip1, 0));
315: rn = REGM(af_p(ip1, 0));
316: if ((ostyle == OF_PUSH) && (m1 == A_IMM)) {
317: if (isimmbyte(af_p(ip1, 0))) {
318: asmab(0x6A);
319: asmxb(af_p(ip1, 0), 0);
320: } else if (!is16bit) {
321: asmab(0x68);
322: asmxl(af_p(ip1, 0), 0);
323: } else {
324: asmab(0x68);
325: asmxw(af_p(ip1, 0), 0);
326: }
327: break;
328: }
329: if (m1 == A_DR || m1 == A_WR) {
330: asmab((ostyle == OF_PUSH) ? 0x50 | rn
331: : 0x58 | rn);
332: break;
333: }
334: if (ostyle == OF_PUSH)
335: asmgen(0xFF, 0x30, af_p(ip1, 0));
336: else
337: asmgen(0x8F, 0x00, af_p(ip1, 0));
338: break;
339:
340: case OF_SHR:
341: prefix = 0xD0 | (opbits&W);
342: opbits &= ~W;
343: if (ip1->i_af[1].a_mode == A_RCL)
344: prefix |= 0x02;
345: else if ((MOD(af_p(ip1, 1))) != A_IMM
346: || ip1->i_af[1].a_sp != NULL)
347: aerr(ip1);
348: disp = ip1->i_af[1].a_value;
349: if ((ip1->i_af[1].a_mode != A_RCL) && (disp != 1)) {
350: /* 286 shift immediate */
351: prefix &= 0xEF; /* Change 0xD0|W to 0xC0|W */
352: asmgen(prefix, opbits, af_p(ip1, 0));
353: asmab(disp);
354: break;
355: }
356: asmgen(prefix, opbits, af_p(ip1, 0));
357: break;
358:
359: case OF_ICALL:
360: asmgen(0xFF, opbits, af_p(ip1, 0));
361: break;
362:
363: case OF_CALL:
364: if ((MOD(af_p(ip1, 0))) != A_DIR)
365: aerr(ip1);
366: asmab(0xE8);
367: asmxl(af_p(ip1, 0), 1);
368: break;
369:
370: case OF_XCALL:
371: if ((MOD(af_p(ip1, 0))) != A_DIR)
372: aerr(ip1);
373: asmab(0x9A);
374: asmxl(af_p(ip1, 0), 0);
375: break;
376:
377: case OF_DOPS:
378: case OF_DOP:
379: m1 = MOD(af_p(ip1, 0));
380: m2 = MOD(af_p(ip1, 1));
381: if (m2 == A_IMM) {
382: /*
383: * Immediate right operand.
384: * Use the special EAX etc. form if possible,
385: * but not for byte immediate operands,
386: * where the byte immediate form is better.
387: */
388: shortflag = (ostyle == OF_DOPS) && isimmbyte(af_p(ip1, 1));
389: if (isEAX(af_p(ip1, 0))
390: && (!shortflag || opbits == 0x84 || opbits == 0x85)) {
391: /* Left operand is EAX, AX or AL. */
392: if (opbits == 0x85)
393: opbits = 0xA9; /* test */
394: else if (opbits == 0x84)
395: opbits = 0xA8; /* testb */
396: else
397: opbits |= 0x04; /* use EAX form */
398: asmab(opbits);
399: } else {
400: /*
401: * Left operand is not EAX, AX or AL,
402: * or (right operand is byte immediate
403: * and operator is not TEST).
404: */
405: if (opbits==0x84 || opbits==0x85) {
406: regm = 0;
407: if (opbits == 0x84)
408: opbits = 0xF6; /* test */
409: else
410: opbits = 0xF7; /* testb */
411: } else {
412: regm = opbits & 0x38;
413: opbits = (opbits&W)|0x80;
414: if (shortflag)
415: opbits |= 0x02;
416: }
417: asmgen(opbits, regm, af_p(ip1, 0));
418: }
419: if (shortflag || (opbits&W)==0)
420: asmxb(af_p(ip1, 1), 0);
421: else if (!is16bit)
422: asmxl(af_p(ip1, 1), 0);
423: else
424: asmxw(af_p(ip1, 1), 0);
425: break;
426: }
427: /* To reg */
428: if (m1==A_DR || m1==A_BR || m1==A_WR) {
429: /* Test[b] */
430: if (opbits!=0x84 && opbits!=0x85)
431: opbits |= 0x02; /* D */
432: asmgen(opbits, (REGM(af_p(ip1, 0)))<<3,
433: af_p(ip1, 1));
434: break;
435: }
436: /* To mem */
437: asmgen(opbits, (REGM(af_p(ip1, 1)))<<3,
438: af_p(ip1, 0));
439: break;
440:
441: case OF_MUL3:
442: m1 = MOD(af_p(ip1, 0));
443: m2 = MOD(af_p(ip1, 1));
444: m3 = MOD(af_p(ip1, 2));
445: if ((m1 != A_DR && m1 != A_WR) || m3 != A_IMM)
446: aerr(ip1);
447: shortflag = 0;
448: if (isimmbyte(af_p(ip1, 2))) {
449: shortflag = 1;
450: opbits |= 0x02; /* Change 0x69 to 0x6B */
451: }
452: asmgen(opbits, (REGM(af_p(ip1, 0)))<<3, af_p(ip1, 1));
453: if (shortflag)
454: asmxb(af_p(ip1, 2), 0);
455: else if (!is16bit)
456: asmxl(af_p(ip1, 2), 0);
457: else
458: asmxw(af_p(ip1, 2), 0);
459: break;
460:
461: case OF_SOP:
462: m1 = MOD(af_p(ip1, 0));
463: prefix = ((opbits < 0x10)?0xFE:0xF6) | (opbits&W);
464: opbits &= ~W;
465: if (prefix==0xFF && (m1==A_DR || m1==A_WR)) {
466: asmab(0x40 | opbits |
467: (REGM(af_p(ip1, 0))));
468: break;
469: }
470: asmgen(prefix, opbits, af_p(ip1, 0));
471: break;
472:
473: case OF_LEA:
474: m1 = MOD(af_p(ip1, 0));
475: m2 = MOD(af_p(ip1, 1));
476: if (m1!=A_DR || (m2!=A_DIR && m2!=A_XB))
477: aerr(ip1);
478: asmgen(opbits, (REGM(af_p(ip1, 0)))<<3,
479: af_p(ip1, 1));
480: break;
481:
482: case OF_MOV:
483: m1 = MOD(af_p(ip1, 0));
484: m2 = MOD(af_p(ip1, 1));
485: /* Sanity check: register specs vs. opcode. */
486: opcode = ip1->i_op;
487: #if 1
488: /*
489: * Kludge flakey register references generated
490: * by the load table in n1/i386/tables/leaves.t.
491: * There must be a better way.
492: */
493: if ((opcode == ZMOVW && m2 == A_DR)
494: || (opcode == ZMOVB && (m2 == A_WR || m2 == A_DR))) {
495: ip1->i_af[1].a_mode &= ~A_AMOD;
496: ip1->i_af[1].a_mode |= (opcode == ZMOVW) ? A_WR : A_BR;
497: m2 = MOD(af_p(ip1, 1));
498: }
499: #endif
500: if (((opcode != ZMOV ) && ((m1 == A_DR) || (m2 == A_DR)))
501: || ((opcode != ZMOVW) && ((m1 == A_WR) || (m2 == A_WR)))
502: || ((opcode != ZMOVB) && ((m1 == A_BR) || (m2 == A_BR))))
503: aerr(ip1);
504: if (m2 == A_IMM) {
505: /* Immediate moves. */
506: if (m1 == A_DR) {
507: /* Immediate to dword register. */
508: asmab(0xB8 |
509: (REGM(af_p(ip1, 0))));
510: asmxl(af_p(ip1, 1), 0);
511: break;
512: } else if (m1 == A_BR) {
513: /* Immediate to byte register. */
514: asmab(0xB0 |
515: (REGM(af_p(ip1, 0))));
516: asmxb(af_p(ip1, 1), 0);
517: break;
518: } else if (m1 == A_WR) {
519: /* Immediate to word register. */
520: asmab(0xB8 |
521: (REGM(af_p(ip1, 0))));
522: asmxw(af_p(ip1, 1), 0);
523: break;
524: }
525: /* Immediate to memory. */
526: asmgen((0xC6 | (opbits&W)), 0, af_p(ip1, 0));
527: if ((opbits&W) == 0)
528: asmxb(af_p(ip1, 1), 0);
529: else if (!is16bit)
530: asmxl(af_p(ip1, 1), 0);
531: else
532: asmxw(af_p(ip1, 1), 0);
533: break;
534: }
535: if (isEAX(af_p(ip1, 0)) && m2==A_DIR) {
536: /* Direct to AL, AX, or EAX. */
537: asmab(0xA0 | (opbits&W));
538: asmxl(af_p(ip1, 1), 0);
539: break;
540: }
541: if (m1==A_DIR && isEAX(af_p(ip1, 1))) {
542: /* AL, AX or EAX to direct. */
543: asmab(0xA2 | (opbits&W));
544: asmxl(af_p(ip1, 0), 0);
545: break;
546: }
547: if (m1==A_DR || m1==A_WR || m1==A_BR) {
548: /* To dword, word or byte register. */
549: asmgen(opbits|D,
550: (REGM(af_p(ip1, 0)))<<3,
551: af_p(ip1, 1));
552: break;
553: }
554: if (m2==A_DR || m2==A_WR || m2==A_BR) {
555: /* From dword, word or byte register. */
556: asmgen(opbits,
557: (REGM(af_p(ip1, 1)))<<3,
558: af_p(ip1, 0));
559: break;
560: }
561: aerr(ip1);
562: break;
563:
564: case OF_MUL:
565: prefix = 0xF6 | (opbits&W);
566: opbits &= ~W;
567: asmgen(prefix, opbits, af_p(ip1, 0));
568: break;
569:
570: case OF_WORD:
571: case OF_BYTE:
572: case OF_LONG:
573: case OF_LPTR:
574: case OF_GPTR:
575: if ((MOD(af_p(ip1, 0))) != A_DIR)
576: aerr(ip1);
577: if (ostyle == OF_BYTE)
578: asmxb(af_p(ip1, 0), 0);
579: else if (ostyle == OF_WORD)
580: asmxw(af_p(ip1, 0), 0);
581: else
582: asmxl(af_p(ip1, 0), 0);
583: break;
584:
585: case OF_2B:
586: /*
587: * movsxw and movzxw do not take 16-bit operand prefix,
588: * hence do not have OP_WORD set in optab.c;
589: * now tell asmgen the operand is a 16-bit object.
590: */
591: if ((opinfop->op_flag & OP_BYTE) == 0)
592: is16bit = 1;
593: m1 = MOD(af_p(ip1, 0));
594: m2 = MOD(af_p(ip1, 1));
595: #if 0
596: if (m1 != A_DR || m2 == A_DR
597: || (is16bit && m2 == A_BR)
598: || (!is16bit && m2 == A_WR))
599: aerr(ip1);
600: #else
601: if (m1 != A_DR)
602: aerr(ip1);
603: /*
604: * Kludge flakey register references generated
605: * by the widen table in n1/i386/tables/leaves.t.
606: * There must be a better way.
607: */
608: if (m2 == A_DR) {
609: ip1->i_af[1].a_mode &= ~A_AMOD;
610: ip1->i_af[1].a_mode |= (is16bit) ? A_WR : A_BR;
611: }
612: #endif
613: asmab(ESC_2B);
614: asmgen(opbits,
615: (REGM(af_p(ip1, 0)))<<3,
616: af_p(ip1, 1));
617: break;
618:
619: /*
620: * 8087 or 80287 floating point operations.
621: * See comments preceding "asmfwait()" below.
622: */
623: case OF_FWAIT:
624: asmfwait();
625: break;
626:
627: case OF_FD9:
628: asmfop(0xD9, 0);
629: asmab(opbits);
630: break;
631:
632: case OF_FDD:
633: asmfop(0xDD, 0);
634: asmab(opbits);
635: break;
636:
637: case OF_FDE:
638: asmfop(0xDE, 0);
639: asmab(opbits);
640: break;
641:
642: case OF_FRM:
643: asmfop(ESC | (opbits & 0x07), 0);
644: asmgen(-1, opbits&0x38, af_p(ip1, 0));
645: break;
646:
647: default:
648: cbotch("cannot assemble %d", opcode);
649: }
650: }
651: }
652:
653: /*
654: * Output an effective address.
655: * Understands ModR/M byte and SIB and all that.
656: * An opcode of -1 is a flag that says don't put
657: * out the opcode and treat a register address field as an error.
658: * It is used for the 8087.
659: * The r field is preshifted left by 3 bits.
660: */
661: asmgen(op, r, afp) int op, r; register AFIELD *afp;
662: {
663: SIGNEDADDRESS disp;
664: int mode, regm, sib, sibflag;
665:
666: if (op >= 0)
667: asmab(op);
668: mode = MOD(afp);
669: regm = REGM(afp);
670: if (mode==A_IMM)
671: cbotch("asmgen op=%d r=%d mode=%d regm=%d",
672: op, r, mode, regm);
673: else if (mode==A_DR || mode==A_BR || mode==A_WR) {
674: /* Register: mod=11. */
675: if (op < 0)
676: cbotch("asmgen");
677: asmab(0xC0 | r | regm);
678: return;
679: } else if (mode == A_DIR) {
680: /* Direct: mod=00, r/m=5, 32-bit displacement. */
681: asmab(0x05 | r);
682: asmxl(afp, 0);
683: return;
684: }
685: /* Neither immediate nor register nor direct, must be symbol based or indexed. */
686: sibflag = (mode == A_XSIB);
687: if (sibflag) {
688: regm = 4; /* r/m=4 indicates SIB present */
689: sib = SIB(afp->a_mode); /* extract SIB contents */
690: if ((sib & A_REGM) == 5) {
691: /* SIB with no base, 32-bit displacement: mod=00. */
692: asmab(r | regm);
693: asmab(sib);
694: asmxl(afp, 0);
695: return;
696: }
697: }
698: if (afp->a_sp == NULL) {
699: /* Not symbol based. */
700: disp = afp->a_value;
701: if (disp == 0) {
702: /* No displacement, mod=00. */
703: if (regm != 5) {
704: asmab(r | regm);
705: if (sibflag)
706: asmab(sib);
707: return;
708: }
709: }
710: if (disp >= -128 && disp <= 127) {
711: /* 8-bit displacement, mod=01. */
712: asmab(0x40 | r | regm);
713: if (sibflag)
714: asmab(sib);
715: asmab(disp);
716: return;
717: }
718: /* Fall through for 32-bit displacement... */
719: }
720: /*
721: * Symbol based (always requires 4-byte value as relocation target)
722: * or indexed with 32-bit displacement, mod=10.
723: */
724: asmab(0x80 | r | regm);
725: if (sibflag)
726: asmab(sib);
727: asmxl(afp, 0);
728: }
729:
730: /*
731: * Output an absolute byte.
732: * Toss the byte away if this is not the second pass.
733: * Check for compiling code into the bss segment.
734: */
735: asmab(b) int b;
736: {
737: if (pass != 0) {
738: berr();
739: outab(b);
740: }
741: ++pc;
742: }
743:
744: /*
745: * Output an absolute word.
746: * Toss the word away if this is not the second pass.
747: * Check for compiling code into the bss segment.
748: */
749: asmaw(w) int w;
750: {
751: if (pass != 0) {
752: berr();
753: outaw(w);
754: }
755: pc += 2;
756: }
757:
758: /*
759: * Output an absolute dword (ival_t).
760: * Toss the word away if this is not the second pass.
761: * Check for compiling code into the bss segment.
762: */
763: asmal(i) ival_t i;
764: {
765: if (pass != 0) {
766: berr();
767: outal(i);
768: }
769: pc += 4;
770: }
771:
772: /*
773: * Output a general byte.
774: * The 'afp' argument is a pointer to an 'afield'.
775: * The 'flag' is true for pc relative addressing.
776: */
777: asmxb(afp, flag) register AFIELD *afp; int flag;
778: {
779: if (pass != 0) {
780: berr();
781: outxb(afp->a_sp, afp->a_value, flag);
782: }
783: ++pc;
784: }
785:
786: /*
787: * Output a general word.
788: * The 'afp' parameter is a pointer to an 'afield'.
789: * The 'flag' is true for pc relative addressing.
790: */
791: asmxw(afp, flag) register AFIELD *afp; int flag;
792: {
793: if (pass != 0) {
794: berr();
795: outxw(afp->a_sp, afp->a_value, flag);
796: }
797: pc += 2;
798: }
799:
800: /*
801: * Output a general word.
802: * The 'afp' parameter is a pointer to an 'afield'.
803: * The 'flag' is true for pc relative addressing.
804: */
805: asmxl(afp, flag) register AFIELD *afp; int flag;
806: {
807: if (pass != 0) {
808: berr();
809: outxl(afp->a_sp, afp->a_value, flag);
810: }
811: pc += 4;
812: }
813:
814: /*
815: * Notes on 8087 and 80287 opcode generation:
816: * The 8086 does not check the coprocessor BUSY line when it encounters
817: * a coprocessor escape (an 8087 opcode).
818: * Therefore, an FWAIT must precede every 8087 opcode.
819: * Sequences which require coprocessor synchronization
820: * (e.g., awaiting completion of store from 8087 to 8086 memory)
821: * can include explicit FWAITs which do not precede 8087 ops.
822: * The 80286 checks its coprocessor BUSY line when it sees an 80287 opcode.
823: * Therefore, the 80287 does not require an FWAIT before each 80287 opcode,
824: * but explicit FWAITs are still required for synchronization.
825: *
826: * If EMUFIXUPS is true when the compiler is built,
827: * the OMF output writer targets the FWAIT which precedes an 8087 opcode
828: * with a magic "M:..." fixup;
829: * this happens only in the OMF output writer n1/i8086/outomf.c.
830: * The linker can then create objects which use either 8087 hardware
831: * or software floating point emulation. In the latter case, the
832: * linker changes the 8087 instructions into traps to the emulator.
833: *
834: * If the compile-time variant VEMU87 is set,
835: * the compiler writes "call emu87" before each 8087 opcode
836: * and suppresses the leading FWAIT.
837: * The emulator "emu87" can execute "fwait; ret" or replace "call emu87" with
838: * "nop; nop; fwait" if an 8087 is actually present at runtime.
839: */
840:
841: /*
842: * Output an explicit FWAIT opcode for the 8087.
843: * The byte will be fiddled by an M:_WT fixup #if EMUFIXUPS.
844: */
845: asmfwait()
846: {
847: hasfloat = 1;
848: #if 0
849: if (isvariant(VEMU87)) {
850: asmemucall(); /* call emu87 */
851: return; /* and suppress the FWAIT */
852: }
853: #endif
854: if (pass != 0) {
855: berr();
856: outfb(WAIT);
857: }
858: ++pc;
859: }
860:
861: /*
862: * Output an 8087 opcode for the 8087.
863: * The "prefix" argument is just the A_PREFX code from the address.
864: * The opcode will be preceded by an FWAIT if necessary,
865: * and the FWAIT will be fiddled by an M:_W?S fixup #if EMUFIXUPS.
866: */
867: asmfop(op, prefix)
868: {
869: hasfloat = 1;
870: #if 0
871: if (isvariant(VEMU87)) {
872: asmemucall(); /* call emu87 */
873: if (pass != 0)
874: outfb(op); /* and suppress FWAIT */
875: pc++;
876: return;
877: }
878: #endif
879: if (pass != 0) {
880: berr();
881: outfb(op); /* no FWAIT for 80x87 */
882: }
883: pc++;
884: }
885:
886: #if 0
887: /*
888: * Assemble a call to the IEEE software floating point 8087 emulator.
889: */
890: asmemucall(){
891: if (pass != 0) {
892: berr();
893: outemucall();
894: }
895: pc += 5;
896: }
897:
898: /*
899: * Output a call to the 8087 emulator.
900: * Called from above and from genepilog (for FWAIT in epilog).
901: */
902: outemucall()
903: {
904: static SYM *emu87p;
905:
906: if (emu87p == NULL)
907: emu87p = glookup("emu87", 0);
908: outab(0x9A); /* far call */
909: outxl(emu87p, 0, 0); /* offset, absolute */
910: }
911: #endif
912:
913: /* Oops. */
914: aerr(ip1) register INS *ip1;
915: {
916: register SYM *sp;
917: register int i;
918:
919: printf("aerr: op=%d\n", ip1->i_op);
920: for (i = 0; i < ip1->i_naddr; ++i) {
921: printf("Operand %d:", i);
922: printf(" mode=%04x", ip1->i_af[i].a_mode);
923: printf(" offs=%d", ip1->i_af[i].a_value);
924: if ((sp=ip1->i_af[i].a_sp) != NULL) {
925: if ((sp->s_flag&S_LABNO) != 0)
926: printf(" off L%d", sp->s_labno);
927: else
928: printf(" off %s", sp->s_id);
929: }
930: printf("\n");
931: }
932: cbotch("aerr");
933: }
934:
935: /* BSS oops. */
936: berr()
937: {
938: if (pcseg == SBSS)
939: cbotch("bss");
940: }
941:
942: /* Return true if afp represents AL, AX or EAX. */
943: isEAX(afp) register AFIELD *afp;
944: {
945: register int mode;
946:
947: mode = afp->a_mode;
948: return (mode==A_REAX || mode==A_RAX || mode==A_RAL);
949: }
950:
951: /*
952: * This routine returns true if the argument AFIELD is a valid byte immediate,
953: * as used by the special s:w encoding on some instructions.
954: * This lets the assembler write imm8 (sign-extended by i386) rather than
955: * an imm32 or imm16.
956: * The legality of the mode and the fact that
957: * the AFIELD is an immediate have already been checked.
958: */
959: isimmbyte(afp) register AFIELD *afp;
960: {
961: register ADDRESS value;
962:
963: if (afp->a_sp == NULL) {
964: value = afp->a_value & 0xFFFFFF80L; /* top 25 bits */
965: if (value==0xFFFFFF80L || value==0L)
966: return 1;
967: }
968: return 0;
969: }
970:
971: /* end of n2/i386/asm.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.