blob: 67339bec92f5662563be560aef92652f4c2f82a8 [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;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001986 int32_t xsizeflags[MAX_OPERANDS];
1987 bool opsizemissing = false;
1988 int i;
1989
1990 for (i = 0; i < instruction->operands; i++)
1991 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001992
1993 merr = MERR_INVALOP;
1994
1995 for (temp = nasm_instructions[instruction->opcode];
1996 temp->opcode != I_none; temp++) {
1997 m = matches(temp, instruction, bits);
1998 if (m == MOK_JUMP) {
1999 if (jmp_match(segment, offset, bits, instruction, temp->code))
2000 m = MOK_GOOD;
2001 else
2002 m = MERR_INVALOP;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002003 } else if (m == MERR_OPSIZEMISSING &&
2004 (temp->flags & IF_SMASK) != IF_SX) {
2005 /*
2006 * Missing operand size and a candidate for fuzzy matching...
2007 */
2008 for (i = 0; i < temp->operands; i++)
2009 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
2010
2011 opsizemissing = true;
2012 }
2013 if (m > merr)
2014 merr = m;
2015 if (merr == MOK_GOOD)
2016 goto done;
2017 }
2018
2019 /* No match, but see if we can get a fuzzy operand size match... */
2020 if (!opsizemissing)
2021 goto done;
2022
2023 for (i = 0; i < instruction->operands; i++) {
2024 /* This tests if xsizeflags[i] has more than one bit set */
2025 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2026 goto done; /* No luck */
2027
2028 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
2029 }
2030
2031 /* Try matching again... */
2032 for (temp = nasm_instructions[instruction->opcode];
2033 temp->opcode != I_none; temp++) {
2034 m = matches(temp, instruction, bits);
2035 if (m == MOK_JUMP) {
2036 if (jmp_match(segment, offset, bits, instruction, temp->code))
2037 m = MOK_GOOD;
2038 else
2039 m = MERR_INVALOP;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002040 }
2041 if (m > merr)
2042 merr = m;
2043 if (merr == MOK_GOOD)
H. Peter Anvina81655b2009-07-25 18:15:28 -07002044 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002045 }
2046
H. Peter Anvina81655b2009-07-25 18:15:28 -07002047done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002048 *tempp = temp;
2049 return merr;
2050}
2051
H. Peter Anvin65289e82009-07-25 17:25:11 -07002052static enum match_result matches(const struct itemplate *itemp,
2053 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002054{
H. Peter Anvin60926242009-07-26 16:25:38 -07002055 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002056 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002057
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002058 /*
2059 * Check the opcode
2060 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002061 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002062 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002063
2064 /*
2065 * Count the operands
2066 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002067 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002068 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002069
2070 /*
2071 * Check that no spurious colons or TOs are present
2072 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002073 for (i = 0; i < itemp->operands; i++)
2074 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002075 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002076
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002077 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002078 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002079 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002080 switch (itemp->flags & IF_SMASK) {
2081 case IF_SB:
2082 asize = BITS8;
2083 break;
2084 case IF_SW:
2085 asize = BITS16;
2086 break;
2087 case IF_SD:
2088 asize = BITS32;
2089 break;
2090 case IF_SQ:
2091 asize = BITS64;
2092 break;
2093 case IF_SO:
2094 asize = BITS128;
2095 break;
2096 case IF_SY:
2097 asize = BITS256;
2098 break;
2099 case IF_SZ:
2100 switch (bits) {
2101 case 16:
2102 asize = BITS16;
2103 break;
2104 case 32:
2105 asize = BITS32;
2106 break;
2107 case 64:
2108 asize = BITS64;
2109 break;
2110 }
2111 break;
2112 default:
2113 asize = 0;
2114 break;
2115 }
2116
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002117 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin60926242009-07-26 16:25:38 -07002118 /* S- flags only apply to a specific operand */
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002119 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
H. Peter Anvin60926242009-07-26 16:25:38 -07002120 memset(size, 0, sizeof size);
2121 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002122 } else {
H. Peter Anvin60926242009-07-26 16:25:38 -07002123 /* S- flags apply to all operands */
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002124 for (i = 0; i < MAX_OPERANDS; i++)
2125 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002126 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002127
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002128 /*
2129 * Check that the operand flags all match up
2130 */
2131 for (i = 0; i < itemp->operands; i++) {
2132 int32_t type = instruction->oprs[i].type;
2133 if (!(type & SIZE_MASK))
2134 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002135
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002136 if (itemp->opd[i] & SAME_AS) {
2137 int j = itemp->opd[i] & ~SAME_AS;
2138 if (type != instruction->oprs[j].type ||
2139 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002140 return MERR_INVALOP;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002141 } else if (itemp->opd[i] & ~type ||
2142 ((itemp->opd[i] & SIZE_MASK) &&
2143 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvina81655b2009-07-25 18:15:28 -07002144 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002145 return MERR_INVALOP;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002146 else
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002147 opsizemissing = true;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002148 }
2149 }
2150
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002151 if (opsizemissing)
2152 return MERR_OPSIZEMISSING;
2153
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002154 /*
2155 * Check operand sizes
2156 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002157 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002158 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2159 asize = 0;
2160 for (i = 0; i < oprs; i++) {
2161 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2162 int j;
2163 for (j = 0; j < oprs; j++)
2164 size[j] = asize;
2165 break;
2166 }
2167 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002168 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002169 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002170 }
2171
Keith Kaniosb7a89542007-04-12 02:40:54 +00002172 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002173 if (!(itemp->opd[i] & SIZE_MASK) &&
2174 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002175 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002176 }
2177
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002178 /*
2179 * Check template is okay at the set cpu level
2180 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002181 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002182 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002183
Keith Kaniosb7a89542007-04-12 02:40:54 +00002184 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002185 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002186 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002187 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002188 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002189
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002190 /*
2191 * Check if special handling needed for Jumps
2192 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002193 if ((itemp->code[0] & 0374) == 0370)
2194 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002195
H. Peter Anvin60926242009-07-26 16:25:38 -07002196 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002197}
2198
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002199static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002200 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002201{
H. Peter Anvin9945fee2009-02-26 14:48:03 -08002202 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002203
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002204 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002205
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002206 /* REX flags for the rfield operand */
2207 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2208
Keith Kaniosb7a89542007-04-12 02:40:54 +00002209 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002210 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002211 int32_t f;
2212
2213 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002214 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002215 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002216 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002217 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002218
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002219 if (REG_EA & ~f)
2220 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002221
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002222 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2223
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002224 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002225 output->bytes = 0; /* no offset necessary either */
2226 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002227 } else { /* it's a memory reference */
2228 if (input->basereg == -1
2229 && (input->indexreg == -1 || input->scale == 0)) {
2230 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002231 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002232 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002233 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002234 scale = 0;
2235 index = 4;
2236 base = 5;
2237 output->sib = (scale << 6) | (index << 3) | base;
2238 output->bytes = 4;
2239 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002240 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002241 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002242 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002243 output->bytes = (addrbits != 16 ? 4 : 2);
2244 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002245 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002246 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002247 } else { /* it's an indirection */
2248 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002249 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002250 int hb = input->hintbase, ht = input->hinttype;
2251 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002252 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002253 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002254
H. Peter Anvine2c80182005-01-15 22:15:51 +00002255 if (s == 0)
2256 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002257
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002258 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002259 it = nasm_regvals[i];
2260 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002261 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002262 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002263 ix = 0;
2264 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002265
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002266 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002267 bt = nasm_regvals[b];
2268 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002269 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002270 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002271 bx = 0;
2272 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002273
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002274 /* check for a 32/64-bit memory reference... */
2275 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002276 /* it must be a 32/64-bit memory reference. Firstly we have
2277 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002278 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002279
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002280 if (it != -1) {
2281 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2282 sok &= ix;
2283 else
2284 return NULL;
2285 }
2286
2287 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002288 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002289 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002290 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002291 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002292 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002293 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002294
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002295 /* While we're here, ensure the user didn't specify
2296 WORD or QWORD. */
2297 if (input->disp_size == 16 || input->disp_size == 64)
2298 return NULL;
2299
2300 if (addrbits == 16 ||
2301 (addrbits == 32 && !(sok & BITS32)) ||
2302 (addrbits == 64 && !(sok & BITS64)))
2303 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002304
Keith Kaniosb7a89542007-04-12 02:40:54 +00002305 /* now reorganize base/index */
2306 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002307 ((hb == b && ht == EAH_NOTBASE)
2308 || (hb == i && ht == EAH_MAKEBASE))) {
2309 /* swap if hints say so */
2310 t = bt, bt = it, it = t;
2311 t = bx, bx = ix, ix = t;
2312 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002313 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002314 bt = -1, bx = 0, s++;
2315 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2316 /* make single reg base, unless hint */
2317 bt = it, bx = ix, it = -1, ix = 0;
2318 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002319 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002320 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002321 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002322 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002323 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002324 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002325 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002326 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002327 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002328 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002329 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002330 t = ix, ix = bx, bx = t;
2331 }
Keith Kanios48af1772007-08-17 07:37:52 +00002332 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002333 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002334 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002335
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002336 output->rex |= rexflags(it, ix, REX_X);
2337 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002338
Keith Kanios48af1772007-08-17 07:37:52 +00002339 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002340 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002341 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002342
Keith Kaniosb7a89542007-04-12 02:40:54 +00002343 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002344 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002345 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002346 } else {
2347 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002348 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002349 seg == NO_SEG && !forw_ref &&
2350 !(input->eaflags &
2351 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2352 mod = 0;
2353 else if (input->eaflags & EAF_BYTEOFFS ||
2354 (o >= -128 && o <= 127 && seg == NO_SEG
2355 && !forw_ref
2356 && !(input->eaflags & EAF_WORDOFFS)))
2357 mod = 1;
2358 else
2359 mod = 2;
2360 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002361
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002362 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002363 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2364 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002365 } else {
2366 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002367 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002368
Keith Kaniosb7a89542007-04-12 02:40:54 +00002369 if (it == -1)
2370 index = 4, s = 1;
2371 else
2372 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002373
H. Peter Anvine2c80182005-01-15 22:15:51 +00002374 switch (s) {
2375 case 1:
2376 scale = 0;
2377 break;
2378 case 2:
2379 scale = 1;
2380 break;
2381 case 4:
2382 scale = 2;
2383 break;
2384 case 8:
2385 scale = 3;
2386 break;
2387 default: /* then what the smeg is it? */
2388 return NULL; /* panic */
2389 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002390
Keith Kaniosb7a89542007-04-12 02:40:54 +00002391 if (bt == -1) {
2392 base = 5;
2393 mod = 0;
2394 } else {
2395 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002396 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002397 seg == NO_SEG && !forw_ref &&
2398 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002399 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2400 mod = 0;
2401 else if (input->eaflags & EAF_BYTEOFFS ||
2402 (o >= -128 && o <= 127 && seg == NO_SEG
2403 && !forw_ref
2404 && !(input->eaflags & EAF_WORDOFFS)))
2405 mod = 1;
2406 else
2407 mod = 2;
2408 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002409
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002410 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002411 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2412 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002413 output->sib = (scale << 6) | (index << 3) | base;
2414 }
2415 } else { /* it's 16-bit */
2416 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002417
Keith Kaniosb7a89542007-04-12 02:40:54 +00002418 /* check for 64-bit long mode */
2419 if (addrbits == 64)
2420 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002421
H. Peter Anvine2c80182005-01-15 22:15:51 +00002422 /* check all registers are BX, BP, SI or DI */
2423 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2424 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2425 && i != R_SI && i != R_DI))
2426 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002427
Keith Kaniosb7a89542007-04-12 02:40:54 +00002428 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002429 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002430 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002431
H. Peter Anvine2c80182005-01-15 22:15:51 +00002432 if (s != 1 && i != -1)
2433 return NULL; /* no can do, in 16-bit EA */
2434 if (b == -1 && i != -1) {
2435 int tmp = b;
2436 b = i;
2437 i = tmp;
2438 } /* swap */
2439 if ((b == R_SI || b == R_DI) && i != -1) {
2440 int tmp = b;
2441 b = i;
2442 i = tmp;
2443 }
2444 /* have BX/BP as base, SI/DI index */
2445 if (b == i)
2446 return NULL; /* shouldn't ever happen, in theory */
2447 if (i != -1 && b != -1 &&
2448 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2449 return NULL; /* invalid combinations */
2450 if (b == -1) /* pure offset: handled above */
2451 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002452
H. Peter Anvine2c80182005-01-15 22:15:51 +00002453 rm = -1;
2454 if (i != -1)
2455 switch (i * 256 + b) {
2456 case R_SI * 256 + R_BX:
2457 rm = 0;
2458 break;
2459 case R_DI * 256 + R_BX:
2460 rm = 1;
2461 break;
2462 case R_SI * 256 + R_BP:
2463 rm = 2;
2464 break;
2465 case R_DI * 256 + R_BP:
2466 rm = 3;
2467 break;
2468 } else
2469 switch (b) {
2470 case R_SI:
2471 rm = 4;
2472 break;
2473 case R_DI:
2474 rm = 5;
2475 break;
2476 case R_BP:
2477 rm = 6;
2478 break;
2479 case R_BX:
2480 rm = 7;
2481 break;
2482 }
2483 if (rm == -1) /* can't happen, in theory */
2484 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002485
H. Peter Anvine2c80182005-01-15 22:15:51 +00002486 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2487 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2488 mod = 0;
2489 else if (input->eaflags & EAF_BYTEOFFS ||
2490 (o >= -128 && o <= 127 && seg == NO_SEG
2491 && !forw_ref
2492 && !(input->eaflags & EAF_WORDOFFS)))
2493 mod = 1;
2494 else
2495 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002496
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002497 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002498 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002499 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002500 }
2501 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002502 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002503
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002504 output->size = 1 + output->sib_present + output->bytes;
2505 return output;
2506}
2507
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002508static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002509{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002510 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002511 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002512
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002513 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002514
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002515 switch (ins->prefixes[PPS_ASIZE]) {
2516 case P_A16:
2517 valid &= 16;
2518 break;
2519 case P_A32:
2520 valid &= 32;
2521 break;
2522 case P_A64:
2523 valid &= 64;
2524 break;
2525 case P_ASP:
2526 valid &= (addrbits == 32) ? 16 : 32;
2527 break;
2528 default:
2529 break;
2530 }
2531
2532 for (j = 0; j < ins->operands; j++) {
2533 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002534 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002535
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002536 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002537 if (ins->oprs[j].indexreg < EXPR_REG_START
2538 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002539 i = 0;
2540 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002541 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002542
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002543 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002544 if (ins->oprs[j].basereg < EXPR_REG_START
2545 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002546 b = 0;
2547 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002548 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002549
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002550 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002551 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002552
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002553 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002554 int ds = ins->oprs[j].disp_size;
2555 if ((addrbits != 64 && ds > 8) ||
2556 (addrbits == 64 && ds == 16))
2557 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002558 } else {
2559 if (!(REG16 & ~b))
2560 valid &= 16;
2561 if (!(REG32 & ~b))
2562 valid &= 32;
2563 if (!(REG64 & ~b))
2564 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002565
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002566 if (!(REG16 & ~i))
2567 valid &= 16;
2568 if (!(REG32 & ~i))
2569 valid &= 32;
2570 if (!(REG64 & ~i))
2571 valid &= 64;
2572 }
2573 }
2574 }
2575
2576 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002577 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002578 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002579 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002580 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002581 ins->prefixes[PPS_ASIZE] = pref;
2582 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002583 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002584 /* Impossible... */
2585 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002586 ins->addr_size = addrbits; /* Error recovery */
2587 }
2588
2589 defdisp = ins->addr_size == 16 ? 16 : 32;
2590
2591 for (j = 0; j < ins->operands; j++) {
2592 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2593 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2594 != ins->addr_size) {
2595 /* mem_offs sizes must match the address size; if not,
2596 strip the MEM_OFFS bit and match only EA instructions */
2597 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2598 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002599 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002600}