blob: dbda08da4988f61440166e39d8f2b08e33aca576 [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.)
H. Peter Anvindcffe4b2008-10-10 22:10:31 -070039 * \1..\4 - that many literal bytes follow in the code stream
40 * \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]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070053 * 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
65 * 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
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070068 * 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
70 * OC0 field set to 0, and the dest field taken from
71 * operand 0..3.
72 * \164..\167 - this instruction uses DREX rather than REX, with the
73 * OC0 field set to 1, and the dest field taken from
74 * operand 0..3.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070075 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070076 * \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.
H. Peter Anvind58656f2008-05-06 20:11:14 -070078 * \173\xab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070079 * 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
H. Peter Anvind85d2502008-05-04 17:53:31 -070089 * V field taken from operand 0..3.
H. Peter Anvina04019c2009-05-03 21:42:34 -070090 * \270 - this instruction uses VEX/XOP rather than REX, with the
H. Peter Anvind85d2502008-05-04 17:53:31 -070091 * V field set to 1111b.
92 *
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 Anvinbd420c72008-05-22 11:24:35 -070096 * [w0] ww = 0 for W = 0
97 * [w1] ww = 1 for W = 1
98 * [wx] ww = 2 for W don't care (always assembled as 0)
99 * [ww] ww = 3 for W used as REX.W
100 *
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.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700120 * \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.
130 * \337 - force a REPNE prefix (0xF3) even if not specified.
131 * \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.
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -0800134 * \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
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700139 * \360 - no SSE prefix (== \364\331)
140 * \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.
148 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000149 * \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 */
178 MOK_JUMP, /* Matching OK but needs jmp_match() */
179 MOK_GOOD /* Matching unconditionally OK */
180};
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,
197 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700198static enum match_result find_match(const struct itemplate **tempp,
199 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])
217 errfunc(ERR_NONFATAL, "invalid %s prefix",
218 prefix_name(ins->prefixes[pos]));
219}
220
221static const char *size_name(int size)
222{
223 switch (size) {
224 case 1:
225 return "byte";
226 case 2:
227 return "word";
228 case 4:
229 return "dword";
230 case 8:
231 return "qword";
232 case 10:
233 return "tword";
234 case 16:
235 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700236 case 32:
237 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700238 default:
239 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,
270 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) {
277 /*
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
283 if (size > 8) {
284 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
285 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800286 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700287
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800288 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800289 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
H. Peter Anvine2c80182005-01-15 22:15:51 +0000304 if (src_get(&lineno, &lnfname)) {
305 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000306 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000307
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800308 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000309}
310
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700311static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700312 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800314 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000315 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000316
Charles Craynef1aefd82008-09-30 16:11:32 -0700317 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700318 return false;
319 if (!optimizing)
320 return false;
321 if (optimizing < 0 && c == 0371)
322 return false;
323
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100325
Victor van den Elzen154e5922009-02-25 17:32:00 +0100326 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100327 /* Be optimistic in pass 1 */
328 return true;
329
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700331 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000332
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700333 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
334 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000336
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800337int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvin65289e82009-07-25 17:25:11 -0700338 insn * instruction, struct ofmt *output, efunc error,
339 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000340{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000341 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700343 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800344 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000345 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800346 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300347 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000348
H. Peter Anvine2c80182005-01-15 22:15:51 +0000349 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000350 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000351 outfmt = output; /* likewise */
352 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000353
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300354 wsize = idata_bytes(instruction->opcode);
355 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000357
H. Peter Anvineba20a72002-04-30 20:53:55 +0000358 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000360 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 if (t < 0)
362 errfunc(ERR_PANIC,
363 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000364
H. Peter Anvine2c80182005-01-15 22:15:51 +0000365 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400366 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700368 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700369 errfunc(ERR_NONFATAL,
370 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000371 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700372 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800374 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700375 offset += wsize;
376 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700377 } else if (e->type == EOT_DB_STRING ||
378 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000380
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800382 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000383 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000384
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 if (align) {
386 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100387 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800388 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 }
390 offset += e->stringlen + align;
391 }
392 }
393 if (t > 0 && t == instruction->times - 1) {
394 /*
395 * Dummy call to list->output to give the offset to the
396 * listing module.
397 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800398 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 list->uplevel(LIST_TIMES);
400 }
401 }
402 if (instruction->times > 1)
403 list->downlevel(LIST_TIMES);
404 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000405 }
406
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700408 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000410
H. Peter Anvin418ca702008-05-30 10:42:30 -0700411 fp = fopen(fname, "rb");
412 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
414 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700415 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000416 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
417 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700418 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700419 static char buf[4096];
420 size_t t = instruction->times;
421 size_t base = 0;
422 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000423
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 len = ftell(fp);
425 if (instruction->eops->next) {
426 base = instruction->eops->next->offset;
427 len -= base;
428 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700429 len > (size_t)instruction->eops->next->next->offset)
430 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 }
432 /*
433 * Dummy call to list->output to give the offset to the
434 * listing module.
435 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800436 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000437 list->uplevel(LIST_INCBIN);
438 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700439 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000440
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 fseek(fp, base, SEEK_SET);
442 l = len;
443 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700444 int32_t m;
445 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 if (!m) {
447 /*
448 * This shouldn't happen unless the file
449 * actually changes while we are reading
450 * it.
451 */
452 error(ERR_NONFATAL,
453 "`incbin': unexpected EOF while"
454 " reading file `%s'", fname);
455 t = 0; /* Try to exit cleanly */
456 break;
457 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800458 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000459 NO_SEG, NO_SEG);
460 l -= m;
461 }
462 }
463 list->downlevel(LIST_INCBIN);
464 if (instruction->times > 1) {
465 /*
466 * Dummy call to list->output to give the offset to the
467 * listing module.
468 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800469 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000470 list->uplevel(LIST_TIMES);
471 list->downlevel(LIST_TIMES);
472 }
473 fclose(fp);
474 return instruction->times * len;
475 }
476 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000477 }
478
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700479 /* Check to see if we need an address-size prefix */
480 add_asp(instruction, bits);
481
H. Peter Anvin23595f52009-07-25 17:44:25 -0700482 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700483
H. Peter Anvin23595f52009-07-25 17:44:25 -0700484 if (m == MOK_GOOD) {
485 /* Matches! */
486 int64_t insn_size = calcsize(segment, offset, bits,
487 instruction, temp->code);
488 itimes = instruction->times;
489 if (insn_size < 0) /* shouldn't be, on pass two */
490 error(ERR_PANIC, "errors made it through from pass one");
491 else
492 while (itimes--) {
493 for (j = 0; j < MAXPREFIX; j++) {
494 uint8_t c = 0;
495 switch (instruction->prefixes[j]) {
496 case P_WAIT:
497 c = 0x9B;
498 break;
499 case P_LOCK:
500 c = 0xF0;
501 break;
502 case P_REPNE:
503 case P_REPNZ:
504 c = 0xF2;
505 break;
506 case P_REPE:
507 case P_REPZ:
508 case P_REP:
509 c = 0xF3;
510 break;
511 case R_CS:
512 if (bits == 64) {
513 error(ERR_WARNING | ERR_PASS2,
514 "cs segment base generated, but will be ignored in 64-bit mode");
515 }
516 c = 0x2E;
517 break;
518 case R_DS:
519 if (bits == 64) {
520 error(ERR_WARNING | ERR_PASS2,
521 "ds segment base generated, but will be ignored in 64-bit mode");
522 }
523 c = 0x3E;
524 break;
525 case R_ES:
526 if (bits == 64) {
527 error(ERR_WARNING | ERR_PASS2,
528 "es segment base generated, but will be ignored in 64-bit mode");
529 }
530 c = 0x26;
531 break;
532 case R_FS:
533 c = 0x64;
534 break;
535 case R_GS:
536 c = 0x65;
537 break;
538 case R_SS:
539 if (bits == 64) {
540 error(ERR_WARNING | ERR_PASS2,
541 "ss segment base generated, but will be ignored in 64-bit mode");
542 }
543 c = 0x36;
544 break;
545 case R_SEGR6:
546 case R_SEGR7:
547 error(ERR_NONFATAL,
548 "segr6 and segr7 cannot be used as prefixes");
549 break;
550 case P_A16:
551 if (bits == 64) {
552 error(ERR_NONFATAL,
553 "16-bit addressing is not supported "
554 "in 64-bit mode");
555 } else if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700556 c = 0x67;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700557 break;
558 case P_A32:
559 if (bits != 32)
560 c = 0x67;
561 break;
562 case P_A64:
563 if (bits != 64) {
564 error(ERR_NONFATAL,
565 "64-bit addressing is only supported "
566 "in 64-bit mode");
567 }
568 break;
569 case P_ASP:
570 c = 0x67;
571 break;
572 case P_O16:
573 if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700574 c = 0x66;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700575 break;
576 case P_O32:
577 if (bits == 16)
578 c = 0x66;
579 break;
580 case P_O64:
581 /* REX.W */
582 break;
583 case P_OSP:
584 c = 0x66;
585 break;
586 case P_none:
587 break;
588 default:
589 error(ERR_PANIC, "invalid instruction prefix");
590 }
591 if (c != 0) {
592 out(offset, segment, &c, OUT_RAWDATA, 1,
593 NO_SEG, NO_SEG);
594 offset++;
595 }
596 }
597 insn_end = offset + insn_size;
598 gencode(segment, offset, bits, instruction,
599 temp, insn_end);
600 offset += insn_size;
601 if (itimes > 0 && itimes == instruction->times - 1) {
602 /*
603 * Dummy call to list->output to give the offset to the
604 * listing module.
605 */
606 list->output(offset, NULL, OUT_RAWDATA, 0);
607 list->uplevel(LIST_TIMES);
608 }
609 }
610 if (instruction->times > 1)
611 list->downlevel(LIST_TIMES);
612 return offset - start;
613 } else {
614 /* No match */
615 switch (m) {
H. Peter Anvin65289e82009-07-25 17:25:11 -0700616 case MERR_OPSIZEMISSING:
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000617 error(ERR_NONFATAL, "operation size not specified");
618 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700619 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000621 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700622 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000624 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700625 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800626 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
627 bits);
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000628 break;
629 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000630 error(ERR_NONFATAL,
631 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000632 break;
633 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000634 }
635 return 0;
636}
637
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800638int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvin65289e82009-07-25 17:25:11 -0700639 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000640{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000641 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700642 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000643
H. Peter Anvine2c80182005-01-15 22:15:51 +0000644 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000645 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400647 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000648 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000649
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700650 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
651 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700652 instruction->opcode == I_DT || instruction->opcode == I_DO ||
653 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000654 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300655 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300658 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400660 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000661 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400664 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000665 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400666 warn_overflow_const(e->offset, wsize);
667 } else if (e->type == EOT_DB_STRING ||
668 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 align = (-osize) % wsize;
672 if (align < 0)
673 align += wsize;
674 isize += osize + align;
675 }
676 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000677 }
678
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700680 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300682 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700683 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000684
H. Peter Anvin418ca702008-05-30 10:42:30 -0700685 fp = fopen(fname, "rb");
686 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
688 fname);
689 else if (fseek(fp, 0L, SEEK_END) < 0)
690 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
691 fname);
692 else {
693 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000694 if (instruction->eops->next) {
695 len -= instruction->eops->next->offset;
696 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700697 len > (size_t)instruction->eops->next->next->offset) {
698 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000699 }
700 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300701 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300703 if (fp)
704 fclose(fp);
705 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000706 }
707
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700708 /* Check to see if we need an address-size prefix */
709 add_asp(instruction, bits);
710
H. Peter Anvin23595f52009-07-25 17:44:25 -0700711 m = find_match(&temp, instruction, segment, offset, bits);
712 if (m == MOK_GOOD) {
713 /* we've matched an instruction. */
714 int64_t isize;
715 const uint8_t *codes = temp->code;
716 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100717
H. Peter Anvin23595f52009-07-25 17:44:25 -0700718 isize = calcsize(segment, offset, bits, instruction, codes);
719 if (isize < 0)
720 return -1;
721 for (j = 0; j < MAXPREFIX; j++) {
722 switch (instruction->prefixes[j]) {
723 case P_A16:
724 if (bits != 16)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700725 isize++;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700726 break;
727 case P_A32:
728 if (bits != 32)
729 isize++;
730 break;
731 case P_O16:
732 if (bits != 16)
733 isize++;
734 break;
735 case P_O32:
736 if (bits == 16)
737 isize++;
738 break;
739 case P_A64:
740 case P_O64:
741 case P_none:
742 break;
743 default:
744 isize++;
745 break;
746 }
747 }
748 return isize * instruction->times;
749 } else {
750 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000751 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000752}
753
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200754static bool possible_sbyte(operand *o, int min_optimizing)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000755{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700756 return o->wrt == NO_SEG && o->segment == NO_SEG &&
H. Peter Anvine8ab8912009-02-26 16:34:56 -0800757 !(o->opflags & OPFLAG_UNKNOWN) &&
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200758 optimizing >= min_optimizing && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000759}
760
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700761/* check that opn[op] is a signed byte of size 16 or 32 */
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200762static bool is_sbyte16(operand *o, int min_optimizing)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700763{
764 int16_t v;
765
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200766 if (!possible_sbyte(o, min_optimizing))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700767 return false;
768
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700769 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700770 return v >= -128 && v <= 127;
771}
772
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200773static bool is_sbyte32(operand *o, int min_optimizing)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774{
775 int32_t v;
776
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200777 if (!possible_sbyte(o, min_optimizing))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700778 return false;
779
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700780 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700781 return v >= -128 && v <= 127;
782}
783
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200784/* Check if o is zero of size 16 or 32 */
785static bool is_zero16(operand *o, int min_optimizing)
786{
787 int16_t v;
788
789 if (!possible_sbyte(o, min_optimizing))
790 return false;
791
792 v = o->offset;
793 return v == 0;
794}
795
796static bool is_zero32(operand *o, int min_optimizing)
797{
798 int32_t v;
799
800 if (!possible_sbyte(o, min_optimizing))
801 return false;
802
803 v = o->offset;
804 return v == 0;
805}
806
H. Peter Anvin507ae032008-10-09 15:37:10 -0700807/* Common construct */
808#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
809
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800810static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700811 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000812{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800813 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000814 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000815 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700816 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700817 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700818 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000819
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700820 ins->rex = 0; /* Ensure REX is reset */
821
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700822 if (ins->prefixes[PPS_OSIZE] == P_O64)
823 ins->rex |= REX_W;
824
H. Peter Anvine2c80182005-01-15 22:15:51 +0000825 (void)segment; /* Don't warn that this parameter is unused */
826 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000827
H. Peter Anvin839eca22007-10-29 23:12:47 -0700828 while (*codes) {
829 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700830 op1 = (c & 3) + ((opex & 1) << 2);
831 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
832 opx = &ins->oprs[op1];
833 opex = 0; /* For the next iteration */
834
H. Peter Anvin839eca22007-10-29 23:12:47 -0700835 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000836 case 01:
837 case 02:
838 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700839 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000840 codes += c, length += c;
841 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700842
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700843 case 05:
844 case 06:
845 case 07:
846 opex = c;
847 break;
848
H. Peter Anvin507ae032008-10-09 15:37:10 -0700849 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000850 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700851 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000852 codes++, length++;
853 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700854
855 case4(014):
856 case4(020):
857 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000858 length++;
859 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700860
861 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000862 length += 2;
863 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700864
865 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700866 if (opx->type & (BITS16 | BITS32 | BITS64))
867 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 else
869 length += (bits == 16) ? 2 : 4;
870 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700871
872 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000873 length += 4;
874 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700875
876 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700877 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700879
880 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 length++;
882 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700883
884 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000885 length += 8; /* MOV reg64/imm */
886 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700887
888 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 length += 2;
890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
892 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700893 if (opx->type & (BITS16 | BITS32 | BITS64))
894 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000895 else
896 length += (bits == 16) ? 2 : 4;
897 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700898
899 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 length += 4;
901 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700902
903 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700904 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000905 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700906
907 case4(0140):
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200908 length += is_sbyte16(opx, 0) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000909 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700910
911 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800912 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000913 length++;
914 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700915
916 case4(0150):
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200917 length += is_sbyte32(opx, 0) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700918 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700919
920 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800921 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700922 length++;
923 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700924
925 case4(0160):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700926 length++;
927 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700928 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700929 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700930
931 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700932 length++;
933 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700934 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700935 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700936
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700937 case 0171:
938 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700939
H. Peter Anvind85d2502008-05-04 17:53:31 -0700940 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700941 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700942 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700943 codes++;
944 length++;
945 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700946
947 case4(0250):
Victor van den Elzenac732cb2009-03-31 04:59:44 +0200948 length += is_sbyte32(opx, 0) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700949 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700950
951 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -0700952 length += 4;
953 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700954
955 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -0700956 ins->rex |= REX_V;
957 ins->drexdst = regval(opx);
H. Peter Anvina04019c2009-05-03 21:42:34 -0700958 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700959 ins->vex_wlp = *codes++;
960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
H. Peter Anvind85d2502008-05-04 17:53:31 -0700962 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700963 ins->rex |= REX_V;
964 ins->drexdst = 0;
H. Peter Anvina04019c2009-05-03 21:42:34 -0700965 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700966 ins->vex_wlp = *codes++;
967 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700968
969 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700970 length++;
971 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700972
973 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700975
H. Peter Anvine2c80182005-01-15 22:15:51 +0000976 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700977 if (bits == 64)
978 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700979 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000980 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700981
H. Peter Anvine2c80182005-01-15 22:15:51 +0000982 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700983 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000984 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700985
H. Peter Anvine2c80182005-01-15 22:15:51 +0000986 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700987 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700988
Keith Kaniosb7a89542007-04-12 02:40:54 +0000989 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700990 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
991 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700992 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000993 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700994
995 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -0800996 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700997
H. Peter Anvine2c80182005-01-15 22:15:51 +0000998 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000999 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001000 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001001
H. Peter Anvine2c80182005-01-15 22:15:51 +00001002 case 0321:
1003 length += (bits == 16);
1004 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001005
H. Peter Anvine2c80182005-01-15 22:15:51 +00001006 case 0322:
1007 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001008
Keith Kaniosb7a89542007-04-12 02:40:54 +00001009 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001010 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001011 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001012
Keith Kaniosb7a89542007-04-12 02:40:54 +00001013 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001014 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001015 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001016
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001017 case 0325:
1018 ins->rex |= REX_NH;
1019 break;
1020
H. Peter Anvine2c80182005-01-15 22:15:51 +00001021 case 0330:
1022 codes++, length++;
1023 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001024
H. Peter Anvine2c80182005-01-15 22:15:51 +00001025 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001026 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001027
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001028 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001029 case 0333:
1030 length++;
1031 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001032
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001033 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001034 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001035 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001036
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001037 case 0335:
1038 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001039
H. Peter Anvin962e3052008-08-28 17:47:16 -07001040 case 0336:
1041 if (!ins->prefixes[PPS_LREP])
1042 ins->prefixes[PPS_LREP] = P_REP;
1043 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001044
H. Peter Anvin962e3052008-08-28 17:47:16 -07001045 case 0337:
1046 if (!ins->prefixes[PPS_LREP])
1047 ins->prefixes[PPS_LREP] = P_REPNE;
1048 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001049
H. Peter Anvine2c80182005-01-15 22:15:51 +00001050 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001051 if (ins->oprs[0].segment != NO_SEG)
1052 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1053 " quantity of BSS space");
1054 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001055 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001056 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001057
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001058 case 0341:
1059 if (!ins->prefixes[PPS_WAIT])
1060 ins->prefixes[PPS_WAIT] = P_WAIT;
1061 break;
1062
H. Peter Anvin507ae032008-10-09 15:37:10 -07001063 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001064 length++;
1065 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001066
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001067 case 0360:
1068 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001069
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001070 case 0361:
1071 case 0362:
1072 case 0363:
1073 length++;
1074 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001075
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001076 case 0364:
1077 case 0365:
1078 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001079
Keith Kanios48af1772007-08-17 07:37:52 +00001080 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001081 case 0367:
1082 length++;
1083 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001084
H. Peter Anvine2c80182005-01-15 22:15:51 +00001085 case 0370:
1086 case 0371:
1087 case 0372:
1088 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001089
H. Peter Anvine2c80182005-01-15 22:15:51 +00001090 case 0373:
1091 length++;
1092 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001093
1094 case4(0100):
1095 case4(0110):
1096 case4(0120):
1097 case4(0130):
1098 case4(0200):
1099 case4(0204):
1100 case4(0210):
1101 case4(0214):
1102 case4(0220):
1103 case4(0224):
1104 case4(0230):
1105 case4(0234):
1106 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001107 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001108 int rfield;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001109 opflags_t rflags;
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001110 struct operand *opy = &ins->oprs[op2];
1111
Keith Kaniosb7a89542007-04-12 02:40:54 +00001112 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001113
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001114 if (c <= 0177) {
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001115 /* pick rfield from operand b (opx) */
1116 rflags = regflag(opx);
1117 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001118 } else {
1119 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001120 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001121 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001122 if (!process_ea(opy, &ea_data, bits,
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001123 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001124 errfunc(ERR_NONFATAL, "invalid effective address");
1125 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001126 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001127 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001128 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001129 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001130 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001131 break;
1132
1133 default:
1134 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001135 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001136 break;
1137 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001138 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001139
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001140 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001141
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001142 if (ins->rex & REX_NH) {
1143 if (ins->rex & REX_H) {
1144 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1145 return -1;
1146 }
1147 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
1148 }
1149
H. Peter Anvind85d2502008-05-04 17:53:31 -07001150 if (ins->rex & REX_V) {
1151 int bad32 = REX_R|REX_W|REX_X|REX_B;
1152
1153 if (ins->rex & REX_H) {
1154 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1155 return -1;
1156 }
1157 switch (ins->vex_wlp & 030) {
1158 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001159 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001160 ins->rex &= ~REX_W;
1161 break;
1162 case 010:
1163 ins->rex |= REX_W;
1164 bad32 &= ~REX_W;
1165 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001166 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001167 /* Follow REX_W */
1168 break;
1169 }
1170
1171 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1172 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1173 return -1;
1174 }
H. Peter Anvina04019c2009-05-03 21:42:34 -07001175 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
H. Peter Anvind85d2502008-05-04 17:53:31 -07001176 length += 3;
1177 else
1178 length += 2;
1179 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001180 if (ins->rex & REX_H) {
1181 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1182 return -1;
1183 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001184 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001185 ins->drexdst > 7)) {
1186 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1187 return -1;
1188 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001189 length++;
1190 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001191 if (ins->rex & REX_H) {
1192 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1193 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001194 } else if (bits == 64) {
1195 length++;
1196 } else if ((ins->rex & REX_L) &&
1197 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1198 cpu >= IF_X86_64) {
1199 /* LOCK-as-REX.R */
1200 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001201 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001202 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001203 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1204 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001205 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001206 }
1207
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001208 return length;
1209}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001210
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001211#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001212 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001213 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001214 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001215 ins->rex = 0; \
1216 offset += 1; \
1217 }
1218
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001219static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001220 insn * ins, const struct itemplate *temp,
1221 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001222{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001223 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001224 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1225 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1226 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001227 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001228 uint8_t c;
1229 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001230 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001231 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001232 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001233 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001234 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001235 uint8_t opex = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001236
H. Peter Anvin839eca22007-10-29 23:12:47 -07001237 while (*codes) {
1238 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001239 op1 = (c & 3) + ((opex & 1) << 2);
1240 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1241 opx = &ins->oprs[op1];
1242 opex = 0; /* For the next iteration */
1243
H. Peter Anvin839eca22007-10-29 23:12:47 -07001244 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 case 01:
1246 case 02:
1247 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001248 case 04:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001249 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001250 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001251 codes += c;
1252 offset += c;
1253 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001254
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001255 case 05:
1256 case 06:
1257 case 07:
1258 opex = c;
1259 break;
1260
H. Peter Anvin507ae032008-10-09 15:37:10 -07001261 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001262 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001263 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001264 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001265 offset += 1;
1266 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001267
H. Peter Anvin507ae032008-10-09 15:37:10 -07001268 case4(014):
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001269 /* The test for BITS8 and SBYTE here is intended to avoid
1270 warning on optimizer actions due to SBYTE, while still
1271 warn on explicit BYTE directives. Also warn, obviously,
1272 if the optimizer isn't enabled. */
1273 if (((opx->type & BITS8) ||
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001274 !(opx->type & temp->opd[op1] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001275 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001276 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001277 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001278 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 if (opx->segment != NO_SEG) {
1280 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001281 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001285 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 NO_SEG);
1287 }
1288 offset += 1;
1289 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001290
H. Peter Anvin507ae032008-10-09 15:37:10 -07001291 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001293 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001294 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001295 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001296 if (opx->segment != NO_SEG) {
1297 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001298 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001299 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001300 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001301 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001302 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001303 NO_SEG);
1304 }
1305 offset += 1;
1306 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001307
H. Peter Anvin507ae032008-10-09 15:37:10 -07001308 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001310 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001311 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001312 if (opx->segment != NO_SEG) {
1313 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001314 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001315 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001316 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001318 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001319 NO_SEG);
1320 }
1321 offset += 1;
1322 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001323
H. Peter Anvin507ae032008-10-09 15:37:10 -07001324 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001325 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001326 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001327 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001328 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001329 offset += 2;
1330 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001331
H. Peter Anvin507ae032008-10-09 15:37:10 -07001332 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 if (opx->type & (BITS16 | BITS32))
1334 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001335 else
1336 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001337 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 offset += size;
1342 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001343
H. Peter Anvin507ae032008-10-09 15:37:10 -07001344 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001345 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001346 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001347 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001348 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001349 offset += 4;
1350 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001351
H. Peter Anvin507ae032008-10-09 15:37:10 -07001352 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001354 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001355 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001356 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001358 offset += size;
1359 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001360
H. Peter Anvin507ae032008-10-09 15:37:10 -07001361 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001362 if (opx->segment != segment) {
1363 data = opx->offset;
1364 out(offset, segment, &data,
1365 OUT_REL1ADR, insn_end - offset,
1366 opx->segment, opx->wrt);
1367 } else {
1368 data = opx->offset - insn_end;
1369 if (data > 127 || data < -128)
1370 errfunc(ERR_NONFATAL, "short jump is out of range");
1371 out(offset, segment, &data,
1372 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1373 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 offset += 1;
1375 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001376
H. Peter Anvin507ae032008-10-09 15:37:10 -07001377 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001379 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001380 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001381 offset += 8;
1382 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001383
H. Peter Anvin507ae032008-10-09 15:37:10 -07001384 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001385 if (opx->segment != segment) {
1386 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001388 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001389 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001392 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001393 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001394 }
1395 offset += 2;
1396 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001397
H. Peter Anvin507ae032008-10-09 15:37:10 -07001398 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001399 if (opx->type & (BITS16 | BITS32 | BITS64))
1400 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001401 else
1402 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001403 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001404 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 out(offset, segment, &data,
1406 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1407 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001408 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001409 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001410 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001411 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001412 }
1413 offset += size;
1414 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001415
H. Peter Anvin507ae032008-10-09 15:37:10 -07001416 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 if (opx->segment != segment) {
1418 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001420 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001421 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001424 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001425 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001426 }
1427 offset += 4;
1428 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001429
H. Peter Anvin507ae032008-10-09 15:37:10 -07001430 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001431 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001432 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1433 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001434 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001435 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001436 outfmt->segbase(1 + opx->segment),
1437 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001438 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001440
H. Peter Anvin507ae032008-10-09 15:37:10 -07001441 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001442 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001443 warn_overflow_opd(opx, 2);
Victor van den Elzenac732cb2009-03-31 04:59:44 +02001444 if (is_sbyte16(opx, 0)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001445 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001446 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001447 NO_SEG);
1448 offset++;
1449 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001450 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001451 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001452 offset += 2;
1453 }
1454 break;
1455
H. Peter Anvin507ae032008-10-09 15:37:10 -07001456 case4(0144):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001457 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001458 bytes[0] = *codes++;
Victor van den Elzenac732cb2009-03-31 04:59:44 +02001459 if (is_sbyte16(opx, 0))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001460 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001461 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001462 offset++;
1463 break;
1464
H. Peter Anvin507ae032008-10-09 15:37:10 -07001465 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001467 warn_overflow_opd(opx, 4);
Victor van den Elzenac732cb2009-03-31 04:59:44 +02001468 if (is_sbyte32(opx, 0)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001470 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001471 NO_SEG);
1472 offset++;
1473 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001474 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001475 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001476 offset += 4;
1477 }
1478 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001479
H. Peter Anvin507ae032008-10-09 15:37:10 -07001480 case4(0154):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001481 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001482 bytes[0] = *codes++;
Victor van den Elzenac732cb2009-03-31 04:59:44 +02001483 if (is_sbyte32(opx, 0))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001484 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001485 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001486 offset++;
1487 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001488
H. Peter Anvin507ae032008-10-09 15:37:10 -07001489 case4(0160):
1490 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001491 break;
1492
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001493 case 0171:
1494 bytes[0] =
1495 (ins->drexdst << 4) |
1496 (ins->rex & REX_OC ? 0x08 : 0) |
1497 (ins->rex & (REX_R|REX_X|REX_B));
1498 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001499 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001500 offset++;
1501 break;
1502
H. Peter Anvind85d2502008-05-04 17:53:31 -07001503 case 0172:
1504 c = *codes++;
1505 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001506 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001507 opx = &ins->oprs[c & 7];
1508 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1509 errfunc(ERR_NONFATAL,
1510 "non-absolute expression not permitted as argument %d",
1511 c & 7);
1512 } else {
1513 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001514 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001515 "four-bit argument exceeds bounds");
1516 }
1517 bytes[0] |= opx->offset & 15;
1518 }
1519 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1520 offset++;
1521 break;
1522
H. Peter Anvind58656f2008-05-06 20:11:14 -07001523 case 0173:
1524 c = *codes++;
1525 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001526 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001527 bytes[0] |= c & 15;
1528 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1529 offset++;
1530 break;
1531
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001532 case 0174:
1533 c = *codes++;
1534 opx = &ins->oprs[c];
1535 bytes[0] = nasm_regvals[opx->basereg] << 4;
1536 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1537 offset++;
1538 break;
1539
H. Peter Anvin507ae032008-10-09 15:37:10 -07001540 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001541 data = opx->offset;
H. Peter Anvinad6b8592008-10-07 09:56:38 -07001542 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1543 (int32_t)data != (int64_t)data) {
1544 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1545 "signed dword immediate exceeds bounds");
1546 }
Victor van den Elzenac732cb2009-03-31 04:59:44 +02001547 if (is_sbyte32(opx, 0)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001548 bytes[0] = data;
1549 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1550 NO_SEG);
1551 offset++;
1552 } else {
1553 out(offset, segment, &data, OUT_ADDRESS, 4,
1554 opx->segment, opx->wrt);
1555 offset += 4;
1556 }
1557 break;
1558
H. Peter Anvin507ae032008-10-09 15:37:10 -07001559 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001560 data = opx->offset;
1561 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1562 (int32_t)data != (int64_t)data) {
1563 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1564 "signed dword immediate exceeds bounds");
1565 }
1566 out(offset, segment, &data, OUT_ADDRESS, 4,
1567 opx->segment, opx->wrt);
1568 offset += 4;
1569 break;
1570
H. Peter Anvin507ae032008-10-09 15:37:10 -07001571 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -07001572 case 0270:
1573 codes += 2;
H. Peter Anvina04019c2009-05-03 21:42:34 -07001574 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1575 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1576 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001577 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001578 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001579 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1580 offset += 3;
1581 } else {
1582 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001583 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1584 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001585 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1586 offset += 2;
1587 }
1588 break;
1589
H. Peter Anvin507ae032008-10-09 15:37:10 -07001590 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001591 {
1592 uint64_t uv, um;
1593 int s;
1594
1595 if (ins->rex & REX_W)
1596 s = 64;
1597 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1598 s = 16;
1599 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1600 s = 32;
1601 else
1602 s = bits;
1603
1604 um = (uint64_t)2 << (s-1);
1605 uv = opx->offset;
1606
1607 if (uv > 127 && uv < (uint64_t)-128 &&
1608 (uv < um-128 || uv > um-1)) {
1609 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1610 "signed byte value exceeds bounds");
1611 }
1612 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001613 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001614 out(offset, segment, &data, OUT_ADDRESS, 1,
1615 opx->segment, opx->wrt);
1616 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001617 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001618 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1619 NO_SEG);
1620 }
1621 offset += 1;
1622 break;
1623 }
1624
H. Peter Anvin507ae032008-10-09 15:37:10 -07001625 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001626 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001627
H. Peter Anvine2c80182005-01-15 22:15:51 +00001628 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001629 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001630 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001631 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001632 offset += 1;
1633 } else
1634 offset += 0;
1635 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001636
H. Peter Anvine2c80182005-01-15 22:15:51 +00001637 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001638 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001639 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001640 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001641 offset += 1;
1642 } else
1643 offset += 0;
1644 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001645
H. Peter Anvine2c80182005-01-15 22:15:51 +00001646 case 0312:
1647 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001648
Keith Kaniosb7a89542007-04-12 02:40:54 +00001649 case 0313:
1650 ins->rex = 0;
1651 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001652
H. Peter Anvin507ae032008-10-09 15:37:10 -07001653 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001654 break;
1655
H. Peter Anvine2c80182005-01-15 22:15:51 +00001656 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001657 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001659 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 offset += 1;
1661 } else
1662 offset += 0;
1663 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001664
H. Peter Anvine2c80182005-01-15 22:15:51 +00001665 case 0321:
1666 if (bits == 16) {
1667 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001668 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 offset += 1;
1670 } else
1671 offset += 0;
1672 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001673
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001675 case 0323:
1676 break;
1677
Keith Kaniosb7a89542007-04-12 02:40:54 +00001678 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001679 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001681
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001682 case 0325:
1683 break;
1684
H. Peter Anvine2c80182005-01-15 22:15:51 +00001685 case 0330:
1686 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001687 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001688 offset += 1;
1689 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001690
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001692 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001693
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001694 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001695 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001696 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001697 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001698 offset += 1;
1699 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001700
Keith Kanios48af1772007-08-17 07:37:52 +00001701 case 0334:
1702 if (ins->rex & REX_R) {
1703 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001704 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001705 offset += 1;
1706 }
1707 ins->rex &= ~(REX_L|REX_R);
1708 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001709
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001710 case 0335:
1711 break;
1712
H. Peter Anvin962e3052008-08-28 17:47:16 -07001713 case 0336:
1714 case 0337:
1715 break;
1716
H. Peter Anvine2c80182005-01-15 22:15:51 +00001717 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001718 if (ins->oprs[0].segment != NO_SEG)
1719 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1720 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001721 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001722 if (size > 0)
1723 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001724 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001725 offset += size;
1726 }
1727 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001728
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001729 case 0341:
1730 break;
1731
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001732 case 0344:
1733 case 0345:
1734 bytes[0] = c & 1;
1735 switch (ins->oprs[0].basereg) {
1736 case R_CS:
1737 bytes[0] += 0x0E;
1738 break;
1739 case R_DS:
1740 bytes[0] += 0x1E;
1741 break;
1742 case R_ES:
1743 bytes[0] += 0x06;
1744 break;
1745 case R_SS:
1746 bytes[0] += 0x16;
1747 break;
1748 default:
1749 errfunc(ERR_PANIC,
1750 "bizarre 8086 segment register received");
1751 }
1752 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1753 offset++;
1754 break;
1755
1756 case 0346:
1757 case 0347:
1758 bytes[0] = c & 1;
1759 switch (ins->oprs[0].basereg) {
1760 case R_FS:
1761 bytes[0] += 0xA0;
1762 break;
1763 case R_GS:
1764 bytes[0] += 0xA8;
1765 break;
1766 default:
1767 errfunc(ERR_PANIC,
1768 "bizarre 386 segment register received");
1769 }
1770 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1771 offset++;
1772 break;
1773
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001774 case 0360:
1775 break;
1776
1777 case 0361:
1778 bytes[0] = 0x66;
1779 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1780 offset += 1;
1781 break;
1782
1783 case 0362:
1784 case 0363:
1785 bytes[0] = c - 0362 + 0xf2;
1786 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1787 offset += 1;
1788 break;
1789
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001790 case 0364:
1791 case 0365:
1792 break;
1793
Keith Kanios48af1772007-08-17 07:37:52 +00001794 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001795 case 0367:
1796 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001797 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001798 offset += 1;
1799 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001800
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 case 0370:
1802 case 0371:
1803 case 0372:
1804 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001805
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 case 0373:
1807 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001808 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 offset += 1;
1810 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001811
H. Peter Anvin507ae032008-10-09 15:37:10 -07001812 case4(0100):
1813 case4(0110):
1814 case4(0120):
1815 case4(0130):
1816 case4(0200):
1817 case4(0204):
1818 case4(0210):
1819 case4(0214):
1820 case4(0220):
1821 case4(0224):
1822 case4(0230):
1823 case4(0234):
1824 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001825 ea ea_data;
1826 int rfield;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001827 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001828 uint8_t *p;
1829 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001830 enum out_type type;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001831 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001832
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001833 if (c <= 0177) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001834 /* pick rfield from operand b (opx) */
1835 rflags = regflag(opx);
1836 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001837 } else {
1838 /* rfield is constant */
1839 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001840 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001841 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001842
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001843 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
1844 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001845 errfunc(ERR_NONFATAL, "invalid effective address");
1846 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001847
Charles Crayne7e975552007-11-03 22:06:13 -07001848
H. Peter Anvine2c80182005-01-15 22:15:51 +00001849 p = bytes;
1850 *p++ = ea_data.modrm;
1851 if (ea_data.sib_present)
1852 *p++ = ea_data.sib;
1853
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001854 /* DREX suffixes come between the SIB and the displacement */
1855 if (ins->rex & REX_D) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001856 *p++ = (ins->drexdst << 4) |
1857 (ins->rex & REX_OC ? 0x08 : 0) |
1858 (ins->rex & (REX_R|REX_X|REX_B));
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001859 ins->rex = 0;
1860 }
1861
H. Peter Anvine2c80182005-01-15 22:15:51 +00001862 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001863 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001864
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001865 /*
1866 * Make sure the address gets the right offset in case
1867 * the line breaks in the .lst file (BR 1197827)
1868 */
1869 offset += s;
1870 s = 0;
1871
H. Peter Anvine2c80182005-01-15 22:15:51 +00001872 switch (ea_data.bytes) {
1873 case 0:
1874 break;
1875 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001876 case 2:
1877 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001878 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001879 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001880 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001881 if (ea_data.rip) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001882 if (opy->segment == segment) {
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001883 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001884 if (overflow_signed(data, ea_data.bytes))
1885 warn_overflow(ERR_PASS2, ea_data.bytes);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001886 out(offset, segment, &data, OUT_ADDRESS,
1887 ea_data.bytes, NO_SEG, NO_SEG);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001888 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001889 /* overflow check in output/linker? */
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001890 out(offset, segment, &data, OUT_REL4ADR,
1891 insn_end - offset, opy->segment, opy->wrt);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001892 }
H. Peter Anvin9f817132008-10-06 19:11:07 -07001893 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001894 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1895 signed_bits(opy->offset, ins->addr_size) !=
1896 signed_bits(opy->offset, ea_data.bytes * 8))
1897 warn_overflow(ERR_PASS2, ea_data.bytes);
1898
H. Peter Anvin9f817132008-10-06 19:11:07 -07001899 type = OUT_ADDRESS;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001900 out(offset, segment, &data, OUT_ADDRESS,
1901 ea_data.bytes, opy->segment, opy->wrt);
H. Peter Anvin9f817132008-10-06 19:11:07 -07001902 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001903 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001904 default:
1905 /* Impossible! */
1906 errfunc(ERR_PANIC,
1907 "Invalid amount of bytes (%d) for offset?!",
1908 ea_data.bytes);
1909 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001910 }
1911 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001912 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001913 break;
1914
1915 default:
1916 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001917 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001918 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001919 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001920 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001921}
1922
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001923static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001924{
1925 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1926 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1927 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001928 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001929}
1930
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001931static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001932{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001933 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1934 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001935 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001936 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001937}
1938
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001939static int op_rexflags(const operand * o, int mask)
1940{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001941 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001942 int val;
1943
1944 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1945 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1946 }
1947
H. Peter Anvina4835d42008-05-20 14:21:29 -07001948 flags = nasm_reg_flags[o->basereg];
1949 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001950
1951 return rexflags(val, flags, mask);
1952}
1953
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001954static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001955{
1956 int rex = 0;
1957
1958 if (val >= 8)
1959 rex |= REX_B|REX_X|REX_R;
1960 if (flags & BITS64)
1961 rex |= REX_W;
1962 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1963 rex |= REX_H;
1964 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1965 rex |= REX_P;
1966
1967 return rex & mask;
1968}
1969
H. Peter Anvin23595f52009-07-25 17:44:25 -07001970static enum match_result find_match(const struct itemplate **tempp,
1971 insn *instruction,
1972 int32_t segment, int64_t offset, int bits)
1973{
1974 const struct itemplate *temp;
1975 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001976 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001977 bool opsizemissing = false;
1978 int i;
1979
1980 for (i = 0; i < instruction->operands; i++)
1981 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001982
1983 merr = MERR_INVALOP;
1984
1985 for (temp = nasm_instructions[instruction->opcode];
1986 temp->opcode != I_none; temp++) {
1987 m = matches(temp, instruction, bits);
1988 if (m == MOK_JUMP) {
1989 if (jmp_match(segment, offset, bits, instruction, temp->code))
1990 m = MOK_GOOD;
1991 else
1992 m = MERR_INVALOP;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001993 } else if (m == MERR_OPSIZEMISSING &&
1994 (temp->flags & IF_SMASK) != IF_SX) {
1995 /*
1996 * Missing operand size and a candidate for fuzzy matching...
1997 */
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001998 for (i = 0; i < temp->operands; i++) {
1999 if ((temp->opd[i] & SAME_AS) == 0)
2000 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
2001 }
H. Peter Anvina81655b2009-07-25 18:15:28 -07002002 opsizemissing = true;
2003 }
2004 if (m > merr)
2005 merr = m;
2006 if (merr == MOK_GOOD)
2007 goto done;
2008 }
2009
2010 /* No match, but see if we can get a fuzzy operand size match... */
2011 if (!opsizemissing)
2012 goto done;
2013
2014 for (i = 0; i < instruction->operands; i++) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002015 /*
2016 * We ignore extrinsic operand sizes on registers, so we should
2017 * never try to fuzzy-match on them. This also resolves the case
2018 * when we have e.g. "xmmrm128" in two different positions.
2019 */
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002020 if (is_class(REGISTER, instruction->oprs[i].type))
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002021 continue;
2022
H. Peter Anvina81655b2009-07-25 18:15:28 -07002023 /* This tests if xsizeflags[i] has more than one bit set */
2024 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2025 goto done; /* No luck */
2026
2027 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
2028 }
2029
2030 /* Try matching again... */
2031 for (temp = nasm_instructions[instruction->opcode];
2032 temp->opcode != I_none; temp++) {
2033 m = matches(temp, instruction, bits);
2034 if (m == MOK_JUMP) {
2035 if (jmp_match(segment, offset, bits, instruction, temp->code))
2036 m = MOK_GOOD;
2037 else
2038 m = MERR_INVALOP;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002039 }
2040 if (m > merr)
2041 merr = m;
2042 if (merr == MOK_GOOD)
H. Peter Anvina81655b2009-07-25 18:15:28 -07002043 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002044 }
2045
H. Peter Anvina81655b2009-07-25 18:15:28 -07002046done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002047 *tempp = temp;
2048 return merr;
2049}
2050
H. Peter Anvin65289e82009-07-25 17:25:11 -07002051static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002052 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002053{
H. Peter Anvin60926242009-07-26 16:25:38 -07002054 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002055 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002056
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002057 /*
2058 * Check the opcode
2059 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002060 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002061 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002062
2063 /*
2064 * Count the operands
2065 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002066 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002067 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002068
2069 /*
2070 * Check that no spurious colons or TOs are present
2071 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002072 for (i = 0; i < itemp->operands; i++)
2073 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002074 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002075
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002076 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002077 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002078 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002079 switch (itemp->flags & IF_SMASK) {
2080 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002081 asize = BITS8;
2082 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002083 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002084 asize = BITS16;
2085 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002086 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002087 asize = BITS32;
2088 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002089 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002090 asize = BITS64;
2091 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002092 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002093 asize = BITS128;
2094 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002095 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002096 asize = BITS256;
2097 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002098 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002099 switch (bits) {
2100 case 16:
2101 asize = BITS16;
2102 break;
2103 case 32:
2104 asize = BITS32;
2105 break;
2106 case 64:
2107 asize = BITS64;
2108 break;
2109 default:
2110 asize = 0;
2111 break;
2112 }
2113 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002114 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002115 asize = 0;
2116 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002117 }
2118
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002119 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002120 /* S- flags only apply to a specific operand */
2121 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2122 memset(size, 0, sizeof size);
2123 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002124 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002125 /* S- flags apply to all operands */
2126 for (i = 0; i < MAX_OPERANDS; i++)
2127 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002128 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002129
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002130 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002131 * Check that the operand flags all match up,
2132 * it's a bit tricky so lets be verbose:
2133 *
2134 * 1) Find out the size of operand. If instruction
2135 * doesn't have one specified -- we're trying to
2136 * guess it either from template (IF_S* flag) or
2137 * from code bits.
2138 *
2139 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2140 * (ie the same operand as was specified somewhere in template, and
2141 * this referred operand index is being achieved via ~SAME_AS)
2142 * we are to be sure that both registers (in template and instruction)
2143 * do exactly match.
2144 *
2145 * 3) If template operand do not match the instruction OR
2146 * template has an operand size specified AND this size differ
2147 * from which instruction has (perhaps we got it from code bits)
2148 * we are:
2149 * a) Check that only size of instruction and operand is differ
2150 * other characteristics do match
2151 * b) Perhaps it's a register specified in instruction so
2152 * for such a case we just mark that operand as "size
2153 * missing" and this will turn on fuzzy operand size
2154 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002155 */
2156 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002157 opflags_t type = instruction->oprs[i].type;
2158 if (!(type & SIZE_MASK))
2159 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002160
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002161 if (itemp->opd[i] & SAME_AS) {
2162 int j = itemp->opd[i] & ~SAME_AS;
2163 if (type != instruction->oprs[j].type ||
2164 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2165 return MERR_INVALOP;
2166 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002167 ((itemp->opd[i] & SIZE_MASK) &&
2168 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002169 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002170 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002171 } else if (!is_class(REGISTER, type)) {
2172 /*
2173 * Note: we don't honor extrinsic operand sizes for registers,
2174 * so "missing operand size" for a register should be
2175 * considered a wildcard match rather than an error.
2176 */
2177 opsizemissing = true;
2178 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002179 }
2180 }
2181
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002182 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002183 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002184
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002185 /*
2186 * Check operand sizes
2187 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002188 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002189 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002190 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002191 asize = itemp->opd[i] & SIZE_MASK;
2192 if (asize) {
2193 for (i = 0; i < oprs; i++)
2194 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002195 break;
2196 }
2197 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002198 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002199 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002200 }
2201
Keith Kaniosb7a89542007-04-12 02:40:54 +00002202 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002203 if (!(itemp->opd[i] & SIZE_MASK) &&
2204 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002205 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002206 }
2207
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002208 /*
2209 * Check template is okay at the set cpu level
2210 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002211 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002212 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002213
Keith Kaniosb7a89542007-04-12 02:40:54 +00002214 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002215 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002216 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002217 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002218 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002219
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002220 /*
2221 * Check if special handling needed for Jumps
2222 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002223 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002224 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002225
H. Peter Anvin60926242009-07-26 16:25:38 -07002226 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002227}
2228
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002229static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002230 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002231{
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002232 bool byte_offs = !!(input->eaflags & EAF_BYTEOFFS);
2233 bool word_offs = !!(input->eaflags & EAF_WORDOFFS);
2234 bool no_offs = !!(input->eaflags & EAF_NO_OFFS);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002235
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002236 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002237
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002238 /* REX flags for the rfield operand */
2239 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2240
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002241 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002242 int i;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002243 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002244
2245 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002246 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002247 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002248 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002249 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002250
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002251 if (REG_EA & ~f)
2252 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002253
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002254 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2255
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002256 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002257 output->bytes = 0; /* no offset necessary either */
2258 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002259 } else { /* it's a memory reference */
2260 if (input->basereg == -1
2261 && (input->indexreg == -1 || input->scale == 0)) {
2262 /* it's a pure offset */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002263
2264 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2265 input->segment == NO_SEG) {
2266 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2267 input->type &= ~IP_REL;
2268 input->type |= MEMORY;
2269 }
2270
2271 if (input->eaflags & EAF_BYTEOFFS ||
2272 (input->eaflags & EAF_WORDOFFS &&
2273 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2274 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2275 }
2276
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002277 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002278 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002279 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002280 scale = 0;
2281 index = 4;
2282 base = 5;
2283 output->sib = (scale << 6) | (index << 3) | base;
2284 output->bytes = 4;
2285 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002286 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002287 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002288 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002289 output->bytes = (addrbits != 16 ? 4 : 2);
2290 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002291 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002292 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002293 } else { /* it's an indirection */
2294 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002295 int hb = input->hintbase, ht = input->hinttype;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002296 int t, it, bt; /* register numbers */
2297 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002298
H. Peter Anvine2c80182005-01-15 22:15:51 +00002299 if (s == 0)
2300 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002301
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002302 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002303 it = nasm_regvals[i];
2304 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002305 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002306 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002307 ix = 0;
2308 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002309
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002310 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002311 bt = nasm_regvals[b];
2312 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002313 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002314 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002315 bx = 0;
2316 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002317
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002318 /* check for a 32/64-bit memory reference... */
2319 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002320 /* it must be a 32/64-bit memory reference. Firstly we have
2321 * to check that all registers involved are type E/Rxx. */
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002322 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002323
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002324 if (it != -1) {
2325 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2326 sok &= ix;
2327 else
2328 return NULL;
2329 }
2330
2331 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002332 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002333 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002334 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002335 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002336 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002337 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002338
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002339 /* While we're here, ensure the user didn't specify
2340 WORD or QWORD. */
2341 if (input->disp_size == 16 || input->disp_size == 64)
2342 return NULL;
2343
2344 if (addrbits == 16 ||
2345 (addrbits == 32 && !(sok & BITS32)) ||
2346 (addrbits == 64 && !(sok & BITS64)))
2347 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002348
Keith Kaniosb7a89542007-04-12 02:40:54 +00002349 /* now reorganize base/index */
2350 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002351 ((hb == b && ht == EAH_NOTBASE)
2352 || (hb == i && ht == EAH_MAKEBASE))) {
2353 /* swap if hints say so */
2354 t = bt, bt = it, it = t;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002355 x = bx, bx = ix, ix = x;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002356 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002357 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002358 bt = -1, bx = 0, s++;
2359 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2360 /* make single reg base, unless hint */
2361 bt = it, bx = ix, it = -1, ix = 0;
2362 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002363 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002364 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002365 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002366 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002367 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002368 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002369 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002370 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002371 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002372 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002373 t = it, it = bt, bt = t;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002374 x = ix, ix = bx, bx = x;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002375 }
Keith Kanios48af1772007-08-17 07:37:52 +00002376 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002377 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002378 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002379
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002380 output->rex |= rexflags(it, ix, REX_X);
2381 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002382
Keith Kanios48af1772007-08-17 07:37:52 +00002383 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002384 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002385 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002386
Keith Kaniosb7a89542007-04-12 02:40:54 +00002387 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002388 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002389 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002390 } else {
2391 rm = (bt & 7);
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002392 if (rm != REG_NUM_EBP &&
2393 (no_offs || is_zero32(input, -1)) &&
2394 !(byte_offs || word_offs))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002395 mod = 0;
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002396 else if (byte_offs ||
2397 (! word_offs && is_sbyte32(input, -1)) ||
2398 (rm == REG_NUM_EBP && no_offs))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002399 mod = 1;
2400 else
2401 mod = 2;
2402 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002403
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002404 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002405 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2406 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002407 } else {
2408 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002409 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002410
Keith Kaniosb7a89542007-04-12 02:40:54 +00002411 if (it == -1)
2412 index = 4, s = 1;
2413 else
2414 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002415
H. Peter Anvine2c80182005-01-15 22:15:51 +00002416 switch (s) {
2417 case 1:
2418 scale = 0;
2419 break;
2420 case 2:
2421 scale = 1;
2422 break;
2423 case 4:
2424 scale = 2;
2425 break;
2426 case 8:
2427 scale = 3;
2428 break;
2429 default: /* then what the smeg is it? */
2430 return NULL; /* panic */
2431 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002432
Keith Kaniosb7a89542007-04-12 02:40:54 +00002433 if (bt == -1) {
2434 base = 5;
2435 mod = 0;
2436 } else {
2437 base = (bt & 7);
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002438 if (base != REG_NUM_EBP &&
2439 (no_offs || is_zero32(input, -1)) &&
2440 !(byte_offs || word_offs))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002441 mod = 0;
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002442 else if (byte_offs ||
2443 (! word_offs && is_sbyte32(input, -1)) ||
2444 (base == REG_NUM_EBP && no_offs))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002445 mod = 1;
2446 else
2447 mod = 2;
2448 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002449
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002450 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002451 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2452 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002453 output->sib = (scale << 6) | (index << 3) | base;
2454 }
2455 } else { /* it's 16-bit */
2456 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002457
Keith Kaniosb7a89542007-04-12 02:40:54 +00002458 /* check for 64-bit long mode */
2459 if (addrbits == 64)
2460 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002461
H. Peter Anvine2c80182005-01-15 22:15:51 +00002462 /* check all registers are BX, BP, SI or DI */
2463 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2464 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2465 && i != R_SI && i != R_DI))
2466 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002467
Keith Kaniosb7a89542007-04-12 02:40:54 +00002468 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002469 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002470 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002471
H. Peter Anvine2c80182005-01-15 22:15:51 +00002472 if (s != 1 && i != -1)
2473 return NULL; /* no can do, in 16-bit EA */
2474 if (b == -1 && i != -1) {
2475 int tmp = b;
2476 b = i;
2477 i = tmp;
2478 } /* swap */
2479 if ((b == R_SI || b == R_DI) && i != -1) {
2480 int tmp = b;
2481 b = i;
2482 i = tmp;
2483 }
2484 /* have BX/BP as base, SI/DI index */
2485 if (b == i)
2486 return NULL; /* shouldn't ever happen, in theory */
2487 if (i != -1 && b != -1 &&
2488 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2489 return NULL; /* invalid combinations */
2490 if (b == -1) /* pure offset: handled above */
2491 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002492
H. Peter Anvine2c80182005-01-15 22:15:51 +00002493 rm = -1;
2494 if (i != -1)
2495 switch (i * 256 + b) {
2496 case R_SI * 256 + R_BX:
2497 rm = 0;
2498 break;
2499 case R_DI * 256 + R_BX:
2500 rm = 1;
2501 break;
2502 case R_SI * 256 + R_BP:
2503 rm = 2;
2504 break;
2505 case R_DI * 256 + R_BP:
2506 rm = 3;
2507 break;
2508 } else
2509 switch (b) {
2510 case R_SI:
2511 rm = 4;
2512 break;
2513 case R_DI:
2514 rm = 5;
2515 break;
2516 case R_BP:
2517 rm = 6;
2518 break;
2519 case R_BX:
2520 rm = 7;
2521 break;
2522 }
2523 if (rm == -1) /* can't happen, in theory */
2524 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002525
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002526 if (rm != 6 &&
2527 (no_offs || is_zero16(input, -1)) &&
2528 !(byte_offs || word_offs))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002529 mod = 0;
Victor van den Elzenac732cb2009-03-31 04:59:44 +02002530 else if (byte_offs ||
2531 (! word_offs && is_sbyte16(input, -1)) ||
2532 (rm == 6 && no_offs))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002533 mod = 1;
2534 else
2535 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002536
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002537 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002538 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002539 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002540 }
2541 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002542 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002543
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002544 output->size = 1 + output->sib_present + output->bytes;
2545 return output;
2546}
2547
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002548static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002549{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002550 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002551 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002552
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002553 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002554
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002555 switch (ins->prefixes[PPS_ASIZE]) {
2556 case P_A16:
2557 valid &= 16;
2558 break;
2559 case P_A32:
2560 valid &= 32;
2561 break;
2562 case P_A64:
2563 valid &= 64;
2564 break;
2565 case P_ASP:
2566 valid &= (addrbits == 32) ? 16 : 32;
2567 break;
2568 default:
2569 break;
2570 }
2571
2572 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunove4f526b2009-10-18 12:41:14 +04002573 if (is_class(MEMORY, ins->oprs[j].type)) {
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002574 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002575
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002576 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002577 if (ins->oprs[j].indexreg < EXPR_REG_START
2578 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002579 i = 0;
2580 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002581 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002582
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002583 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002584 if (ins->oprs[j].basereg < EXPR_REG_START
2585 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002586 b = 0;
2587 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002588 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002589
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002590 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002591 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002592
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002593 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002594 int ds = ins->oprs[j].disp_size;
2595 if ((addrbits != 64 && ds > 8) ||
2596 (addrbits == 64 && ds == 16))
2597 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002598 } else {
2599 if (!(REG16 & ~b))
2600 valid &= 16;
2601 if (!(REG32 & ~b))
2602 valid &= 32;
2603 if (!(REG64 & ~b))
2604 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002605
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002606 if (!(REG16 & ~i))
2607 valid &= 16;
2608 if (!(REG32 & ~i))
2609 valid &= 32;
2610 if (!(REG64 & ~i))
2611 valid &= 64;
2612 }
2613 }
2614 }
2615
2616 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002617 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002618 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002619 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002620 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002621 ins->prefixes[PPS_ASIZE] = pref;
2622 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002623 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002624 /* Impossible... */
2625 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002626 ins->addr_size = addrbits; /* Error recovery */
2627 }
2628
2629 defdisp = ins->addr_size == 16 ? 16 : 32;
2630
2631 for (j = 0; j < ins->operands; j++) {
2632 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2633 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2634 != ins->addr_size) {
2635 /* mem_offs sizes must match the address size; if not,
2636 strip the MEM_OFFS bit and match only EA instructions */
2637 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2638 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002639 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002640}