123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- /*
- * (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 "$Id$"
- /*
- * INTEL 80386 special routines
- */
- ea_1_16(param)
- {
- reg_1 &= 0377;
- if ((reg_1 & 070) || (param & ~070)) {
- serror("bad operand");
- }
- emit1(reg_1 | param);
- switch(reg_1 >> 6) {
- case 0:
- if (reg_1 == 6 || (reg_1 & 040)) {
- #ifdef RELOCATION
- RELOMOVE(relonami, rel_1);
- newrelo(exp_1.typ, RELO2);
- #endif
- emit2(exp_1.val);
- }
- break;
- case 1:
- emit1(exp_1.val);
- break;
- case 2:
- #ifdef RELOCATION
- RELOMOVE(relonami, rel_1);
- newrelo(exp_1.typ, RELO2);
- #endif
- emit2(exp_1.val);
- break;
- }
- }
- ea_1(param) {
- if (! address_long) {
- ea_1_16(param);
- return;
- }
- if (is_expr(reg_1)) {
- serror("bad operand");
- return;
- }
- if (is_reg(reg_1)) {
- 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);
- }
- else emit1(mod_1<<6 | param | (reg_1&07));
- if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
- /* ??? should this be protected by a call to "small" ??? */
- #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 (! address_long) {
- serror("scaling not allowed in 16-bit mode");
- return 0;
- }
- 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");
- if (! address_long) {
- reg_1 &= ~010;
- reg_2 &= ~010;
- }
- }
- indexed() {
- if (address_long) {
- 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 (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
- if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
- }
- else mod_2 = 01;
- }
- else if (small(0, 1)) {
- }
- else mod_2 = 02;
- }
- else {
- if (reg_2 & ~7)
- serror("register error");
- if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
- if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
- }
- else reg_2 |= 0100;
- }
- else if (small(0, 1)) {
- }
- else reg_2 |= 0200;
- }
- }
- 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;
- if (opc == 0353) saving--;
- 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) {
- if (opc == 0353) {
- emit1(0xe9);
- }
- else {
- emit1(0xF);
- emit1(opc | 0x80);
- }
- dist -= saving;
- exp.val = dist;
- adsize_exp(exp, RELPC);
- }
- else {
- if (opc == 0353) {
- emit1(opc);
- }
- 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 (small(exp_1.typ == S_ABS && fitb(exp_1.val),
- operand_long ? 3 : 1)) {
- 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, relpc)
- expr_t exp;
- {
- if (address_long) {
- #ifdef RELOCATION
- newrelo(exp.typ, RELO4 | relpc);
- #endif
- emit4((long)(exp.val));
- }
- else {
- #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 (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
- operand_long ? 3 : 1)) {
- 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 | (address_long ? 0 : 0300))) {
- /* cl register */
- emit1(0322 | (opc&1)); ea_1(opc&070);
- } else if (is_expr(oreg)) {
- if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
- /* shift by 1 */
- emit1(0320 | (opc&1)); ea_1(opc&070);
- } else {
- /* 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 + (address_long ? 2 : 0));
- emit1(opc>>8);
- RELOMOVE(relonami, rel_1);
- adsize_exp(exp_1, RELPC);
- }
- } 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&07)<<3);
- } else if (is_segreg(reg_2)) {
- /* from segment register */
- emit1(0214); ea_1((reg_2&07)<<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, 0);
- } 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, 0);
- } else if (is_reg(reg_2)) {
- /* from register to memory or register */
- emit1(0210 | opc); ea_1((reg_2&07)<<3);
- } else if (is_reg(reg_1)) {
- /* from memory or register to register */
- emit1(0212 | opc); ea_2((reg_1&07)<<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 | (address_long ? 0 : 0300))) {
- /* 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<<3));
- 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 (small(exp_2.typ == S_ABS && fitb(exp_2.val),
- operand_long ? 3 : 1)) {
- /* case 1: 1 byte encoding of immediate */
- emit1(0153);
- ea_1((reg & 07) << 3);
- emit1((int)(exp_2.val));
- }
- else {
- /* case 2: WORD or DWORD encoding of immediate */
- emit1(0151);
- ea_1((reg & 07) << 3);
- RELOMOVE(relonami, rel_2);
- opsize_exp(exp_2, 1);
- }
- }
- else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
- /* 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 */
- /* However, we cannot make an optimization for f.i.
- imul eax, blablabla
- because the latter does not affect edx, whereas
- imul blablabla
- does! Therefore, "reg" is or-ed with 0x10 in the
- former case, so that the test above fails.
- */
- emit1(0367);
- ea_2(050);
- }
- else {
- /* another register ... */
- emit1(0xF);
- emit1(0257);
- ea_2((reg & 07) << 3);
- }
- }
- else badsyntax();
- }
|