blob: 76cf43934b1a5391d46aa51196b312120fb67a5d [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvinfea84d72010-05-06 15:32:20 -07003 * Copyright 1996-2010 The NASM Authors - All Rights Reserved
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07004 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
Cyrill Gorcunov1de95002009-11-06 00:08:38 +030017 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -070018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * assemble.c code generation for the Netwide Assembler
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036 *
37 * the actual codes (C syntax, i.e. octal):
38 * \0 - terminates the code. (Unless it's a literal of course.)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040039 * \1..\4 - that many literal bytes follow in the code stream
H. Peter Anvindcffe4b2008-10-10 22:10:31 -070040 * \5 - add 4 to the primary operand number (b, low octdigit)
41 * \6 - add 4 to the secondary operand number (a, middle octdigit)
42 * \7 - add 4 to both the primary and the secondary operand number
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070043 * \10..\13 - a literal byte follows in the code stream, to be added
44 * to the register value of operand 0..3
45 * \14..\17 - a signed byte immediate operand, from operand 0..3
46 * \20..\23 - a byte immediate operand, from operand 0..3
47 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
48 * \30..\33 - a word immediate operand, from operand 0..3
49 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000050 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070051 * \40..\43 - a long immediate operand, from operand 0..3
52 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040053 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070054 * \50..\53 - a byte relative operand, from operand 0..3
55 * \54..\57 - a qword immediate operand, from operand 0..3
56 * \60..\63 - a word relative operand, from operand 0..3
57 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000058 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070059 * \70..\73 - a long relative operand, from operand 0..3
H. Peter Anvinc1377e92008-10-06 23:40:31 -070060 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000061 * \1ab - a ModRM, calculated on EA in operand a, with the spare
62 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070063 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080064 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040065 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvinc1377e92008-10-06 23:40:31 -070066 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080067 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040068 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070069 * \160..\163 - this instruction uses DREX rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040070 * OC0 field set to 0, and the dest field taken from
H. Peter Anvin401c07e2007-09-17 16:55:04 -070071 * operand 0..3.
72 * \164..\167 - this instruction uses DREX rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040073 * OC0 field set to 1, and the dest field taken from
H. Peter Anvin401c07e2007-09-17 16:55:04 -070074 * operand 0..3.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040075 * \171 - placement of DREX suffix in the absence of an EA
76 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070077 * the 4-bit immediate from operand b in bits 3..0.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040078 * \173\xab - the register number from operand a in bits 7..4, with
79 * the value b in bits 3..0.
80 * \174\a - the register number from operand a in bits 7..4, and
81 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000082 * \2ab - a ModRM, calculated on EA in operand a, with the spare
83 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070084 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
85 * is not equal to the truncated and sign-extended 32-bit
86 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvin588df782008-10-07 10:05:10 -070087 * \254..\257 - a signed 32-bit operand to be extended to 64 bits.
H. Peter Anvina04019c2009-05-03 21:42:34 -070088 * \260..\263 - this instruction uses VEX/XOP rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040089 * V field taken from operand 0..3.
90 * \270 - this instruction uses VEX/XOP rather than REX, with the
91 * V field set to 1111b.
H. Peter Anvind85d2502008-05-04 17:53:31 -070092 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070093 * VEX/XOP prefixes are followed by the sequence:
94 * \tmm\wlp where mm is the M field; and wlp is:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070095 * 00 0ww lpp
H. Peter Anvin978c2172010-08-16 13:48:43 -070096 * [w0] ww = 0 for W = 0
97 * [w1 ] ww = 1 for W = 1
98 * [wig] ww = 2 for W don't care (always assembled as 0)
99 * [ww] ww = 3 for W used as REX.W
H. Peter Anvinbd420c72008-05-22 11:24:35 -0700100 *
H. Peter Anvina04019c2009-05-03 21:42:34 -0700101 * t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
H. Peter Anvind85d2502008-05-04 17:53:31 -0700102 *
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700103 * \274..\277 - a signed byte immediate operand, from operand 0..3,
104 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000105 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
106 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -0700107 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +0000108 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -0800109 * \314 - (disassembler only) invalid with REX.B
110 * \315 - (disassembler only) invalid with REX.X
111 * \316 - (disassembler only) invalid with REX.R
112 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
114 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
115 * \322 - indicates that this instruction is only valid when the
116 * operand size is the default (instruction to disassembler,
117 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000118 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000119 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400120 * \325 - instruction which always uses spl/bpl/sil/dil
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000121 * \330 - a literal byte follows in the code stream, to be added
122 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000123 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000124 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700125 * \332 - REP prefix (0xF2 byte) used as opcode extension.
126 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700127 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700128 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700129 * \336 - force a REP(E) prefix (0xF2) even if not specified.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400130 * \337 - force a REPNE prefix (0xF3) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700131 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000132 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000133 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400134 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700135 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
136 * (POP is never used for CS) depending on operand 0
137 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
138 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400139 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700140 * \361 - 66 SSE prefix (== \366\331)
141 * \362 - F2 SSE prefix (== \364\332)
142 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000143 * \364 - operand-size prefix (0x66) not permitted
144 * \365 - address-size prefix (0x67) not permitted
145 * \366 - operand-size prefix (0x66) used as opcode extension
146 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000147 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400148 * 370 is used for Jcc, 371 is used for JMP.
149 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
150 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000151 */
152
H. Peter Anvinfe501952007-10-02 21:53:51 -0700153#include "compiler.h"
154
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000155#include <stdio.h>
156#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000157#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000158
159#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000160#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000161#include "assemble.h"
162#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700163#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000164
H. Peter Anvin65289e82009-07-25 17:25:11 -0700165enum match_result {
166 /*
167 * Matching errors. These should be sorted so that more specific
168 * errors come later in the sequence.
169 */
170 MERR_INVALOP,
171 MERR_OPSIZEMISSING,
172 MERR_OPSIZEMISMATCH,
173 MERR_BADCPU,
174 MERR_BADMODE,
175 /*
176 * Matching success; the conditional ones first
177 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400178 MOK_JUMP, /* Matching OK but needs jmp_match() */
179 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700180};
181
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000182typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000183 int sib_present; /* is a SIB byte necessary? */
184 int bytes; /* # of bytes of offset needed */
185 int size; /* lazy - this is sib+bytes+1 */
186 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000187} ea;
188
Keith Kaniosb7a89542007-04-12 02:40:54 +0000189static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000190static efunc errfunc;
191static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000192static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000193
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700194static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700195static void gencode(int32_t segment, int64_t offset, int bits,
196 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400197 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700198static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400199 insn *instruction,
200 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700201static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700202static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000203static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700204static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000205static int op_rexflags(const operand *, int);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700206static ea *process_ea(operand *, ea *, int, int, int, opflags_t);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700207static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000208
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700209static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000210{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700211 return ins->prefixes[pos] == prefix;
212}
213
214static void assert_no_prefix(insn * ins, enum prefix_pos pos)
215{
216 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400217 errfunc(ERR_NONFATAL, "invalid %s prefix",
218 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700219}
220
221static const char *size_name(int size)
222{
223 switch (size) {
224 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400225 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700226 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400227 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700228 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400229 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700230 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400231 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700232 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400233 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700234 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400235 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700236 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400237 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700238 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400239 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000240 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700241}
242
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400243static void warn_overflow(int pass, int size)
244{
245 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
246 "%s data exceeds bounds", size_name(size));
247}
248
249static void warn_overflow_const(int64_t data, int size)
250{
251 if (overflow_general(data, size))
252 warn_overflow(ERR_PASS1, size);
253}
254
255static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700256{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100257 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400258 if (overflow_general(o->offset, size))
259 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700260 }
261}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400262
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000263/*
264 * This routine wrappers the real output format's output routine,
265 * in order to pass a copy of the data off to the listing file
266 * generator at the same time.
267 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800268static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800269 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400270 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000271{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000272 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000273 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800274 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000275
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800276 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400277 /*
278 * This is a non-relocated address, and we're going to
279 * convert it into RAWDATA format.
280 */
281 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800282
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400283 if (size > 8) {
284 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
285 return;
286 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700287
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400288 WRITEADDR(q, *(int64_t *)data, size);
289 data = p;
290 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000291 }
292
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800293 list->output(offset, data, type, size);
294
Frank Kotlerabebb082003-09-06 04:45:37 +0000295 /*
296 * this call to src_get determines when we call the
297 * debug-format-specific "linenum" function
298 * it updates lineno and lnfname to the current values
299 * returning 0 if "same as last time", -2 if lnfname
300 * changed, and the amount by which lineno changed,
301 * if it did. thus, these variables must be static
302 */
303
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400304 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000305 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000306
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800307 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000308}
309
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700310static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700311 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000312{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800313 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000314 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000315
Charles Craynef1aefd82008-09-30 16:11:32 -0700316 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700317 return false;
318 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400319 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700320 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400321 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700322
H. Peter Anvine2c80182005-01-15 22:15:51 +0000323 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100324
Victor van den Elzen154e5922009-02-25 17:32:00 +0100325 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100326 /* Be optimistic in pass 1 */
327 return true;
328
H. Peter Anvine2c80182005-01-15 22:15:51 +0000329 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700330 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000331
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700332 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
333 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000334}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000335
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800336int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400337 insn * instruction, struct ofmt *output, efunc error,
338 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000339{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000340 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000341 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700342 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800343 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000344 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800345 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300346 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000347
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000349 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 outfmt = output; /* likewise */
351 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000352
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300353 wsize = idata_bytes(instruction->opcode);
354 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000355 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000356
H. Peter Anvineba20a72002-04-30 20:53:55 +0000357 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000358 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000359 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000360 if (t < 0)
361 errfunc(ERR_PANIC,
362 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000363
H. Peter Anvine2c80182005-01-15 22:15:51 +0000364 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400365 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400367 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700368 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400369 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000370 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700371 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000372 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800373 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400374 offset += wsize;
375 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700376 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400377 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000378 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000379
H. Peter Anvine2c80182005-01-15 22:15:51 +0000380 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800381 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000383
H. Peter Anvine2c80182005-01-15 22:15:51 +0000384 if (align) {
385 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100386 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800387 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000388 }
389 offset += e->stringlen + align;
390 }
391 }
392 if (t > 0 && t == instruction->times - 1) {
393 /*
394 * Dummy call to list->output to give the offset to the
395 * listing module.
396 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800397 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 list->uplevel(LIST_TIMES);
399 }
400 }
401 if (instruction->times > 1)
402 list->downlevel(LIST_TIMES);
403 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000404 }
405
H. Peter Anvine2c80182005-01-15 22:15:51 +0000406 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700407 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000408 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000409
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400410 fp = fopen(fname, "rb");
411 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000412 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
413 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400414 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000415 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
416 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400417 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700418 static char buf[4096];
419 size_t t = instruction->times;
420 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400421 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000422
H. Peter Anvine2c80182005-01-15 22:15:51 +0000423 len = ftell(fp);
424 if (instruction->eops->next) {
425 base = instruction->eops->next->offset;
426 len -= base;
427 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700428 len > (size_t)instruction->eops->next->next->offset)
429 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000430 }
431 /*
432 * Dummy call to list->output to give the offset to the
433 * listing module.
434 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800435 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000436 list->uplevel(LIST_INCBIN);
437 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700438 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000439
H. Peter Anvine2c80182005-01-15 22:15:51 +0000440 fseek(fp, base, SEEK_SET);
441 l = len;
442 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700443 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400444 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000445 if (!m) {
446 /*
447 * This shouldn't happen unless the file
448 * actually changes while we are reading
449 * it.
450 */
451 error(ERR_NONFATAL,
452 "`incbin': unexpected EOF while"
453 " reading file `%s'", fname);
454 t = 0; /* Try to exit cleanly */
455 break;
456 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800457 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000458 NO_SEG, NO_SEG);
459 l -= m;
460 }
461 }
462 list->downlevel(LIST_INCBIN);
463 if (instruction->times > 1) {
464 /*
465 * Dummy call to list->output to give the offset to the
466 * listing module.
467 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800468 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000469 list->uplevel(LIST_TIMES);
470 list->downlevel(LIST_TIMES);
471 }
472 fclose(fp);
473 return instruction->times * len;
474 }
475 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000476 }
477
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700478 /* Check to see if we need an address-size prefix */
479 add_asp(instruction, bits);
480
H. Peter Anvin23595f52009-07-25 17:44:25 -0700481 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700482
H. Peter Anvin23595f52009-07-25 17:44:25 -0700483 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400484 /* Matches! */
485 int64_t insn_size = calcsize(segment, offset, bits,
486 instruction, temp->code);
487 itimes = instruction->times;
488 if (insn_size < 0) /* shouldn't be, on pass two */
489 error(ERR_PANIC, "errors made it through from pass one");
490 else
491 while (itimes--) {
492 for (j = 0; j < MAXPREFIX; j++) {
493 uint8_t c = 0;
494 switch (instruction->prefixes[j]) {
495 case P_WAIT:
496 c = 0x9B;
497 break;
498 case P_LOCK:
499 c = 0xF0;
500 break;
501 case P_REPNE:
502 case P_REPNZ:
503 c = 0xF2;
504 break;
505 case P_REPE:
506 case P_REPZ:
507 case P_REP:
508 c = 0xF3;
509 break;
510 case R_CS:
511 if (bits == 64) {
512 error(ERR_WARNING | ERR_PASS2,
513 "cs segment base generated, but will be ignored in 64-bit mode");
514 }
515 c = 0x2E;
516 break;
517 case R_DS:
518 if (bits == 64) {
519 error(ERR_WARNING | ERR_PASS2,
520 "ds segment base generated, but will be ignored in 64-bit mode");
521 }
522 c = 0x3E;
523 break;
524 case R_ES:
525 if (bits == 64) {
526 error(ERR_WARNING | ERR_PASS2,
527 "es segment base generated, but will be ignored in 64-bit mode");
528 }
529 c = 0x26;
530 break;
531 case R_FS:
532 c = 0x64;
533 break;
534 case R_GS:
535 c = 0x65;
536 break;
537 case R_SS:
538 if (bits == 64) {
539 error(ERR_WARNING | ERR_PASS2,
540 "ss segment base generated, but will be ignored in 64-bit mode");
541 }
542 c = 0x36;
543 break;
544 case R_SEGR6:
545 case R_SEGR7:
546 error(ERR_NONFATAL,
547 "segr6 and segr7 cannot be used as prefixes");
548 break;
549 case P_A16:
550 if (bits == 64) {
551 error(ERR_NONFATAL,
552 "16-bit addressing is not supported "
553 "in 64-bit mode");
554 } else if (bits != 16)
555 c = 0x67;
556 break;
557 case P_A32:
558 if (bits != 32)
559 c = 0x67;
560 break;
561 case P_A64:
562 if (bits != 64) {
563 error(ERR_NONFATAL,
564 "64-bit addressing is only supported "
565 "in 64-bit mode");
566 }
567 break;
568 case P_ASP:
569 c = 0x67;
570 break;
571 case P_O16:
572 if (bits != 16)
573 c = 0x66;
574 break;
575 case P_O32:
576 if (bits == 16)
577 c = 0x66;
578 break;
579 case P_O64:
580 /* REX.W */
581 break;
582 case P_OSP:
583 c = 0x66;
584 break;
585 case P_none:
586 break;
587 default:
588 error(ERR_PANIC, "invalid instruction prefix");
589 }
590 if (c != 0) {
591 out(offset, segment, &c, OUT_RAWDATA, 1,
592 NO_SEG, NO_SEG);
593 offset++;
594 }
595 }
596 insn_end = offset + insn_size;
597 gencode(segment, offset, bits, instruction,
598 temp, insn_end);
599 offset += insn_size;
600 if (itimes > 0 && itimes == instruction->times - 1) {
601 /*
602 * Dummy call to list->output to give the offset to the
603 * listing module.
604 */
605 list->output(offset, NULL, OUT_RAWDATA, 0);
606 list->uplevel(LIST_TIMES);
607 }
608 }
609 if (instruction->times > 1)
610 list->downlevel(LIST_TIMES);
611 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700612 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400613 /* No match */
614 switch (m) {
615 case MERR_OPSIZEMISSING:
616 error(ERR_NONFATAL, "operation size not specified");
617 break;
618 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000619 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400620 break;
621 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000622 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400623 break;
624 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800625 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400626 bits);
627 break;
628 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000629 error(ERR_NONFATAL,
630 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400631 break;
632 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000633 }
634 return 0;
635}
636
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800637int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400638 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000639{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000640 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700641 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000642
H. Peter Anvine2c80182005-01-15 22:15:51 +0000643 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000644 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000645
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400646 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000647 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000648
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700649 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
650 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400651 instruction->opcode == I_DT || instruction->opcode == I_DO ||
652 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000653 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300654 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000655
H. Peter Anvine2c80182005-01-15 22:15:51 +0000656 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300657 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000658
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400659 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000660 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000661
H. Peter Anvine2c80182005-01-15 22:15:51 +0000662 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400663 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000664 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400665 warn_overflow_const(e->offset, wsize);
666 } else if (e->type == EOT_DB_STRING ||
667 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000668 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000669
H. Peter Anvine2c80182005-01-15 22:15:51 +0000670 align = (-osize) % wsize;
671 if (align < 0)
672 align += wsize;
673 isize += osize + align;
674 }
675 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000676 }
677
H. Peter Anvine2c80182005-01-15 22:15:51 +0000678 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400679 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300681 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700682 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000683
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400684 fp = fopen(fname, "rb");
685 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000686 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
687 fname);
688 else if (fseek(fp, 0L, SEEK_END) < 0)
689 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
690 fname);
691 else {
692 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 if (instruction->eops->next) {
694 len -= instruction->eops->next->offset;
695 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700696 len > (size_t)instruction->eops->next->next->offset) {
697 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000698 }
699 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300700 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000701 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300702 if (fp)
703 fclose(fp);
704 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000705 }
706
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700707 /* Check to see if we need an address-size prefix */
708 add_asp(instruction, bits);
709
H. Peter Anvin23595f52009-07-25 17:44:25 -0700710 m = find_match(&temp, instruction, segment, offset, bits);
711 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400712 /* we've matched an instruction. */
713 int64_t isize;
714 const uint8_t *codes = temp->code;
715 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100716
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400717 isize = calcsize(segment, offset, bits, instruction, codes);
718 if (isize < 0)
719 return -1;
720 for (j = 0; j < MAXPREFIX; j++) {
721 switch (instruction->prefixes[j]) {
722 case P_A16:
723 if (bits != 16)
724 isize++;
725 break;
726 case P_A32:
727 if (bits != 32)
728 isize++;
729 break;
730 case P_O16:
731 if (bits != 16)
732 isize++;
733 break;
734 case P_O32:
735 if (bits == 16)
736 isize++;
737 break;
738 case P_A64:
739 case P_O64:
740 case P_none:
741 break;
742 default:
743 isize++;
744 break;
745 }
746 }
747 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700748 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400749 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000750 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000751}
752
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700753static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000754{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700755 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400756 !(o->opflags & OPFLAG_UNKNOWN) &&
757 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000758}
759
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700760/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700761static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700762{
763 int16_t v;
764
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700765 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400766 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700767
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700768 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700769 return v >= -128 && v <= 127;
770}
771
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700772static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700773{
774 int32_t v;
775
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700776 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400777 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700778
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700779 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700780 return v >= -128 && v <= 127;
781}
782
H. Peter Anvin507ae032008-10-09 15:37:10 -0700783/* Common construct */
784#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
785
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800786static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400787 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000788{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800789 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000790 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000791 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700792 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700793 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700794 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000795
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700796 ins->rex = 0; /* Ensure REX is reset */
797
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700798 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400799 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700800
H. Peter Anvine2c80182005-01-15 22:15:51 +0000801 (void)segment; /* Don't warn that this parameter is unused */
802 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000803
H. Peter Anvin839eca22007-10-29 23:12:47 -0700804 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400805 c = *codes++;
806 op1 = (c & 3) + ((opex & 1) << 2);
807 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
808 opx = &ins->oprs[op1];
809 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700810
H. Peter Anvin839eca22007-10-29 23:12:47 -0700811 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000812 case 01:
813 case 02:
814 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400815 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000816 codes += c, length += c;
817 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700818
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400819 case 05:
820 case 06:
821 case 07:
822 opex = c;
823 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700824
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400825 case4(010):
826 ins->rex |=
827 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000828 codes++, length++;
829 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700830
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400831 case4(014):
832 case4(020):
833 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000834 length++;
835 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700836
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400837 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000838 length += 2;
839 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700840
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400841 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700842 if (opx->type & (BITS16 | BITS32 | BITS64))
843 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000844 else
845 length += (bits == 16) ? 2 : 4;
846 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700847
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400848 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 length += 4;
850 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700851
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400852 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700853 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700855
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400856 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 length++;
858 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700859
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400860 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000861 length += 8; /* MOV reg64/imm */
862 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700863
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400864 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 length += 2;
866 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700867
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400868 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700869 if (opx->type & (BITS16 | BITS32 | BITS64))
870 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000871 else
872 length += (bits == 16) ? 2 : 4;
873 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700874
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400875 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000876 length += 4;
877 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700878
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400879 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700880 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700882
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400883 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700884 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700886
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400887 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800888 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 length++;
890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400892 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700893 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700894 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700895
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400896 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800897 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700898 length++;
899 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700900
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400901 case4(0160):
902 length++;
903 ins->rex |= REX_D;
904 ins->drexdst = regval(opx);
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700905 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700906
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400907 case4(0164):
908 length++;
909 ins->rex |= REX_D|REX_OC;
910 ins->drexdst = regval(opx);
911 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700912
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400913 case 0171:
914 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700915
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400916 case 0172:
917 case 0173:
918 case 0174:
919 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700920 length++;
921 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700922
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400923 case4(0250):
924 length += is_sbyte32(opx) ? 1 : 4;
925 break;
926
927 case4(0254):
928 length += 4;
929 break;
930
931 case4(0260):
932 ins->rex |= REX_V;
933 ins->drexdst = regval(opx);
934 ins->vex_cm = *codes++;
935 ins->vex_wlp = *codes++;
936 break;
937
938 case 0270:
939 ins->rex |= REX_V;
940 ins->drexdst = 0;
941 ins->vex_cm = *codes++;
942 ins->vex_wlp = *codes++;
943 break;
944
945 case4(0274):
946 length++;
947 break;
948
949 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000950 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700951
H. Peter Anvine2c80182005-01-15 22:15:51 +0000952 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400953 if (bits == 64)
954 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700955 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000956 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700957
H. Peter Anvine2c80182005-01-15 22:15:51 +0000958 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700959 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
H. Peter Anvine2c80182005-01-15 22:15:51 +0000962 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700963 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700964
Keith Kaniosb7a89542007-04-12 02:40:54 +0000965 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400966 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
967 has_prefix(ins, PPS_ASIZE, P_A32))
968 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000969 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700970
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400971 case4(0314):
972 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700973
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000975 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000976 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700977
H. Peter Anvine2c80182005-01-15 22:15:51 +0000978 case 0321:
979 length += (bits == 16);
980 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700981
H. Peter Anvine2c80182005-01-15 22:15:51 +0000982 case 0322:
983 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700984
Keith Kaniosb7a89542007-04-12 02:40:54 +0000985 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000986 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000987 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700988
Keith Kaniosb7a89542007-04-12 02:40:54 +0000989 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400990 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000991 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700992
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400993 case 0325:
994 ins->rex |= REX_NH;
995 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700996
H. Peter Anvine2c80182005-01-15 22:15:51 +0000997 case 0330:
998 codes++, length++;
999 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001000
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001002 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001003
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001004 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001005 case 0333:
1006 length++;
1007 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001008
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001009 case 0334:
1010 ins->rex |= REX_L;
1011 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001012
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001013 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001014 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001015
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001016 case 0336:
1017 if (!ins->prefixes[PPS_LREP])
1018 ins->prefixes[PPS_LREP] = P_REP;
1019 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001020
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001021 case 0337:
1022 if (!ins->prefixes[PPS_LREP])
1023 ins->prefixes[PPS_LREP] = P_REPNE;
1024 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001025
H. Peter Anvine2c80182005-01-15 22:15:51 +00001026 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001027 if (ins->oprs[0].segment != NO_SEG)
1028 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1029 " quantity of BSS space");
1030 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001031 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001032 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001033
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001034 case 0341:
1035 if (!ins->prefixes[PPS_WAIT])
1036 ins->prefixes[PPS_WAIT] = P_WAIT;
1037 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001038
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001039 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001040 length++;
1041 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001042
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001043 case 0360:
1044 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001045
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001046 case 0361:
1047 case 0362:
1048 case 0363:
1049 length++;
1050 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001051
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001052 case 0364:
1053 case 0365:
1054 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001055
Keith Kanios48af1772007-08-17 07:37:52 +00001056 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001057 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001058 length++;
1059 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001060
H. Peter Anvine2c80182005-01-15 22:15:51 +00001061 case 0370:
1062 case 0371:
1063 case 0372:
1064 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001065
H. Peter Anvine2c80182005-01-15 22:15:51 +00001066 case 0373:
1067 length++;
1068 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001069
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001070 case4(0100):
1071 case4(0110):
1072 case4(0120):
1073 case4(0130):
1074 case4(0200):
1075 case4(0204):
1076 case4(0210):
1077 case4(0214):
1078 case4(0220):
1079 case4(0224):
1080 case4(0230):
1081 case4(0234):
1082 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001083 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001084 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001085 opflags_t rflags;
1086 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001087
Keith Kaniosb7a89542007-04-12 02:40:54 +00001088 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001089
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001090 if (c <= 0177) {
1091 /* pick rfield from operand b (opx) */
1092 rflags = regflag(opx);
1093 rfield = nasm_regvals[opx->basereg];
1094 } else {
1095 rflags = 0;
1096 rfield = c & 7;
1097 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001098 if (!process_ea(opy, &ea_data, bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001099 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001100 errfunc(ERR_NONFATAL, "invalid effective address");
1101 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001102 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001103 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001104 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001105 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001106 }
1107 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001108
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001109 default:
1110 errfunc(ERR_PANIC, "internal instruction table corrupt"
1111 ": instruction code \\%o (0x%02X) given", c, c);
1112 break;
1113 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001114 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001115
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001116 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001117
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001118 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001119 if (ins->rex & REX_H) {
1120 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1121 return -1;
1122 }
1123 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001124 }
1125
H. Peter Anvind85d2502008-05-04 17:53:31 -07001126 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001127 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001128
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001129 if (ins->rex & REX_H) {
1130 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1131 return -1;
1132 }
1133 switch (ins->vex_wlp & 030) {
1134 case 000:
1135 case 020:
1136 ins->rex &= ~REX_W;
1137 break;
1138 case 010:
1139 ins->rex |= REX_W;
1140 bad32 &= ~REX_W;
1141 break;
1142 case 030:
1143 /* Follow REX_W */
1144 break;
1145 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001146
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001147 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1148 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1149 return -1;
1150 }
1151 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1152 length += 3;
1153 else
1154 length += 2;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001155 } else if (ins->rex & REX_D) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001156 if (ins->rex & REX_H) {
1157 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1158 return -1;
1159 }
1160 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
1161 ins->drexdst > 7)) {
1162 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1163 return -1;
1164 }
1165 length++;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001166 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001167 if (ins->rex & REX_H) {
1168 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1169 return -1;
1170 } else if (bits == 64) {
1171 length++;
1172 } else if ((ins->rex & REX_L) &&
1173 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1174 cpu >= IF_X86_64) {
1175 /* LOCK-as-REX.R */
1176 assert_no_prefix(ins, PPS_LREP);
1177 length++;
1178 } else {
1179 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1180 return -1;
1181 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001182 }
1183
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001184 return length;
1185}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001186
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001187#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001188 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001189 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1190 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1191 ins->rex = 0; \
1192 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001193 }
1194
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001195static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001196 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001197 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001198{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001199 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001200 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1201 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1202 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001203 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001204 uint8_t c;
1205 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001206 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001207 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001208 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001209 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001210 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001211 uint8_t opex = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001212
H. Peter Anvin839eca22007-10-29 23:12:47 -07001213 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001214 c = *codes++;
1215 op1 = (c & 3) + ((opex & 1) << 2);
1216 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1217 opx = &ins->oprs[op1];
1218 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001219
H. Peter Anvin839eca22007-10-29 23:12:47 -07001220 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001221 case 01:
1222 case 02:
1223 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001224 case 04:
1225 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001226 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001227 codes += c;
1228 offset += c;
1229 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001230
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001231 case 05:
1232 case 06:
1233 case 07:
1234 opex = c;
1235 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001236
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001237 case4(010):
1238 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001239 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001240 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001241 offset += 1;
1242 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001243
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001244 case4(014):
1245 /*
1246 * The test for BITS8 and SBYTE here is intended to avoid
1247 * warning on optimizer actions due to SBYTE, while still
1248 * warn on explicit BYTE directives. Also warn, obviously,
1249 * if the optimizer isn't enabled.
1250 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001251 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001252 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1253 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001254 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001255 "signed byte value exceeds bounds");
1256 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001257 if (opx->segment != NO_SEG) {
1258 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001259 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001260 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001261 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001262 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001263 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001264 NO_SEG);
1265 }
1266 offset += 1;
1267 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001268
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001269 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001270 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001271 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001272 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001273 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001274 if (opx->segment != NO_SEG) {
1275 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001276 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001277 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001278 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001280 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 NO_SEG);
1282 }
1283 offset += 1;
1284 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001285
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001286 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001287 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001288 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001289 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 if (opx->segment != NO_SEG) {
1291 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001292 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001293 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001294 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001295 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001296 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001297 NO_SEG);
1298 }
1299 offset += 1;
1300 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001301
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001302 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001303 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001304 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001305 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001307 offset += 2;
1308 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001309
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001310 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001311 if (opx->type & (BITS16 | BITS32))
1312 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 else
1314 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001315 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001316 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001317 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001318 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001319 offset += size;
1320 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001321
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001322 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001323 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001324 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001325 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001326 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001327 offset += 4;
1328 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001329
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001330 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001332 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001333 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001334 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001335 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001336 offset += size;
1337 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001338
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001339 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001340 if (opx->segment != segment) {
1341 data = opx->offset;
1342 out(offset, segment, &data,
1343 OUT_REL1ADR, insn_end - offset,
1344 opx->segment, opx->wrt);
1345 } else {
1346 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001347 if (data > 127 || data < -128)
1348 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001349 out(offset, segment, &data,
1350 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1351 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001352 offset += 1;
1353 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001354
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001355 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001356 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001357 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001358 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001359 offset += 8;
1360 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001361
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001362 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 if (opx->segment != segment) {
1364 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001365 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001366 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001368 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001371 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 }
1373 offset += 2;
1374 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001375
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001376 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001377 if (opx->type & (BITS16 | BITS32 | BITS64))
1378 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001379 else
1380 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001382 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001383 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001384 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1385 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001386 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001387 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001388 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001389 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 }
1391 offset += size;
1392 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001393
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001394 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 if (opx->segment != segment) {
1396 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001397 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001398 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001399 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001400 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001401 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001403 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 }
1405 offset += 4;
1406 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001407
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001408 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001409 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001410 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1411 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001412 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001413 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001414 outfmt->segbase(1 + opx->segment),
1415 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001416 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001417 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001418
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001419 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001421 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001422 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001423 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001424 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001425 NO_SEG);
1426 offset++;
1427 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001428 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001429 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001430 offset += 2;
1431 }
1432 break;
1433
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001434 case4(0144):
1435 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001436 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001437 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001438 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001439 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001440 offset++;
1441 break;
1442
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001443 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001444 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001445 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001446 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001447 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001448 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001449 NO_SEG);
1450 offset++;
1451 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001452 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001453 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001454 offset += 4;
1455 }
1456 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001457
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001458 case4(0154):
1459 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001461 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001463 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 offset++;
1465 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001466
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001467 case4(0160):
1468 case4(0164):
1469 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001470
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001471 case 0171:
1472 bytes[0] =
1473 (ins->drexdst << 4) |
1474 (ins->rex & REX_OC ? 0x08 : 0) |
1475 (ins->rex & (REX_R|REX_X|REX_B));
1476 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001477 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001478 offset++;
1479 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001480
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001481 case 0172:
1482 c = *codes++;
1483 opx = &ins->oprs[c >> 3];
1484 bytes[0] = nasm_regvals[opx->basereg] << 4;
1485 opx = &ins->oprs[c & 7];
1486 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1487 errfunc(ERR_NONFATAL,
1488 "non-absolute expression not permitted as argument %d",
1489 c & 7);
1490 } else {
1491 if (opx->offset & ~15) {
1492 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1493 "four-bit argument exceeds bounds");
1494 }
1495 bytes[0] |= opx->offset & 15;
1496 }
1497 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1498 offset++;
1499 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001500
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001501 case 0173:
1502 c = *codes++;
1503 opx = &ins->oprs[c >> 4];
1504 bytes[0] = nasm_regvals[opx->basereg] << 4;
1505 bytes[0] |= c & 15;
1506 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1507 offset++;
1508 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001509
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001510 case 0174:
1511 c = *codes++;
1512 opx = &ins->oprs[c];
1513 bytes[0] = nasm_regvals[opx->basereg] << 4;
1514 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1515 offset++;
1516 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001517
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001518 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001519 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001520 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1521 (int32_t)data != (int64_t)data) {
1522 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1523 "signed dword immediate exceeds bounds");
1524 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001525 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001526 bytes[0] = data;
1527 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1528 NO_SEG);
1529 offset++;
1530 } else {
1531 out(offset, segment, &data, OUT_ADDRESS, 4,
1532 opx->segment, opx->wrt);
1533 offset += 4;
1534 }
1535 break;
1536
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001537 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001538 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001539 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1540 (int32_t)data != (int64_t)data) {
1541 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1542 "signed dword immediate exceeds bounds");
1543 }
1544 out(offset, segment, &data, OUT_ADDRESS, 4,
1545 opx->segment, opx->wrt);
1546 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001547 break;
1548
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001549 case4(0260):
1550 case 0270:
1551 codes += 2;
1552 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1553 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1554 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1555 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
1556 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
1557 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1558 offset += 3;
1559 } else {
1560 bytes[0] = 0xc5;
1561 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1562 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
1563 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1564 offset += 2;
1565 }
1566 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001567
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001568 case4(0274):
1569 {
1570 uint64_t uv, um;
1571 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001572
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001573 if (ins->rex & REX_W)
1574 s = 64;
1575 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1576 s = 16;
1577 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1578 s = 32;
1579 else
1580 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001581
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001582 um = (uint64_t)2 << (s-1);
1583 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001584
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001585 if (uv > 127 && uv < (uint64_t)-128 &&
1586 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001587 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001588 "signed byte value exceeds bounds");
1589 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001590 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001591 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001592 out(offset, segment, &data, OUT_ADDRESS, 1,
1593 opx->segment, opx->wrt);
1594 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001595 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001596 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1597 NO_SEG);
1598 }
1599 offset += 1;
1600 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001601 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001602
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001603 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001605
H. Peter Anvine2c80182005-01-15 22:15:51 +00001606 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001607 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001608 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001609 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001610 offset += 1;
1611 } else
1612 offset += 0;
1613 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001614
H. Peter Anvine2c80182005-01-15 22:15:51 +00001615 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001616 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001617 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001618 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001619 offset += 1;
1620 } else
1621 offset += 0;
1622 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001623
H. Peter Anvine2c80182005-01-15 22:15:51 +00001624 case 0312:
1625 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001626
Keith Kaniosb7a89542007-04-12 02:40:54 +00001627 case 0313:
1628 ins->rex = 0;
1629 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001630
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001631 case4(0314):
1632 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001633
H. Peter Anvine2c80182005-01-15 22:15:51 +00001634 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001635 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001636 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001637 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 offset += 1;
1639 } else
1640 offset += 0;
1641 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001642
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 case 0321:
1644 if (bits == 16) {
1645 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001646 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 offset += 1;
1648 } else
1649 offset += 0;
1650 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001651
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001653 case 0323:
1654 break;
1655
Keith Kaniosb7a89542007-04-12 02:40:54 +00001656 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001657 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001659
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001660 case 0325:
1661 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001662
H. Peter Anvine2c80182005-01-15 22:15:51 +00001663 case 0330:
1664 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001665 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001666 offset += 1;
1667 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001668
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001671
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001672 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001674 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001675 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001676 offset += 1;
1677 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001678
Keith Kanios48af1772007-08-17 07:37:52 +00001679 case 0334:
1680 if (ins->rex & REX_R) {
1681 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001682 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001683 offset += 1;
1684 }
1685 ins->rex &= ~(REX_L|REX_R);
1686 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001687
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001688 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001689 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001690
H. Peter Anvin962e3052008-08-28 17:47:16 -07001691 case 0336:
1692 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001693 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001694
H. Peter Anvine2c80182005-01-15 22:15:51 +00001695 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001696 if (ins->oprs[0].segment != NO_SEG)
1697 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1698 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001699 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001700 if (size > 0)
1701 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001702 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001703 offset += size;
1704 }
1705 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001706
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001707 case 0341:
1708 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001709
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001710 case 0344:
1711 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001712 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001713 switch (ins->oprs[0].basereg) {
1714 case R_CS:
1715 bytes[0] += 0x0E;
1716 break;
1717 case R_DS:
1718 bytes[0] += 0x1E;
1719 break;
1720 case R_ES:
1721 bytes[0] += 0x06;
1722 break;
1723 case R_SS:
1724 bytes[0] += 0x16;
1725 break;
1726 default:
1727 errfunc(ERR_PANIC,
1728 "bizarre 8086 segment register received");
1729 }
1730 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1731 offset++;
1732 break;
1733
1734 case 0346:
1735 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001736 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001737 switch (ins->oprs[0].basereg) {
1738 case R_FS:
1739 bytes[0] += 0xA0;
1740 break;
1741 case R_GS:
1742 bytes[0] += 0xA8;
1743 break;
1744 default:
1745 errfunc(ERR_PANIC,
1746 "bizarre 386 segment register received");
1747 }
1748 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1749 offset++;
1750 break;
1751
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001752 case 0360:
1753 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001754
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001755 case 0361:
1756 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001757 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1758 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001759 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001760
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001761 case 0362:
1762 case 0363:
1763 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001764 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1765 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001766 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001767
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001768 case 0364:
1769 case 0365:
1770 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001771
Keith Kanios48af1772007-08-17 07:37:52 +00001772 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001773 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001774 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001775 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001776 offset += 1;
1777 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001778
H. Peter Anvine2c80182005-01-15 22:15:51 +00001779 case 0370:
1780 case 0371:
1781 case 0372:
1782 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001783
H. Peter Anvine2c80182005-01-15 22:15:51 +00001784 case 0373:
1785 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001786 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001787 offset += 1;
1788 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001789
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001790 case4(0100):
1791 case4(0110):
1792 case4(0120):
1793 case4(0130):
1794 case4(0200):
1795 case4(0204):
1796 case4(0210):
1797 case4(0214):
1798 case4(0220):
1799 case4(0224):
1800 case4(0230):
1801 case4(0234):
1802 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001803 ea ea_data;
1804 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001805 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001806 uint8_t *p;
1807 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001808 enum out_type type;
1809 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001810
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001811 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001812 /* pick rfield from operand b (opx) */
1813 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001814 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001815 } else {
1816 /* rfield is constant */
1817 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001818 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001819 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001820
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001821 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001822 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001823 errfunc(ERR_NONFATAL, "invalid effective address");
1824 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001825
Charles Crayne7e975552007-11-03 22:06:13 -07001826
H. Peter Anvine2c80182005-01-15 22:15:51 +00001827 p = bytes;
1828 *p++ = ea_data.modrm;
1829 if (ea_data.sib_present)
1830 *p++ = ea_data.sib;
1831
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001832 /* DREX suffixes come between the SIB and the displacement */
1833 if (ins->rex & REX_D) {
1834 *p++ = (ins->drexdst << 4) |
1835 (ins->rex & REX_OC ? 0x08 : 0) |
1836 (ins->rex & (REX_R|REX_X|REX_B));
1837 ins->rex = 0;
1838 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001839
H. Peter Anvine2c80182005-01-15 22:15:51 +00001840 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001841 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001842
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001843 /*
1844 * Make sure the address gets the right offset in case
1845 * the line breaks in the .lst file (BR 1197827)
1846 */
1847 offset += s;
1848 s = 0;
1849
H. Peter Anvine2c80182005-01-15 22:15:51 +00001850 switch (ea_data.bytes) {
1851 case 0:
1852 break;
1853 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001854 case 2:
1855 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001856 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001857 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001858 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001859 if (ea_data.rip) {
1860 if (opy->segment == segment) {
1861 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001862 if (overflow_signed(data, ea_data.bytes))
1863 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001864 out(offset, segment, &data, OUT_ADDRESS,
1865 ea_data.bytes, NO_SEG, NO_SEG);
1866 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001867 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001868 out(offset, segment, &data, OUT_REL4ADR,
1869 insn_end - offset, opy->segment, opy->wrt);
1870 }
1871 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001872 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1873 signed_bits(opy->offset, ins->addr_size) !=
1874 signed_bits(opy->offset, ea_data.bytes * 8))
1875 warn_overflow(ERR_PASS2, ea_data.bytes);
1876
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001877 type = OUT_ADDRESS;
1878 out(offset, segment, &data, OUT_ADDRESS,
1879 ea_data.bytes, opy->segment, opy->wrt);
1880 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001881 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001882 default:
1883 /* Impossible! */
1884 errfunc(ERR_PANIC,
1885 "Invalid amount of bytes (%d) for offset?!",
1886 ea_data.bytes);
1887 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001888 }
1889 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001890 }
1891 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001892
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001893 default:
1894 errfunc(ERR_PANIC, "internal instruction table corrupt"
1895 ": instruction code \\%o (0x%02X) given", c, c);
1896 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001897 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001898 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001899}
1900
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001901static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001902{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001903 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001904 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001905 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001906}
1907
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001908static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001909{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001910 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001911 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001912 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001913}
1914
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001915static int op_rexflags(const operand * o, int mask)
1916{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001917 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001918 int val;
1919
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001920 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001921 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001922
H. Peter Anvina4835d42008-05-20 14:21:29 -07001923 flags = nasm_reg_flags[o->basereg];
1924 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001925
1926 return rexflags(val, flags, mask);
1927}
1928
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001929static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001930{
1931 int rex = 0;
1932
1933 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001934 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001935 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001936 rex |= REX_W;
1937 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1938 rex |= REX_H;
1939 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1940 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001941
1942 return rex & mask;
1943}
1944
H. Peter Anvin23595f52009-07-25 17:44:25 -07001945static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001946 insn *instruction,
1947 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001948{
1949 const struct itemplate *temp;
1950 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001951 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001952 bool opsizemissing = false;
1953 int i;
1954
1955 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001956 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001957
1958 merr = MERR_INVALOP;
1959
1960 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001961 temp->opcode != I_none; temp++) {
1962 m = matches(temp, instruction, bits);
1963 if (m == MOK_JUMP) {
1964 if (jmp_match(segment, offset, bits, instruction, temp->code))
1965 m = MOK_GOOD;
1966 else
1967 m = MERR_INVALOP;
1968 } else if (m == MERR_OPSIZEMISSING &&
1969 (temp->flags & IF_SMASK) != IF_SX) {
1970 /*
1971 * Missing operand size and a candidate for fuzzy matching...
1972 */
1973 for (i = 0; i < temp->operands; i++) {
1974 if ((temp->opd[i] & SAME_AS) == 0)
1975 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1976 }
1977 opsizemissing = true;
1978 }
1979 if (m > merr)
1980 merr = m;
1981 if (merr == MOK_GOOD)
1982 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001983 }
1984
1985 /* No match, but see if we can get a fuzzy operand size match... */
1986 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001987 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001988
1989 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001990 /*
1991 * We ignore extrinsic operand sizes on registers, so we should
1992 * never try to fuzzy-match on them. This also resolves the case
1993 * when we have e.g. "xmmrm128" in two different positions.
1994 */
1995 if (is_class(REGISTER, instruction->oprs[i].type))
1996 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001997
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001998 /* This tests if xsizeflags[i] has more than one bit set */
1999 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2000 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002001
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002002 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002003 }
2004
2005 /* Try matching again... */
2006 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002007 temp->opcode != I_none; temp++) {
2008 m = matches(temp, instruction, bits);
2009 if (m == MOK_JUMP) {
2010 if (jmp_match(segment, offset, bits, instruction, temp->code))
2011 m = MOK_GOOD;
2012 else
2013 m = MERR_INVALOP;
2014 }
2015 if (m > merr)
2016 merr = m;
2017 if (merr == MOK_GOOD)
2018 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002019 }
2020
H. Peter Anvina81655b2009-07-25 18:15:28 -07002021done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002022 *tempp = temp;
2023 return merr;
2024}
2025
H. Peter Anvin65289e82009-07-25 17:25:11 -07002026static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002027 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002028{
H. Peter Anvin60926242009-07-26 16:25:38 -07002029 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002030 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002031
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002032 /*
2033 * Check the opcode
2034 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002035 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002036 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002037
2038 /*
2039 * Count the operands
2040 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002041 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002042 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002043
2044 /*
2045 * Check that no spurious colons or TOs are present
2046 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002047 for (i = 0; i < itemp->operands; i++)
2048 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002049 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002050
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002051 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002052 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002053 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002054 switch (itemp->flags & IF_SMASK) {
2055 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002056 asize = BITS8;
2057 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002058 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002059 asize = BITS16;
2060 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002061 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002062 asize = BITS32;
2063 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002064 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002065 asize = BITS64;
2066 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002067 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002068 asize = BITS128;
2069 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002070 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002071 asize = BITS256;
2072 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002073 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002074 switch (bits) {
2075 case 16:
2076 asize = BITS16;
2077 break;
2078 case 32:
2079 asize = BITS32;
2080 break;
2081 case 64:
2082 asize = BITS64;
2083 break;
2084 default:
2085 asize = 0;
2086 break;
2087 }
2088 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002089 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002090 asize = 0;
2091 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002092 }
2093
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002094 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002095 /* S- flags only apply to a specific operand */
2096 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2097 memset(size, 0, sizeof size);
2098 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002099 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002100 /* S- flags apply to all operands */
2101 for (i = 0; i < MAX_OPERANDS; i++)
2102 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002103 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002104
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002105 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002106 * Check that the operand flags all match up,
2107 * it's a bit tricky so lets be verbose:
2108 *
2109 * 1) Find out the size of operand. If instruction
2110 * doesn't have one specified -- we're trying to
2111 * guess it either from template (IF_S* flag) or
2112 * from code bits.
2113 *
2114 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2115 * (ie the same operand as was specified somewhere in template, and
2116 * this referred operand index is being achieved via ~SAME_AS)
2117 * we are to be sure that both registers (in template and instruction)
2118 * do exactly match.
2119 *
2120 * 3) If template operand do not match the instruction OR
2121 * template has an operand size specified AND this size differ
2122 * from which instruction has (perhaps we got it from code bits)
2123 * we are:
2124 * a) Check that only size of instruction and operand is differ
2125 * other characteristics do match
2126 * b) Perhaps it's a register specified in instruction so
2127 * for such a case we just mark that operand as "size
2128 * missing" and this will turn on fuzzy operand size
2129 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002130 */
2131 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002132 opflags_t type = instruction->oprs[i].type;
2133 if (!(type & SIZE_MASK))
2134 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002135
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002136 if (itemp->opd[i] & SAME_AS) {
2137 int j = itemp->opd[i] & ~SAME_AS;
2138 if (type != instruction->oprs[j].type ||
2139 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2140 return MERR_INVALOP;
2141 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002142 ((itemp->opd[i] & SIZE_MASK) &&
2143 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002144 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002145 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002146 } else if (!is_class(REGISTER, type)) {
2147 /*
2148 * Note: we don't honor extrinsic operand sizes for registers,
2149 * so "missing operand size" for a register should be
2150 * considered a wildcard match rather than an error.
2151 */
2152 opsizemissing = true;
2153 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002154 }
2155 }
2156
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002157 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002158 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002159
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002160 /*
2161 * Check operand sizes
2162 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002163 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002164 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002165 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002166 asize = itemp->opd[i] & SIZE_MASK;
2167 if (asize) {
2168 for (i = 0; i < oprs; i++)
2169 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002170 break;
2171 }
2172 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002173 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002174 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002175 }
2176
Keith Kaniosb7a89542007-04-12 02:40:54 +00002177 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002178 if (!(itemp->opd[i] & SIZE_MASK) &&
2179 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002180 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002181 }
2182
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002183 /*
2184 * Check template is okay at the set cpu level
2185 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002186 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002187 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002188
Keith Kaniosb7a89542007-04-12 02:40:54 +00002189 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002190 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002191 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002192 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002193 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002194
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002195 /*
2196 * Check if special handling needed for Jumps
2197 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002198 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002199 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002200
H. Peter Anvin60926242009-07-26 16:25:38 -07002201 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002202}
2203
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002204static ea *process_ea(operand * input, ea * output, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002205 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002206{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002207 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002208
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002209 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002210
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002211 /* REX flags for the rfield operand */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002212 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002213
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002214 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002215 int i;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002216 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002217
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002218 if (!is_register(input->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002219 return NULL;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002220 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002221 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002222
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002223 if (REG_EA & ~f)
2224 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002225
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002226 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002227
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002228 output->sib_present = false; /* no SIB necessary */
2229 output->bytes = 0; /* no offset necessary either */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002230 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002231 } else { /* it's a memory reference */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002232 if (input->basereg == -1 &&
2233 (input->indexreg == -1 || input->scale == 0)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002234 /* it's a pure offset */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002235
2236 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2237 input->segment == NO_SEG) {
2238 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2239 input->type &= ~IP_REL;
2240 input->type |= MEMORY;
2241 }
2242
2243 if (input->eaflags & EAF_BYTEOFFS ||
2244 (input->eaflags & EAF_WORDOFFS &&
2245 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2246 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2247 }
2248
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002249 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002250 int scale, index, base;
2251 output->sib_present = true;
2252 scale = 0;
2253 index = 4;
2254 base = 5;
2255 output->sib = (scale << 6) | (index << 3) | base;
2256 output->bytes = 4;
2257 output->modrm = 4 | ((rfield & 7) << 3);
2258 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002259 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002260 output->sib_present = false;
2261 output->bytes = (addrbits != 16 ? 4 : 2);
2262 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
2263 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002264 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002265 } else { /* it's an indirection */
2266 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002267 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002268 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002269 int t, it, bt; /* register numbers */
2270 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002271
H. Peter Anvine2c80182005-01-15 22:15:51 +00002272 if (s == 0)
2273 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002274
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002275 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002276 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002277 ix = nasm_reg_flags[i];
2278 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002279 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002280 ix = 0;
2281 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002282
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002283 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002284 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002285 bx = nasm_reg_flags[b];
2286 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002287 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002288 bx = 0;
2289 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002290
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002291 /* check for a 32/64-bit memory reference... */
2292 if ((ix|bx) & (BITS32|BITS64)) {
2293 /*
2294 * it must be a 32/64-bit memory reference. Firstly we have
2295 * to check that all registers involved are type E/Rxx.
2296 */
2297 int32_t sok = BITS32 | BITS64, o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002298
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002299 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002300 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2301 sok &= ix;
2302 else
2303 return NULL;
2304 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002305
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002306 if (bt != -1) {
2307 if (REG_GPR & ~bx)
2308 return NULL; /* Invalid register */
2309 if (~sok & bx & SIZE_MASK)
2310 return NULL; /* Invalid size */
2311 sok &= bx;
2312 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002313
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002314 /*
2315 * While we're here, ensure the user didn't specify
2316 * WORD or QWORD
2317 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002318 if (input->disp_size == 16 || input->disp_size == 64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002319 return NULL;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002320
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002321 if (addrbits == 16 ||
2322 (addrbits == 32 && !(sok & BITS32)) ||
2323 (addrbits == 64 && !(sok & BITS64)))
2324 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002325
Keith Kaniosb7a89542007-04-12 02:40:54 +00002326 /* now reorganize base/index */
2327 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002328 ((hb == b && ht == EAH_NOTBASE) ||
2329 (hb == i && ht == EAH_MAKEBASE))) {
2330 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002331 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002332 x = bx, bx = ix, ix = x;
2333 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002334 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002335 bt = -1, bx = 0, s++;
2336 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002337 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002338 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002339 }
2340 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2341 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002342 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002343 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2344 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002345 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002346 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002347 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002348 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002349 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002350 x = ix, ix = bx, bx = x;
2351 }
2352 if (it == REG_NUM_ESP ||
2353 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002354 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002355
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002356 output->rex |= rexflags(it, ix, REX_X);
2357 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002358
Keith Kanios48af1772007-08-17 07:37:52 +00002359 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002360 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002361 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002362
Keith Kaniosb7a89542007-04-12 02:40:54 +00002363 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002364 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002365 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002366 } else {
2367 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002368 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002369 seg == NO_SEG && !forw_ref &&
2370 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002371 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002372 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002373 (o >= -128 && o <= 127 &&
2374 seg == NO_SEG && !forw_ref &&
2375 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002376 mod = 1;
2377 else
2378 mod = 2;
2379 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002380
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002381 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002382 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2383 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002384 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002385 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002386 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002387
Keith Kaniosb7a89542007-04-12 02:40:54 +00002388 if (it == -1)
2389 index = 4, s = 1;
2390 else
2391 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002392
H. Peter Anvine2c80182005-01-15 22:15:51 +00002393 switch (s) {
2394 case 1:
2395 scale = 0;
2396 break;
2397 case 2:
2398 scale = 1;
2399 break;
2400 case 4:
2401 scale = 2;
2402 break;
2403 case 8:
2404 scale = 3;
2405 break;
2406 default: /* then what the smeg is it? */
2407 return NULL; /* panic */
2408 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002409
Keith Kaniosb7a89542007-04-12 02:40:54 +00002410 if (bt == -1) {
2411 base = 5;
2412 mod = 0;
2413 } else {
2414 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002415 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002416 seg == NO_SEG && !forw_ref &&
2417 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002418 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002419 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002420 (o >= -128 && o <= 127 &&
2421 seg == NO_SEG && !forw_ref &&
2422 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002423 mod = 1;
2424 else
2425 mod = 2;
2426 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002427
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002428 output->sib_present = true;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002429 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002430 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002431 output->sib = (scale << 6) | (index << 3) | base;
2432 }
2433 } else { /* it's 16-bit */
2434 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002435 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002436
Keith Kaniosb7a89542007-04-12 02:40:54 +00002437 /* check for 64-bit long mode */
2438 if (addrbits == 64)
2439 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002440
H. Peter Anvine2c80182005-01-15 22:15:51 +00002441 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002442 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2443 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002444 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002445
Keith Kaniosb7a89542007-04-12 02:40:54 +00002446 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002447 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002448 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002449
H. Peter Anvine2c80182005-01-15 22:15:51 +00002450 if (s != 1 && i != -1)
2451 return NULL; /* no can do, in 16-bit EA */
2452 if (b == -1 && i != -1) {
2453 int tmp = b;
2454 b = i;
2455 i = tmp;
2456 } /* swap */
2457 if ((b == R_SI || b == R_DI) && i != -1) {
2458 int tmp = b;
2459 b = i;
2460 i = tmp;
2461 }
2462 /* have BX/BP as base, SI/DI index */
2463 if (b == i)
2464 return NULL; /* shouldn't ever happen, in theory */
2465 if (i != -1 && b != -1 &&
2466 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2467 return NULL; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002468 if (b == -1) /* pure offset: handled above */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002469 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002470
H. Peter Anvine2c80182005-01-15 22:15:51 +00002471 rm = -1;
2472 if (i != -1)
2473 switch (i * 256 + b) {
2474 case R_SI * 256 + R_BX:
2475 rm = 0;
2476 break;
2477 case R_DI * 256 + R_BX:
2478 rm = 1;
2479 break;
2480 case R_SI * 256 + R_BP:
2481 rm = 2;
2482 break;
2483 case R_DI * 256 + R_BP:
2484 rm = 3;
2485 break;
2486 } else
2487 switch (b) {
2488 case R_SI:
2489 rm = 4;
2490 break;
2491 case R_DI:
2492 rm = 5;
2493 break;
2494 case R_BP:
2495 rm = 6;
2496 break;
2497 case R_BX:
2498 rm = 7;
2499 break;
2500 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002501 if (rm == -1) /* can't happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002502 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002503
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002504 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2505 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002506 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002507 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002508 (o >= -128 && o <= 127 && seg == NO_SEG &&
2509 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002510 mod = 1;
2511 else
2512 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002513
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002514 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002515 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002516 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002517 }
2518 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002519 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002520
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002521 output->size = 1 + output->sib_present + output->bytes;
2522 return output;
2523}
2524
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002525static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002526{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002527 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002528 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002529
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002530 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002531
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002532 switch (ins->prefixes[PPS_ASIZE]) {
2533 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002534 valid &= 16;
2535 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002536 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002537 valid &= 32;
2538 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002539 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002540 valid &= 64;
2541 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002542 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002543 valid &= (addrbits == 32) ? 16 : 32;
2544 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002545 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002546 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002547 }
2548
2549 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002550 if (is_class(MEMORY, ins->oprs[j].type)) {
2551 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002552
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002553 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002554 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002555 i = 0;
2556 else
2557 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002558
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002559 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002560 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002561 b = 0;
2562 else
2563 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002564
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002565 if (ins->oprs[j].scale == 0)
2566 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002567
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002568 if (!i && !b) {
2569 int ds = ins->oprs[j].disp_size;
2570 if ((addrbits != 64 && ds > 8) ||
2571 (addrbits == 64 && ds == 16))
2572 valid &= ds;
2573 } else {
2574 if (!(REG16 & ~b))
2575 valid &= 16;
2576 if (!(REG32 & ~b))
2577 valid &= 32;
2578 if (!(REG64 & ~b))
2579 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002580
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002581 if (!(REG16 & ~i))
2582 valid &= 16;
2583 if (!(REG32 & ~i))
2584 valid &= 32;
2585 if (!(REG64 & ~i))
2586 valid &= 64;
2587 }
2588 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002589 }
2590
2591 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002592 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002593 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002594 /* Add an address size prefix */
2595 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2596 ins->prefixes[PPS_ASIZE] = pref;
2597 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002598 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002599 /* Impossible... */
2600 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2601 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002602 }
2603
2604 defdisp = ins->addr_size == 16 ? 16 : 32;
2605
2606 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002607 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2608 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2609 /*
2610 * mem_offs sizes must match the address size; if not,
2611 * strip the MEM_OFFS bit and match only EA instructions
2612 */
2613 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2614 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002615 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002616}