blob: 7823539026965d430f375b85f85cea23453f9d3e [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 */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400381 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 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
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400670 if (instruction->opcode == I_none)
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
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400707 list_for_each(e, instruction->eops) {
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 */
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002008 for (i = 0; i < temp->operands; i++) {
2009 if ((temp->opd[i] & SAME_AS) == 0)
2010 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
2011 }
H. Peter Anvina81655b2009-07-25 18:15:28 -07002012 opsizemissing = true;
2013 }
2014 if (m > merr)
2015 merr = m;
2016 if (merr == MOK_GOOD)
2017 goto done;
2018 }
2019
2020 /* No match, but see if we can get a fuzzy operand size match... */
2021 if (!opsizemissing)
2022 goto done;
2023
2024 for (i = 0; i < instruction->operands; i++) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002025 /*
2026 * We ignore extrinsic operand sizes on registers, so we should
2027 * never try to fuzzy-match on them. This also resolves the case
2028 * when we have e.g. "xmmrm128" in two different positions.
2029 */
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002030 if (is_class(REGISTER, instruction->oprs[i].type))
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002031 continue;
2032
H. Peter Anvina81655b2009-07-25 18:15:28 -07002033 /* This tests if xsizeflags[i] has more than one bit set */
2034 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2035 goto done; /* No luck */
2036
2037 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
2038 }
2039
2040 /* Try matching again... */
2041 for (temp = nasm_instructions[instruction->opcode];
2042 temp->opcode != I_none; temp++) {
2043 m = matches(temp, instruction, bits);
2044 if (m == MOK_JUMP) {
2045 if (jmp_match(segment, offset, bits, instruction, temp->code))
2046 m = MOK_GOOD;
2047 else
2048 m = MERR_INVALOP;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002049 }
2050 if (m > merr)
2051 merr = m;
2052 if (merr == MOK_GOOD)
H. Peter Anvina81655b2009-07-25 18:15:28 -07002053 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002054 }
2055
H. Peter Anvina81655b2009-07-25 18:15:28 -07002056done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002057 *tempp = temp;
2058 return merr;
2059}
2060
H. Peter Anvin65289e82009-07-25 17:25:11 -07002061static enum match_result matches(const struct itemplate *itemp,
2062 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002063{
H. Peter Anvin60926242009-07-26 16:25:38 -07002064 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002065 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002066
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002067 /*
2068 * Check the opcode
2069 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002070 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002071 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002072
2073 /*
2074 * Count the operands
2075 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002076 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002077 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002078
2079 /*
2080 * Check that no spurious colons or TOs are present
2081 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002082 for (i = 0; i < itemp->operands; i++)
2083 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002084 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002085
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002086 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002087 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002088 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002089 switch (itemp->flags & IF_SMASK) {
2090 case IF_SB:
2091 asize = BITS8;
2092 break;
2093 case IF_SW:
2094 asize = BITS16;
2095 break;
2096 case IF_SD:
2097 asize = BITS32;
2098 break;
2099 case IF_SQ:
2100 asize = BITS64;
2101 break;
2102 case IF_SO:
2103 asize = BITS128;
2104 break;
2105 case IF_SY:
2106 asize = BITS256;
2107 break;
2108 case IF_SZ:
2109 switch (bits) {
2110 case 16:
2111 asize = BITS16;
2112 break;
2113 case 32:
2114 asize = BITS32;
2115 break;
2116 case 64:
2117 asize = BITS64;
2118 break;
H. Peter Anvined3e84f2009-07-27 11:10:33 -07002119 default:
2120 asize = 0;
2121 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002122 }
2123 break;
2124 default:
2125 asize = 0;
2126 break;
2127 }
2128
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002129 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin60926242009-07-26 16:25:38 -07002130 /* S- flags only apply to a specific operand */
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002131 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
H. Peter Anvin60926242009-07-26 16:25:38 -07002132 memset(size, 0, sizeof size);
2133 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002134 } else {
H. Peter Anvin60926242009-07-26 16:25:38 -07002135 /* S- flags apply to all operands */
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002136 for (i = 0; i < MAX_OPERANDS; i++)
2137 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002138 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002139
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002140 /*
2141 * Check that the operand flags all match up
2142 */
2143 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1f754202009-10-11 13:40:44 +04002144 opflags_t type = instruction->oprs[i].type;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002145 if (!(type & SIZE_MASK))
2146 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002147
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002148 if (itemp->opd[i] & SAME_AS) {
2149 int j = itemp->opd[i] & ~SAME_AS;
2150 if (type != instruction->oprs[j].type ||
2151 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002152 return MERR_INVALOP;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002153 } else if (itemp->opd[i] & ~type ||
2154 ((itemp->opd[i] & SIZE_MASK) &&
2155 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002156 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002157 return MERR_INVALOP;
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002158 } else if (!is_class(REGISTER, type)) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002159 /*
2160 * Note: we don't honor extrinsic operand sizes for registers,
2161 * so "missing operand size" for a register should be
2162 * considered a wildcard match rather than an error.
2163 */
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002164 opsizemissing = true;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002165 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002166 }
2167 }
2168
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002169 if (opsizemissing)
2170 return MERR_OPSIZEMISSING;
2171
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002172 /*
2173 * Check operand sizes
2174 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002175 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002176 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2177 asize = 0;
2178 for (i = 0; i < oprs; i++) {
2179 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2180 int j;
2181 for (j = 0; j < oprs; j++)
2182 size[j] = asize;
2183 break;
2184 }
2185 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002186 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002187 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002188 }
2189
Keith Kaniosb7a89542007-04-12 02:40:54 +00002190 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002191 if (!(itemp->opd[i] & SIZE_MASK) &&
2192 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002193 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002194 }
2195
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002196 /*
2197 * Check template is okay at the set cpu level
2198 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002199 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002200 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002201
Keith Kaniosb7a89542007-04-12 02:40:54 +00002202 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002203 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002205 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002206 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002207
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002208 /*
2209 * Check if special handling needed for Jumps
2210 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002211 if ((itemp->code[0] & 0374) == 0370)
2212 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002213
H. Peter Anvin60926242009-07-26 16:25:38 -07002214 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002215}
2216
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002217static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002218 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002219{
H. Peter Anvin9945fee2009-02-26 14:48:03 -08002220 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002221
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002222 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002223
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002224 /* REX flags for the rfield operand */
2225 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2226
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002227 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002228 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002229 int32_t f;
2230
2231 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002232 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002233 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002234 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002235 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002236
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002237 if (REG_EA & ~f)
2238 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002239
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002240 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2241
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002242 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002243 output->bytes = 0; /* no offset necessary either */
2244 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002245 } else { /* it's a memory reference */
2246 if (input->basereg == -1
2247 && (input->indexreg == -1 || input->scale == 0)) {
2248 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002249 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002250 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002251 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002252 scale = 0;
2253 index = 4;
2254 base = 5;
2255 output->sib = (scale << 6) | (index << 3) | base;
2256 output->bytes = 4;
2257 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002258 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002259 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002260 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002261 output->bytes = (addrbits != 16 ? 4 : 2);
2262 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002263 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002264 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002265 } else { /* it's an indirection */
2266 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002267 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002268 int hb = input->hintbase, ht = input->hinttype;
2269 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002270 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002271 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002272
H. Peter Anvine2c80182005-01-15 22:15:51 +00002273 if (s == 0)
2274 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002275
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002276 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002277 it = nasm_regvals[i];
2278 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002279 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002280 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002281 ix = 0;
2282 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002283
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002284 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002285 bt = nasm_regvals[b];
2286 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002287 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002288 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002289 bx = 0;
2290 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002291
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002292 /* check for a 32/64-bit memory reference... */
2293 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002294 /* it must be a 32/64-bit memory reference. Firstly we have
2295 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002296 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002297
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002298 if (it != -1) {
2299 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2300 sok &= ix;
2301 else
2302 return NULL;
2303 }
2304
2305 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002306 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002307 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002308 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002309 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002310 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002311 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002312
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002313 /* While we're here, ensure the user didn't specify
2314 WORD or QWORD. */
2315 if (input->disp_size == 16 || input->disp_size == 64)
2316 return NULL;
2317
2318 if (addrbits == 16 ||
2319 (addrbits == 32 && !(sok & BITS32)) ||
2320 (addrbits == 64 && !(sok & BITS64)))
2321 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002322
Keith Kaniosb7a89542007-04-12 02:40:54 +00002323 /* now reorganize base/index */
2324 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002325 ((hb == b && ht == EAH_NOTBASE)
2326 || (hb == i && ht == EAH_MAKEBASE))) {
2327 /* swap if hints say so */
2328 t = bt, bt = it, it = t;
2329 t = bx, bx = ix, ix = t;
2330 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002331 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002332 bt = -1, bx = 0, s++;
2333 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2334 /* make single reg base, unless hint */
2335 bt = it, bx = ix, it = -1, ix = 0;
2336 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002337 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002338 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002339 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002340 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002341 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002342 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002343 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002344 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002345 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002346 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002347 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002348 t = ix, ix = bx, bx = t;
2349 }
Keith Kanios48af1772007-08-17 07:37:52 +00002350 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002351 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002352 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002353
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002354 output->rex |= rexflags(it, ix, REX_X);
2355 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002356
Keith Kanios48af1772007-08-17 07:37:52 +00002357 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002358 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002359 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002360
Keith Kaniosb7a89542007-04-12 02:40:54 +00002361 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002362 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002363 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002364 } else {
2365 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002366 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002367 seg == NO_SEG && !forw_ref &&
2368 !(input->eaflags &
2369 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2370 mod = 0;
2371 else if (input->eaflags & EAF_BYTEOFFS ||
2372 (o >= -128 && o <= 127 && seg == NO_SEG
2373 && !forw_ref
2374 && !(input->eaflags & EAF_WORDOFFS)))
2375 mod = 1;
2376 else
2377 mod = 2;
2378 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002379
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002380 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002381 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2382 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002383 } else {
2384 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002385 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002386
Keith Kaniosb7a89542007-04-12 02:40:54 +00002387 if (it == -1)
2388 index = 4, s = 1;
2389 else
2390 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002391
H. Peter Anvine2c80182005-01-15 22:15:51 +00002392 switch (s) {
2393 case 1:
2394 scale = 0;
2395 break;
2396 case 2:
2397 scale = 1;
2398 break;
2399 case 4:
2400 scale = 2;
2401 break;
2402 case 8:
2403 scale = 3;
2404 break;
2405 default: /* then what the smeg is it? */
2406 return NULL; /* panic */
2407 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002408
Keith Kaniosb7a89542007-04-12 02:40:54 +00002409 if (bt == -1) {
2410 base = 5;
2411 mod = 0;
2412 } else {
2413 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002414 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002415 seg == NO_SEG && !forw_ref &&
2416 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002417 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2418 mod = 0;
2419 else if (input->eaflags & EAF_BYTEOFFS ||
2420 (o >= -128 && o <= 127 && seg == NO_SEG
2421 && !forw_ref
2422 && !(input->eaflags & EAF_WORDOFFS)))
2423 mod = 1;
2424 else
2425 mod = 2;
2426 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002427
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002428 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002429 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2430 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002431 output->sib = (scale << 6) | (index << 3) | base;
2432 }
2433 } else { /* it's 16-bit */
2434 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002435
Keith Kaniosb7a89542007-04-12 02:40:54 +00002436 /* check for 64-bit long mode */
2437 if (addrbits == 64)
2438 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002439
H. Peter Anvine2c80182005-01-15 22:15:51 +00002440 /* check all registers are BX, BP, SI or DI */
2441 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2442 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2443 && i != R_SI && i != R_DI))
2444 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002445
Keith Kaniosb7a89542007-04-12 02:40:54 +00002446 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002447 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002448 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002449
H. Peter Anvine2c80182005-01-15 22:15:51 +00002450 if (s != 1 && i != -1)
2451 return NULL; /* no can do, in 16-bit EA */
2452 if (b == -1 && i != -1) {
2453 int tmp = b;
2454 b = i;
2455 i = tmp;
2456 } /* swap */
2457 if ((b == R_SI || b == R_DI) && i != -1) {
2458 int tmp = b;
2459 b = i;
2460 i = tmp;
2461 }
2462 /* have BX/BP as base, SI/DI index */
2463 if (b == i)
2464 return NULL; /* shouldn't ever happen, in theory */
2465 if (i != -1 && b != -1 &&
2466 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2467 return NULL; /* invalid combinations */
2468 if (b == -1) /* pure offset: handled above */
2469 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002470
H. Peter Anvine2c80182005-01-15 22:15:51 +00002471 rm = -1;
2472 if (i != -1)
2473 switch (i * 256 + b) {
2474 case R_SI * 256 + R_BX:
2475 rm = 0;
2476 break;
2477 case R_DI * 256 + R_BX:
2478 rm = 1;
2479 break;
2480 case R_SI * 256 + R_BP:
2481 rm = 2;
2482 break;
2483 case R_DI * 256 + R_BP:
2484 rm = 3;
2485 break;
2486 } else
2487 switch (b) {
2488 case R_SI:
2489 rm = 4;
2490 break;
2491 case R_DI:
2492 rm = 5;
2493 break;
2494 case R_BP:
2495 rm = 6;
2496 break;
2497 case R_BX:
2498 rm = 7;
2499 break;
2500 }
2501 if (rm == -1) /* can't happen, in theory */
2502 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002503
H. Peter Anvine2c80182005-01-15 22:15:51 +00002504 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2505 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2506 mod = 0;
2507 else if (input->eaflags & EAF_BYTEOFFS ||
2508 (o >= -128 && o <= 127 && seg == NO_SEG
2509 && !forw_ref
2510 && !(input->eaflags & EAF_WORDOFFS)))
2511 mod = 1;
2512 else
2513 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002514
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002515 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002516 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002517 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002518 }
2519 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002520 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002521
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002522 output->size = 1 + output->sib_present + output->bytes;
2523 return output;
2524}
2525
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002526static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002527{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002528 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002529 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002530
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002531 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002532
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002533 switch (ins->prefixes[PPS_ASIZE]) {
2534 case P_A16:
2535 valid &= 16;
2536 break;
2537 case P_A32:
2538 valid &= 32;
2539 break;
2540 case P_A64:
2541 valid &= 64;
2542 break;
2543 case P_ASP:
2544 valid &= (addrbits == 32) ? 16 : 32;
2545 break;
2546 default:
2547 break;
2548 }
2549
2550 for (j = 0; j < ins->operands; j++) {
2551 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002552 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002553
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002554 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002555 if (ins->oprs[j].indexreg < EXPR_REG_START
2556 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002557 i = 0;
2558 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002559 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002560
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002561 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002562 if (ins->oprs[j].basereg < EXPR_REG_START
2563 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002564 b = 0;
2565 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002566 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002567
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002568 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002569 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002570
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002571 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002572 int ds = ins->oprs[j].disp_size;
2573 if ((addrbits != 64 && ds > 8) ||
2574 (addrbits == 64 && ds == 16))
2575 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002576 } else {
2577 if (!(REG16 & ~b))
2578 valid &= 16;
2579 if (!(REG32 & ~b))
2580 valid &= 32;
2581 if (!(REG64 & ~b))
2582 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002583
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002584 if (!(REG16 & ~i))
2585 valid &= 16;
2586 if (!(REG32 & ~i))
2587 valid &= 32;
2588 if (!(REG64 & ~i))
2589 valid &= 64;
2590 }
2591 }
2592 }
2593
2594 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002595 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002596 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002597 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002598 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002599 ins->prefixes[PPS_ASIZE] = pref;
2600 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002601 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002602 /* Impossible... */
2603 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002604 ins->addr_size = addrbits; /* Error recovery */
2605 }
2606
2607 defdisp = ins->addr_size == 16 ? 16 : 32;
2608
2609 for (j = 0; j < ins->operands; j++) {
2610 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2611 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2612 != ins->addr_size) {
2613 /* mem_offs sizes must match the address size; if not,
2614 strip the MEM_OFFS bit and match only EA instructions */
2615 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2616 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002617 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002618}