blob: ca6f18f115e18f78d28e758713cd30d5ede140e8 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07003 * Copyright 1996-2009 The NASM Authors - All Rights Reserved
4 * 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) {
368 if (wsize == 1) {
369 if (e->segment != NO_SEG)
370 errfunc(ERR_NONFATAL,
371 "one-byte relocation attempted");
372 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000373 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800375 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000377 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700378 errfunc(ERR_NONFATAL,
379 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000380 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 } else
382 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800383 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000384 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700385 } else if (e->type == EOT_DB_STRING ||
386 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000387 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000388
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800390 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000392
H. Peter Anvine2c80182005-01-15 22:15:51 +0000393 if (align) {
394 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100395 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800396 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000397 }
398 offset += e->stringlen + align;
399 }
400 }
401 if (t > 0 && t == instruction->times - 1) {
402 /*
403 * Dummy call to list->output to give the offset to the
404 * listing module.
405 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800406 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 list->uplevel(LIST_TIMES);
408 }
409 }
410 if (instruction->times > 1)
411 list->downlevel(LIST_TIMES);
412 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000413 }
414
H. Peter Anvine2c80182005-01-15 22:15:51 +0000415 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700416 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000417 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000418
H. Peter Anvin418ca702008-05-30 10:42:30 -0700419 fp = fopen(fname, "rb");
420 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000421 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
422 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700423 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
425 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700426 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700427 static char buf[4096];
428 size_t t = instruction->times;
429 size_t base = 0;
430 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000431
H. Peter Anvine2c80182005-01-15 22:15:51 +0000432 len = ftell(fp);
433 if (instruction->eops->next) {
434 base = instruction->eops->next->offset;
435 len -= base;
436 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700437 len > (size_t)instruction->eops->next->next->offset)
438 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000439 }
440 /*
441 * Dummy call to list->output to give the offset to the
442 * listing module.
443 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800444 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000445 list->uplevel(LIST_INCBIN);
446 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700447 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000448
H. Peter Anvine2c80182005-01-15 22:15:51 +0000449 fseek(fp, base, SEEK_SET);
450 l = len;
451 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700452 int32_t m;
453 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000454 if (!m) {
455 /*
456 * This shouldn't happen unless the file
457 * actually changes while we are reading
458 * it.
459 */
460 error(ERR_NONFATAL,
461 "`incbin': unexpected EOF while"
462 " reading file `%s'", fname);
463 t = 0; /* Try to exit cleanly */
464 break;
465 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800466 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000467 NO_SEG, NO_SEG);
468 l -= m;
469 }
470 }
471 list->downlevel(LIST_INCBIN);
472 if (instruction->times > 1) {
473 /*
474 * Dummy call to list->output to give the offset to the
475 * listing module.
476 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800477 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000478 list->uplevel(LIST_TIMES);
479 list->downlevel(LIST_TIMES);
480 }
481 fclose(fp);
482 return instruction->times * len;
483 }
484 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000485 }
486
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700487 /* Check to see if we need an address-size prefix */
488 add_asp(instruction, bits);
489
H. Peter Anvin23595f52009-07-25 17:44:25 -0700490 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700491
H. Peter Anvin23595f52009-07-25 17:44:25 -0700492 if (m == MOK_GOOD) {
493 /* Matches! */
494 int64_t insn_size = calcsize(segment, offset, bits,
495 instruction, temp->code);
496 itimes = instruction->times;
497 if (insn_size < 0) /* shouldn't be, on pass two */
498 error(ERR_PANIC, "errors made it through from pass one");
499 else
500 while (itimes--) {
501 for (j = 0; j < MAXPREFIX; j++) {
502 uint8_t c = 0;
503 switch (instruction->prefixes[j]) {
504 case P_WAIT:
505 c = 0x9B;
506 break;
507 case P_LOCK:
508 c = 0xF0;
509 break;
510 case P_REPNE:
511 case P_REPNZ:
512 c = 0xF2;
513 break;
514 case P_REPE:
515 case P_REPZ:
516 case P_REP:
517 c = 0xF3;
518 break;
519 case R_CS:
520 if (bits == 64) {
521 error(ERR_WARNING | ERR_PASS2,
522 "cs segment base generated, but will be ignored in 64-bit mode");
523 }
524 c = 0x2E;
525 break;
526 case R_DS:
527 if (bits == 64) {
528 error(ERR_WARNING | ERR_PASS2,
529 "ds segment base generated, but will be ignored in 64-bit mode");
530 }
531 c = 0x3E;
532 break;
533 case R_ES:
534 if (bits == 64) {
535 error(ERR_WARNING | ERR_PASS2,
536 "es segment base generated, but will be ignored in 64-bit mode");
537 }
538 c = 0x26;
539 break;
540 case R_FS:
541 c = 0x64;
542 break;
543 case R_GS:
544 c = 0x65;
545 break;
546 case R_SS:
547 if (bits == 64) {
548 error(ERR_WARNING | ERR_PASS2,
549 "ss segment base generated, but will be ignored in 64-bit mode");
550 }
551 c = 0x36;
552 break;
553 case R_SEGR6:
554 case R_SEGR7:
555 error(ERR_NONFATAL,
556 "segr6 and segr7 cannot be used as prefixes");
557 break;
558 case P_A16:
559 if (bits == 64) {
560 error(ERR_NONFATAL,
561 "16-bit addressing is not supported "
562 "in 64-bit mode");
563 } else if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700564 c = 0x67;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700565 break;
566 case P_A32:
567 if (bits != 32)
568 c = 0x67;
569 break;
570 case P_A64:
571 if (bits != 64) {
572 error(ERR_NONFATAL,
573 "64-bit addressing is only supported "
574 "in 64-bit mode");
575 }
576 break;
577 case P_ASP:
578 c = 0x67;
579 break;
580 case P_O16:
581 if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700582 c = 0x66;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700583 break;
584 case P_O32:
585 if (bits == 16)
586 c = 0x66;
587 break;
588 case P_O64:
589 /* REX.W */
590 break;
591 case P_OSP:
592 c = 0x66;
593 break;
594 case P_none:
595 break;
596 default:
597 error(ERR_PANIC, "invalid instruction prefix");
598 }
599 if (c != 0) {
600 out(offset, segment, &c, OUT_RAWDATA, 1,
601 NO_SEG, NO_SEG);
602 offset++;
603 }
604 }
605 insn_end = offset + insn_size;
606 gencode(segment, offset, bits, instruction,
607 temp, insn_end);
608 offset += insn_size;
609 if (itimes > 0 && itimes == instruction->times - 1) {
610 /*
611 * Dummy call to list->output to give the offset to the
612 * listing module.
613 */
614 list->output(offset, NULL, OUT_RAWDATA, 0);
615 list->uplevel(LIST_TIMES);
616 }
617 }
618 if (instruction->times > 1)
619 list->downlevel(LIST_TIMES);
620 return offset - start;
621 } else {
622 /* No match */
623 switch (m) {
H. Peter Anvin65289e82009-07-25 17:25:11 -0700624 case MERR_OPSIZEMISSING:
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000625 error(ERR_NONFATAL, "operation size not specified");
626 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700627 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000628 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000629 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700630 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000631 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000632 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700633 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800634 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
635 bits);
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000636 break;
637 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000638 error(ERR_NONFATAL,
639 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000640 break;
641 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000642 }
643 return 0;
644}
645
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800646int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvin65289e82009-07-25 17:25:11 -0700647 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000648{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000649 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700650 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000651
H. Peter Anvine2c80182005-01-15 22:15:51 +0000652 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000653 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000654
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400655 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000656 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000657
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700658 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
659 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700660 instruction->opcode == I_DT || instruction->opcode == I_DO ||
661 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000662 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300663 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000664
H. Peter Anvine2c80182005-01-15 22:15:51 +0000665 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300666 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000667
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400668 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000669 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400672 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000673 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400674 warn_overflow_const(e->offset, wsize);
675 } else if (e->type == EOT_DB_STRING ||
676 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000678
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 align = (-osize) % wsize;
680 if (align < 0)
681 align += wsize;
682 isize += osize + align;
683 }
684 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000685 }
686
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700688 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300690 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700691 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000692
H. Peter Anvin418ca702008-05-30 10:42:30 -0700693 fp = fopen(fname, "rb");
694 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000695 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
696 fname);
697 else if (fseek(fp, 0L, SEEK_END) < 0)
698 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
699 fname);
700 else {
701 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 if (instruction->eops->next) {
703 len -= instruction->eops->next->offset;
704 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700705 len > (size_t)instruction->eops->next->next->offset) {
706 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000707 }
708 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300709 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000710 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300711 if (fp)
712 fclose(fp);
713 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000714 }
715
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700716 /* Check to see if we need an address-size prefix */
717 add_asp(instruction, bits);
718
H. Peter Anvin23595f52009-07-25 17:44:25 -0700719 m = find_match(&temp, instruction, segment, offset, bits);
720 if (m == MOK_GOOD) {
721 /* we've matched an instruction. */
722 int64_t isize;
723 const uint8_t *codes = temp->code;
724 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100725
H. Peter Anvin23595f52009-07-25 17:44:25 -0700726 isize = calcsize(segment, offset, bits, instruction, codes);
727 if (isize < 0)
728 return -1;
729 for (j = 0; j < MAXPREFIX; j++) {
730 switch (instruction->prefixes[j]) {
731 case P_A16:
732 if (bits != 16)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700733 isize++;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700734 break;
735 case P_A32:
736 if (bits != 32)
737 isize++;
738 break;
739 case P_O16:
740 if (bits != 16)
741 isize++;
742 break;
743 case P_O32:
744 if (bits == 16)
745 isize++;
746 break;
747 case P_A64:
748 case P_O64:
749 case P_none:
750 break;
751 default:
752 isize++;
753 break;
754 }
755 }
756 return isize * instruction->times;
757 } else {
758 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000759 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000760}
761
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700762static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000763{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700764 return o->wrt == NO_SEG && o->segment == NO_SEG &&
H. Peter Anvine8ab8912009-02-26 16:34:56 -0800765 !(o->opflags & OPFLAG_UNKNOWN) &&
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700766 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000767}
768
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700769/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700770static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700771{
772 int16_t v;
773
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700774 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700775 return false;
776
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700777 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700778 return v >= -128 && v <= 127;
779}
780
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700781static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700782{
783 int32_t v;
784
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700785 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700786 return false;
787
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700788 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700789 return v >= -128 && v <= 127;
790}
791
H. Peter Anvin507ae032008-10-09 15:37:10 -0700792/* Common construct */
793#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
794
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800795static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700796 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000797{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800798 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000799 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000800 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700801 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700802 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700803 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000804
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700805 ins->rex = 0; /* Ensure REX is reset */
806
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700807 if (ins->prefixes[PPS_OSIZE] == P_O64)
808 ins->rex |= REX_W;
809
H. Peter Anvine2c80182005-01-15 22:15:51 +0000810 (void)segment; /* Don't warn that this parameter is unused */
811 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000812
H. Peter Anvin839eca22007-10-29 23:12:47 -0700813 while (*codes) {
814 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700815 op1 = (c & 3) + ((opex & 1) << 2);
816 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
817 opx = &ins->oprs[op1];
818 opex = 0; /* For the next iteration */
819
H. Peter Anvin839eca22007-10-29 23:12:47 -0700820 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000821 case 01:
822 case 02:
823 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700824 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000825 codes += c, length += c;
826 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700827
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700828 case 05:
829 case 06:
830 case 07:
831 opex = c;
832 break;
833
H. Peter Anvin507ae032008-10-09 15:37:10 -0700834 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000835 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700836 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 codes++, length++;
838 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700839
840 case4(014):
841 case4(020):
842 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000843 length++;
844 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700845
846 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 length += 2;
848 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700849
850 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700851 if (opx->type & (BITS16 | BITS32 | BITS64))
852 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000853 else
854 length += (bits == 16) ? 2 : 4;
855 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700856
857 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000858 length += 4;
859 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700860
861 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700862 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000863 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700864
865 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000866 length++;
867 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700868
869 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000870 length += 8; /* MOV reg64/imm */
871 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700872
873 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 length += 2;
875 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700876
877 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700878 if (opx->type & (BITS16 | BITS32 | BITS64))
879 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000880 else
881 length += (bits == 16) ? 2 : 4;
882 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700883
884 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 length += 4;
886 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700887
888 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700889 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
892 case4(0140):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700893 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700895
896 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800897 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000898 length++;
899 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700900
901 case4(0150):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700902 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700903 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700904
905 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800906 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700907 length++;
908 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700909
910 case4(0160):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700911 length++;
912 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700913 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700914 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700915
916 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700917 length++;
918 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700919 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700920 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700921
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700922 case 0171:
923 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700924
H. Peter Anvind85d2502008-05-04 17:53:31 -0700925 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700926 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700927 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700928 codes++;
929 length++;
930 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700931
932 case4(0250):
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700933 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700934 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700935
936 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -0700937 length += 4;
938 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700939
940 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -0700941 ins->rex |= REX_V;
942 ins->drexdst = regval(opx);
H. Peter Anvina04019c2009-05-03 21:42:34 -0700943 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700944 ins->vex_wlp = *codes++;
945 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700946
H. Peter Anvind85d2502008-05-04 17:53:31 -0700947 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700948 ins->rex |= REX_V;
949 ins->drexdst = 0;
H. Peter Anvina04019c2009-05-03 21:42:34 -0700950 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700951 ins->vex_wlp = *codes++;
952 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700953
954 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700955 length++;
956 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700957
958 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000959 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700960
H. Peter Anvine2c80182005-01-15 22:15:51 +0000961 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700962 if (bits == 64)
963 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700964 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000965 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700966
H. Peter Anvine2c80182005-01-15 22:15:51 +0000967 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700968 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000969 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700970
H. Peter Anvine2c80182005-01-15 22:15:51 +0000971 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700972 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700973
Keith Kaniosb7a89542007-04-12 02:40:54 +0000974 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700975 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
976 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700977 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000978 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700979
980 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -0800981 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700982
H. Peter Anvine2c80182005-01-15 22:15:51 +0000983 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000984 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000985 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700986
H. Peter Anvine2c80182005-01-15 22:15:51 +0000987 case 0321:
988 length += (bits == 16);
989 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700990
H. Peter Anvine2c80182005-01-15 22:15:51 +0000991 case 0322:
992 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700993
Keith Kaniosb7a89542007-04-12 02:40:54 +0000994 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000995 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000996 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700997
Keith Kaniosb7a89542007-04-12 02:40:54 +0000998 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000999 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001000 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001001
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001002 case 0325:
1003 ins->rex |= REX_NH;
1004 break;
1005
H. Peter Anvine2c80182005-01-15 22:15:51 +00001006 case 0330:
1007 codes++, length++;
1008 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001009
H. Peter Anvine2c80182005-01-15 22:15:51 +00001010 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001011 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001012
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001013 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001014 case 0333:
1015 length++;
1016 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001017
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001018 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001019 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001020 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001021
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001022 case 0335:
1023 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001024
H. Peter Anvin962e3052008-08-28 17:47:16 -07001025 case 0336:
1026 if (!ins->prefixes[PPS_LREP])
1027 ins->prefixes[PPS_LREP] = P_REP;
1028 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001029
H. Peter Anvin962e3052008-08-28 17:47:16 -07001030 case 0337:
1031 if (!ins->prefixes[PPS_LREP])
1032 ins->prefixes[PPS_LREP] = P_REPNE;
1033 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001034
H. Peter Anvine2c80182005-01-15 22:15:51 +00001035 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001036 if (ins->oprs[0].segment != NO_SEG)
1037 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1038 " quantity of BSS space");
1039 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001040 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001041 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001042
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001043 case 0341:
1044 if (!ins->prefixes[PPS_WAIT])
1045 ins->prefixes[PPS_WAIT] = P_WAIT;
1046 break;
1047
H. Peter Anvin507ae032008-10-09 15:37:10 -07001048 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001049 length++;
1050 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001051
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001052 case 0360:
1053 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001054
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001055 case 0361:
1056 case 0362:
1057 case 0363:
1058 length++;
1059 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001060
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001061 case 0364:
1062 case 0365:
1063 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001064
Keith Kanios48af1772007-08-17 07:37:52 +00001065 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001066 case 0367:
1067 length++;
1068 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001069
H. Peter Anvine2c80182005-01-15 22:15:51 +00001070 case 0370:
1071 case 0371:
1072 case 0372:
1073 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001074
H. Peter Anvine2c80182005-01-15 22:15:51 +00001075 case 0373:
1076 length++;
1077 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001078
1079 case4(0100):
1080 case4(0110):
1081 case4(0120):
1082 case4(0130):
1083 case4(0200):
1084 case4(0204):
1085 case4(0210):
1086 case4(0214):
1087 case4(0220):
1088 case4(0224):
1089 case4(0230):
1090 case4(0234):
1091 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001092 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001093 int rfield;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001094 opflags_t rflags;
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001095 struct operand *opy = &ins->oprs[op2];
1096
Keith Kaniosb7a89542007-04-12 02:40:54 +00001097 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001098
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001099 if (c <= 0177) {
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001100 /* pick rfield from operand b (opx) */
1101 rflags = regflag(opx);
1102 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001103 } else {
1104 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001105 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001106 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001107 if (!process_ea(opy, &ea_data, bits,
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001108 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001109 errfunc(ERR_NONFATAL, "invalid effective address");
1110 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001111 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001112 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001113 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001114 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001115 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001116 break;
1117
1118 default:
1119 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001120 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001121 break;
1122 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001123 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001124
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001125 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001126
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001127 if (ins->rex & REX_NH) {
1128 if (ins->rex & REX_H) {
1129 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1130 return -1;
1131 }
1132 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
1133 }
1134
H. Peter Anvind85d2502008-05-04 17:53:31 -07001135 if (ins->rex & REX_V) {
1136 int bad32 = REX_R|REX_W|REX_X|REX_B;
1137
1138 if (ins->rex & REX_H) {
1139 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1140 return -1;
1141 }
1142 switch (ins->vex_wlp & 030) {
1143 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001144 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001145 ins->rex &= ~REX_W;
1146 break;
1147 case 010:
1148 ins->rex |= REX_W;
1149 bad32 &= ~REX_W;
1150 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001151 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001152 /* Follow REX_W */
1153 break;
1154 }
1155
1156 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1157 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1158 return -1;
1159 }
H. Peter Anvina04019c2009-05-03 21:42:34 -07001160 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
H. Peter Anvind85d2502008-05-04 17:53:31 -07001161 length += 3;
1162 else
1163 length += 2;
1164 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001165 if (ins->rex & REX_H) {
1166 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1167 return -1;
1168 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001169 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001170 ins->drexdst > 7)) {
1171 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1172 return -1;
1173 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001174 length++;
1175 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001176 if (ins->rex & REX_H) {
1177 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1178 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001179 } else if (bits == 64) {
1180 length++;
1181 } else if ((ins->rex & REX_L) &&
1182 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1183 cpu >= IF_X86_64) {
1184 /* LOCK-as-REX.R */
1185 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001186 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001187 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001188 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1189 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001190 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001191 }
1192
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001193 return length;
1194}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001195
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001196#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001197 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001198 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001199 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001200 ins->rex = 0; \
1201 offset += 1; \
1202 }
1203
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001204static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001205 insn * ins, const struct itemplate *temp,
1206 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001207{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001208 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001209 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1210 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1211 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001212 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001213 uint8_t c;
1214 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001215 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001216 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001217 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001218 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001219 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001220 uint8_t opex = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001221
H. Peter Anvin839eca22007-10-29 23:12:47 -07001222 while (*codes) {
1223 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001224 op1 = (c & 3) + ((opex & 1) << 2);
1225 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1226 opx = &ins->oprs[op1];
1227 opex = 0; /* For the next iteration */
1228
H. Peter Anvin839eca22007-10-29 23:12:47 -07001229 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001230 case 01:
1231 case 02:
1232 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001233 case 04:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001234 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001235 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001236 codes += c;
1237 offset += c;
1238 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001239
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001240 case 05:
1241 case 06:
1242 case 07:
1243 opex = c;
1244 break;
1245
H. Peter Anvin507ae032008-10-09 15:37:10 -07001246 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001247 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001248 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001249 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001250 offset += 1;
1251 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001252
H. Peter Anvin507ae032008-10-09 15:37:10 -07001253 case4(014):
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001254 /* The test for BITS8 and SBYTE here is intended to avoid
1255 warning on optimizer actions due to SBYTE, while still
1256 warn on explicit BYTE directives. Also warn, obviously,
1257 if the optimizer isn't enabled. */
1258 if (((opx->type & BITS8) ||
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001259 !(opx->type & temp->opd[op1] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001260 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001261 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001262 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001263 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001264 if (opx->segment != NO_SEG) {
1265 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001266 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001267 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001268 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001269 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001270 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001271 NO_SEG);
1272 }
1273 offset += 1;
1274 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001275
H. Peter Anvin507ae032008-10-09 15:37:10 -07001276 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001277 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001278 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001279 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001280 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 if (opx->segment != NO_SEG) {
1282 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001283 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001285 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001286 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001287 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001288 NO_SEG);
1289 }
1290 offset += 1;
1291 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001292
H. Peter Anvin507ae032008-10-09 15:37:10 -07001293 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001294 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001295 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001296 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 if (opx->segment != NO_SEG) {
1298 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001299 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001302 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001303 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001304 NO_SEG);
1305 }
1306 offset += 1;
1307 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001308
H. Peter Anvin507ae032008-10-09 15:37:10 -07001309 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001310 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001311 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001312 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001313 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001314 offset += 2;
1315 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001316
H. Peter Anvin507ae032008-10-09 15:37:10 -07001317 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001318 if (opx->type & (BITS16 | BITS32))
1319 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001320 else
1321 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001322 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001323 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001324 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001325 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 offset += size;
1327 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001328
H. Peter Anvin507ae032008-10-09 15:37:10 -07001329 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001330 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001332 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001334 offset += 4;
1335 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001336
H. Peter Anvin507ae032008-10-09 15:37:10 -07001337 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001339 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001340 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001341 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001342 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001343 offset += size;
1344 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001345
H. Peter Anvin507ae032008-10-09 15:37:10 -07001346 case4(050):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001348 errfunc(ERR_NONFATAL,
1349 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 if (data > 127 || data < -128)
1352 errfunc(ERR_NONFATAL, "short jump is out of range");
1353 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001354 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 offset += 1;
1356 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001357
H. Peter Anvin507ae032008-10-09 15:37:10 -07001358 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001360 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001362 offset += 8;
1363 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001364
H. Peter Anvin507ae032008-10-09 15:37:10 -07001365 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001366 if (opx->segment != segment) {
1367 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001368 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001369 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001370 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001371 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001372 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001374 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001375 }
1376 offset += 2;
1377 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001378
H. Peter Anvin507ae032008-10-09 15:37:10 -07001379 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001380 if (opx->type & (BITS16 | BITS32 | BITS64))
1381 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001382 else
1383 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001385 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001386 out(offset, segment, &data,
1387 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1388 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001389 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001390 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001392 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 }
1394 offset += size;
1395 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001396
H. Peter Anvin507ae032008-10-09 15:37:10 -07001397 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 if (opx->segment != segment) {
1399 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001400 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001401 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001402 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001403 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001404 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001405 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001406 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 }
1408 offset += 4;
1409 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001410
H. Peter Anvin507ae032008-10-09 15:37:10 -07001411 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001412 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001413 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1414 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001415 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001416 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 outfmt->segbase(1 + opx->segment),
1418 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001419 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001420 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001421
H. Peter Anvin507ae032008-10-09 15:37:10 -07001422 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001424 warn_overflow_opd(opx, 2);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001425 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001426 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001427 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001428 NO_SEG);
1429 offset++;
1430 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001431 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001432 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001433 offset += 2;
1434 }
1435 break;
1436
H. Peter Anvin507ae032008-10-09 15:37:10 -07001437 case4(0144):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001438 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001439 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001440 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001441 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001442 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001443 offset++;
1444 break;
1445
H. Peter Anvin507ae032008-10-09 15:37:10 -07001446 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001447 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001448 warn_overflow_opd(opx, 4);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001449 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001450 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001451 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001452 NO_SEG);
1453 offset++;
1454 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001455 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001456 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001457 offset += 4;
1458 }
1459 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001460
H. Peter Anvin507ae032008-10-09 15:37:10 -07001461 case4(0154):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001462 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001463 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001464 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001465 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001466 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 offset++;
1468 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001469
H. Peter Anvin507ae032008-10-09 15:37:10 -07001470 case4(0160):
1471 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001472 break;
1473
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001474 case 0171:
1475 bytes[0] =
1476 (ins->drexdst << 4) |
1477 (ins->rex & REX_OC ? 0x08 : 0) |
1478 (ins->rex & (REX_R|REX_X|REX_B));
1479 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001480 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001481 offset++;
1482 break;
1483
H. Peter Anvind85d2502008-05-04 17:53:31 -07001484 case 0172:
1485 c = *codes++;
1486 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001487 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001488 opx = &ins->oprs[c & 7];
1489 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1490 errfunc(ERR_NONFATAL,
1491 "non-absolute expression not permitted as argument %d",
1492 c & 7);
1493 } else {
1494 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001495 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001496 "four-bit argument exceeds bounds");
1497 }
1498 bytes[0] |= opx->offset & 15;
1499 }
1500 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1501 offset++;
1502 break;
1503
H. Peter Anvind58656f2008-05-06 20:11:14 -07001504 case 0173:
1505 c = *codes++;
1506 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001507 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001508 bytes[0] |= c & 15;
1509 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1510 offset++;
1511 break;
1512
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001513 case 0174:
1514 c = *codes++;
1515 opx = &ins->oprs[c];
1516 bytes[0] = nasm_regvals[opx->basereg] << 4;
1517 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1518 offset++;
1519 break;
1520
H. Peter Anvin507ae032008-10-09 15:37:10 -07001521 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001522 data = opx->offset;
H. Peter Anvinad6b8592008-10-07 09:56:38 -07001523 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1524 (int32_t)data != (int64_t)data) {
1525 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1526 "signed dword immediate exceeds bounds");
1527 }
1528 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001529 bytes[0] = data;
1530 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1531 NO_SEG);
1532 offset++;
1533 } else {
1534 out(offset, segment, &data, OUT_ADDRESS, 4,
1535 opx->segment, opx->wrt);
1536 offset += 4;
1537 }
1538 break;
1539
H. Peter Anvin507ae032008-10-09 15:37:10 -07001540 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001541 data = opx->offset;
1542 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 }
1547 out(offset, segment, &data, OUT_ADDRESS, 4,
1548 opx->segment, opx->wrt);
1549 offset += 4;
1550 break;
1551
H. Peter Anvin507ae032008-10-09 15:37:10 -07001552 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -07001553 case 0270:
1554 codes += 2;
H. Peter Anvina04019c2009-05-03 21:42:34 -07001555 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1556 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1557 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001558 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001559 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001560 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1561 offset += 3;
1562 } else {
1563 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001564 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1565 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001566 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1567 offset += 2;
1568 }
1569 break;
1570
H. Peter Anvin507ae032008-10-09 15:37:10 -07001571 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001572 {
1573 uint64_t uv, um;
1574 int s;
1575
1576 if (ins->rex & REX_W)
1577 s = 64;
1578 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1579 s = 16;
1580 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1581 s = 32;
1582 else
1583 s = bits;
1584
1585 um = (uint64_t)2 << (s-1);
1586 uv = opx->offset;
1587
1588 if (uv > 127 && uv < (uint64_t)-128 &&
1589 (uv < um-128 || uv > um-1)) {
1590 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1591 "signed byte value exceeds bounds");
1592 }
1593 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001594 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001595 out(offset, segment, &data, OUT_ADDRESS, 1,
1596 opx->segment, opx->wrt);
1597 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001598 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001599 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1600 NO_SEG);
1601 }
1602 offset += 1;
1603 break;
1604 }
1605
H. Peter Anvin507ae032008-10-09 15:37:10 -07001606 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001607 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001608
H. Peter Anvine2c80182005-01-15 22:15:51 +00001609 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001610 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001611 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001612 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001613 offset += 1;
1614 } else
1615 offset += 0;
1616 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001617
H. Peter Anvine2c80182005-01-15 22:15:51 +00001618 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001619 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001620 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001621 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001622 offset += 1;
1623 } else
1624 offset += 0;
1625 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001626
H. Peter Anvine2c80182005-01-15 22:15:51 +00001627 case 0312:
1628 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001629
Keith Kaniosb7a89542007-04-12 02:40:54 +00001630 case 0313:
1631 ins->rex = 0;
1632 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001633
H. Peter Anvin507ae032008-10-09 15:37:10 -07001634 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001635 break;
1636
H. Peter Anvine2c80182005-01-15 22:15:51 +00001637 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001638 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001639 *bytes = 0x66;
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 0321:
1647 if (bits == 16) {
1648 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001649 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 offset += 1;
1651 } else
1652 offset += 0;
1653 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001654
H. Peter Anvine2c80182005-01-15 22:15:51 +00001655 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001656 case 0323:
1657 break;
1658
Keith Kaniosb7a89542007-04-12 02:40:54 +00001659 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001660 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001661 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001662
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001663 case 0325:
1664 break;
1665
H. Peter Anvine2c80182005-01-15 22:15:51 +00001666 case 0330:
1667 *bytes = *codes++ ^ condval[ins->condition];
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 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001671
H. Peter Anvine2c80182005-01-15 22:15:51 +00001672 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001674
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001675 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001676 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001677 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001678 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001679 offset += 1;
1680 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001681
Keith Kanios48af1772007-08-17 07:37:52 +00001682 case 0334:
1683 if (ins->rex & REX_R) {
1684 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001685 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001686 offset += 1;
1687 }
1688 ins->rex &= ~(REX_L|REX_R);
1689 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001690
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001691 case 0335:
1692 break;
1693
H. Peter Anvin962e3052008-08-28 17:47:16 -07001694 case 0336:
1695 case 0337:
1696 break;
1697
H. Peter Anvine2c80182005-01-15 22:15:51 +00001698 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001699 if (ins->oprs[0].segment != NO_SEG)
1700 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1701 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001702 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001703 if (size > 0)
1704 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001705 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001706 offset += size;
1707 }
1708 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001709
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001710 case 0341:
1711 break;
1712
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001713 case 0344:
1714 case 0345:
1715 bytes[0] = c & 1;
1716 switch (ins->oprs[0].basereg) {
1717 case R_CS:
1718 bytes[0] += 0x0E;
1719 break;
1720 case R_DS:
1721 bytes[0] += 0x1E;
1722 break;
1723 case R_ES:
1724 bytes[0] += 0x06;
1725 break;
1726 case R_SS:
1727 bytes[0] += 0x16;
1728 break;
1729 default:
1730 errfunc(ERR_PANIC,
1731 "bizarre 8086 segment register received");
1732 }
1733 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1734 offset++;
1735 break;
1736
1737 case 0346:
1738 case 0347:
1739 bytes[0] = c & 1;
1740 switch (ins->oprs[0].basereg) {
1741 case R_FS:
1742 bytes[0] += 0xA0;
1743 break;
1744 case R_GS:
1745 bytes[0] += 0xA8;
1746 break;
1747 default:
1748 errfunc(ERR_PANIC,
1749 "bizarre 386 segment register received");
1750 }
1751 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1752 offset++;
1753 break;
1754
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001755 case 0360:
1756 break;
1757
1758 case 0361:
1759 bytes[0] = 0x66;
1760 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1761 offset += 1;
1762 break;
1763
1764 case 0362:
1765 case 0363:
1766 bytes[0] = c - 0362 + 0xf2;
1767 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1768 offset += 1;
1769 break;
1770
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001771 case 0364:
1772 case 0365:
1773 break;
1774
Keith Kanios48af1772007-08-17 07:37:52 +00001775 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001776 case 0367:
1777 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001778 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001779 offset += 1;
1780 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001781
H. Peter Anvine2c80182005-01-15 22:15:51 +00001782 case 0370:
1783 case 0371:
1784 case 0372:
1785 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001786
H. Peter Anvine2c80182005-01-15 22:15:51 +00001787 case 0373:
1788 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001789 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001790 offset += 1;
1791 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001792
H. Peter Anvin507ae032008-10-09 15:37:10 -07001793 case4(0100):
1794 case4(0110):
1795 case4(0120):
1796 case4(0130):
1797 case4(0200):
1798 case4(0204):
1799 case4(0210):
1800 case4(0214):
1801 case4(0220):
1802 case4(0224):
1803 case4(0230):
1804 case4(0234):
1805 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 ea ea_data;
1807 int rfield;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001808 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001809 uint8_t *p;
1810 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001811 enum out_type type;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001812 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001813
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001814 if (c <= 0177) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001815 /* pick rfield from operand b (opx) */
1816 rflags = regflag(opx);
1817 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001818 } else {
1819 /* rfield is constant */
1820 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001821 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001822 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001823
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001824 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
1825 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001826 errfunc(ERR_NONFATAL, "invalid effective address");
1827 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001828
Charles Crayne7e975552007-11-03 22:06:13 -07001829
H. Peter Anvine2c80182005-01-15 22:15:51 +00001830 p = bytes;
1831 *p++ = ea_data.modrm;
1832 if (ea_data.sib_present)
1833 *p++ = ea_data.sib;
1834
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001835 /* DREX suffixes come between the SIB and the displacement */
1836 if (ins->rex & REX_D) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001837 *p++ = (ins->drexdst << 4) |
1838 (ins->rex & REX_OC ? 0x08 : 0) |
1839 (ins->rex & (REX_R|REX_X|REX_B));
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001840 ins->rex = 0;
1841 }
1842
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001844 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001845
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001846 /*
1847 * Make sure the address gets the right offset in case
1848 * the line breaks in the .lst file (BR 1197827)
1849 */
1850 offset += s;
1851 s = 0;
1852
H. Peter Anvine2c80182005-01-15 22:15:51 +00001853 switch (ea_data.bytes) {
1854 case 0:
1855 break;
1856 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001857 case 2:
1858 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001859 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001860 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001861 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001862 if (ea_data.rip) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001863 if (opy->segment == segment) {
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001864 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001865 if (overflow_signed(data, ea_data.bytes))
1866 warn_overflow(ERR_PASS2, ea_data.bytes);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001867 out(offset, segment, &data, OUT_ADDRESS,
1868 ea_data.bytes, NO_SEG, NO_SEG);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001869 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001870 /* overflow check in output/linker? */
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001871 out(offset, segment, &data, OUT_REL4ADR,
1872 insn_end - offset, opy->segment, opy->wrt);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001873 }
H. Peter Anvin9f817132008-10-06 19:11:07 -07001874 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001875 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1876 signed_bits(opy->offset, ins->addr_size) !=
1877 signed_bits(opy->offset, ea_data.bytes * 8))
1878 warn_overflow(ERR_PASS2, ea_data.bytes);
1879
H. Peter Anvin9f817132008-10-06 19:11:07 -07001880 type = OUT_ADDRESS;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001881 out(offset, segment, &data, OUT_ADDRESS,
1882 ea_data.bytes, opy->segment, opy->wrt);
H. Peter Anvin9f817132008-10-06 19:11:07 -07001883 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001884 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001885 default:
1886 /* Impossible! */
1887 errfunc(ERR_PANIC,
1888 "Invalid amount of bytes (%d) for offset?!",
1889 ea_data.bytes);
1890 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001891 }
1892 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001893 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001894 break;
1895
1896 default:
1897 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001898 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001899 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001900 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001901 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001902}
1903
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001904static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001905{
1906 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1907 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1908 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001909 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001910}
1911
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001912static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001913{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001914 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1915 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001916 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001917 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001918}
1919
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001920static int op_rexflags(const operand * o, int mask)
1921{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001922 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001923 int val;
1924
1925 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1926 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1927 }
1928
H. Peter Anvina4835d42008-05-20 14:21:29 -07001929 flags = nasm_reg_flags[o->basereg];
1930 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001931
1932 return rexflags(val, flags, mask);
1933}
1934
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001935static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001936{
1937 int rex = 0;
1938
1939 if (val >= 8)
1940 rex |= REX_B|REX_X|REX_R;
1941 if (flags & BITS64)
1942 rex |= REX_W;
1943 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1944 rex |= REX_H;
1945 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1946 rex |= REX_P;
1947
1948 return rex & mask;
1949}
1950
H. Peter Anvin23595f52009-07-25 17:44:25 -07001951static enum match_result find_match(const struct itemplate **tempp,
1952 insn *instruction,
1953 int32_t segment, int64_t offset, int bits)
1954{
1955 const struct itemplate *temp;
1956 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001957 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001958 bool opsizemissing = false;
1959 int i;
1960
1961 for (i = 0; i < instruction->operands; i++)
1962 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001963
1964 merr = MERR_INVALOP;
1965
1966 for (temp = nasm_instructions[instruction->opcode];
1967 temp->opcode != I_none; temp++) {
1968 m = matches(temp, instruction, bits);
1969 if (m == MOK_JUMP) {
1970 if (jmp_match(segment, offset, bits, instruction, temp->code))
1971 m = MOK_GOOD;
1972 else
1973 m = MERR_INVALOP;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001974 } else if (m == MERR_OPSIZEMISSING &&
1975 (temp->flags & IF_SMASK) != IF_SX) {
1976 /*
1977 * Missing operand size and a candidate for fuzzy matching...
1978 */
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001979 for (i = 0; i < temp->operands; i++) {
1980 if ((temp->opd[i] & SAME_AS) == 0)
1981 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1982 }
H. Peter Anvina81655b2009-07-25 18:15:28 -07001983 opsizemissing = true;
1984 }
1985 if (m > merr)
1986 merr = m;
1987 if (merr == MOK_GOOD)
1988 goto done;
1989 }
1990
1991 /* No match, but see if we can get a fuzzy operand size match... */
1992 if (!opsizemissing)
1993 goto done;
1994
1995 for (i = 0; i < instruction->operands; i++) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001996 /*
1997 * We ignore extrinsic operand sizes on registers, so we should
1998 * never try to fuzzy-match on them. This also resolves the case
1999 * when we have e.g. "xmmrm128" in two different positions.
2000 */
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002001 if (is_class(REGISTER, instruction->oprs[i].type))
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002002 continue;
2003
H. Peter Anvina81655b2009-07-25 18:15:28 -07002004 /* This tests if xsizeflags[i] has more than one bit set */
2005 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2006 goto done; /* No luck */
2007
2008 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
2009 }
2010
2011 /* Try matching again... */
2012 for (temp = nasm_instructions[instruction->opcode];
2013 temp->opcode != I_none; temp++) {
2014 m = matches(temp, instruction, bits);
2015 if (m == MOK_JUMP) {
2016 if (jmp_match(segment, offset, bits, instruction, temp->code))
2017 m = MOK_GOOD;
2018 else
2019 m = MERR_INVALOP;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002020 }
2021 if (m > merr)
2022 merr = m;
2023 if (merr == MOK_GOOD)
H. Peter Anvina81655b2009-07-25 18:15:28 -07002024 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002025 }
2026
H. Peter Anvina81655b2009-07-25 18:15:28 -07002027done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002028 *tempp = temp;
2029 return merr;
2030}
2031
H. Peter Anvin65289e82009-07-25 17:25:11 -07002032static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002033 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002034{
H. Peter Anvin60926242009-07-26 16:25:38 -07002035 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002036 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002037
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002038 /*
2039 * Check the opcode
2040 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002041 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002042 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002043
2044 /*
2045 * Count the operands
2046 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002047 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002048 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002049
2050 /*
2051 * Check that no spurious colons or TOs are present
2052 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002053 for (i = 0; i < itemp->operands; i++)
2054 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002055 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002056
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002057 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002058 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002059 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002060 switch (itemp->flags & IF_SMASK) {
2061 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002062 asize = BITS8;
2063 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002064 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002065 asize = BITS16;
2066 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002067 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002068 asize = BITS32;
2069 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002070 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002071 asize = BITS64;
2072 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002073 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002074 asize = BITS128;
2075 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002076 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002077 asize = BITS256;
2078 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002079 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002080 switch (bits) {
2081 case 16:
2082 asize = BITS16;
2083 break;
2084 case 32:
2085 asize = BITS32;
2086 break;
2087 case 64:
2088 asize = BITS64;
2089 break;
2090 default:
2091 asize = 0;
2092 break;
2093 }
2094 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002095 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002096 asize = 0;
2097 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002098 }
2099
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002100 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002101 /* S- flags only apply to a specific operand */
2102 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2103 memset(size, 0, sizeof size);
2104 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002105 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002106 /* S- flags apply to all operands */
2107 for (i = 0; i < MAX_OPERANDS; i++)
2108 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002109 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002110
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002111 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002112 * Check that the operand flags all match up,
2113 * it's a bit tricky so lets be verbose:
2114 *
2115 * 1) Find out the size of operand. If instruction
2116 * doesn't have one specified -- we're trying to
2117 * guess it either from template (IF_S* flag) or
2118 * from code bits.
2119 *
2120 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2121 * (ie the same operand as was specified somewhere in template, and
2122 * this referred operand index is being achieved via ~SAME_AS)
2123 * we are to be sure that both registers (in template and instruction)
2124 * do exactly match.
2125 *
2126 * 3) If template operand do not match the instruction OR
2127 * template has an operand size specified AND this size differ
2128 * from which instruction has (perhaps we got it from code bits)
2129 * we are:
2130 * a) Check that only size of instruction and operand is differ
2131 * other characteristics do match
2132 * b) Perhaps it's a register specified in instruction so
2133 * for such a case we just mark that operand as "size
2134 * missing" and this will turn on fuzzy operand size
2135 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002136 */
2137 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002138 opflags_t type = instruction->oprs[i].type;
2139 if (!(type & SIZE_MASK))
2140 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002141
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002142 if (itemp->opd[i] & SAME_AS) {
2143 int j = itemp->opd[i] & ~SAME_AS;
2144 if (type != instruction->oprs[j].type ||
2145 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2146 return MERR_INVALOP;
2147 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002148 ((itemp->opd[i] & SIZE_MASK) &&
2149 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002150 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002151 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002152 } else if (!is_class(REGISTER, type)) {
2153 /*
2154 * Note: we don't honor extrinsic operand sizes for registers,
2155 * so "missing operand size" for a register should be
2156 * considered a wildcard match rather than an error.
2157 */
2158 opsizemissing = true;
2159 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002160 }
2161 }
2162
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002163 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002164 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002165
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002166 /*
2167 * Check operand sizes
2168 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002169 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002170 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002171 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002172 asize = itemp->opd[i] & SIZE_MASK;
2173 if (asize) {
2174 for (i = 0; i < oprs; i++)
2175 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002176 break;
2177 }
2178 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002179 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002180 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002181 }
2182
Keith Kaniosb7a89542007-04-12 02:40:54 +00002183 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002184 if (!(itemp->opd[i] & SIZE_MASK) &&
2185 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002186 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002187 }
2188
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002189 /*
2190 * Check template is okay at the set cpu level
2191 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002192 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002193 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002194
Keith Kaniosb7a89542007-04-12 02:40:54 +00002195 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002196 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002197 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002198 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002199 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002200
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002201 /*
2202 * Check if special handling needed for Jumps
2203 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002204 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002205 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002206
H. Peter Anvin60926242009-07-26 16:25:38 -07002207 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002208}
2209
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002210static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002211 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002212{
H. Peter Anvin9945fee2009-02-26 14:48:03 -08002213 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002214
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002215 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002216
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002217 /* REX flags for the rfield operand */
2218 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2219
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002220 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002221 int i;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002222 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002223
2224 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002225 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002226 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002227 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002228 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002229
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002230 if (REG_EA & ~f)
2231 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002232
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002233 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2234
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002235 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002236 output->bytes = 0; /* no offset necessary either */
2237 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002238 } else { /* it's a memory reference */
2239 if (input->basereg == -1
2240 && (input->indexreg == -1 || input->scale == 0)) {
2241 /* it's a pure offset */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002242
2243 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2244 input->segment == NO_SEG) {
2245 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2246 input->type &= ~IP_REL;
2247 input->type |= MEMORY;
2248 }
2249
2250 if (input->eaflags & EAF_BYTEOFFS ||
2251 (input->eaflags & EAF_WORDOFFS &&
2252 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2253 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2254 }
2255
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002256 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002257 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002258 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002259 scale = 0;
2260 index = 4;
2261 base = 5;
2262 output->sib = (scale << 6) | (index << 3) | base;
2263 output->bytes = 4;
2264 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002265 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002266 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002267 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002268 output->bytes = (addrbits != 16 ? 4 : 2);
2269 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002270 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002271 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002272 } else { /* it's an indirection */
2273 int i = input->indexreg, b = input->basereg, s = input->scale;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002274 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002275 int hb = input->hintbase, ht = input->hinttype;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002276 int t, it, bt; /* register numbers */
2277 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002278
H. Peter Anvine2c80182005-01-15 22:15:51 +00002279 if (s == 0)
2280 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002281
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002282 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002283 it = nasm_regvals[i];
2284 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002285 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002286 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002287 ix = 0;
2288 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002289
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002290 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002291 bt = nasm_regvals[b];
2292 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002293 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002294 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002295 bx = 0;
2296 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002297
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002298 /* check for a 32/64-bit memory reference... */
2299 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002300 /* it must be a 32/64-bit memory reference. Firstly we have
2301 * to check that all registers involved are type E/Rxx. */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002302 int32_t sok = BITS32|BITS64, o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002303
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002304 if (it != -1) {
2305 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2306 sok &= ix;
2307 else
2308 return NULL;
2309 }
2310
2311 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002312 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002313 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002314 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002315 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002316 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002317 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002318
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002319 /* While we're here, ensure the user didn't specify
2320 WORD or QWORD. */
2321 if (input->disp_size == 16 || input->disp_size == 64)
2322 return NULL;
2323
2324 if (addrbits == 16 ||
2325 (addrbits == 32 && !(sok & BITS32)) ||
2326 (addrbits == 64 && !(sok & BITS64)))
2327 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002328
Keith Kaniosb7a89542007-04-12 02:40:54 +00002329 /* now reorganize base/index */
2330 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002331 ((hb == b && ht == EAH_NOTBASE)
2332 || (hb == i && ht == EAH_MAKEBASE))) {
2333 /* swap if hints say so */
2334 t = bt, bt = it, it = t;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002335 x = bx, bx = ix, ix = x;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002336 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002337 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002338 bt = -1, bx = 0, s++;
2339 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2340 /* make single reg base, unless hint */
2341 bt = it, bx = ix, it = -1, ix = 0;
2342 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002343 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002344 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002345 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002346 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002347 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002348 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002349 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002350 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002351 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002352 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002353 t = it, it = bt, bt = t;
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002354 x = ix, ix = bx, bx = x;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002355 }
Keith Kanios48af1772007-08-17 07:37:52 +00002356 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002357 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002358 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002359
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002360 output->rex |= rexflags(it, ix, REX_X);
2361 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002362
Keith Kanios48af1772007-08-17 07:37:52 +00002363 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002364 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002365 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002366
Keith Kaniosb7a89542007-04-12 02:40:54 +00002367 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002368 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002369 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002370 } else {
2371 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002372 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002373 seg == NO_SEG && !forw_ref &&
2374 !(input->eaflags &
2375 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2376 mod = 0;
2377 else if (input->eaflags & EAF_BYTEOFFS ||
2378 (o >= -128 && o <= 127 && seg == NO_SEG
2379 && !forw_ref
2380 && !(input->eaflags & EAF_WORDOFFS)))
2381 mod = 1;
2382 else
2383 mod = 2;
2384 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002385
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002386 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002387 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2388 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002389 } else {
2390 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002391 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002392
Keith Kaniosb7a89542007-04-12 02:40:54 +00002393 if (it == -1)
2394 index = 4, s = 1;
2395 else
2396 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002397
H. Peter Anvine2c80182005-01-15 22:15:51 +00002398 switch (s) {
2399 case 1:
2400 scale = 0;
2401 break;
2402 case 2:
2403 scale = 1;
2404 break;
2405 case 4:
2406 scale = 2;
2407 break;
2408 case 8:
2409 scale = 3;
2410 break;
2411 default: /* then what the smeg is it? */
2412 return NULL; /* panic */
2413 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002414
Keith Kaniosb7a89542007-04-12 02:40:54 +00002415 if (bt == -1) {
2416 base = 5;
2417 mod = 0;
2418 } else {
2419 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002420 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002421 seg == NO_SEG && !forw_ref &&
2422 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002423 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2424 mod = 0;
2425 else if (input->eaflags & EAF_BYTEOFFS ||
2426 (o >= -128 && o <= 127 && seg == NO_SEG
2427 && !forw_ref
2428 && !(input->eaflags & EAF_WORDOFFS)))
2429 mod = 1;
2430 else
2431 mod = 2;
2432 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002433
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002434 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002435 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2436 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002437 output->sib = (scale << 6) | (index << 3) | base;
2438 }
2439 } else { /* it's 16-bit */
2440 int mod, rm;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002441 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002442
Keith Kaniosb7a89542007-04-12 02:40:54 +00002443 /* check for 64-bit long mode */
2444 if (addrbits == 64)
2445 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002446
H. Peter Anvine2c80182005-01-15 22:15:51 +00002447 /* check all registers are BX, BP, SI or DI */
2448 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2449 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2450 && i != R_SI && i != R_DI))
2451 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002452
Keith Kaniosb7a89542007-04-12 02:40:54 +00002453 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002454 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002455 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002456
H. Peter Anvine2c80182005-01-15 22:15:51 +00002457 if (s != 1 && i != -1)
2458 return NULL; /* no can do, in 16-bit EA */
2459 if (b == -1 && i != -1) {
2460 int tmp = b;
2461 b = i;
2462 i = tmp;
2463 } /* swap */
2464 if ((b == R_SI || b == R_DI) && i != -1) {
2465 int tmp = b;
2466 b = i;
2467 i = tmp;
2468 }
2469 /* have BX/BP as base, SI/DI index */
2470 if (b == i)
2471 return NULL; /* shouldn't ever happen, in theory */
2472 if (i != -1 && b != -1 &&
2473 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2474 return NULL; /* invalid combinations */
2475 if (b == -1) /* pure offset: handled above */
2476 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002477
H. Peter Anvine2c80182005-01-15 22:15:51 +00002478 rm = -1;
2479 if (i != -1)
2480 switch (i * 256 + b) {
2481 case R_SI * 256 + R_BX:
2482 rm = 0;
2483 break;
2484 case R_DI * 256 + R_BX:
2485 rm = 1;
2486 break;
2487 case R_SI * 256 + R_BP:
2488 rm = 2;
2489 break;
2490 case R_DI * 256 + R_BP:
2491 rm = 3;
2492 break;
2493 } else
2494 switch (b) {
2495 case R_SI:
2496 rm = 4;
2497 break;
2498 case R_DI:
2499 rm = 5;
2500 break;
2501 case R_BP:
2502 rm = 6;
2503 break;
2504 case R_BX:
2505 rm = 7;
2506 break;
2507 }
2508 if (rm == -1) /* can't happen, in theory */
2509 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002510
H. Peter Anvine2c80182005-01-15 22:15:51 +00002511 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2512 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2513 mod = 0;
2514 else if (input->eaflags & EAF_BYTEOFFS ||
2515 (o >= -128 && o <= 127 && seg == NO_SEG
2516 && !forw_ref
2517 && !(input->eaflags & EAF_WORDOFFS)))
2518 mod = 1;
2519 else
2520 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002521
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002522 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002523 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002524 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002525 }
2526 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002527 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002528
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002529 output->size = 1 + output->sib_present + output->bytes;
2530 return output;
2531}
2532
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002533static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002534{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002535 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002536 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002537
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002538 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002539
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002540 switch (ins->prefixes[PPS_ASIZE]) {
2541 case P_A16:
2542 valid &= 16;
2543 break;
2544 case P_A32:
2545 valid &= 32;
2546 break;
2547 case P_A64:
2548 valid &= 64;
2549 break;
2550 case P_ASP:
2551 valid &= (addrbits == 32) ? 16 : 32;
2552 break;
2553 default:
2554 break;
2555 }
2556
2557 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunove4f526b2009-10-18 12:41:14 +04002558 if (is_class(MEMORY, ins->oprs[j].type)) {
H. Peter Anvinf8563f72009-10-13 12:28:14 -07002559 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002560
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002561 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002562 if (ins->oprs[j].indexreg < EXPR_REG_START
2563 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002564 i = 0;
2565 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002566 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002567
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002568 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002569 if (ins->oprs[j].basereg < EXPR_REG_START
2570 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002571 b = 0;
2572 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002573 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002574
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002575 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002576 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002577
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002578 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002579 int ds = ins->oprs[j].disp_size;
2580 if ((addrbits != 64 && ds > 8) ||
2581 (addrbits == 64 && ds == 16))
2582 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002583 } else {
2584 if (!(REG16 & ~b))
2585 valid &= 16;
2586 if (!(REG32 & ~b))
2587 valid &= 32;
2588 if (!(REG64 & ~b))
2589 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002590
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002591 if (!(REG16 & ~i))
2592 valid &= 16;
2593 if (!(REG32 & ~i))
2594 valid &= 32;
2595 if (!(REG64 & ~i))
2596 valid &= 64;
2597 }
2598 }
2599 }
2600
2601 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002602 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002603 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002604 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002605 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002606 ins->prefixes[PPS_ASIZE] = pref;
2607 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002608 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002609 /* Impossible... */
2610 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002611 ins->addr_size = addrbits; /* Error recovery */
2612 }
2613
2614 defdisp = ins->addr_size == 16 ? 16 : 32;
2615
2616 for (j = 0; j < ins->operands; j++) {
2617 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2618 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2619 != ins->addr_size) {
2620 /* mem_offs sizes must match the address size; if not,
2621 strip the MEM_OFFS bit and match only EA instructions */
2622 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2623 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002624 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002625}