blob: e5df72822fd4df19767a94d02fb01986b2326d81 [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
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700243static void warn_overflow(int size, const struct operand *o)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700244{
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700245 if (size < 8 && o->wrt == NO_SEG && o->segment == NO_SEG) {
Charles Craynedd462c82007-11-04 15:28:30 -0800246 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700247 int64_t data = o->offset;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000248
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700249 if (data < ~lim || data > lim)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700250 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700251 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700252 }
253}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000254/*
255 * This routine wrappers the real output format's output routine,
256 * in order to pass a copy of the data off to the listing file
257 * generator at the same time.
258 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800259static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800260 enum out_type type, uint64_t size,
261 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000262{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000263 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000264 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800265 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000266
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800267 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
268 /*
269 * This is a non-relocated address, and we're going to
270 * convert it into RAWDATA format.
271 */
272 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800273
274 if (size > 8) {
275 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
276 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800277 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700278
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800279 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800280 data = p;
281 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000282 }
283
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800284 list->output(offset, data, type, size);
285
Frank Kotlerabebb082003-09-06 04:45:37 +0000286 /*
287 * this call to src_get determines when we call the
288 * debug-format-specific "linenum" function
289 * it updates lineno and lnfname to the current values
290 * returning 0 if "same as last time", -2 if lnfname
291 * changed, and the amount by which lineno changed,
292 * if it did. thus, these variables must be static
293 */
294
H. Peter Anvine2c80182005-01-15 22:15:51 +0000295 if (src_get(&lineno, &lnfname)) {
296 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000297 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000298
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800299 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000300}
301
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700302static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700303 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000304{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800305 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000306 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000307
Charles Craynef1aefd82008-09-30 16:11:32 -0700308 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700309 return false;
310 if (!optimizing)
311 return false;
312 if (optimizing < 0 && c == 0371)
313 return false;
314
H. Peter Anvine2c80182005-01-15 22:15:51 +0000315 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100316
Victor van den Elzen154e5922009-02-25 17:32:00 +0100317 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100318 /* Be optimistic in pass 1 */
319 return true;
320
H. Peter Anvine2c80182005-01-15 22:15:51 +0000321 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700322 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000323
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700324 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
325 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000326}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000327
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800328int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvin65289e82009-07-25 17:25:11 -0700329 insn * instruction, struct ofmt *output, efunc error,
330 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000331{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000332 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700334 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800335 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000336 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800337 int64_t start = offset;
338 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000339
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000341 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 outfmt = output; /* likewise */
343 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000344
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 switch (instruction->opcode) {
346 case -1:
347 return 0;
348 case I_DB:
349 wsize = 1;
350 break;
351 case I_DW:
352 wsize = 2;
353 break;
354 case I_DD:
355 wsize = 4;
356 break;
357 case I_DQ:
358 wsize = 8;
359 break;
360 case I_DT:
361 wsize = 10;
362 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700363 case I_DO:
364 wsize = 16;
365 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700366 case I_DY:
367 wsize = 32;
368 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700369 default:
370 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000371 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000372
H. Peter Anvineba20a72002-04-30 20:53:55 +0000373 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000375 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 if (t < 0)
377 errfunc(ERR_PANIC,
378 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000379
H. Peter Anvine2c80182005-01-15 22:15:51 +0000380 while (t--) { /* repeat TIMES times */
381 for (e = instruction->eops; e; e = e->next) {
382 if (e->type == EOT_DB_NUMBER) {
383 if (wsize == 1) {
384 if (e->segment != NO_SEG)
385 errfunc(ERR_NONFATAL,
386 "one-byte relocation attempted");
387 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000388 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800390 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000392 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700393 errfunc(ERR_NONFATAL,
394 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000395 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000396 } else
397 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800398 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700400 } else if (e->type == EOT_DB_STRING ||
401 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000402 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000403
H. Peter Anvine2c80182005-01-15 22:15:51 +0000404 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800405 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000406 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000407
H. Peter Anvine2c80182005-01-15 22:15:51 +0000408 if (align) {
409 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100410 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800411 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000412 }
413 offset += e->stringlen + align;
414 }
415 }
416 if (t > 0 && t == instruction->times - 1) {
417 /*
418 * Dummy call to list->output to give the offset to the
419 * listing module.
420 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800421 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 list->uplevel(LIST_TIMES);
423 }
424 }
425 if (instruction->times > 1)
426 list->downlevel(LIST_TIMES);
427 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000428 }
429
H. Peter Anvine2c80182005-01-15 22:15:51 +0000430 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700431 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000432 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000433
H. Peter Anvin418ca702008-05-30 10:42:30 -0700434 fp = fopen(fname, "rb");
435 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000436 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
437 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700438 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000439 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
440 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700441 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700442 static char buf[4096];
443 size_t t = instruction->times;
444 size_t base = 0;
445 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000446
H. Peter Anvine2c80182005-01-15 22:15:51 +0000447 len = ftell(fp);
448 if (instruction->eops->next) {
449 base = instruction->eops->next->offset;
450 len -= base;
451 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700452 len > (size_t)instruction->eops->next->next->offset)
453 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000454 }
455 /*
456 * Dummy call to list->output to give the offset to the
457 * listing module.
458 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800459 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000460 list->uplevel(LIST_INCBIN);
461 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700462 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000463
H. Peter Anvine2c80182005-01-15 22:15:51 +0000464 fseek(fp, base, SEEK_SET);
465 l = len;
466 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700467 int32_t m;
468 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000469 if (!m) {
470 /*
471 * This shouldn't happen unless the file
472 * actually changes while we are reading
473 * it.
474 */
475 error(ERR_NONFATAL,
476 "`incbin': unexpected EOF while"
477 " reading file `%s'", fname);
478 t = 0; /* Try to exit cleanly */
479 break;
480 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800481 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000482 NO_SEG, NO_SEG);
483 l -= m;
484 }
485 }
486 list->downlevel(LIST_INCBIN);
487 if (instruction->times > 1) {
488 /*
489 * Dummy call to list->output to give the offset to the
490 * listing module.
491 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800492 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000493 list->uplevel(LIST_TIMES);
494 list->downlevel(LIST_TIMES);
495 }
496 fclose(fp);
497 return instruction->times * len;
498 }
499 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000500 }
501
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700502 /* Check to see if we need an address-size prefix */
503 add_asp(instruction, bits);
504
H. Peter Anvin23595f52009-07-25 17:44:25 -0700505 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700506
H. Peter Anvin23595f52009-07-25 17:44:25 -0700507 if (m == MOK_GOOD) {
508 /* Matches! */
509 int64_t insn_size = calcsize(segment, offset, bits,
510 instruction, temp->code);
511 itimes = instruction->times;
512 if (insn_size < 0) /* shouldn't be, on pass two */
513 error(ERR_PANIC, "errors made it through from pass one");
514 else
515 while (itimes--) {
516 for (j = 0; j < MAXPREFIX; j++) {
517 uint8_t c = 0;
518 switch (instruction->prefixes[j]) {
519 case P_WAIT:
520 c = 0x9B;
521 break;
522 case P_LOCK:
523 c = 0xF0;
524 break;
525 case P_REPNE:
526 case P_REPNZ:
527 c = 0xF2;
528 break;
529 case P_REPE:
530 case P_REPZ:
531 case P_REP:
532 c = 0xF3;
533 break;
534 case R_CS:
535 if (bits == 64) {
536 error(ERR_WARNING | ERR_PASS2,
537 "cs segment base generated, but will be ignored in 64-bit mode");
538 }
539 c = 0x2E;
540 break;
541 case R_DS:
542 if (bits == 64) {
543 error(ERR_WARNING | ERR_PASS2,
544 "ds segment base generated, but will be ignored in 64-bit mode");
545 }
546 c = 0x3E;
547 break;
548 case R_ES:
549 if (bits == 64) {
550 error(ERR_WARNING | ERR_PASS2,
551 "es segment base generated, but will be ignored in 64-bit mode");
552 }
553 c = 0x26;
554 break;
555 case R_FS:
556 c = 0x64;
557 break;
558 case R_GS:
559 c = 0x65;
560 break;
561 case R_SS:
562 if (bits == 64) {
563 error(ERR_WARNING | ERR_PASS2,
564 "ss segment base generated, but will be ignored in 64-bit mode");
565 }
566 c = 0x36;
567 break;
568 case R_SEGR6:
569 case R_SEGR7:
570 error(ERR_NONFATAL,
571 "segr6 and segr7 cannot be used as prefixes");
572 break;
573 case P_A16:
574 if (bits == 64) {
575 error(ERR_NONFATAL,
576 "16-bit addressing is not supported "
577 "in 64-bit mode");
578 } else if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700579 c = 0x67;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700580 break;
581 case P_A32:
582 if (bits != 32)
583 c = 0x67;
584 break;
585 case P_A64:
586 if (bits != 64) {
587 error(ERR_NONFATAL,
588 "64-bit addressing is only supported "
589 "in 64-bit mode");
590 }
591 break;
592 case P_ASP:
593 c = 0x67;
594 break;
595 case P_O16:
596 if (bits != 16)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700597 c = 0x66;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700598 break;
599 case P_O32:
600 if (bits == 16)
601 c = 0x66;
602 break;
603 case P_O64:
604 /* REX.W */
605 break;
606 case P_OSP:
607 c = 0x66;
608 break;
609 case P_none:
610 break;
611 default:
612 error(ERR_PANIC, "invalid instruction prefix");
613 }
614 if (c != 0) {
615 out(offset, segment, &c, OUT_RAWDATA, 1,
616 NO_SEG, NO_SEG);
617 offset++;
618 }
619 }
620 insn_end = offset + insn_size;
621 gencode(segment, offset, bits, instruction,
622 temp, insn_end);
623 offset += insn_size;
624 if (itimes > 0 && itimes == instruction->times - 1) {
625 /*
626 * Dummy call to list->output to give the offset to the
627 * listing module.
628 */
629 list->output(offset, NULL, OUT_RAWDATA, 0);
630 list->uplevel(LIST_TIMES);
631 }
632 }
633 if (instruction->times > 1)
634 list->downlevel(LIST_TIMES);
635 return offset - start;
636 } else {
637 /* No match */
638 switch (m) {
H. Peter Anvin65289e82009-07-25 17:25:11 -0700639 case MERR_OPSIZEMISSING:
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000640 error(ERR_NONFATAL, "operation size not specified");
641 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700642 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000643 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000644 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700645 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000646 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000647 break;
H. Peter Anvin65289e82009-07-25 17:25:11 -0700648 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800649 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
650 bits);
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000651 break;
652 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000653 error(ERR_NONFATAL,
654 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000655 break;
656 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000657 }
658 return 0;
659}
660
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800661int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvin65289e82009-07-25 17:25:11 -0700662 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000663{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000664 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700665 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000666
H. Peter Anvine2c80182005-01-15 22:15:51 +0000667 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000668 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000669
670 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000672
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700673 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
674 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700675 instruction->opcode == I_DT || instruction->opcode == I_DO ||
676 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000678 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000679
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 isize = 0;
681 switch (instruction->opcode) {
682 case I_DB:
683 wsize = 1;
684 break;
685 case I_DW:
686 wsize = 2;
687 break;
688 case I_DD:
689 wsize = 4;
690 break;
691 case I_DQ:
692 wsize = 8;
693 break;
694 case I_DT:
695 wsize = 10;
696 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700697 case I_DO:
698 wsize = 16;
699 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700700 case I_DY:
701 wsize = 32;
702 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700703 default:
704 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000705 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000706
H. Peter Anvine2c80182005-01-15 22:15:51 +0000707 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000708 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000709
H. Peter Anvine2c80182005-01-15 22:15:51 +0000710 osize = 0;
711 if (e->type == EOT_DB_NUMBER)
712 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700713 else if (e->type == EOT_DB_STRING ||
714 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000715 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000716
H. Peter Anvine2c80182005-01-15 22:15:51 +0000717 align = (-osize) % wsize;
718 if (align < 0)
719 align += wsize;
720 isize += osize + align;
721 }
722 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000723 }
724
H. Peter Anvine2c80182005-01-15 22:15:51 +0000725 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700726 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000727 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700728 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000729
H. Peter Anvin418ca702008-05-30 10:42:30 -0700730 fp = fopen(fname, "rb");
731 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000732 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
733 fname);
734 else if (fseek(fp, 0L, SEEK_END) < 0)
735 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
736 fname);
737 else {
738 len = ftell(fp);
739 fclose(fp);
740 if (instruction->eops->next) {
741 len -= instruction->eops->next->offset;
742 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700743 len > (size_t)instruction->eops->next->next->offset) {
744 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000745 }
746 }
747 return instruction->times * len;
748 }
749 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000750 }
751
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700752 /* Check to see if we need an address-size prefix */
753 add_asp(instruction, bits);
754
H. Peter Anvin23595f52009-07-25 17:44:25 -0700755 m = find_match(&temp, instruction, segment, offset, bits);
756 if (m == MOK_GOOD) {
757 /* we've matched an instruction. */
758 int64_t isize;
759 const uint8_t *codes = temp->code;
760 int j;
761
762 isize = calcsize(segment, offset, bits, instruction, codes);
763 if (isize < 0)
764 return -1;
765 for (j = 0; j < MAXPREFIX; j++) {
766 switch (instruction->prefixes[j]) {
767 case P_A16:
768 if (bits != 16)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700769 isize++;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700770 break;
771 case P_A32:
772 if (bits != 32)
773 isize++;
774 break;
775 case P_O16:
776 if (bits != 16)
777 isize++;
778 break;
779 case P_O32:
780 if (bits == 16)
781 isize++;
782 break;
783 case P_A64:
784 case P_O64:
785 case P_none:
786 break;
787 default:
788 isize++;
789 break;
790 }
791 }
792 return isize * instruction->times;
793 } else {
794 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000795 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000796}
797
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700798static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000799{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700800 return o->wrt == NO_SEG && o->segment == NO_SEG &&
H. Peter Anvine8ab8912009-02-26 16:34:56 -0800801 !(o->opflags & OPFLAG_UNKNOWN) &&
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700802 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000803}
804
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700805/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700806static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700807{
808 int16_t v;
809
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700810 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700811 return false;
812
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700813 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700814 return v >= -128 && v <= 127;
815}
816
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700817static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700818{
819 int32_t v;
820
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700821 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700822 return false;
823
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700824 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700825 return v >= -128 && v <= 127;
826}
827
H. Peter Anvin507ae032008-10-09 15:37:10 -0700828/* Common construct */
829#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
830
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800831static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700832 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000833{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800834 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000835 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000836 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700837 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700838 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700839 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000840
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700841 ins->rex = 0; /* Ensure REX is reset */
842
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700843 if (ins->prefixes[PPS_OSIZE] == P_O64)
844 ins->rex |= REX_W;
845
H. Peter Anvine2c80182005-01-15 22:15:51 +0000846 (void)segment; /* Don't warn that this parameter is unused */
847 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000848
H. Peter Anvin839eca22007-10-29 23:12:47 -0700849 while (*codes) {
850 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700851 op1 = (c & 3) + ((opex & 1) << 2);
852 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
853 opx = &ins->oprs[op1];
854 opex = 0; /* For the next iteration */
855
H. Peter Anvin839eca22007-10-29 23:12:47 -0700856 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 case 01:
858 case 02:
859 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700860 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 codes += c, length += c;
862 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700863
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700864 case 05:
865 case 06:
866 case 07:
867 opex = c;
868 break;
869
H. Peter Anvin507ae032008-10-09 15:37:10 -0700870 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000871 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700872 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000873 codes++, length++;
874 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700875
876 case4(014):
877 case4(020):
878 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 length++;
880 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700881
882 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 length += 2;
884 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700885
886 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700887 if (opx->type & (BITS16 | BITS32 | BITS64))
888 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 else
890 length += (bits == 16) ? 2 : 4;
891 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700892
893 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 length += 4;
895 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700896
897 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700898 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000899 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700900
901 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000902 length++;
903 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700904
905 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000906 length += 8; /* MOV reg64/imm */
907 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700908
909 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000910 length += 2;
911 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700912
913 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700914 if (opx->type & (BITS16 | BITS32 | BITS64))
915 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000916 else
917 length += (bits == 16) ? 2 : 4;
918 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700919
920 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000921 length += 4;
922 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700923
924 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700925 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000926 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700927
928 case4(0140):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700929 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000930 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700931
932 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800933 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000934 length++;
935 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700936
937 case4(0150):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700938 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700939 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700940
941 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800942 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 length++;
944 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700945
946 case4(0160):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700947 length++;
948 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700949 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700950 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700951
952 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700953 length++;
954 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700955 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700956 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700957
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700958 case 0171:
959 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700960
H. Peter Anvind85d2502008-05-04 17:53:31 -0700961 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700962 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700963 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700964 codes++;
965 length++;
966 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700967
968 case4(0250):
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700969 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700970 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700971
972 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -0700973 length += 4;
974 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700975
976 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -0700977 ins->rex |= REX_V;
978 ins->drexdst = regval(opx);
H. Peter Anvina04019c2009-05-03 21:42:34 -0700979 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700980 ins->vex_wlp = *codes++;
981 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700982
H. Peter Anvind85d2502008-05-04 17:53:31 -0700983 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700984 ins->rex |= REX_V;
985 ins->drexdst = 0;
H. Peter Anvina04019c2009-05-03 21:42:34 -0700986 ins->vex_cm = *codes++;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700987 ins->vex_wlp = *codes++;
988 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700989
990 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700991 length++;
992 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700993
994 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000995 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700996
H. Peter Anvine2c80182005-01-15 22:15:51 +0000997 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700998 if (bits == 64)
999 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001000 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001002
H. Peter Anvine2c80182005-01-15 22:15:51 +00001003 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001004 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
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 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001008 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001009
Keith Kaniosb7a89542007-04-12 02:40:54 +00001010 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001011 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1012 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001013 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001014 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001015
1016 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001017 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001018
H. Peter Anvine2c80182005-01-15 22:15:51 +00001019 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001020 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001021 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001022
H. Peter Anvine2c80182005-01-15 22:15:51 +00001023 case 0321:
1024 length += (bits == 16);
1025 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001026
H. Peter Anvine2c80182005-01-15 22:15:51 +00001027 case 0322:
1028 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001029
Keith Kaniosb7a89542007-04-12 02:40:54 +00001030 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001031 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001032 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001033
Keith Kaniosb7a89542007-04-12 02:40:54 +00001034 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001035 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001036 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001037
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001038 case 0325:
1039 ins->rex |= REX_NH;
1040 break;
1041
H. Peter Anvine2c80182005-01-15 22:15:51 +00001042 case 0330:
1043 codes++, length++;
1044 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001045
H. Peter Anvine2c80182005-01-15 22:15:51 +00001046 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001048
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001049 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001050 case 0333:
1051 length++;
1052 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001053
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001054 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001055 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001056 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001057
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001058 case 0335:
1059 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001060
H. Peter Anvin962e3052008-08-28 17:47:16 -07001061 case 0336:
1062 if (!ins->prefixes[PPS_LREP])
1063 ins->prefixes[PPS_LREP] = P_REP;
1064 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001065
H. Peter Anvin962e3052008-08-28 17:47:16 -07001066 case 0337:
1067 if (!ins->prefixes[PPS_LREP])
1068 ins->prefixes[PPS_LREP] = P_REPNE;
1069 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001070
H. Peter Anvine2c80182005-01-15 22:15:51 +00001071 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001072 if (ins->oprs[0].segment != NO_SEG)
1073 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1074 " quantity of BSS space");
1075 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001076 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001077 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001078
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001079 case 0341:
1080 if (!ins->prefixes[PPS_WAIT])
1081 ins->prefixes[PPS_WAIT] = P_WAIT;
1082 break;
1083
H. Peter Anvin507ae032008-10-09 15:37:10 -07001084 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001085 length++;
1086 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001087
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001088 case 0360:
1089 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001090
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001091 case 0361:
1092 case 0362:
1093 case 0363:
1094 length++;
1095 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001096
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001097 case 0364:
1098 case 0365:
1099 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001100
Keith Kanios48af1772007-08-17 07:37:52 +00001101 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001102 case 0367:
1103 length++;
1104 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001105
H. Peter Anvine2c80182005-01-15 22:15:51 +00001106 case 0370:
1107 case 0371:
1108 case 0372:
1109 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001110
H. Peter Anvine2c80182005-01-15 22:15:51 +00001111 case 0373:
1112 length++;
1113 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001114
1115 case4(0100):
1116 case4(0110):
1117 case4(0120):
1118 case4(0130):
1119 case4(0200):
1120 case4(0204):
1121 case4(0210):
1122 case4(0214):
1123 case4(0220):
1124 case4(0224):
1125 case4(0230):
1126 case4(0234):
1127 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001128 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001129 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001130 int32_t rflags;
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001131 struct operand *opy = &ins->oprs[op2];
1132
Keith Kaniosb7a89542007-04-12 02:40:54 +00001133 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001134
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001135 if (c <= 0177) {
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001136 /* pick rfield from operand b (opx) */
1137 rflags = regflag(opx);
1138 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001139 } else {
1140 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001141 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001142 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001143 if (!process_ea(opy, &ea_data, bits,
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001144 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001145 errfunc(ERR_NONFATAL, "invalid effective address");
1146 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001147 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001148 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001149 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001150 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001151 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001152 break;
1153
1154 default:
1155 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001156 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001157 break;
1158 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001159 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001160
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001161 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001162
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001163 if (ins->rex & REX_NH) {
1164 if (ins->rex & REX_H) {
1165 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1166 return -1;
1167 }
1168 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
1169 }
1170
H. Peter Anvind85d2502008-05-04 17:53:31 -07001171 if (ins->rex & REX_V) {
1172 int bad32 = REX_R|REX_W|REX_X|REX_B;
1173
1174 if (ins->rex & REX_H) {
1175 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1176 return -1;
1177 }
1178 switch (ins->vex_wlp & 030) {
1179 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001180 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001181 ins->rex &= ~REX_W;
1182 break;
1183 case 010:
1184 ins->rex |= REX_W;
1185 bad32 &= ~REX_W;
1186 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001187 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001188 /* Follow REX_W */
1189 break;
1190 }
1191
1192 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1193 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1194 return -1;
1195 }
H. Peter Anvina04019c2009-05-03 21:42:34 -07001196 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
H. Peter Anvind85d2502008-05-04 17:53:31 -07001197 length += 3;
1198 else
1199 length += 2;
1200 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001201 if (ins->rex & REX_H) {
1202 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1203 return -1;
1204 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001205 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001206 ins->drexdst > 7)) {
1207 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1208 return -1;
1209 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001210 length++;
1211 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001212 if (ins->rex & REX_H) {
1213 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1214 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001215 } else if (bits == 64) {
1216 length++;
1217 } else if ((ins->rex & REX_L) &&
1218 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1219 cpu >= IF_X86_64) {
1220 /* LOCK-as-REX.R */
1221 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001222 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001223 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001224 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1225 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001226 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001227 }
1228
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001229 return length;
1230}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001231
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001232#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001233 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001234 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001235 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001236 ins->rex = 0; \
1237 offset += 1; \
1238 }
1239
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001240static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001241 insn * ins, const struct itemplate *temp,
1242 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001243{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001244 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1246 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1247 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001248 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001249 uint8_t c;
1250 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001251 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001252 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001253 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001254 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001255 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001256 uint8_t opex = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001257
H. Peter Anvin839eca22007-10-29 23:12:47 -07001258 while (*codes) {
1259 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001260 op1 = (c & 3) + ((opex & 1) << 2);
1261 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1262 opx = &ins->oprs[op1];
1263 opex = 0; /* For the next iteration */
1264
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 case 01:
1267 case 02:
1268 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001269 case 04:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001270 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001271 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001272 codes += c;
1273 offset += c;
1274 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001275
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001276 case 05:
1277 case 06:
1278 case 07:
1279 opex = c;
1280 break;
1281
H. Peter Anvin507ae032008-10-09 15:37:10 -07001282 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001283 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001284 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001285 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 offset += 1;
1287 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001288
H. Peter Anvin507ae032008-10-09 15:37:10 -07001289 case4(014):
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001290 /* The test for BITS8 and SBYTE here is intended to avoid
1291 warning on optimizer actions due to SBYTE, while still
1292 warn on explicit BYTE directives. Also warn, obviously,
1293 if the optimizer isn't enabled. */
1294 if (((opx->type & BITS8) ||
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001295 !(opx->type & temp->opd[op1] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001296 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001297 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001298 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001299 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 if (opx->segment != NO_SEG) {
1301 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001302 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001303 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001304 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001305 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001306 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001307 NO_SEG);
1308 }
1309 offset += 1;
1310 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001311
H. Peter Anvin507ae032008-10-09 15:37:10 -07001312 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001313 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001314 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001315 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001316 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 if (opx->segment != NO_SEG) {
1318 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001319 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001320 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001323 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 NO_SEG);
1325 }
1326 offset += 1;
1327 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001328
H. Peter Anvin507ae032008-10-09 15:37:10 -07001329 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001331 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001332 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 if (opx->segment != NO_SEG) {
1334 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001335 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001336 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001337 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 NO_SEG);
1341 }
1342 offset += 1;
1343 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001344
H. Peter Anvin507ae032008-10-09 15:37:10 -07001345 case4(030):
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001346 warn_overflow(2, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001348 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001349 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001350 offset += 2;
1351 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001352
H. Peter Anvin507ae032008-10-09 15:37:10 -07001353 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001354 if (opx->type & (BITS16 | BITS32))
1355 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001356 else
1357 size = (bits == 16) ? 2 : 4;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001358 warn_overflow(size, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001360 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 offset += size;
1363 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001364
H. Peter Anvin507ae032008-10-09 15:37:10 -07001365 case4(040):
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001366 warn_overflow(4, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001368 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 offset += 4;
1371 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001372
H. Peter Anvin507ae032008-10-09 15:37:10 -07001373 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001374 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001375 size = ins->addr_size >> 3;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001376 warn_overflow(size, opx);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001377 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001379 offset += size;
1380 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001381
H. Peter Anvin507ae032008-10-09 15:37:10 -07001382 case4(050):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001383 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001384 errfunc(ERR_NONFATAL,
1385 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 if (data > 127 || data < -128)
1388 errfunc(ERR_NONFATAL, "short jump is out of range");
1389 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001390 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 offset += 1;
1392 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001393
H. Peter Anvin507ae032008-10-09 15:37:10 -07001394 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001396 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001397 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001398 offset += 8;
1399 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001400
H. Peter Anvin507ae032008-10-09 15:37:10 -07001401 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001402 if (opx->segment != segment) {
1403 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001408 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001409 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001410 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001411 }
1412 offset += 2;
1413 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001414
H. Peter Anvin507ae032008-10-09 15:37:10 -07001415 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001416 if (opx->type & (BITS16 | BITS32 | BITS64))
1417 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001418 else
1419 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001421 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001422 out(offset, segment, &data,
1423 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1424 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001426 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001427 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001428 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001429 }
1430 offset += size;
1431 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001432
H. Peter Anvin507ae032008-10-09 15:37:10 -07001433 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 if (opx->segment != segment) {
1435 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001437 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001438 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001440 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001441 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001442 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001443 }
1444 offset += 4;
1445 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001446
H. Peter Anvin507ae032008-10-09 15:37:10 -07001447 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001448 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001449 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1450 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001451 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001452 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001453 outfmt->segbase(1 + opx->segment),
1454 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001455 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001456 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001457
H. Peter Anvin507ae032008-10-09 15:37:10 -07001458 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001459 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001460 warn_overflow(2, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001461 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001462 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001463 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001464 NO_SEG);
1465 offset++;
1466 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001467 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001468 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001469 offset += 2;
1470 }
1471 break;
1472
H. Peter Anvin507ae032008-10-09 15:37:10 -07001473 case4(0144):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001474 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001475 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001476 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001477 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001478 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001479 offset++;
1480 break;
1481
H. Peter Anvin507ae032008-10-09 15:37:10 -07001482 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001483 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001484 warn_overflow(4, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001485 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001486 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001487 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 NO_SEG);
1489 offset++;
1490 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001491 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001492 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001493 offset += 4;
1494 }
1495 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001496
H. Peter Anvin507ae032008-10-09 15:37:10 -07001497 case4(0154):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001498 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001499 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001500 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001501 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001502 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001503 offset++;
1504 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001505
H. Peter Anvin507ae032008-10-09 15:37:10 -07001506 case4(0160):
1507 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001508 break;
1509
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001510 case 0171:
1511 bytes[0] =
1512 (ins->drexdst << 4) |
1513 (ins->rex & REX_OC ? 0x08 : 0) |
1514 (ins->rex & (REX_R|REX_X|REX_B));
1515 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001516 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001517 offset++;
1518 break;
1519
H. Peter Anvind85d2502008-05-04 17:53:31 -07001520 case 0172:
1521 c = *codes++;
1522 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001523 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001524 opx = &ins->oprs[c & 7];
1525 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1526 errfunc(ERR_NONFATAL,
1527 "non-absolute expression not permitted as argument %d",
1528 c & 7);
1529 } else {
1530 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001531 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001532 "four-bit argument exceeds bounds");
1533 }
1534 bytes[0] |= opx->offset & 15;
1535 }
1536 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1537 offset++;
1538 break;
1539
H. Peter Anvind58656f2008-05-06 20:11:14 -07001540 case 0173:
1541 c = *codes++;
1542 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001543 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001544 bytes[0] |= c & 15;
1545 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1546 offset++;
1547 break;
1548
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001549 case 0174:
1550 c = *codes++;
1551 opx = &ins->oprs[c];
1552 bytes[0] = nasm_regvals[opx->basereg] << 4;
1553 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1554 offset++;
1555 break;
1556
H. Peter Anvin507ae032008-10-09 15:37:10 -07001557 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001558 data = opx->offset;
H. Peter Anvinad6b8592008-10-07 09:56:38 -07001559 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1560 (int32_t)data != (int64_t)data) {
1561 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1562 "signed dword immediate exceeds bounds");
1563 }
1564 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001565 bytes[0] = data;
1566 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1567 NO_SEG);
1568 offset++;
1569 } else {
1570 out(offset, segment, &data, OUT_ADDRESS, 4,
1571 opx->segment, opx->wrt);
1572 offset += 4;
1573 }
1574 break;
1575
H. Peter Anvin507ae032008-10-09 15:37:10 -07001576 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001577 data = opx->offset;
1578 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1579 (int32_t)data != (int64_t)data) {
1580 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1581 "signed dword immediate exceeds bounds");
1582 }
1583 out(offset, segment, &data, OUT_ADDRESS, 4,
1584 opx->segment, opx->wrt);
1585 offset += 4;
1586 break;
1587
H. Peter Anvin507ae032008-10-09 15:37:10 -07001588 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -07001589 case 0270:
1590 codes += 2;
H. Peter Anvina04019c2009-05-03 21:42:34 -07001591 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1592 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1593 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001594 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001595 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001596 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1597 offset += 3;
1598 } else {
1599 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001600 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1601 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001602 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1603 offset += 2;
1604 }
1605 break;
1606
H. Peter Anvin507ae032008-10-09 15:37:10 -07001607 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001608 {
1609 uint64_t uv, um;
1610 int s;
1611
1612 if (ins->rex & REX_W)
1613 s = 64;
1614 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1615 s = 16;
1616 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1617 s = 32;
1618 else
1619 s = bits;
1620
1621 um = (uint64_t)2 << (s-1);
1622 uv = opx->offset;
1623
1624 if (uv > 127 && uv < (uint64_t)-128 &&
1625 (uv < um-128 || uv > um-1)) {
1626 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1627 "signed byte value exceeds bounds");
1628 }
1629 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001630 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001631 out(offset, segment, &data, OUT_ADDRESS, 1,
1632 opx->segment, opx->wrt);
1633 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001634 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001635 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1636 NO_SEG);
1637 }
1638 offset += 1;
1639 break;
1640 }
1641
H. Peter Anvin507ae032008-10-09 15:37:10 -07001642 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001644
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001646 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001648 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001649 offset += 1;
1650 } else
1651 offset += 0;
1652 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001653
H. Peter Anvine2c80182005-01-15 22:15:51 +00001654 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001655 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001656 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001657 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 offset += 1;
1659 } else
1660 offset += 0;
1661 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001662
H. Peter Anvine2c80182005-01-15 22:15:51 +00001663 case 0312:
1664 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001665
Keith Kaniosb7a89542007-04-12 02:40:54 +00001666 case 0313:
1667 ins->rex = 0;
1668 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001669
H. Peter Anvin507ae032008-10-09 15:37:10 -07001670 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001671 break;
1672
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001674 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001676 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001677 offset += 1;
1678 } else
1679 offset += 0;
1680 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001681
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 case 0321:
1683 if (bits == 16) {
1684 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001685 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001686 offset += 1;
1687 } else
1688 offset += 0;
1689 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001690
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001692 case 0323:
1693 break;
1694
Keith Kaniosb7a89542007-04-12 02:40:54 +00001695 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001696 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001697 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001698
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001699 case 0325:
1700 break;
1701
H. Peter Anvine2c80182005-01-15 22:15:51 +00001702 case 0330:
1703 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001704 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001705 offset += 1;
1706 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001707
H. Peter Anvine2c80182005-01-15 22:15:51 +00001708 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001709 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001710
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001711 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001712 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001713 *bytes = c - 0332 + 0xF2;
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
Keith Kanios48af1772007-08-17 07:37:52 +00001718 case 0334:
1719 if (ins->rex & REX_R) {
1720 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001721 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001722 offset += 1;
1723 }
1724 ins->rex &= ~(REX_L|REX_R);
1725 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001726
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001727 case 0335:
1728 break;
1729
H. Peter Anvin962e3052008-08-28 17:47:16 -07001730 case 0336:
1731 case 0337:
1732 break;
1733
H. Peter Anvine2c80182005-01-15 22:15:51 +00001734 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 if (ins->oprs[0].segment != NO_SEG)
1736 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1737 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001738 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001739 if (size > 0)
1740 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001741 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001742 offset += size;
1743 }
1744 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001745
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001746 case 0341:
1747 break;
1748
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001749 case 0344:
1750 case 0345:
1751 bytes[0] = c & 1;
1752 switch (ins->oprs[0].basereg) {
1753 case R_CS:
1754 bytes[0] += 0x0E;
1755 break;
1756 case R_DS:
1757 bytes[0] += 0x1E;
1758 break;
1759 case R_ES:
1760 bytes[0] += 0x06;
1761 break;
1762 case R_SS:
1763 bytes[0] += 0x16;
1764 break;
1765 default:
1766 errfunc(ERR_PANIC,
1767 "bizarre 8086 segment register received");
1768 }
1769 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1770 offset++;
1771 break;
1772
1773 case 0346:
1774 case 0347:
1775 bytes[0] = c & 1;
1776 switch (ins->oprs[0].basereg) {
1777 case R_FS:
1778 bytes[0] += 0xA0;
1779 break;
1780 case R_GS:
1781 bytes[0] += 0xA8;
1782 break;
1783 default:
1784 errfunc(ERR_PANIC,
1785 "bizarre 386 segment register received");
1786 }
1787 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1788 offset++;
1789 break;
1790
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001791 case 0360:
1792 break;
1793
1794 case 0361:
1795 bytes[0] = 0x66;
1796 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1797 offset += 1;
1798 break;
1799
1800 case 0362:
1801 case 0363:
1802 bytes[0] = c - 0362 + 0xf2;
1803 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1804 offset += 1;
1805 break;
1806
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001807 case 0364:
1808 case 0365:
1809 break;
1810
Keith Kanios48af1772007-08-17 07:37:52 +00001811 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001812 case 0367:
1813 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001814 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001815 offset += 1;
1816 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001817
H. Peter Anvine2c80182005-01-15 22:15:51 +00001818 case 0370:
1819 case 0371:
1820 case 0372:
1821 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001822
H. Peter Anvine2c80182005-01-15 22:15:51 +00001823 case 0373:
1824 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001825 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001826 offset += 1;
1827 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001828
H. Peter Anvin507ae032008-10-09 15:37:10 -07001829 case4(0100):
1830 case4(0110):
1831 case4(0120):
1832 case4(0130):
1833 case4(0200):
1834 case4(0204):
1835 case4(0210):
1836 case4(0214):
1837 case4(0220):
1838 case4(0224):
1839 case4(0230):
1840 case4(0234):
1841 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001842 ea ea_data;
1843 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001844 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001845 uint8_t *p;
1846 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001847 enum out_type type;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001848 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001849
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001850 if (c <= 0177) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001851 /* pick rfield from operand b (opx) */
1852 rflags = regflag(opx);
1853 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001854 } else {
1855 /* rfield is constant */
1856 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001857 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001858 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001859
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001860 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
1861 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001862 errfunc(ERR_NONFATAL, "invalid effective address");
1863 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001864
Charles Crayne7e975552007-11-03 22:06:13 -07001865
H. Peter Anvine2c80182005-01-15 22:15:51 +00001866 p = bytes;
1867 *p++ = ea_data.modrm;
1868 if (ea_data.sib_present)
1869 *p++ = ea_data.sib;
1870
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001871 /* DREX suffixes come between the SIB and the displacement */
1872 if (ins->rex & REX_D) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001873 *p++ = (ins->drexdst << 4) |
1874 (ins->rex & REX_OC ? 0x08 : 0) |
1875 (ins->rex & (REX_R|REX_X|REX_B));
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001876 ins->rex = 0;
1877 }
1878
H. Peter Anvine2c80182005-01-15 22:15:51 +00001879 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001880 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001881
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001882 /*
1883 * Make sure the address gets the right offset in case
1884 * the line breaks in the .lst file (BR 1197827)
1885 */
1886 offset += s;
1887 s = 0;
1888
H. Peter Anvine2c80182005-01-15 22:15:51 +00001889 switch (ea_data.bytes) {
1890 case 0:
1891 break;
1892 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001893 case 2:
1894 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001895 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001896 data = opy->offset;
1897 warn_overflow(ea_data.bytes, opy);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001898 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001899 if (ea_data.rip) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001900 if (opy->segment == segment) {
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001901 data -= insn_end;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001902 out(offset, segment, &data, OUT_ADDRESS,
1903 ea_data.bytes, NO_SEG, NO_SEG);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001904 } else {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001905 out(offset, segment, &data, OUT_REL4ADR,
1906 insn_end - offset, opy->segment, opy->wrt);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001907 }
H. Peter Anvin9f817132008-10-06 19:11:07 -07001908 } else {
1909 type = OUT_ADDRESS;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001910 out(offset, segment, &data, OUT_ADDRESS,
1911 ea_data.bytes, opy->segment, opy->wrt);
H. Peter Anvin9f817132008-10-06 19:11:07 -07001912 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001913 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001914 default:
1915 /* Impossible! */
1916 errfunc(ERR_PANIC,
1917 "Invalid amount of bytes (%d) for offset?!",
1918 ea_data.bytes);
1919 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001920 }
1921 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001922 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001923 break;
1924
1925 default:
1926 errfunc(ERR_PANIC, "internal instruction table corrupt"
H. Peter Anvin16a856c2009-03-01 00:22:16 -08001927 ": instruction code \\%o (0x%02X) given", c, c);
H. Peter Anvin507ae032008-10-09 15:37:10 -07001928 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001929 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001930 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001931}
1932
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001933static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001934{
1935 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1936 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1937 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001938 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001939}
1940
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001941static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001942{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001943 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1944 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001945 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001946 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001947}
1948
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001949static int op_rexflags(const operand * o, int mask)
1950{
1951 int32_t flags;
1952 int val;
1953
1954 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1955 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1956 }
1957
H. Peter Anvina4835d42008-05-20 14:21:29 -07001958 flags = nasm_reg_flags[o->basereg];
1959 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001960
1961 return rexflags(val, flags, mask);
1962}
1963
1964static int rexflags(int val, int32_t flags, int mask)
1965{
1966 int rex = 0;
1967
1968 if (val >= 8)
1969 rex |= REX_B|REX_X|REX_R;
1970 if (flags & BITS64)
1971 rex |= REX_W;
1972 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1973 rex |= REX_H;
1974 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1975 rex |= REX_P;
1976
1977 return rex & mask;
1978}
1979
H. Peter Anvin23595f52009-07-25 17:44:25 -07001980static enum match_result find_match(const struct itemplate **tempp,
1981 insn *instruction,
1982 int32_t segment, int64_t offset, int bits)
1983{
1984 const struct itemplate *temp;
1985 enum match_result m, merr;
1986
1987 merr = MERR_INVALOP;
1988
1989 for (temp = nasm_instructions[instruction->opcode];
1990 temp->opcode != I_none; temp++) {
1991 m = matches(temp, instruction, bits);
1992 if (m == MOK_JUMP) {
1993 if (jmp_match(segment, offset, bits, instruction, temp->code))
1994 m = MOK_GOOD;
1995 else
1996 m = MERR_INVALOP;
1997 }
1998 if (m > merr)
1999 merr = m;
2000 if (merr == MOK_GOOD)
2001 break;
2002 }
2003
2004 *tempp = temp;
2005 return merr;
2006}
2007
H. Peter Anvin65289e82009-07-25 17:25:11 -07002008static enum match_result matches(const struct itemplate *itemp,
2009 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002010{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002011 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002012
H. Peter Anvin65289e82009-07-25 17:25:11 -07002013 ret = MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002014
2015 /*
2016 * Check the opcode
2017 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002018 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002019 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002020
2021 /*
2022 * Count the operands
2023 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002024 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002025 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002026
2027 /*
2028 * Check that no spurious colons or TOs are present
2029 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002030 for (i = 0; i < itemp->operands; i++)
2031 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002032 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002033
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002034 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002035 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002036 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002037 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002038 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002039
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002040 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2041
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002042 switch (itemp->flags & IF_SMASK) {
2043 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002044 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002045 break;
2046 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002047 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002048 break;
2049 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002050 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002051 break;
2052 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002053 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002054 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002055 case IF_SO:
2056 size[i] = BITS128;
2057 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002058 case IF_SY:
2059 size[i] = BITS256;
2060 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002061 case IF_SZ:
2062 switch (bits) {
2063 case 16:
2064 size[i] = BITS16;
2065 break;
2066 case 32:
2067 size[i] = BITS32;
2068 break;
2069 case 64:
2070 size[i] = BITS64;
2071 break;
2072 }
2073 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002074 default:
2075 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002076 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002077 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002078 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002079 switch (itemp->flags & IF_SMASK) {
2080 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002081 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002082 break;
2083 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002084 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002085 break;
2086 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002087 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002088 break;
2089 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002090 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002091 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002092 case IF_SO:
2093 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002094 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002095 case IF_SY:
2096 asize = BITS256;
2097 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002098 case IF_SZ:
2099 switch (bits) {
2100 case 16:
2101 asize = BITS16;
2102 break;
2103 case 32:
2104 asize = BITS32;
2105 break;
2106 case 64:
2107 asize = BITS64;
2108 break;
2109 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002110 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002111 default:
2112 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002113 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002114 for (i = 0; i < MAX_OPERANDS; i++)
2115 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002116 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002117
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002118 /*
2119 * Check that the operand flags all match up
2120 */
2121 for (i = 0; i < itemp->operands; i++) {
2122 int32_t type = instruction->oprs[i].type;
2123 if (!(type & SIZE_MASK))
2124 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002125
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002126 if (itemp->opd[i] & SAME_AS) {
2127 int j = itemp->opd[i] & ~SAME_AS;
2128 if (type != instruction->oprs[j].type ||
2129 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002130 return MERR_INVALOP;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002131 } else if (itemp->opd[i] & ~type ||
2132 ((itemp->opd[i] & SIZE_MASK) &&
2133 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2134 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2135 (type & SIZE_MASK))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002136 return MERR_INVALOP;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002137 else
H. Peter Anvin65289e82009-07-25 17:25:11 -07002138 return MERR_OPSIZEMISSING;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002139 }
2140 }
2141
2142 /*
2143 * Check operand sizes
2144 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002145 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002146 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2147 asize = 0;
2148 for (i = 0; i < oprs; i++) {
2149 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2150 int j;
2151 for (j = 0; j < oprs; j++)
2152 size[j] = asize;
2153 break;
2154 }
2155 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002156 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002157 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002158 }
2159
Keith Kaniosb7a89542007-04-12 02:40:54 +00002160 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002161 if (!(itemp->opd[i] & SIZE_MASK) &&
2162 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002163 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002164 }
2165
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002166 /*
2167 * Check template is okay at the set cpu level
2168 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002169 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002170 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002171
Keith Kaniosb7a89542007-04-12 02:40:54 +00002172 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002173 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002174 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002175 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002176 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002177
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002178 /*
2179 * Check if special handling needed for Jumps
2180 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002181 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002182 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002183
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002184 return ret;
2185}
2186
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002187static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002188 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002189{
H. Peter Anvin9945fee2009-02-26 14:48:03 -08002190 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002191
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002192 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002193
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002194 /* REX flags for the rfield operand */
2195 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2196
Keith Kaniosb7a89542007-04-12 02:40:54 +00002197 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002198 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002199 int32_t f;
2200
2201 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002202 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002203 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002204 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002205 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002206
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002207 if (REG_EA & ~f)
2208 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002209
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002210 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2211
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002212 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002213 output->bytes = 0; /* no offset necessary either */
2214 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002215 } else { /* it's a memory reference */
2216 if (input->basereg == -1
2217 && (input->indexreg == -1 || input->scale == 0)) {
2218 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002219 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002220 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002221 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002222 scale = 0;
2223 index = 4;
2224 base = 5;
2225 output->sib = (scale << 6) | (index << 3) | base;
2226 output->bytes = 4;
2227 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002228 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002229 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002230 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002231 output->bytes = (addrbits != 16 ? 4 : 2);
2232 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002233 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002234 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002235 } else { /* it's an indirection */
2236 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002237 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002238 int hb = input->hintbase, ht = input->hinttype;
2239 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002240 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002241 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002242
H. Peter Anvine2c80182005-01-15 22:15:51 +00002243 if (s == 0)
2244 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002245
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002246 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002247 it = nasm_regvals[i];
2248 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002249 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002250 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002251 ix = 0;
2252 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002253
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002254 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002255 bt = nasm_regvals[b];
2256 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002257 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002258 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002259 bx = 0;
2260 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002261
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002262 /* check for a 32/64-bit memory reference... */
2263 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002264 /* it must be a 32/64-bit memory reference. Firstly we have
2265 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002266 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002267
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002268 if (it != -1) {
2269 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2270 sok &= ix;
2271 else
2272 return NULL;
2273 }
2274
2275 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002276 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002277 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002278 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002279 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002280 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002281 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002282
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002283 /* While we're here, ensure the user didn't specify
2284 WORD or QWORD. */
2285 if (input->disp_size == 16 || input->disp_size == 64)
2286 return NULL;
2287
2288 if (addrbits == 16 ||
2289 (addrbits == 32 && !(sok & BITS32)) ||
2290 (addrbits == 64 && !(sok & BITS64)))
2291 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002292
Keith Kaniosb7a89542007-04-12 02:40:54 +00002293 /* now reorganize base/index */
2294 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002295 ((hb == b && ht == EAH_NOTBASE)
2296 || (hb == i && ht == EAH_MAKEBASE))) {
2297 /* swap if hints say so */
2298 t = bt, bt = it, it = t;
2299 t = bx, bx = ix, ix = t;
2300 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002301 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002302 bt = -1, bx = 0, s++;
2303 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2304 /* make single reg base, unless hint */
2305 bt = it, bx = ix, it = -1, ix = 0;
2306 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002307 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002308 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002309 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002310 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002311 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002312 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002313 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002314 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002315 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002316 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002317 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002318 t = ix, ix = bx, bx = t;
2319 }
Keith Kanios48af1772007-08-17 07:37:52 +00002320 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002321 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002322 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002323
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002324 output->rex |= rexflags(it, ix, REX_X);
2325 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002326
Keith Kanios48af1772007-08-17 07:37:52 +00002327 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002328 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002329 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002330
Keith Kaniosb7a89542007-04-12 02:40:54 +00002331 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002332 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002333 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002334 } else {
2335 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002336 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002337 seg == NO_SEG && !forw_ref &&
2338 !(input->eaflags &
2339 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2340 mod = 0;
2341 else if (input->eaflags & EAF_BYTEOFFS ||
2342 (o >= -128 && o <= 127 && seg == NO_SEG
2343 && !forw_ref
2344 && !(input->eaflags & EAF_WORDOFFS)))
2345 mod = 1;
2346 else
2347 mod = 2;
2348 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002349
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002350 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002351 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2352 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002353 } else {
2354 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002355 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002356
Keith Kaniosb7a89542007-04-12 02:40:54 +00002357 if (it == -1)
2358 index = 4, s = 1;
2359 else
2360 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002361
H. Peter Anvine2c80182005-01-15 22:15:51 +00002362 switch (s) {
2363 case 1:
2364 scale = 0;
2365 break;
2366 case 2:
2367 scale = 1;
2368 break;
2369 case 4:
2370 scale = 2;
2371 break;
2372 case 8:
2373 scale = 3;
2374 break;
2375 default: /* then what the smeg is it? */
2376 return NULL; /* panic */
2377 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002378
Keith Kaniosb7a89542007-04-12 02:40:54 +00002379 if (bt == -1) {
2380 base = 5;
2381 mod = 0;
2382 } else {
2383 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002384 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002385 seg == NO_SEG && !forw_ref &&
2386 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002387 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2388 mod = 0;
2389 else if (input->eaflags & EAF_BYTEOFFS ||
2390 (o >= -128 && o <= 127 && seg == NO_SEG
2391 && !forw_ref
2392 && !(input->eaflags & EAF_WORDOFFS)))
2393 mod = 1;
2394 else
2395 mod = 2;
2396 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002397
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002398 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002399 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2400 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002401 output->sib = (scale << 6) | (index << 3) | base;
2402 }
2403 } else { /* it's 16-bit */
2404 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002405
Keith Kaniosb7a89542007-04-12 02:40:54 +00002406 /* check for 64-bit long mode */
2407 if (addrbits == 64)
2408 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002409
H. Peter Anvine2c80182005-01-15 22:15:51 +00002410 /* check all registers are BX, BP, SI or DI */
2411 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2412 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2413 && i != R_SI && i != R_DI))
2414 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002415
Keith Kaniosb7a89542007-04-12 02:40:54 +00002416 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002417 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002418 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002419
H. Peter Anvine2c80182005-01-15 22:15:51 +00002420 if (s != 1 && i != -1)
2421 return NULL; /* no can do, in 16-bit EA */
2422 if (b == -1 && i != -1) {
2423 int tmp = b;
2424 b = i;
2425 i = tmp;
2426 } /* swap */
2427 if ((b == R_SI || b == R_DI) && i != -1) {
2428 int tmp = b;
2429 b = i;
2430 i = tmp;
2431 }
2432 /* have BX/BP as base, SI/DI index */
2433 if (b == i)
2434 return NULL; /* shouldn't ever happen, in theory */
2435 if (i != -1 && b != -1 &&
2436 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2437 return NULL; /* invalid combinations */
2438 if (b == -1) /* pure offset: handled above */
2439 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002440
H. Peter Anvine2c80182005-01-15 22:15:51 +00002441 rm = -1;
2442 if (i != -1)
2443 switch (i * 256 + b) {
2444 case R_SI * 256 + R_BX:
2445 rm = 0;
2446 break;
2447 case R_DI * 256 + R_BX:
2448 rm = 1;
2449 break;
2450 case R_SI * 256 + R_BP:
2451 rm = 2;
2452 break;
2453 case R_DI * 256 + R_BP:
2454 rm = 3;
2455 break;
2456 } else
2457 switch (b) {
2458 case R_SI:
2459 rm = 4;
2460 break;
2461 case R_DI:
2462 rm = 5;
2463 break;
2464 case R_BP:
2465 rm = 6;
2466 break;
2467 case R_BX:
2468 rm = 7;
2469 break;
2470 }
2471 if (rm == -1) /* can't happen, in theory */
2472 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002473
H. Peter Anvine2c80182005-01-15 22:15:51 +00002474 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2475 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2476 mod = 0;
2477 else if (input->eaflags & EAF_BYTEOFFS ||
2478 (o >= -128 && o <= 127 && seg == NO_SEG
2479 && !forw_ref
2480 && !(input->eaflags & EAF_WORDOFFS)))
2481 mod = 1;
2482 else
2483 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002484
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002485 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002486 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002487 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002488 }
2489 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002490 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002491
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002492 output->size = 1 + output->sib_present + output->bytes;
2493 return output;
2494}
2495
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002496static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002497{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002498 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002499 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002500
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002501 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002502
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002503 switch (ins->prefixes[PPS_ASIZE]) {
2504 case P_A16:
2505 valid &= 16;
2506 break;
2507 case P_A32:
2508 valid &= 32;
2509 break;
2510 case P_A64:
2511 valid &= 64;
2512 break;
2513 case P_ASP:
2514 valid &= (addrbits == 32) ? 16 : 32;
2515 break;
2516 default:
2517 break;
2518 }
2519
2520 for (j = 0; j < ins->operands; j++) {
2521 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002522 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002523
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002524 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002525 if (ins->oprs[j].indexreg < EXPR_REG_START
2526 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002527 i = 0;
2528 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002529 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002530
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002531 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002532 if (ins->oprs[j].basereg < EXPR_REG_START
2533 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002534 b = 0;
2535 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002536 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002537
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002538 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002539 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002540
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002541 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002542 int ds = ins->oprs[j].disp_size;
2543 if ((addrbits != 64 && ds > 8) ||
2544 (addrbits == 64 && ds == 16))
2545 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002546 } else {
2547 if (!(REG16 & ~b))
2548 valid &= 16;
2549 if (!(REG32 & ~b))
2550 valid &= 32;
2551 if (!(REG64 & ~b))
2552 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002553
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002554 if (!(REG16 & ~i))
2555 valid &= 16;
2556 if (!(REG32 & ~i))
2557 valid &= 32;
2558 if (!(REG64 & ~i))
2559 valid &= 64;
2560 }
2561 }
2562 }
2563
2564 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002565 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002566 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002567 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002568 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002569 ins->prefixes[PPS_ASIZE] = pref;
2570 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002571 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002572 /* Impossible... */
2573 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002574 ins->addr_size = addrbits; /* Error recovery */
2575 }
2576
2577 defdisp = ins->addr_size == 16 ? 16 : 32;
2578
2579 for (j = 0; j < ins->operands; j++) {
2580 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2581 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2582 != ins->addr_size) {
2583 /* mem_offs sizes must match the address size; if not,
2584 strip the MEM_OFFS bit and match only EA instructions */
2585 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2586 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002587 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002588}