--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#define RCSID0 "$Header$"
+
+/*
+ * INTEL 80386 options
+ */
+#define THREE_PASS /* branch and offset optimization */
+#define LISTING /* enable listing facilities */
+#define RELOCATION /* generate relocation info */
+#define DEBUG 2
+
+#undef valu_t
+#define valu_t long
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#define RCSID1 "$Header$"
+
+/*
+ * INTEL 80386 C declarations
+ */
+
+#define low6(z) (z & 077)
+#define fit6(z) (low6(z) == z)
+
+#define ufitb(z) ((unsigned)(z) <= 255)
+
+#define IS_R8 0x100
+#define IS_R32 0x200
+#define IS_EXPR 0x400
+#define IS_RSEG 0x800
+
+#define is_expr(reg) ((reg)&IS_EXPR)
+#define is_segreg(reg) ((reg)&IS_RSEG)
+#define is_reg(reg) (((reg)&(IS_R8|IS_R32)) != 0)
+#define is_acc(reg) (((reg)&(IS_R8|IS_R32)) == (reg))
+
+struct operand {
+ int mod;
+ int rm;
+ int reg;
+ int sib; /* scale-index-base */
+ expr_t exp;
+};
+
+extern struct operand op_1, op_2;
+
+#define mod_1 op_1.mod
+#define mod_2 op_2.mod
+#define rm_1 op_1.rm
+#define rm_2 op_2.rm
+#define reg_1 op_1.reg
+#define reg_2 op_2.reg
+#define sib_1 op_1.sib
+#define sib_2 op_2.sib
+#define exp_1 op_1.exp
+#define exp_2 op_2.exp
+
+#ifdef RELOCATION
+extern int rel_1, rel_2;
+#endif
+
+#ifndef extern
+extern char regindex_ind[8][8];
+#else
+/* First index is base register; second index is index register;
+ sp cannot be an index register.
+ For base and index register indirect mode, bp cannot be the
+ base register, but this info is not included in this array.
+ This can always be handled by using the base and index register with
+ displacement mode.
+*/
+char regindex_ind[8][8] = {
+ 000, 010, 020, 030, -1, 050, 060, 070,
+ 001, 011, 021, 031, -1, 051, 061, 071,
+ 002, 012, 022, 032, -1, 052, 062, 072,
+ 003, 013, 023, 033, -1, 053, 063, 073,
+ 004, 014, 024, 034, -1, 054, 064, 074,
+ 005, 015, 025, 035, -1, 055, 065, 075,
+ 006, 016, 026, 036, -1, 056, 066, 076,
+ 007, 017, 027, 037, -1, 057, 067, 077,
+};
+#endif
+
+extern int address_long INIT(1), operand_long INIT(1);
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#define RCSID2 "$Header$"
+
+/*
+ * INTEL 80386 tokens
+ */
+
+%token <y_word> R32
+%token <y_word> R16
+%token <y_word> R8
+%token <y_word> RSEG
+%token <y_word> RSYSCR
+%token <y_word> RSYSDR
+%token <y_word> RSYSTR
+%token <y_word> PREFIX
+%token <y_word> ADDOP
+%token <y_word> BITTEST
+%token <y_word> BOUND
+%token <y_word> CALFOP
+%token <y_word> CALLOP
+%token <y_word> ENTER
+%token <y_word> EXTEND
+%token <y_word> EXTOP
+%token <y_word> EXTOP1
+%token <y_word> IMUL
+%token <y_word> IMULB
+%token <y_word> INCOP
+%token <y_word> INT
+%token <y_word> IOOP
+%token <y_word> JOP
+%token <y_word> JOP2
+%token <y_word> LEAOP
+%token <y_word> LEAOP2
+%token <y_word> LSHFT
+%token <y_word> MOV
+%token <y_word> NOOP_1
+%token <y_word> NOOP_2
+%token <y_word> NOTOP
+%token <y_word> PUSHOP
+%token <y_word> RET
+%token <y_word> ROLOP
+%token <y_word> SETCC
+%token <y_word> TEST
+%token <y_word> XCHG
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#define RCSID3 "$Header$"
+
+/*
+ * INTEL 80386 keywords
+ *
+ * No system registers for now ...
+ */
+
+0, R32, 0, "ax",
+0, R32, 1, "cx",
+0, R32, 2, "dx",
+0, R32, 3, "bx",
+0, R32, 4, "sp",
+0, R32, 5, "bp",
+0, R32, 6, "si",
+0, R32, 7, "di",
+0, R32, 0, "eax",
+0, R32, 1, "ecx",
+0, R32, 2, "edx",
+0, R32, 3, "ebx",
+0, R32, 4, "esp",
+0, R32, 5, "ebp",
+0, R32, 6, "esi",
+0, R32, 7, "edi",
+0, R8, 0, "al",
+0, R8, 1, "cl",
+0, R8, 2, "dl",
+0, R8, 3, "bl",
+0, R8, 4, "ah",
+0, R8, 5, "ch",
+0, R8, 6, "dh",
+0, R8, 7, "bh",
+0, RSEG, 0, "es",
+0, RSEG, 1, "cs",
+0, RSEG, 2, "ss",
+0, RSEG, 3, "ds",
+0, RSEG, 4, "fs",
+0, RSEG, 5, "gs",
+0, RSYSCR, 0, "cr0",
+0, RSYSCR, 2, "cr2",
+0, RSYSCR, 3, "cr3",
+0, RSYSDR, 0, "dr0",
+0, RSYSDR, 1, "dr1",
+0, RSYSDR, 2, "dr2",
+0, RSYSDR, 3, "dr3",
+0, RSYSDR, 6, "dr6",
+0, RSYSDR, 7, "dr7",
+0, RSYSTR, 6, "tr6",
+0, RSYSTR, 7, "tr7",
+0, ADDOP, 000, "addb",
+0, ADDOP, 001, "add",
+0, ADDOP, 010, "orb",
+0, ADDOP, 011, "or",
+0, ADDOP, 020, "adcb",
+0, ADDOP, 021, "adc",
+0, ADDOP, 030, "sbbb",
+0, ADDOP, 031, "sbb",
+0, ADDOP, 040, "andb",
+0, ADDOP, 041, "and",
+0, ADDOP, 050, "subb",
+0, ADDOP, 051, "sub",
+0, ADDOP, 060, "xorb",
+0, ADDOP, 061, "xor",
+0, ADDOP, 070, "cmpb",
+0, ADDOP, 071, "cmp",
+0, BITTEST, 04, "bt",
+0, BITTEST, 05, "bts",
+0, BITTEST, 06, "btr",
+0, BITTEST, 07, "btc",
+0, CALFOP, 030+(0232<<8), "callf",
+0, CALFOP, 050+(0352<<8), "jmpf",
+0, CALLOP, 020+(0350<<8), "call",
+0, CALLOP, 040+(0351<<8), "jmp",
+0, ENTER, 0310, "enter",
+0, EXTEND, 0266, "movzx",
+0, EXTEND, 0276, "movsx",
+0, EXTOP, 0002, "lar",
+0, EXTOP, 0003, "lsl",
+0, EXTOP, 0274, "bsf",
+0, EXTOP, 0275, "bsr",
+0, EXTOP1, 0000, "sldt",
+0, EXTOP1, 0001, "sgdt",
+0, EXTOP1, 0010, "str",
+0, EXTOP1, 0011, "sidt",
+0, EXTOP1, 0020, "lldt",
+0, EXTOP1, 0021, "lgdt",
+0, EXTOP1, 0030, "ltr",
+0, EXTOP1, 0031, "lidt",
+0, EXTOP1, 0040, "verr",
+0, EXTOP1, 0041, "smsw",
+0, EXTOP1, 0050, "verw",
+0, EXTOP1, 0061, "lmsw",
+0, IMUL, 0, "imul",
+0, IMULB, 0, "imulb",
+0, INCOP, 000, "incb",
+0, INCOP, 001, "inc",
+0, INCOP, 010, "decb",
+0, INCOP, 011, "dec",
+0, INT, 0, "int",
+0, IOOP, 0344, "inb",
+0, IOOP, 0345, "in",
+0, IOOP, 0346, "outb",
+0, IOOP, 0347, "out",
+0, JOP, 0340, "loopne",
+0, JOP, 0340, "loopnz",
+0, JOP, 0341, "loope",
+0, JOP, 0341, "loopz",
+0, JOP, 0342, "loop",
+0, JOP, 0343, "jcxz",
+0, JOP, 0343, "jecxz",
+0, JOP2, 0000, "jo",
+0, JOP2, 0001, "jno",
+0, JOP2, 0002, "jb",
+0, JOP2, 0002, "jnae",
+0, JOP2, 0003, "jae",
+0, JOP2, 0003, "jnb",
+0, JOP2, 0004, "je",
+0, JOP2, 0004, "jz",
+0, JOP2, 0005, "jne",
+0, JOP2, 0005, "jnz",
+0, JOP2, 0006, "jbe",
+0, JOP2, 0006, "jna",
+0, JOP2, 0007, "ja",
+0, JOP2, 0007, "jnbe",
+0, JOP2, 0010, "js",
+0, JOP2, 0011, "jns",
+0, JOP2, 0012, "jp",
+0, JOP2, 0012, "jpe",
+0, JOP2, 0013, "jnp",
+0, JOP2, 0013, "jpo",
+0, JOP2, 0014, "jl",
+0, JOP2, 0014, "jnge",
+0, JOP2, 0015, "jge",
+0, JOP2, 0015, "jnl",
+0, JOP2, 0016, "jle",
+0, JOP2, 0016, "jng",
+0, JOP2, 0017, "jg",
+0, JOP2, 0017, "jnle",
+0, LEAOP, 0142, "bound",
+0, LEAOP, 0215, "lea",
+0, LEAOP, 0304, "les",
+0, LEAOP, 0305, "lds",
+0, LEAOP2, 0262, "lss",
+0, LEAOP2, 0264, "lfs",
+0, LEAOP2, 0265, "lgs",
+0, LSHFT, 0244, "shld",
+0, LSHFT, 0254, "shrd",
+0, MOV, 0, "movb",
+0, MOV, 1, "mov",
+0, NOOP_1, 0140, "pusha",
+0, NOOP_1, 0140, "pushad",
+0, NOOP_1, 0141, "popa",
+0, NOOP_1, 0141, "popad",
+0, NOOP_1, 0156, "outsb",
+0, NOOP_1, 0157, "outs",
+0, NOOP_1, 0220, "nop",
+0, NOOP_1, 0230, "cbw",
+0, NOOP_1, 0230, "cwde", /* same opcode as cbw! */
+0, NOOP_1, 0231, "cdq", /* same opcode as cwd! */
+0, NOOP_1, 0231, "cwd",
+0, NOOP_1, 0233, "wait",
+0, NOOP_1, 0234, "pushf",
+0, NOOP_1, 0235, "popf",
+0, NOOP_1, 0236, "sahf",
+0, NOOP_1, 0237, "lahf",
+0, NOOP_1, 0244, "movsb",
+0, NOOP_1, 0245, "movs",
+0, NOOP_1, 0246, "cmpsb",
+0, NOOP_1, 0246, "insb",
+0, NOOP_1, 0247, "cmps",
+0, NOOP_1, 0247, "ins",
+0, NOOP_1, 0252, "stosb",
+0, NOOP_1, 0253, "stos",
+0, NOOP_1, 0254, "lodsb",
+0, NOOP_1, 0255, "lods",
+0, NOOP_1, 0256, "scasb",
+0, NOOP_1, 0257, "scas",
+0, NOOP_1, 0311, "leave",
+0, NOOP_1, 0316, "into",
+0, NOOP_1, 0317, "iret",
+0, NOOP_1, 0317, "iretd",
+0, NOOP_1, 0327, "xlat",
+0, NOOP_1, 0364, "hlt",
+0, NOOP_1, 0365, "cmc",
+0, NOOP_1, 0370, "clc",
+0, NOOP_1, 0371, "stc",
+0, NOOP_1, 0372, "cli",
+0, NOOP_1, 0373, "sti",
+0, NOOP_1, 0374, "cld",
+0, NOOP_1, 0375, "std",
+0, NOOP_1, 047, "daa",
+0, NOOP_1, 057, "das",
+0, NOOP_1, 067, "aaa",
+0, NOOP_1, 077, "aas",
+0, NOOP_2, 017+06<<8, "clts",
+0, NOOP_2, 0324+012<<8, "aam",
+0, NOOP_2, 0325+012<<8, "aad",
+0, NOTOP, 020, "notb",
+0, NOTOP, 021, "not",
+0, NOTOP, 030, "negb",
+0, NOTOP, 031, "neg",
+0, NOTOP, 040, "mulb",
+0, NOTOP, 041, "mul",
+0, NOTOP, 060, "divb",
+0, NOTOP, 061, "div",
+0, NOTOP, 070, "idivb",
+0, NOTOP, 071, "idiv",
+0, PREFIX, 0144, "fseg",
+0, PREFIX, 0145, "gseg",
+0, PREFIX, 0146, "o16", /* operand size toggle */
+0, PREFIX, 0146, "o32", /* operand size toggle */
+0, PREFIX, 0147, "a16", /* address size toggle */
+0, PREFIX, 0147, "a32", /* address size toggle */
+0, PREFIX, 0360, "lock",
+0, PREFIX, 0362, "rep",
+0, PREFIX, 0362, "repne",
+0, PREFIX, 0362, "repnz",
+0, PREFIX, 0363, "repe",
+0, PREFIX, 0363, "repz",
+0, PREFIX, 046, "eseg",
+0, PREFIX, 056, "cseg",
+0, PREFIX, 066, "sseg",
+0, PREFIX, 076, "dseg",
+0, PUSHOP, 0, "push",
+0, PUSHOP, 1, "pop",
+0, RET, 0303, "ret",
+0, RET, 0313, "retf",
+0, ROLOP, 000, "rolb",
+0, ROLOP, 001, "rol",
+0, ROLOP, 010, "rorb",
+0, ROLOP, 011, "ror",
+0, ROLOP, 020, "rclb",
+0, ROLOP, 021, "rcl",
+0, ROLOP, 030, "rcrb",
+0, ROLOP, 031, "rcr",
+0, ROLOP, 040, "salb",
+0, ROLOP, 040, "shlb",
+0, ROLOP, 041, "sal",
+0, ROLOP, 041, "shl",
+0, ROLOP, 050, "shrb",
+0, ROLOP, 051, "shr",
+0, ROLOP, 070, "sarb",
+0, ROLOP, 071, "sar",
+0, SETCC, 0000, "seto",
+0, SETCC, 0001, "setno",
+0, SETCC, 0002, "setb",
+0, SETCC, 0002, "setnae",
+0, SETCC, 0003, "setae",
+0, SETCC, 0003, "setnb",
+0, SETCC, 0004, "sete",
+0, SETCC, 0004, "setz",
+0, SETCC, 0005, "setne",
+0, SETCC, 0005, "setnz",
+0, SETCC, 0006, "setbe",
+0, SETCC, 0006, "setna",
+0, SETCC, 0007, "seta",
+0, SETCC, 0007, "setnbe",
+0, SETCC, 0010, "sets",
+0, SETCC, 0011, "setns",
+0, SETCC, 0012, "setp",
+0, SETCC, 0012, "setpe",
+0, SETCC, 0013, "setnp",
+0, SETCC, 0013, "setpo",
+0, SETCC, 0014, "setl",
+0, SETCC, 0014, "setnge",
+0, SETCC, 0015, "setge",
+0, SETCC, 0015, "setnl",
+0, SETCC, 0016, "setle",
+0, SETCC, 0016, "setng",
+0, SETCC, 0017, "setg",
+0, SETCC, 0017, "setnle",
+0, TEST, 0, "testb",
+0, TEST, 1, "test",
+0, XCHG, 0, "xchgb",
+0, XCHG, 1, "xchg",
--- /dev/null
+#define RCSID4 "$Header$"
+
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ *
+ */
+
+operation
+ : { address_long = 1; operand_long = 1; }
+ prefix oper
+ ;
+prefix : /* empty */
+ | prefix PREFIX
+ { if ($2 == 0146) operand_long = ! operand_long;
+ if ($2 == 0147) address_long = ! address_long;
+ emit1($2);
+ }
+ ;
+oper : NOOP_1
+ { emit1($1);}
+ | NOOP_2
+ { emit2($1);}
+ | JOP expr
+ { branch($1,$2);}
+ | JOP2 expr
+ { ebranch($1,$2);}
+ | PUSHOP ea_1
+ { pushop($1);}
+ | IOOP absexp
+ { emit1($1);
+ fit(ufitb($2));
+ emit1((int)$2);
+ }
+ | IOOP R32
+ { if ($2!=2) serror("register error");
+ emit1($1+010);
+ }
+ | BITTEST ea_ea
+ { bittestop($1);}
+ | BOUND R32 ',' mem
+ { emit1($1); ea_2($2<<3); }
+ | ADDOP ea_ea
+ { addop($1);}
+ | ROLOP ea_ea
+ { rolop($1);}
+ | INCOP ea_1
+ { incop($1);}
+ | NOTOP ea_1
+ { regsize($1); emit1(0366|($1&1)); ea_1($1&070);}
+ | CALLOP ea_1
+ { callop($1&0xFFFF);}
+ | CALFOP expr ':' expr
+ { emit1($1>>8);
+#ifdef RELOCATION
+ newrelo($4.typ, RELO4);
+#endif
+ emit4((long)($4.val));
+#ifdef RELOCATION
+ newrelo($2.typ, RELO2);
+#endif
+ emit2((int)($2.val));
+ }
+ | CALFOP mem
+ { emit1(0377); ea_2($1&0xFF);}
+ | ENTER absexp ',' absexp
+ { fit(fitw($2)); fit(fitb($4));
+ emit1($1); emit2((int)$2); emit1((int)$4);
+ }
+ | LEAOP R32 ',' mem
+ { emit1($1); ea_2($2<<3);}
+ | LEAOP2 R32 ',' mem
+ { emit1(0xF); emit1($1); ea_2($2<<3);}
+ | LSHFT ea_1 ',' R32 ',' ea_2
+ { extshft($1, $4);}
+ | EXTEND R32 ',' ea_2
+ { emit1(0xF); emit1($1|1); ea_2($2<<3);}
+ | EXTOP R32 ',' ea_2
+ { emit1(0xF); emit1($1); ea_2($2<<3);}
+ | EXTOP1 ea_1
+ { emit1(0xF); emit1($1&07); ea_1($1&070);}
+ | IMULB ea_1
+ { regsize(0); emit1(0366); ea_1($1&070);}
+ | IMUL ea_2
+ { reg_1 = IS_R32; imul(0); }
+ | IMUL R32 ',' ea_2
+ { reg_1 = $2 | IS_R32; imul($2); }
+ | IMUL R32 ',' ea_ea
+ { imul($2);}
+ | INT absexp
+ { if ($2==3)
+ emit1(0314);
+ else {
+ fit(ufitb($2));
+ emit1(0315); emit1((int)$2);
+ }
+ }
+ | RET
+ { emit1($1);}
+ | RET expr
+ { emit1($1-1);
+#ifdef RELOCATION
+ newrelo($2.typ, RELO2);
+#endif
+ emit2((int)($2.val));
+ }
+ | SETCC ea_2
+ { emit1(0xF); emit1($1); ea_2(0);}
+ | XCHG ea_ea
+ { xchg($1);}
+ | TEST ea_ea
+ { test($1);}
+ | MOV ea_ea
+ { mov($1);}
+ | /* What is really needed is just
+ MOV R32 ',' RSYSCR
+ but this gives a bad yacc conflict
+ */
+ MOV ea_1 ',' RSYSCR
+ {
+ if ($1 != 1 || !(reg_1 & IS_R32))
+ serror("syntax error");
+ emit1(0xF); emit1(042); emit1(0200|($4<<3)|(reg_1&07));}
+ | MOV ea_1 ',' RSYSDR
+ {
+ if ($1 != 1 || !(reg_1 & IS_R32))
+ serror("syntax error");
+ emit1(0xF); emit1(043); emit1(0200|($4<<3)|(reg_1&07));}
+ | MOV ea_1 ',' RSYSTR
+ {
+ if ($1 != 1 || !(reg_1 & IS_R32))
+ serror("syntax error");
+ emit1(0xF); emit1(046); emit1(0200|($4<<3)|(reg_1&07));}
+ | MOV RSYSCR ',' R32
+ {
+ if ($1 != 1) serror("syntax error");
+ emit1(0xF); emit1(040); emit1(0200|($4<<3)|$2);}
+ | MOV RSYSDR ',' R32
+ {
+ if ($1 != 1) serror("syntax error");
+ emit1(0xF); emit1(041); emit1(0200|($4<<3)|$2);}
+ | MOV RSYSTR ',' R32
+ {
+ if ($1 != 1) serror("syntax error");
+ emit1(0xF); emit1(044); emit1(0200|($4<<3)|$2);}
+ ;
+mem : '(' expr ')'
+ { rm_2 = 05; exp_2 = $2; reg_2 = 05; mod_2 = 0;
+ RELOMOVE(rel_2, relonami);
+ }
+ | bases
+ { exp_2.val = 0; exp_2.typ = S_ABS; indexed();}
+ | expr bases
+ { exp_2 = $1; indexed();
+ RELOMOVE(rel_2, relonami);
+ }
+ ;
+bases : '(' R32 ')'
+ { reg_2 = $2; sib_2 = 0; rm_2 = 0;}
+ | '(' R32 ')' '(' R32 scale ')'
+ { rm_2 = 04; sib_2 |= regindex_ind[$2][$5];
+ reg_2 = $2;
+ }
+ | '(' R32 '*' absexp ')'
+ { if ($4 == 1) {
+ reg_2 = $2; sib_2 = 0; rm_2 = 0;
+ }
+ else {
+ rm_2 = 04;
+ sib_2 = checkscale($4) | regindex_ind[05][$2];
+ reg_2 = 015;
+ }
+ }
+ ;
+scale : /* empty */
+ { sib_2 = 0;}
+ | '*' absexp
+ { sib_2 = checkscale($2);}
+ ;
+ea_2 : mem
+ | R8
+ { reg_2 = $1 | IS_R8; rm_2 = 0;}
+ | R32
+ { reg_2 = $1 | IS_R32; rm_2 = 0;}
+ | RSEG
+ { reg_2 = $1 | IS_RSEG; rm_2 = 0;}
+ | expr
+ { reg_2 = IS_EXPR; exp_2 = $1; rm_2 = 0;
+ RELOMOVE(rel_2, relonami);
+ }
+ ;
+ea_1 : ea_2
+ { op_1 = op_2;
+ RELOMOVE(rel_1, rel_2);
+ }
+ ;
+ea_ea : ea_1 ',' ea_2
+ ;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#define RCSID5 "$Header$"
+
+/*
+ * INTEL 80386 special routines
+ */
+
+ea_1(param) {
+ if (is_expr(reg_1)) {
+ serror("bad operand");
+ return;
+ }
+ if (is_reg(reg_1)) {
+ switch(reg_1&07) {
+ case 4:
+ emit1(0300 | param | 04);
+ emit1(0300 | 0100);
+ default:
+ emit1(0300 | param | (reg_1&07));
+ }
+ return;
+ }
+ if (rm_1 == 04) {
+ /* sib field use here */
+ emit1(mod_1 << 6 | param | 04);
+ emit1(sib_1 | reg_1);
+ if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
+#ifdef RELOCATION
+ RELOMOVE(relonami, rel_1);
+ newrelo(exp_1.typ, RELO4);
+#endif
+ emit4((long)(exp_1.val));
+ }
+ else if (mod_1 == 1) emit1((int)(exp_1.val));
+ return;
+ }
+ emit1(mod_1<<6 | param | (reg_1&07));
+ if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
+#ifdef RELOCATION
+ RELOMOVE(relonami, rel_1);
+ newrelo(exp_1.typ, RELO4);
+#endif
+ emit4((long)(exp_1.val));
+ }
+ else if (mod_1 == 1) {
+ emit1((int)(exp_1.val));
+ }
+}
+
+ea_2(param) {
+
+ op_1 = op_2;
+ RELOMOVE(rel_1, rel_2);
+ ea_1(param);
+}
+
+int
+checkscale(val)
+ valu_t val;
+{
+ int v = val;
+
+ if (v != val) v = 0;
+ switch(v) {
+ case 1:
+ return 0;
+ case 2:
+ return 1 << 6;
+ case 4:
+ return 2 << 6;
+ case 8:
+ return 3 << 6;
+ default:
+ serror("bad scale");
+ return 0;
+ }
+ /*NOTREACHED*/
+}
+
+reverse() {
+ struct operand op;
+#ifdef RELOCATION
+ int r = rel_1;
+
+ rel_1 = rel_2; rel_2 = r;
+#endif
+ op = op_1; op_1 = op_2; op_2 = op;
+}
+
+badsyntax() {
+
+ serror("bad operands");
+}
+
+regsize(sz)
+ int sz;
+{
+ register int bit;
+
+ bit = (sz&1) ? 0 : IS_R8;
+ if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
+ (is_reg(reg_2) && (reg_2 & IS_R8) != bit))
+ serror("register error");
+}
+
+indexed() {
+ mod_2 = 0;
+ if (sib_2 == -1)
+ serror("register error");
+ if (rm_2 == 0 && reg_2 == 4) {
+ /* base register sp, no index register; use
+ indexed mode without index register
+ */
+ rm_2 = 04;
+ sib_2 = 044;
+ }
+ if (reg_2 == 015) {
+ reg_2 = 05;
+ return;
+ }
+ if (exp_2.typ != S_ABS || fitb(exp_2.val) == 0)
+ mod_2 = 02;
+ else if (exp_2.val != 0 || reg_2 == 5)
+ mod_2 = 01;
+}
+
+ebranch(opc,exp)
+ register int opc;
+ expr_t exp;
+{
+ /* Conditional branching; Full displacements are available
+ on the 80386, so the welknown trick with the reverse branch
+ over a jump is not needed here.
+ The only complication here is with the address size, which
+ can be set with a prefix. In this case, the user gets what
+ he asked for.
+ */
+ register int sm;
+ register long dist;
+ int saving = address_long ? 4 : 2;
+
+ dist = exp.val - (DOTVAL + 2);
+ if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
+ dist -= DOTGAIN;
+ sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
+ if ((exp.typ & ~S_DOT) != DOTTYP)
+ sm = 0;
+ if ((sm = small(sm,saving)) == 0) {
+ emit1(0xF);
+ emit1(opc | 0x80);
+ dist -= 2;
+ exp.val = dist;
+ adsize_exp(exp);
+ }
+ else {
+ emit1(opc | 0x70);
+ emit1((int)dist);
+ }
+}
+
+branch(opc,exp)
+ register int opc;
+ expr_t exp;
+{
+ /* LOOP, JCXZ, etc. branch instructions.
+ Here, the offset just must fit in a byte.
+ */
+ register long dist;
+
+ dist = exp.val - (DOTVAL + 2);
+ if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
+ dist -= DOTGAIN;
+ fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
+ emit1(opc);
+ emit1((int)dist);
+}
+
+pushop(opc)
+ register int opc;
+{
+
+ regsize(1);
+ if (is_segreg(reg_1)) {
+ /* segment register */
+ if ((reg_1 & 07) <= 3)
+ emit1(6 | opc | (reg_1&7)<<3);
+ else {
+ emit1(0xF);
+ emit1(0200 | opc | ((reg_1&7)<<3));
+ }
+ } else if (is_reg(reg_1)) {
+ /* normal register */
+ emit1(0120 | opc<<3 | (reg_1&7));
+ } else if (opc == 0) {
+ if (is_expr(reg_1)) {
+ if (exp_1.typ == S_ABS && fitb(exp_1.val)) {
+ emit1(0152);
+ emit1((int)(exp_1.val));
+ }
+ else {
+ emit1(0150);
+ RELOMOVE(relonami, rel_1);
+ opsize_exp(exp_1, 1);
+ }
+ }
+ else {
+ emit1(0377); ea_1(6<<3);
+ }
+ } else {
+ emit1(0217); ea_1(0<<3);
+ }
+}
+
+opsize_exp(exp, nobyte)
+ expr_t exp;
+{
+ if (! nobyte) {
+#ifdef RELOCATION
+ newrelo(exp.typ, RELO1);
+#endif
+ emit1((int)(exp.val));
+ }
+ else if (operand_long) {
+#ifdef RELOCATION
+ newrelo(exp.typ, RELO4);
+#endif
+ emit4((long)(exp.val));
+ }
+ else {
+#ifdef RELOCATION
+ newrelo(exp.typ, RELO2);
+#endif
+ emit2((int)(exp.val));
+ }
+}
+
+adsize_exp(exp)
+ expr_t exp;
+{
+ if (address_long) {
+#ifdef RELOCATION
+ newrelo(exp.typ, RELO4 | RELPC);
+#endif
+ emit4((long)(exp.val));
+ }
+ else {
+ if (! fitw(exp.val)) {
+ warning("offset does not fit in 2 bytes; remove prefix");
+ }
+#ifdef RELOCATION
+ newrelo(exp.typ, RELO2 | RELPC);
+#endif
+ emit2((int)(exp.val));
+ }
+}
+
+addop(opc)
+ register int opc;
+{
+
+ regsize(opc);
+ if (is_reg(reg_2)) {
+ /* Add register to register or memory */
+ emit1(opc); ea_1((reg_2&7)<<3);
+ } else if (is_acc(reg_1) && is_expr(reg_2)) {
+ /* Add immediate to accumulator */
+ emit1(opc | 4);
+ RELOMOVE(relonami, rel_2);
+ opsize_exp(exp_2, (opc&1));
+ } else if (is_expr(reg_2)) {
+ /* Add immediate to register or memory */
+ if ((opc&1) == 0) {
+ emit1(0200);
+ } else if (exp_2.typ != S_ABS || fitb(exp_2.val) == 0) {
+ emit1(0201);
+ } else {
+ emit1(0203); opc &= ~1;
+ }
+ ea_1(opc & 070);
+ RELOMOVE(relonami, rel_2);
+ opsize_exp(exp_2, (opc&1));
+ } else if (is_reg(reg_1)) {
+ /* Add register or memory to register */
+ emit1(opc | 2);
+ ea_2((reg_1&7)<<3);
+ } else
+ badsyntax();
+}
+
+rolop(opc)
+ register int opc;
+{
+ register int oreg;
+
+ oreg = reg_2;
+ reg_2 = reg_1;
+ regsize(opc);
+ if (oreg == (IS_R8 | 1)) {
+ /* cl register */
+ emit1(0322 | (opc&1)); ea_1(opc&070);
+ } else if (is_expr(oreg) && exp_2.typ == S_ABS && exp_2.val == 1) {
+ /* shift by 1 */
+ emit1(0320 | (opc&1)); ea_1(opc&070);
+ } else if (is_expr(oreg)) {
+ /* shift by byte count */
+ emit1(0300 | (opc & 1));
+ ea_1(opc & 070);
+#ifdef RELOCATION
+ RELOMOVE(relonami, rel_2);
+ newrelo(exp_2.typ, RELO1);
+#endif
+ emit1((int)(exp_2.val));
+ }
+ else
+ badsyntax();
+}
+
+incop(opc)
+ register int opc;
+{
+
+ regsize(opc);
+ if ((opc&1) && is_reg(reg_1)) {
+ /* word register */
+ emit1(0100 | (opc&010) | (reg_1&7));
+ } else {
+ emit1(0376 | (opc&1));
+ ea_1(opc & 010);
+ }
+}
+
+callop(opc)
+ register int opc;
+{
+
+ regsize(1);
+ if (is_expr(reg_1)) {
+ if (opc == (040+(0351<<8))) {
+ RELOMOVE(relonami, rel_1);
+ ebranch(0353,exp_1);
+ } else {
+ exp_1.val -= (DOTVAL+3);
+ emit1(opc>>8);
+ RELOMOVE(relonami, rel_1);
+ adsize_exp(exp_1);
+ }
+ } else {
+ emit1(0377); ea_1(opc&070);
+ }
+}
+
+xchg(opc)
+ register int opc;
+{
+
+ regsize(opc);
+ if (! is_reg(reg_1) || is_acc(reg_2)) {
+ reverse();
+ }
+ if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
+ emit1(0220 | (reg_2&7));
+ } else if (is_reg(reg_1)) {
+ emit1(0206 | opc); ea_2((reg_1&7)<<3);
+ } else
+ badsyntax();
+}
+
+test(opc)
+ register int opc;
+{
+
+ regsize(opc);
+ if (is_reg(reg_2) || is_expr(reg_1))
+ reverse();
+ if (is_expr(reg_2)) {
+ if (is_acc(reg_1)) {
+ emit1(0250 | opc);
+ RELOMOVE(relonami, rel_2);
+ opsize_exp(exp_2, (opc&1));
+ }
+ else {
+ emit1(0366 | opc);
+ ea_1(0<<3);
+ RELOMOVE(relonami, rel_2);
+ opsize_exp(exp_2, (opc&1));
+ }
+ } else if (is_reg(reg_1)) {
+ emit1(0204 | opc); ea_2((reg_1&7)<<3);
+ } else
+ badsyntax();
+}
+
+mov(opc)
+ register int opc;
+{
+
+ regsize(opc);
+ if (is_segreg(reg_1)) {
+ /* to segment register */
+ emit1(0216); ea_2((reg_1&3)<<3);
+ } else if (is_segreg(reg_2)) {
+ /* from segment register */
+ emit1(0214); ea_1((reg_2&3)<<3);
+ } else if (is_expr(reg_2)) {
+ /* from immediate */
+ if (is_reg(reg_1)) {
+ /* to register */
+ emit1(0260 | opc<<3 | (reg_1&7));
+ } else {
+ /* to memory */
+ emit1(0306 | opc); ea_1(0<<3);
+ }
+ RELOMOVE(relonami, rel_2);
+ opsize_exp(exp_2, (opc&1));
+ } else if (rm_1 == 05 && is_acc(reg_2)) {
+ /* from accumulator to memory (displacement) */
+ emit1(0242 | opc);
+ RELOMOVE(relonami, rel_1);
+ adsize_exp(exp_1);
+ } else if (rm_2 == 05 && is_acc(reg_1)) {
+ /* from memory (displacement) to accumulator */
+ emit1(0240 | opc);
+ RELOMOVE(relonami, rel_2);
+ adsize_exp(exp_2);
+ } else if (is_reg(reg_2)) {
+ /* from register to memory or register */
+ emit1(0210 | opc); ea_1((reg_2&7)<<3);
+ } else if (is_reg(reg_1)) {
+ /* from memory or register to register */
+ emit1(0212 | opc); ea_2((reg_1&7)<<3);
+ } else
+ badsyntax();
+}
+
+extshft(opc, reg)
+ int opc;
+{
+ int oreg2 = reg_2;
+
+ reg_2 = reg_1;
+ regsize(1);
+
+ emit1(0xF);
+ if (oreg2 == (IS_R8 | 1)) {
+ /* cl register */
+ emit1(opc|1);
+ ea_1(reg << 3);
+ }
+ else if (is_expr(oreg2)) {
+ emit1(opc);
+ ea_1(reg << 3);
+#ifdef RELOCATION
+ RELOMOVE(relonami, rel_2);
+ newrelo(exp_2.typ, RELO1);
+#endif
+ emit1((int)(exp_2.val));
+ }
+ else badsyntax();
+}
+
+bittestop(opc)
+ int opc;
+{
+ regsize(1);
+ emit1(0xF);
+ if (is_expr(reg_2)) {
+ emit1(0272);
+ ea_1(opc << 3);
+#ifdef RELOCATION
+ RELOMOVE(relonami, rel_2);
+ newrelo(exp_2.typ, RELO1);
+#endif
+ emit1((int)(exp_2.val));
+ }
+ else if (is_reg(reg_2)) {
+ emit1(0203 | opc);
+ ea_1((reg_2&7)<<3);
+ }
+ else badsyntax();
+}
+
+imul(reg)
+ int reg;
+{
+ /* This instruction is more elaborate on the 80386. Its most
+ general form is:
+ imul reg, reg_or_mem, immediate.
+ This is the form processed here.
+ */
+ regsize(1);
+ if (is_expr(reg_1)) {
+ /* To also handle
+ imul reg, immediate, reg_or_mem
+ */
+ reverse();
+ }
+ if (is_expr(reg_2)) {
+ /* The immediate form; two cases: */
+ if (exp_2.typ == S_ABS && fitb(exp_2.val)) {
+ /* case 1: 1 byte encoding of immediate */
+ emit1(0153);
+ ea_1(reg << 3);
+ emit1((int)(exp_2.val));
+ }
+ else {
+ /* case 2: WORD or DWORD encoding of immediate */
+ emit1(0151);
+ ea_1(reg << 3);
+ RELOMOVE(relonami, rel_2);
+ opsize_exp(exp_2, 1);
+ }
+ }
+ else if (is_reg(reg_1) && ((reg_1&7) == reg)) {
+ /* the "reg" field and the "reg_or_mem" field are the same,
+ and the 3rd operand is not an immediate ...
+ */
+ if (reg == 0) {
+ /* how lucky we are, the target is the ax register */
+ emit1(0367);
+ ea_2(06 << 3);
+ }
+ else {
+ /* another register ... */
+ emit1(0xF);
+ emit1(0257);
+ ea_2(reg << 3);
+ }
+ }
+ else badsyntax();
+}