blob: 7ea5fb9c457adf93bdce422ccb730595f5dfcdc9 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
2 *
3 * 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.
17 *
18 * 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 Anvin3df97a72007-05-30 03:25:21 +0000202static int32_t regflag(const operand *);
203static int32_t regval(const operand *);
204static int rexflags(int, int32_t, int);
205static int op_rexflags(const operand *, int);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700206static ea *process_ea(operand *, ea *, int, int, int, int32_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{
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700257 if (size < 8 && 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;
347 int64_t wsize = 0; /* 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
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 switch (instruction->opcode) {
355 case -1:
356 return 0;
357 case I_DB:
358 wsize = 1;
359 break;
360 case I_DW:
361 wsize = 2;
362 break;
363 case I_DD:
364 wsize = 4;
365 break;
366 case I_DQ:
367 wsize = 8;
368 break;
369 case I_DT:
370 wsize = 10;
371 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700372 case I_DO:
373 wsize = 16;
374 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700375 case I_DY:
376 wsize = 32;
377 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700378 default:
379 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000380 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000381
H. Peter Anvineba20a72002-04-30 20:53:55 +0000382 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000383 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000384 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 if (t < 0)
386 errfunc(ERR_PANIC,
387 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000388
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400390 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 if (e->type == EOT_DB_NUMBER) {
392 if (wsize == 1) {
393 if (e->segment != NO_SEG)
394 errfunc(ERR_NONFATAL,
395 "one-byte relocation attempted");
396 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000397 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800399 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000400 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000401 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700402 errfunc(ERR_NONFATAL,
403 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000404 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000405 } else
406 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800407 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000408 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700409 } else if (e->type == EOT_DB_STRING ||
410 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000411 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000412
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800414 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000415 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000416
H. Peter Anvine2c80182005-01-15 22:15:51 +0000417 if (align) {
418 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100419 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800420 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000421 }
422 offset += e->stringlen + align;
423 }
424 }
425 if (t > 0 && t == instruction->times - 1) {
426 /*
427 * Dummy call to list->output to give the offset to the
428 * listing module.
429 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800430 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 list->uplevel(LIST_TIMES);
432 }
433 }
434 if (instruction->times > 1)
435 list->downlevel(LIST_TIMES);
436 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000437 }
438
H. Peter Anvine2c80182005-01-15 22:15:51 +0000439 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700440 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000442
H. Peter Anvin418ca702008-05-30 10:42:30 -0700443 fp = fopen(fname, "rb");
444 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000445 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
446 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700447 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000448 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
449 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700450 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700451 static char buf[4096];
452 size_t t = instruction->times;
453 size_t base = 0;
454 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000455
H. Peter Anvine2c80182005-01-15 22:15:51 +0000456 len = ftell(fp);
457 if (instruction->eops->next) {
458 base = instruction->eops->next->offset;
459 len -= base;
460 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700461 len > (size_t)instruction->eops->next->next->offset)
462 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000463 }
464 /*
465 * Dummy call to list->output to give the offset to the
466 * listing module.
467 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800468 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000469 list->uplevel(LIST_INCBIN);
470 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700471 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000472
H. Peter Anvine2c80182005-01-15 22:15:51 +0000473 fseek(fp, base, SEEK_SET);
474 l = len;
475 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700476 int32_t m;
477 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000478 if (!m) {
479 /*
480 * This shouldn't happen unless the file
481 * actually changes while we are reading
482 * it.
483 */
484 error(ERR_NONFATAL,
485 "`incbin': unexpected EOF while"
486 " reading file `%s'", fname);
487 t = 0; /* Try to exit cleanly */
488 break;
489 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800490 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000491 NO_SEG, NO_SEG);
492 l -= m;
493 }
494 }
495 list->downlevel(LIST_INCBIN);
496 if (instruction->times > 1) {
497 /*
498 * Dummy call to list->output to give the offset to the
499 * listing module.
500 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800501 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000502 list->uplevel(LIST_TIMES);
503 list->downlevel(LIST_TIMES);
504 }
505 fclose(fp);
506 return instruction->times * len;
507 }
508 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000509 }
510
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700511 /* Check to see if we need an address-size prefix */
512 add_asp(instruction, bits);
513
H. Peter Anvin23595f52009-07-25 17:44:25 -0700514 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700515
H. Peter Anvin23595f52009-07-25 17:44:25 -0700516 if (m == MOK_GOOD) {
517 /* Matches! */
518 int64_t insn_size = calcsize(segment, offset, bits,
519 instruction, temp->code);
520 itimes = instruction->times;
521 if (insn_size < 0) /* shouldn't be, on pass two */
522 error(ERR_PANIC, "errors made it through from pass one");
523 else
524 while (itimes--) {
525 for (j = 0; j < MAXPREFIX; j++) {
526 uint8_t c = 0;
527 switch (instruction->prefixes[j]) {
528 case P_WAIT:
529 c = 0x9B;
530 break;
531 case P_LOCK:
532 c = 0xF0;
533 break;
534 case P_REPNE:
535 case P_REPNZ:
536 c = 0xF2;
537 break;
538 case P_REPE:
539 case P_REPZ:
540 case P_REP:
541 c = 0xF3;
542 break;
543 case R_CS:
544 if (bits == 64) {
545 error(ERR_WARNING | ERR_PASS2,
546 "cs segment base generated, but will be ignored in 64-bit mode");
547 }
548 c = 0x2E;
549 break;
550 case R_DS:
551 if (bits == 64) {
552 error(ERR_WARNING | ERR_PASS2,
553 "ds segment base generated, but will be ignored in 64-bit mode");
554 }
555 c = 0x3E;
556 break;
557 case R_ES:
558 if (bits == 64) {
559 error(ERR_WARNING | ERR_PASS2,
560 "es segment base generated, but will be ignored in 64-bit mode");
561 }
562 c = 0x26;
563 break;
564 case R_FS:
565 c = 0x64;
566 break;
567 case R_GS:
568 c = 0x65;
569 break;
570 case R_SS:
571 if (bits == 64) {
572 error(ERR_WARNING | ERR_PASS2,
573 "ss segment base generated, but will be ignored in 64-bit mode");
574 }
575 c = 0x36;
576 break;
577 case R_SEGR6:
578 case R_SEGR7:
579 error(ERR_NONFATAL,
580 "segr6 and segr7 cannot be used as prefixes");
581 break;
582 case P_A16:
583 if (bits == 64) {
584 error(ERR_NONFATAL,
585 "16-bit addressing is not supported "
586 "in 64-bit mode");
587 } else if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700588 c = 0x67;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700589 break;
590 case P_A32:
591 if (bits != 32)
592 c = 0x67;
593 break;
594 case P_A64:
595 if (bits != 64) {
596 error(ERR_NONFATAL,
597 "64-bit addressing is only supported "
598 "in 64-bit mode");
599 }
600 break;
601 case P_ASP:
602 c = 0x67;
603 break;
604 case P_O16:
605 if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700606 c = 0x66;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700607 break;
608 case P_O32:
609 if (bits == 16)
610 c = 0x66;
611 break;
612 case P_O64:
613 /* REX.W */
614 break;
615 case P_OSP:
616 c = 0x66;
617 break;
618 case P_none:
619 break;
620 default:
621 error(ERR_PANIC, "invalid instruction prefix");
622 }
623 if (c != 0) {
624 out(offset, segment, &c, OUT_RAWDATA, 1,
625 NO_SEG, NO_SEG);
626 offset++;
627 }
628 }
629 insn_end = offset + insn_size;
630 gencode(segment, offset, bits, instruction,
631 temp, insn_end);
632 offset += insn_size;
633 if (itimes > 0 && itimes == instruction->times - 1) {
634 /*
635 * Dummy call to list->output to give the offset to the
636 * listing module.
637 */
638 list->output(offset, NULL, OUT_RAWDATA, 0);
639 list->uplevel(LIST_TIMES);
640 }
641 }
642 if (instruction->times > 1)
643 list->downlevel(LIST_TIMES);
644 return offset - start;
645 } else {
646 /* No match */
647 switch (m) {
H. Peter Anvin65289e82009-07-25 17:25:11 -0700648 case MERR_OPSIZEMISSING:
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000649 error(ERR_NONFATAL, "operation size not specified");
650 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700651 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000652 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000653 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700654 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000655 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000656 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700657 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800658 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
659 bits);
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000660 break;
661 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000662 error(ERR_NONFATAL,
663 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000664 break;
665 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000666 }
667 return 0;
668}
669
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800670int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvin65289e82009-07-25 17:25:11 -0700671 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000672{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000673 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700674 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000675
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000677 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000678
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400679 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000681
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700682 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
683 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700684 instruction->opcode == I_DT || instruction->opcode == I_DO ||
685 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000686 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000687 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000688
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 isize = 0;
690 switch (instruction->opcode) {
691 case I_DB:
692 wsize = 1;
693 break;
694 case I_DW:
695 wsize = 2;
696 break;
697 case I_DD:
698 wsize = 4;
699 break;
700 case I_DQ:
701 wsize = 8;
702 break;
703 case I_DT:
704 wsize = 10;
705 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700706 case I_DO:
707 wsize = 16;
708 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700709 case I_DY:
710 wsize = 32;
711 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700712 default:
713 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000714 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000715
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400716 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000717 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000718
H. Peter Anvine2c80182005-01-15 22:15:51 +0000719 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400720 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000721 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400722 warn_overflow_const(e->offset, wsize);
723 } else if (e->type == EOT_DB_STRING ||
724 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000725 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000726
H. Peter Anvine2c80182005-01-15 22:15:51 +0000727 align = (-osize) % wsize;
728 if (align < 0)
729 align += wsize;
730 isize += osize + align;
731 }
732 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000733 }
734
H. Peter Anvine2c80182005-01-15 22:15:51 +0000735 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700736 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000737 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700738 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000739
H. Peter Anvin418ca702008-05-30 10:42:30 -0700740 fp = fopen(fname, "rb");
741 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000742 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
743 fname);
744 else if (fseek(fp, 0L, SEEK_END) < 0)
745 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
746 fname);
747 else {
748 len = ftell(fp);
749 fclose(fp);
750 if (instruction->eops->next) {
751 len -= instruction->eops->next->offset;
752 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700753 len > (size_t)instruction->eops->next->next->offset) {
754 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000755 }
756 }
757 return instruction->times * len;
758 }
759 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000760 }
761
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700762 /* Check to see if we need an address-size prefix */
763 add_asp(instruction, bits);
764
H. Peter Anvin23595f52009-07-25 17:44:25 -0700765 m = find_match(&temp, instruction, segment, offset, bits);
766 if (m == MOK_GOOD) {
767 /* we've matched an instruction. */
768 int64_t isize;
769 const uint8_t *codes = temp->code;
770 int j;
771
772 isize = calcsize(segment, offset, bits, instruction, codes);
773 if (isize < 0)
774 return -1;
775 for (j = 0; j < MAXPREFIX; j++) {
776 switch (instruction->prefixes[j]) {
777 case P_A16:
778 if (bits != 16)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700779 isize++;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700780 break;
781 case P_A32:
782 if (bits != 32)
783 isize++;
784 break;
785 case P_O16:
786 if (bits != 16)
787 isize++;
788 break;
789 case P_O32:
790 if (bits == 16)
791 isize++;
792 break;
793 case P_A64:
794 case P_O64:
795 case P_none:
796 break;
797 default:
798 isize++;
799 break;
800 }
801 }
802 return isize * instruction->times;
803 } else {
804 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000805 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000806}
807
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700808static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000809{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700810 return o->wrt == NO_SEG && o->segment == NO_SEG &&
H. Peter Anvine8ab8912009-02-26 16:34:56 -0800811 !(o->opflags & OPFLAG_UNKNOWN) &&
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700812 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000813}
814
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700815/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700816static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700817{
818 int16_t v;
819
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700820 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700821 return false;
822
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700823 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700824 return v >= -128 && v <= 127;
825}
826
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700827static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700828{
829 int32_t v;
830
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700831 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700832 return false;
833
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700834 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700835 return v >= -128 && v <= 127;
836}
837
H. Peter Anvin507ae032008-10-09 15:37:10 -0700838/* Common construct */
839#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
840
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800841static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700842 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000843{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800844 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000845 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000846 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700847 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700848 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700849 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000850
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700851 ins->rex = 0; /* Ensure REX is reset */
852
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700853 if (ins->prefixes[PPS_OSIZE] == P_O64)
854 ins->rex |= REX_W;
855
H. Peter Anvine2c80182005-01-15 22:15:51 +0000856 (void)segment; /* Don't warn that this parameter is unused */
857 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000858
H. Peter Anvin839eca22007-10-29 23:12:47 -0700859 while (*codes) {
860 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700861 op1 = (c & 3) + ((opex & 1) << 2);
862 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
863 opx = &ins->oprs[op1];
864 opex = 0; /* For the next iteration */
865
H. Peter Anvin839eca22007-10-29 23:12:47 -0700866 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 case 01:
868 case 02:
869 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700870 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000871 codes += c, length += c;
872 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700873
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700874 case 05:
875 case 06:
876 case 07:
877 opex = c;
878 break;
879
H. Peter Anvin507ae032008-10-09 15:37:10 -0700880 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000881 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700882 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 codes++, length++;
884 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700885
886 case4(014):
887 case4(020):
888 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 length++;
890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
892 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000893 length += 2;
894 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700895
896 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700897 if (opx->type & (BITS16 | BITS32 | BITS64))
898 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000899 else
900 length += (bits == 16) ? 2 : 4;
901 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700902
903 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000904 length += 4;
905 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700906
907 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700908 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000909 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700910
911 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000912 length++;
913 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700914
915 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000916 length += 8; /* MOV reg64/imm */
917 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700918
919 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000920 length += 2;
921 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700922
923 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700924 if (opx->type & (BITS16 | BITS32 | BITS64))
925 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000926 else
927 length += (bits == 16) ? 2 : 4;
928 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700929
930 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000931 length += 4;
932 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700933
934 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700935 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000936 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700937
938 case4(0140):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700939 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000940 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700941
942 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800943 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000944 length++;
945 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700946
947 case4(0150):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700948 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700949 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700950
951 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800952 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700953 length++;
954 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700955
956 case4(0160):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700957 length++;
958 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700959 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
962 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700963 length++;
964 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700965 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700966 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700967
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700968 case 0171:
969 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700970
H. Peter Anvind85d2502008-05-04 17:53:31 -0700971 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700972 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700973 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700974 codes++;
975 length++;
976 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700977
978 case4(0250):
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700979 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700980 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700981
982 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -0700983 length += 4;
984 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700985
986 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -0700987 ins->rex |= REX_V;
988 ins->drexdst = regval(opx);
H. Peter Anvina04019c2009-05-03 21:42:34 -0700989 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700990 ins->vex_wlp = *codes++;
991 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700992
H. Peter Anvind85d2502008-05-04 17:53:31 -0700993 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700994 ins->rex |= REX_V;
995 ins->drexdst = 0;
H. Peter Anvina04019c2009-05-03 21:42:34 -0700996 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700997 ins->vex_wlp = *codes++;
998 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700999
1000 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001001 length++;
1002 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001003
1004 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001005 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001006
H. Peter Anvine2c80182005-01-15 22:15:51 +00001007 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001008 if (bits == 64)
1009 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001010 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001011 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001012
H. Peter Anvine2c80182005-01-15 22:15:51 +00001013 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001014 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001015 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001016
H. Peter Anvine2c80182005-01-15 22:15:51 +00001017 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001018 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001019
Keith Kaniosb7a89542007-04-12 02:40:54 +00001020 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001021 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1022 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001023 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001024 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001025
1026 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001027 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001028
H. Peter Anvine2c80182005-01-15 22:15:51 +00001029 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001030 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001031 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001032
H. Peter Anvine2c80182005-01-15 22:15:51 +00001033 case 0321:
1034 length += (bits == 16);
1035 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001036
H. Peter Anvine2c80182005-01-15 22:15:51 +00001037 case 0322:
1038 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001039
Keith Kaniosb7a89542007-04-12 02:40:54 +00001040 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001041 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001042 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001043
Keith Kaniosb7a89542007-04-12 02:40:54 +00001044 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001045 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001046 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001047
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001048 case 0325:
1049 ins->rex |= REX_NH;
1050 break;
1051
H. Peter Anvine2c80182005-01-15 22:15:51 +00001052 case 0330:
1053 codes++, length++;
1054 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001055
H. Peter Anvine2c80182005-01-15 22:15:51 +00001056 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001057 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001058
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001059 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001060 case 0333:
1061 length++;
1062 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001063
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001064 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001065 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001066 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001067
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001068 case 0335:
1069 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001070
H. Peter Anvin962e3052008-08-28 17:47:16 -07001071 case 0336:
1072 if (!ins->prefixes[PPS_LREP])
1073 ins->prefixes[PPS_LREP] = P_REP;
1074 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001075
H. Peter Anvin962e3052008-08-28 17:47:16 -07001076 case 0337:
1077 if (!ins->prefixes[PPS_LREP])
1078 ins->prefixes[PPS_LREP] = P_REPNE;
1079 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001080
H. Peter Anvine2c80182005-01-15 22:15:51 +00001081 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001082 if (ins->oprs[0].segment != NO_SEG)
1083 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1084 " quantity of BSS space");
1085 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001086 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001087 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001088
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001089 case 0341:
1090 if (!ins->prefixes[PPS_WAIT])
1091 ins->prefixes[PPS_WAIT] = P_WAIT;
1092 break;
1093
H. Peter Anvin507ae032008-10-09 15:37:10 -07001094 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001095 length++;
1096 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001097
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001098 case 0360:
1099 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001100
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001101 case 0361:
1102 case 0362:
1103 case 0363:
1104 length++;
1105 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001106
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001107 case 0364:
1108 case 0365:
1109 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001110
Keith Kanios48af1772007-08-17 07:37:52 +00001111 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001112 case 0367:
1113 length++;
1114 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001115
H. Peter Anvine2c80182005-01-15 22:15:51 +00001116 case 0370:
1117 case 0371:
1118 case 0372:
1119 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001120
H. Peter Anvine2c80182005-01-15 22:15:51 +00001121 case 0373:
1122 length++;
1123 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001124
1125 case4(0100):
1126 case4(0110):
1127 case4(0120):
1128 case4(0130):
1129 case4(0200):
1130 case4(0204):
1131 case4(0210):
1132 case4(0214):
1133 case4(0220):
1134 case4(0224):
1135 case4(0230):
1136 case4(0234):
1137 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001138 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001139 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001140 int32_t rflags;
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001141 struct operand *opy = &ins->oprs[op2];
1142
Keith Kaniosb7a89542007-04-12 02:40:54 +00001143 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001144
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001145 if (c <= 0177) {
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001146 /* pick rfield from operand b (opx) */
1147 rflags = regflag(opx);
1148 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001149 } else {
1150 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001151 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001152 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001153 if (!process_ea(opy, &ea_data, bits,
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001154 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001155 errfunc(ERR_NONFATAL, "invalid effective address");
1156 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001157 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001158 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001159 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001160 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001161 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001162 break;
1163
1164 default:
1165 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001166 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001167 break;
1168 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001169 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001170
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001171 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001172
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001173 if (ins->rex & REX_NH) {
1174 if (ins->rex & REX_H) {
1175 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1176 return -1;
1177 }
1178 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
1179 }
1180
H. Peter Anvind85d2502008-05-04 17:53:31 -07001181 if (ins->rex & REX_V) {
1182 int bad32 = REX_R|REX_W|REX_X|REX_B;
1183
1184 if (ins->rex & REX_H) {
1185 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1186 return -1;
1187 }
1188 switch (ins->vex_wlp & 030) {
1189 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001190 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001191 ins->rex &= ~REX_W;
1192 break;
1193 case 010:
1194 ins->rex |= REX_W;
1195 bad32 &= ~REX_W;
1196 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001197 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001198 /* Follow REX_W */
1199 break;
1200 }
1201
1202 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1203 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1204 return -1;
1205 }
H. Peter Anvina04019c2009-05-03 21:42:34 -07001206 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
H. Peter Anvind85d2502008-05-04 17:53:31 -07001207 length += 3;
1208 else
1209 length += 2;
1210 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001211 if (ins->rex & REX_H) {
1212 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1213 return -1;
1214 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001215 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001216 ins->drexdst > 7)) {
1217 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1218 return -1;
1219 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001220 length++;
1221 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001222 if (ins->rex & REX_H) {
1223 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1224 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001225 } else if (bits == 64) {
1226 length++;
1227 } else if ((ins->rex & REX_L) &&
1228 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1229 cpu >= IF_X86_64) {
1230 /* LOCK-as-REX.R */
1231 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001232 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001233 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001234 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1235 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001236 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001237 }
1238
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001239 return length;
1240}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001241
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001242#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001243 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001244 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001245 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001246 ins->rex = 0; \
1247 offset += 1; \
1248 }
1249
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001250static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001251 insn * ins, const struct itemplate *temp,
1252 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001253{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001254 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001255 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1256 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1257 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001258 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001259 uint8_t c;
1260 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001261 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001262 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001263 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001264 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001265 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001266 uint8_t opex = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001267
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 while (*codes) {
1269 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001270 op1 = (c & 3) + ((opex & 1) << 2);
1271 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1272 opx = &ins->oprs[op1];
1273 opex = 0; /* For the next iteration */
1274
H. Peter Anvin839eca22007-10-29 23:12:47 -07001275 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001276 case 01:
1277 case 02:
1278 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001279 case 04:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001280 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001281 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001282 codes += c;
1283 offset += c;
1284 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001285
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001286 case 05:
1287 case 06:
1288 case 07:
1289 opex = c;
1290 break;
1291
H. Peter Anvin507ae032008-10-09 15:37:10 -07001292 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001293 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001294 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001295 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001296 offset += 1;
1297 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001298
H. Peter Anvin507ae032008-10-09 15:37:10 -07001299 case4(014):
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001300 /* The test for BITS8 and SBYTE here is intended to avoid
1301 warning on optimizer actions due to SBYTE, while still
1302 warn on explicit BYTE directives. Also warn, obviously,
1303 if the optimizer isn't enabled. */
1304 if (((opx->type & BITS8) ||
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001305 !(opx->type & temp->opd[op1] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001306 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001307 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001308 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001309 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 if (opx->segment != NO_SEG) {
1311 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001312 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001313 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001314 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001315 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001316 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001317 NO_SEG);
1318 }
1319 offset += 1;
1320 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001321
H. Peter Anvin507ae032008-10-09 15:37:10 -07001322 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001323 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001324 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001325 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001327 if (opx->segment != NO_SEG) {
1328 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001329 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001331 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001332 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001333 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001334 NO_SEG);
1335 }
1336 offset += 1;
1337 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001338
H. Peter Anvin507ae032008-10-09 15:37:10 -07001339 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001341 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001342 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001343 if (opx->segment != NO_SEG) {
1344 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001345 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001346 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001347 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001348 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001349 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001350 NO_SEG);
1351 }
1352 offset += 1;
1353 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001354
H. Peter Anvin507ae032008-10-09 15:37:10 -07001355 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001356 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001358 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001360 offset += 2;
1361 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001362
H. Peter Anvin507ae032008-10-09 15:37:10 -07001363 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001364 if (opx->type & (BITS16 | BITS32))
1365 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001366 else
1367 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001368 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001370 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 offset += size;
1373 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001374
H. Peter Anvin507ae032008-10-09 15:37:10 -07001375 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001376 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001377 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001378 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001379 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 offset += 4;
1381 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001382
H. Peter Anvin507ae032008-10-09 15:37:10 -07001383 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001385 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001386 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001387 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001388 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001389 offset += size;
1390 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001391
H. Peter Anvin507ae032008-10-09 15:37:10 -07001392 case4(050):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001393 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001394 errfunc(ERR_NONFATAL,
1395 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001396 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001397 if (data > 127 || data < -128)
1398 errfunc(ERR_NONFATAL, "short jump is out of range");
1399 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001400 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001401 offset += 1;
1402 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001403
H. Peter Anvin507ae032008-10-09 15:37:10 -07001404 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001405 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001406 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001407 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001408 offset += 8;
1409 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001410
H. Peter Anvin507ae032008-10-09 15:37:10 -07001411 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001412 if (opx->segment != segment) {
1413 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001414 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001415 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001416 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001417 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001420 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 }
1422 offset += 2;
1423 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001424
H. Peter Anvin507ae032008-10-09 15:37:10 -07001425 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001426 if (opx->type & (BITS16 | BITS32 | BITS64))
1427 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 else
1429 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001430 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001431 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001432 out(offset, segment, &data,
1433 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1434 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001435 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001436 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001437 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001438 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 }
1440 offset += size;
1441 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001442
H. Peter Anvin507ae032008-10-09 15:37:10 -07001443 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001444 if (opx->segment != segment) {
1445 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001447 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001448 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001449 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001450 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001452 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001453 }
1454 offset += 4;
1455 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001456
H. Peter Anvin507ae032008-10-09 15:37:10 -07001457 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001458 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001459 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1460 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001461 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001462 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001463 outfmt->segbase(1 + opx->segment),
1464 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001465 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001466 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001467
H. Peter Anvin507ae032008-10-09 15:37:10 -07001468 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001469 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001470 warn_overflow_opd(opx, 2);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001471 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001472 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001473 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001474 NO_SEG);
1475 offset++;
1476 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001477 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001478 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001479 offset += 2;
1480 }
1481 break;
1482
H. Peter Anvin507ae032008-10-09 15:37:10 -07001483 case4(0144):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001484 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001485 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001486 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001487 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001488 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001489 offset++;
1490 break;
1491
H. Peter Anvin507ae032008-10-09 15:37:10 -07001492 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001493 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001494 warn_overflow_opd(opx, 4);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001495 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001496 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001497 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001498 NO_SEG);
1499 offset++;
1500 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001501 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001502 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001503 offset += 4;
1504 }
1505 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001506
H. Peter Anvin507ae032008-10-09 15:37:10 -07001507 case4(0154):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001508 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001509 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001510 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001511 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001512 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001513 offset++;
1514 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001515
H. Peter Anvin507ae032008-10-09 15:37:10 -07001516 case4(0160):
1517 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001518 break;
1519
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001520 case 0171:
1521 bytes[0] =
1522 (ins->drexdst << 4) |
1523 (ins->rex & REX_OC ? 0x08 : 0) |
1524 (ins->rex & (REX_R|REX_X|REX_B));
1525 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001526 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001527 offset++;
1528 break;
1529
H. Peter Anvind85d2502008-05-04 17:53:31 -07001530 case 0172:
1531 c = *codes++;
1532 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001533 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001534 opx = &ins->oprs[c & 7];
1535 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1536 errfunc(ERR_NONFATAL,
1537 "non-absolute expression not permitted as argument %d",
1538 c & 7);
1539 } else {
1540 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001541 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001542 "four-bit argument exceeds bounds");
1543 }
1544 bytes[0] |= opx->offset & 15;
1545 }
1546 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1547 offset++;
1548 break;
1549
H. Peter Anvind58656f2008-05-06 20:11:14 -07001550 case 0173:
1551 c = *codes++;
1552 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001553 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001554 bytes[0] |= c & 15;
1555 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1556 offset++;
1557 break;
1558
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001559 case 0174:
1560 c = *codes++;
1561 opx = &ins->oprs[c];
1562 bytes[0] = nasm_regvals[opx->basereg] << 4;
1563 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1564 offset++;
1565 break;
1566
H. Peter Anvin507ae032008-10-09 15:37:10 -07001567 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001568 data = opx->offset;
H. Peter Anvinad6b8592008-10-07 09:56:38 -07001569 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1570 (int32_t)data != (int64_t)data) {
1571 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1572 "signed dword immediate exceeds bounds");
1573 }
1574 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001575 bytes[0] = data;
1576 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1577 NO_SEG);
1578 offset++;
1579 } else {
1580 out(offset, segment, &data, OUT_ADDRESS, 4,
1581 opx->segment, opx->wrt);
1582 offset += 4;
1583 }
1584 break;
1585
H. Peter Anvin507ae032008-10-09 15:37:10 -07001586 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001587 data = opx->offset;
1588 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1589 (int32_t)data != (int64_t)data) {
1590 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1591 "signed dword immediate exceeds bounds");
1592 }
1593 out(offset, segment, &data, OUT_ADDRESS, 4,
1594 opx->segment, opx->wrt);
1595 offset += 4;
1596 break;
1597
H. Peter Anvin507ae032008-10-09 15:37:10 -07001598 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -07001599 case 0270:
1600 codes += 2;
H. Peter Anvina04019c2009-05-03 21:42:34 -07001601 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1602 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1603 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001604 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001605 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001606 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1607 offset += 3;
1608 } else {
1609 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001610 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1611 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001612 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1613 offset += 2;
1614 }
1615 break;
1616
H. Peter Anvin507ae032008-10-09 15:37:10 -07001617 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001618 {
1619 uint64_t uv, um;
1620 int s;
1621
1622 if (ins->rex & REX_W)
1623 s = 64;
1624 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1625 s = 16;
1626 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1627 s = 32;
1628 else
1629 s = bits;
1630
1631 um = (uint64_t)2 << (s-1);
1632 uv = opx->offset;
1633
1634 if (uv > 127 && uv < (uint64_t)-128 &&
1635 (uv < um-128 || uv > um-1)) {
1636 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1637 "signed byte value exceeds bounds");
1638 }
1639 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001640 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001641 out(offset, segment, &data, OUT_ADDRESS, 1,
1642 opx->segment, opx->wrt);
1643 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001644 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001645 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1646 NO_SEG);
1647 }
1648 offset += 1;
1649 break;
1650 }
1651
H. Peter Anvin507ae032008-10-09 15:37:10 -07001652 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001654
H. Peter Anvine2c80182005-01-15 22:15:51 +00001655 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001656 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001657 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001658 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001659 offset += 1;
1660 } else
1661 offset += 0;
1662 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001663
H. Peter Anvine2c80182005-01-15 22:15:51 +00001664 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001665 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001666 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001667 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001668 offset += 1;
1669 } else
1670 offset += 0;
1671 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001672
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 case 0312:
1674 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001675
Keith Kaniosb7a89542007-04-12 02:40:54 +00001676 case 0313:
1677 ins->rex = 0;
1678 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001679
H. Peter Anvin507ae032008-10-09 15:37:10 -07001680 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001681 break;
1682
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001684 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001685 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001686 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 offset += 1;
1688 } else
1689 offset += 0;
1690 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001691
H. Peter Anvine2c80182005-01-15 22:15:51 +00001692 case 0321:
1693 if (bits == 16) {
1694 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001695 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001696 offset += 1;
1697 } else
1698 offset += 0;
1699 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001700
H. Peter Anvine2c80182005-01-15 22:15:51 +00001701 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001702 case 0323:
1703 break;
1704
Keith Kaniosb7a89542007-04-12 02:40:54 +00001705 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001706 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001707 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001708
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001709 case 0325:
1710 break;
1711
H. Peter Anvine2c80182005-01-15 22:15:51 +00001712 case 0330:
1713 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001714 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001715 offset += 1;
1716 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001717
H. Peter Anvine2c80182005-01-15 22:15:51 +00001718 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001719 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001720
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001721 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001722 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001723 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001724 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001725 offset += 1;
1726 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001727
Keith Kanios48af1772007-08-17 07:37:52 +00001728 case 0334:
1729 if (ins->rex & REX_R) {
1730 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001731 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001732 offset += 1;
1733 }
1734 ins->rex &= ~(REX_L|REX_R);
1735 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001736
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001737 case 0335:
1738 break;
1739
H. Peter Anvin962e3052008-08-28 17:47:16 -07001740 case 0336:
1741 case 0337:
1742 break;
1743
H. Peter Anvine2c80182005-01-15 22:15:51 +00001744 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001745 if (ins->oprs[0].segment != NO_SEG)
1746 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1747 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001748 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001749 if (size > 0)
1750 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001751 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001752 offset += size;
1753 }
1754 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001755
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001756 case 0341:
1757 break;
1758
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001759 case 0344:
1760 case 0345:
1761 bytes[0] = c & 1;
1762 switch (ins->oprs[0].basereg) {
1763 case R_CS:
1764 bytes[0] += 0x0E;
1765 break;
1766 case R_DS:
1767 bytes[0] += 0x1E;
1768 break;
1769 case R_ES:
1770 bytes[0] += 0x06;
1771 break;
1772 case R_SS:
1773 bytes[0] += 0x16;
1774 break;
1775 default:
1776 errfunc(ERR_PANIC,
1777 "bizarre 8086 segment register received");
1778 }
1779 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1780 offset++;
1781 break;
1782
1783 case 0346:
1784 case 0347:
1785 bytes[0] = c & 1;
1786 switch (ins->oprs[0].basereg) {
1787 case R_FS:
1788 bytes[0] += 0xA0;
1789 break;
1790 case R_GS:
1791 bytes[0] += 0xA8;
1792 break;
1793 default:
1794 errfunc(ERR_PANIC,
1795 "bizarre 386 segment register received");
1796 }
1797 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1798 offset++;
1799 break;
1800
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001801 case 0360:
1802 break;
1803
1804 case 0361:
1805 bytes[0] = 0x66;
1806 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1807 offset += 1;
1808 break;
1809
1810 case 0362:
1811 case 0363:
1812 bytes[0] = c - 0362 + 0xf2;
1813 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1814 offset += 1;
1815 break;
1816
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001817 case 0364:
1818 case 0365:
1819 break;
1820
Keith Kanios48af1772007-08-17 07:37:52 +00001821 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001822 case 0367:
1823 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001824 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001825 offset += 1;
1826 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001827
H. Peter Anvine2c80182005-01-15 22:15:51 +00001828 case 0370:
1829 case 0371:
1830 case 0372:
1831 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001832
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 case 0373:
1834 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001835 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001836 offset += 1;
1837 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001838
H. Peter Anvin507ae032008-10-09 15:37:10 -07001839 case4(0100):
1840 case4(0110):
1841 case4(0120):
1842 case4(0130):
1843 case4(0200):
1844 case4(0204):
1845 case4(0210):
1846 case4(0214):
1847 case4(0220):
1848 case4(0224):
1849 case4(0230):
1850 case4(0234):
1851 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001852 ea ea_data;
1853 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001854 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001855 uint8_t *p;
1856 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001857 enum out_type type;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001858 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001859
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001860 if (c <= 0177) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001861 /* pick rfield from operand b (opx) */
1862 rflags = regflag(opx);
1863 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001864 } else {
1865 /* rfield is constant */
1866 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001867 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001868 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001869
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001870 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
1871 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001872 errfunc(ERR_NONFATAL, "invalid effective address");
1873 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001874
Charles Crayne7e975552007-11-03 22:06:13 -07001875
H. Peter Anvine2c80182005-01-15 22:15:51 +00001876 p = bytes;
1877 *p++ = ea_data.modrm;
1878 if (ea_data.sib_present)
1879 *p++ = ea_data.sib;
1880
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001881 /* DREX suffixes come between the SIB and the displacement */
1882 if (ins->rex & REX_D) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001883 *p++ = (ins->drexdst << 4) |
1884 (ins->rex & REX_OC ? 0x08 : 0) |
1885 (ins->rex & (REX_R|REX_X|REX_B));
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001886 ins->rex = 0;
1887 }
1888
H. Peter Anvine2c80182005-01-15 22:15:51 +00001889 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001890 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001891
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001892 /*
1893 * Make sure the address gets the right offset in case
1894 * the line breaks in the .lst file (BR 1197827)
1895 */
1896 offset += s;
1897 s = 0;
1898
H. Peter Anvine2c80182005-01-15 22:15:51 +00001899 switch (ea_data.bytes) {
1900 case 0:
1901 break;
1902 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001903 case 2:
1904 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001905 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001906 data = opy->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001907 warn_overflow_opd(opy, ea_data.bytes);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001908 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001909 if (ea_data.rip) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001910 if (opy->segment == segment) {
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001911 data -= insn_end;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001912 out(offset, segment, &data, OUT_ADDRESS,
1913 ea_data.bytes, NO_SEG, NO_SEG);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001914 } else {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001915 out(offset, segment, &data, OUT_REL4ADR,
1916 insn_end - offset, opy->segment, opy->wrt);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001917 }
H. Peter Anvin9f817132008-10-06 19:11:07 -07001918 } else {
1919 type = OUT_ADDRESS;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001920 out(offset, segment, &data, OUT_ADDRESS,
1921 ea_data.bytes, opy->segment, opy->wrt);
H. Peter Anvin9f817132008-10-06 19:11:07 -07001922 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001923 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001924 default:
1925 /* Impossible! */
1926 errfunc(ERR_PANIC,
1927 "Invalid amount of bytes (%d) for offset?!",
1928 ea_data.bytes);
1929 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001930 }
1931 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001932 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001933 break;
1934
1935 default:
1936 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001937 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001938 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001939 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001940 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001941}
1942
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001943static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001944{
1945 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1946 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1947 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001948 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001949}
1950
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001951static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001952{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001953 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1954 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001955 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001956 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001957}
1958
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001959static int op_rexflags(const operand * o, int mask)
1960{
1961 int32_t flags;
1962 int val;
1963
1964 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1965 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1966 }
1967
H. Peter Anvina4835d42008-05-20 14:21:29 -07001968 flags = nasm_reg_flags[o->basereg];
1969 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001970
1971 return rexflags(val, flags, mask);
1972}
1973
1974static int rexflags(int val, int32_t flags, int mask)
1975{
1976 int rex = 0;
1977
1978 if (val >= 8)
1979 rex |= REX_B|REX_X|REX_R;
1980 if (flags & BITS64)
1981 rex |= REX_W;
1982 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1983 rex |= REX_H;
1984 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1985 rex |= REX_P;
1986
1987 return rex & mask;
1988}
1989
H. Peter Anvin23595f52009-07-25 17:44:25 -07001990static enum match_result find_match(const struct itemplate **tempp,
1991 insn *instruction,
1992 int32_t segment, int64_t offset, int bits)
1993{
1994 const struct itemplate *temp;
1995 enum match_result m, merr;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001996 int32_t xsizeflags[MAX_OPERANDS];
1997 bool opsizemissing = false;
1998 int i;
1999
2000 for (i = 0; i < instruction->operands; i++)
2001 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002002
2003 merr = MERR_INVALOP;
2004
2005 for (temp = nasm_instructions[instruction->opcode];
2006 temp->opcode != I_none; temp++) {
2007 m = matches(temp, instruction, bits);
2008 if (m == MOK_JUMP) {
2009 if (jmp_match(segment, offset, bits, instruction, temp->code))
2010 m = MOK_GOOD;
2011 else
2012 m = MERR_INVALOP;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002013 } else if (m == MERR_OPSIZEMISSING &&
2014 (temp->flags & IF_SMASK) != IF_SX) {
2015 /*
2016 * Missing operand size and a candidate for fuzzy matching...
2017 */
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002018 for (i = 0; i < temp->operands; i++) {
2019 if ((temp->opd[i] & SAME_AS) == 0)
2020 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
2021 }
H. Peter Anvina81655b2009-07-25 18:15:28 -07002022 opsizemissing = true;
2023 }
2024 if (m > merr)
2025 merr = m;
2026 if (merr == MOK_GOOD)
2027 goto done;
2028 }
2029
2030 /* No match, but see if we can get a fuzzy operand size match... */
2031 if (!opsizemissing)
2032 goto done;
2033
2034 for (i = 0; i < instruction->operands; i++) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002035 /*
2036 * We ignore extrinsic operand sizes on registers, so we should
2037 * never try to fuzzy-match on them. This also resolves the case
2038 * when we have e.g. "xmmrm128" in two different positions.
2039 */
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002040 if (is_class(REGISTER, instruction->oprs[i].type))
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002041 continue;
2042
H. Peter Anvina81655b2009-07-25 18:15:28 -07002043 /* This tests if xsizeflags[i] has more than one bit set */
2044 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2045 goto done; /* No luck */
2046
2047 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
2048 }
2049
2050 /* Try matching again... */
2051 for (temp = nasm_instructions[instruction->opcode];
2052 temp->opcode != I_none; temp++) {
2053 m = matches(temp, instruction, bits);
2054 if (m == MOK_JUMP) {
2055 if (jmp_match(segment, offset, bits, instruction, temp->code))
2056 m = MOK_GOOD;
2057 else
2058 m = MERR_INVALOP;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002059 }
2060 if (m > merr)
2061 merr = m;
2062 if (merr == MOK_GOOD)
H. Peter Anvina81655b2009-07-25 18:15:28 -07002063 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002064 }
2065
H. Peter Anvina81655b2009-07-25 18:15:28 -07002066done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002067 *tempp = temp;
2068 return merr;
2069}
2070
H. Peter Anvin65289e82009-07-25 17:25:11 -07002071static enum match_result matches(const struct itemplate *itemp,
2072 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002073{
H. Peter Anvin60926242009-07-26 16:25:38 -07002074 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002075 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002076
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002077 /*
2078 * Check the opcode
2079 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002080 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002081 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002082
2083 /*
2084 * Count the operands
2085 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002086 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002087 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002088
2089 /*
2090 * Check that no spurious colons or TOs are present
2091 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002092 for (i = 0; i < itemp->operands; i++)
2093 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002094 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002095
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002096 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002097 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002098 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002099 switch (itemp->flags & IF_SMASK) {
2100 case IF_SB:
2101 asize = BITS8;
2102 break;
2103 case IF_SW:
2104 asize = BITS16;
2105 break;
2106 case IF_SD:
2107 asize = BITS32;
2108 break;
2109 case IF_SQ:
2110 asize = BITS64;
2111 break;
2112 case IF_SO:
2113 asize = BITS128;
2114 break;
2115 case IF_SY:
2116 asize = BITS256;
2117 break;
2118 case IF_SZ:
2119 switch (bits) {
2120 case 16:
2121 asize = BITS16;
2122 break;
2123 case 32:
2124 asize = BITS32;
2125 break;
2126 case 64:
2127 asize = BITS64;
2128 break;
H. Peter Anvined3e84f2009-07-27 11:10:33 -07002129 default:
2130 asize = 0;
2131 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002132 }
2133 break;
2134 default:
2135 asize = 0;
2136 break;
2137 }
2138
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002139 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin60926242009-07-26 16:25:38 -07002140 /* S- flags only apply to a specific operand */
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002141 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
H. Peter Anvin60926242009-07-26 16:25:38 -07002142 memset(size, 0, sizeof size);
2143 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002144 } else {
H. Peter Anvin60926242009-07-26 16:25:38 -07002145 /* S- flags apply to all operands */
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002146 for (i = 0; i < MAX_OPERANDS; i++)
2147 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002148 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002149
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002150 /*
2151 * Check that the operand flags all match up
2152 */
2153 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1f754202009-10-11 13:40:44 +04002154 opflags_t type = instruction->oprs[i].type;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002155 if (!(type & SIZE_MASK))
2156 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002157
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002158 if (itemp->opd[i] & SAME_AS) {
2159 int j = itemp->opd[i] & ~SAME_AS;
2160 if (type != instruction->oprs[j].type ||
2161 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002162 return MERR_INVALOP;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002163 } else if (itemp->opd[i] & ~type ||
2164 ((itemp->opd[i] & SIZE_MASK) &&
2165 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002166 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002167 return MERR_INVALOP;
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002168 } else if (!is_class(REGISTER, type)) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002169 /*
2170 * Note: we don't honor extrinsic operand sizes for registers,
2171 * so "missing operand size" for a register should be
2172 * considered a wildcard match rather than an error.
2173 */
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002174 opsizemissing = true;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002175 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002176 }
2177 }
2178
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002179 if (opsizemissing)
2180 return MERR_OPSIZEMISSING;
2181
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002182 /*
2183 * Check operand sizes
2184 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002185 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002186 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2187 asize = 0;
2188 for (i = 0; i < oprs; i++) {
2189 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2190 int j;
2191 for (j = 0; j < oprs; j++)
2192 size[j] = asize;
2193 break;
2194 }
2195 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002196 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002197 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002198 }
2199
Keith Kaniosb7a89542007-04-12 02:40:54 +00002200 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002201 if (!(itemp->opd[i] & SIZE_MASK) &&
2202 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002203 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204 }
2205
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002206 /*
2207 * Check template is okay at the set cpu level
2208 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002209 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002210 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002211
Keith Kaniosb7a89542007-04-12 02:40:54 +00002212 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002213 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002214 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002215 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002216 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002217
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002218 /*
2219 * Check if special handling needed for Jumps
2220 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002221 if ((itemp->code[0] & 0374) == 0370)
2222 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002223
H. Peter Anvin60926242009-07-26 16:25:38 -07002224 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002225}
2226
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002227static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002228 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002229{
H. Peter Anvin9945fee2009-02-26 14:48:03 -08002230 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002231
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002232 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002233
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002234 /* REX flags for the rfield operand */
2235 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2236
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002237 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002238 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002239 int32_t f;
2240
2241 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002242 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002243 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002244 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002245 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002246
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002247 if (REG_EA & ~f)
2248 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002249
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002250 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2251
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002252 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002253 output->bytes = 0; /* no offset necessary either */
2254 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002255 } else { /* it's a memory reference */
2256 if (input->basereg == -1
2257 && (input->indexreg == -1 || input->scale == 0)) {
2258 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002259 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002260 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002261 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002262 scale = 0;
2263 index = 4;
2264 base = 5;
2265 output->sib = (scale << 6) | (index << 3) | base;
2266 output->bytes = 4;
2267 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002268 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002269 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002270 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002271 output->bytes = (addrbits != 16 ? 4 : 2);
2272 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002273 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002274 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002275 } else { /* it's an indirection */
2276 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002277 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002278 int hb = input->hintbase, ht = input->hinttype;
2279 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002280 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002281 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002282
H. Peter Anvine2c80182005-01-15 22:15:51 +00002283 if (s == 0)
2284 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002285
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002286 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002287 it = nasm_regvals[i];
2288 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002289 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002290 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002291 ix = 0;
2292 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002293
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002294 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002295 bt = nasm_regvals[b];
2296 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002297 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002298 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002299 bx = 0;
2300 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002301
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002302 /* check for a 32/64-bit memory reference... */
2303 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002304 /* it must be a 32/64-bit memory reference. Firstly we have
2305 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002306 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002307
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002308 if (it != -1) {
2309 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2310 sok &= ix;
2311 else
2312 return NULL;
2313 }
2314
2315 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002316 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002317 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002318 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002319 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002320 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002321 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002322
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002323 /* While we're here, ensure the user didn't specify
2324 WORD or QWORD. */
2325 if (input->disp_size == 16 || input->disp_size == 64)
2326 return NULL;
2327
2328 if (addrbits == 16 ||
2329 (addrbits == 32 && !(sok & BITS32)) ||
2330 (addrbits == 64 && !(sok & BITS64)))
2331 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002332
Keith Kaniosb7a89542007-04-12 02:40:54 +00002333 /* now reorganize base/index */
2334 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002335 ((hb == b && ht == EAH_NOTBASE)
2336 || (hb == i && ht == EAH_MAKEBASE))) {
2337 /* swap if hints say so */
2338 t = bt, bt = it, it = t;
2339 t = bx, bx = ix, ix = t;
2340 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002341 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002342 bt = -1, bx = 0, s++;
2343 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2344 /* make single reg base, unless hint */
2345 bt = it, bx = ix, it = -1, ix = 0;
2346 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002347 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002348 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002349 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002350 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002351 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002352 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002353 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002354 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002355 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002356 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002357 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002358 t = ix, ix = bx, bx = t;
2359 }
Keith Kanios48af1772007-08-17 07:37:52 +00002360 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002361 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002362 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002363
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002364 output->rex |= rexflags(it, ix, REX_X);
2365 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002366
Keith Kanios48af1772007-08-17 07:37:52 +00002367 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002368 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002369 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002370
Keith Kaniosb7a89542007-04-12 02:40:54 +00002371 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002372 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002373 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002374 } else {
2375 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002376 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002377 seg == NO_SEG && !forw_ref &&
2378 !(input->eaflags &
2379 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2380 mod = 0;
2381 else if (input->eaflags & EAF_BYTEOFFS ||
2382 (o >= -128 && o <= 127 && seg == NO_SEG
2383 && !forw_ref
2384 && !(input->eaflags & EAF_WORDOFFS)))
2385 mod = 1;
2386 else
2387 mod = 2;
2388 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002389
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002390 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002391 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2392 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002393 } else {
2394 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002395 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002396
Keith Kaniosb7a89542007-04-12 02:40:54 +00002397 if (it == -1)
2398 index = 4, s = 1;
2399 else
2400 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002401
H. Peter Anvine2c80182005-01-15 22:15:51 +00002402 switch (s) {
2403 case 1:
2404 scale = 0;
2405 break;
2406 case 2:
2407 scale = 1;
2408 break;
2409 case 4:
2410 scale = 2;
2411 break;
2412 case 8:
2413 scale = 3;
2414 break;
2415 default: /* then what the smeg is it? */
2416 return NULL; /* panic */
2417 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002418
Keith Kaniosb7a89542007-04-12 02:40:54 +00002419 if (bt == -1) {
2420 base = 5;
2421 mod = 0;
2422 } else {
2423 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002424 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002425 seg == NO_SEG && !forw_ref &&
2426 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002427 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2428 mod = 0;
2429 else if (input->eaflags & EAF_BYTEOFFS ||
2430 (o >= -128 && o <= 127 && seg == NO_SEG
2431 && !forw_ref
2432 && !(input->eaflags & EAF_WORDOFFS)))
2433 mod = 1;
2434 else
2435 mod = 2;
2436 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002437
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002438 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002439 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2440 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002441 output->sib = (scale << 6) | (index << 3) | base;
2442 }
2443 } else { /* it's 16-bit */
2444 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002445
Keith Kaniosb7a89542007-04-12 02:40:54 +00002446 /* check for 64-bit long mode */
2447 if (addrbits == 64)
2448 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002449
H. Peter Anvine2c80182005-01-15 22:15:51 +00002450 /* check all registers are BX, BP, SI or DI */
2451 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2452 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2453 && i != R_SI && i != R_DI))
2454 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002455
Keith Kaniosb7a89542007-04-12 02:40:54 +00002456 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002457 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002458 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002459
H. Peter Anvine2c80182005-01-15 22:15:51 +00002460 if (s != 1 && i != -1)
2461 return NULL; /* no can do, in 16-bit EA */
2462 if (b == -1 && i != -1) {
2463 int tmp = b;
2464 b = i;
2465 i = tmp;
2466 } /* swap */
2467 if ((b == R_SI || b == R_DI) && i != -1) {
2468 int tmp = b;
2469 b = i;
2470 i = tmp;
2471 }
2472 /* have BX/BP as base, SI/DI index */
2473 if (b == i)
2474 return NULL; /* shouldn't ever happen, in theory */
2475 if (i != -1 && b != -1 &&
2476 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2477 return NULL; /* invalid combinations */
2478 if (b == -1) /* pure offset: handled above */
2479 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002480
H. Peter Anvine2c80182005-01-15 22:15:51 +00002481 rm = -1;
2482 if (i != -1)
2483 switch (i * 256 + b) {
2484 case R_SI * 256 + R_BX:
2485 rm = 0;
2486 break;
2487 case R_DI * 256 + R_BX:
2488 rm = 1;
2489 break;
2490 case R_SI * 256 + R_BP:
2491 rm = 2;
2492 break;
2493 case R_DI * 256 + R_BP:
2494 rm = 3;
2495 break;
2496 } else
2497 switch (b) {
2498 case R_SI:
2499 rm = 4;
2500 break;
2501 case R_DI:
2502 rm = 5;
2503 break;
2504 case R_BP:
2505 rm = 6;
2506 break;
2507 case R_BX:
2508 rm = 7;
2509 break;
2510 }
2511 if (rm == -1) /* can't happen, in theory */
2512 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002513
H. Peter Anvine2c80182005-01-15 22:15:51 +00002514 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2515 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2516 mod = 0;
2517 else if (input->eaflags & EAF_BYTEOFFS ||
2518 (o >= -128 && o <= 127 && seg == NO_SEG
2519 && !forw_ref
2520 && !(input->eaflags & EAF_WORDOFFS)))
2521 mod = 1;
2522 else
2523 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002524
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002525 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002526 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002527 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002528 }
2529 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002530 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002531
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002532 output->size = 1 + output->sib_present + output->bytes;
2533 return output;
2534}
2535
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002536static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002537{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002538 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002539 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002540
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002541 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002542
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002543 switch (ins->prefixes[PPS_ASIZE]) {
2544 case P_A16:
2545 valid &= 16;
2546 break;
2547 case P_A32:
2548 valid &= 32;
2549 break;
2550 case P_A64:
2551 valid &= 64;
2552 break;
2553 case P_ASP:
2554 valid &= (addrbits == 32) ? 16 : 32;
2555 break;
2556 default:
2557 break;
2558 }
2559
2560 for (j = 0; j < ins->operands; j++) {
2561 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002562 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002563
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002564 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002565 if (ins->oprs[j].indexreg < EXPR_REG_START
2566 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002567 i = 0;
2568 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002569 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002570
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002571 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002572 if (ins->oprs[j].basereg < EXPR_REG_START
2573 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002574 b = 0;
2575 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002576 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002577
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002578 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002579 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002580
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002581 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002582 int ds = ins->oprs[j].disp_size;
2583 if ((addrbits != 64 && ds > 8) ||
2584 (addrbits == 64 && ds == 16))
2585 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002586 } else {
2587 if (!(REG16 & ~b))
2588 valid &= 16;
2589 if (!(REG32 & ~b))
2590 valid &= 32;
2591 if (!(REG64 & ~b))
2592 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002593
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002594 if (!(REG16 & ~i))
2595 valid &= 16;
2596 if (!(REG32 & ~i))
2597 valid &= 32;
2598 if (!(REG64 & ~i))
2599 valid &= 64;
2600 }
2601 }
2602 }
2603
2604 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002605 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002606 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002607 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002608 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002609 ins->prefixes[PPS_ASIZE] = pref;
2610 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002611 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002612 /* Impossible... */
2613 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002614 ins->addr_size = addrbits; /* Error recovery */
2615 }
2616
2617 defdisp = ins->addr_size == 16 ? 16 : 32;
2618
2619 for (j = 0; j < ins->operands; j++) {
2620 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2621 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2622 != ins->addr_size) {
2623 /* mem_offs sizes must match the address size; if not,
2624 strip the MEM_OFFS bit and match only EA instructions */
2625 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2626 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002627 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002628}