From 6833adfb502a8a9fdae004348a539a5066e1edf7 Mon Sep 17 00:00:00 2001 From: ceriel Date: Thu, 19 Jan 1989 16:20:46 +0000 Subject: [PATCH] Initial revision --- mach/i386/as/mach0.c | 16 ++ mach/i386/as/mach1.c | 73 ++++++ mach/i386/as/mach2.c | 47 ++++ mach/i386/as/mach3.c | 279 ++++++++++++++++++++++ mach/i386/as/mach4.c | 198 ++++++++++++++++ mach/i386/as/mach5.c | 533 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1146 insertions(+) create mode 100644 mach/i386/as/mach0.c create mode 100644 mach/i386/as/mach1.c create mode 100644 mach/i386/as/mach2.c create mode 100644 mach/i386/as/mach3.c create mode 100644 mach/i386/as/mach4.c create mode 100644 mach/i386/as/mach5.c diff --git a/mach/i386/as/mach0.c b/mach/i386/as/mach0.c new file mode 100644 index 000000000..6721a6f84 --- /dev/null +++ b/mach/i386/as/mach0.c @@ -0,0 +1,16 @@ +/* + * (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 diff --git a/mach/i386/as/mach1.c b/mach/i386/as/mach1.c new file mode 100644 index 000000000..981d7bd5a --- /dev/null +++ b/mach/i386/as/mach1.c @@ -0,0 +1,73 @@ +/* + * (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); diff --git a/mach/i386/as/mach2.c b/mach/i386/as/mach2.c new file mode 100644 index 000000000..303e648c2 --- /dev/null +++ b/mach/i386/as/mach2.c @@ -0,0 +1,47 @@ +/* + * (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 R32 +%token R16 +%token R8 +%token RSEG +%token RSYSCR +%token RSYSDR +%token RSYSTR +%token PREFIX +%token ADDOP +%token BITTEST +%token BOUND +%token CALFOP +%token CALLOP +%token ENTER +%token EXTEND +%token EXTOP +%token EXTOP1 +%token IMUL +%token IMULB +%token INCOP +%token INT +%token IOOP +%token JOP +%token JOP2 +%token LEAOP +%token LEAOP2 +%token LSHFT +%token MOV +%token NOOP_1 +%token NOOP_2 +%token NOTOP +%token PUSHOP +%token RET +%token ROLOP +%token SETCC +%token TEST +%token XCHG diff --git a/mach/i386/as/mach3.c b/mach/i386/as/mach3.c new file mode 100644 index 000000000..c2be16b75 --- /dev/null +++ b/mach/i386/as/mach3.c @@ -0,0 +1,279 @@ +/* + * (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", diff --git a/mach/i386/as/mach4.c b/mach/i386/as/mach4.c new file mode 100644 index 000000000..b8da7279e --- /dev/null +++ b/mach/i386/as/mach4.c @@ -0,0 +1,198 @@ +#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 + ; diff --git a/mach/i386/as/mach5.c b/mach/i386/as/mach5.c new file mode 100644 index 000000000..1bc9eb9d9 --- /dev/null +++ b/mach/i386/as/mach5.c @@ -0,0 +1,533 @@ +/* + * (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(); +} -- 2.34.1