blob: 17def3aafa8bd60fa81c65f502254413de2a7cab [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07003 * Copyright 1996-2011 The NASM Authors - All Rights Reserved
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07004 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
Cyrill Gorcunov1de95002009-11-06 00:08:38 +030017 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -070018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * assemble.c code generation for the Netwide Assembler
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036 *
37 * the actual codes (C syntax, i.e. octal):
38 * \0 - terminates the code. (Unless it's a literal of course.)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040039 * \1..\4 - that many literal bytes follow in the code stream
H. Peter Anvindcffe4b2008-10-10 22:10:31 -070040 * \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]
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040053 * 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
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040065 * 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
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040068 * is a signed byte rather than a dword. Opcode byte follows.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040069 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070070 * the 4-bit immediate from operand b in bits 3..0.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040071 * \173\xab - the register number from operand a in bits 7..4, with
72 * the value b in bits 3..0.
73 * \174\a - the register number from operand a in bits 7..4, and
74 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000075 * \2ab - a ModRM, calculated on EA in operand a, with the spare
76 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070077 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
78 * is not equal to the truncated and sign-extended 32-bit
79 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvin588df782008-10-07 10:05:10 -070080 * \254..\257 - a signed 32-bit operand to be extended to 64 bits.
H. Peter Anvina04019c2009-05-03 21:42:34 -070081 * \260..\263 - this instruction uses VEX/XOP rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040082 * V field taken from operand 0..3.
83 * \270 - this instruction uses VEX/XOP rather than REX, with the
84 * V field set to 1111b.
H. Peter Anvind85d2502008-05-04 17:53:31 -070085 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070086 * VEX/XOP prefixes are followed by the sequence:
87 * \tmm\wlp where mm is the M field; and wlp is:
H. Peter Anvin421059c2010-08-16 14:56:33 -070088 * 00 wwl lpp
89 * [l0] ll = 0 for L = 0 (.128, .lz)
90 * [l1] ll = 1 for L = 1 (.256)
91 * [lig] ll = 2 for L don't care (always assembled as 0)
92 *
H. Peter Anvin978c2172010-08-16 13:48:43 -070093 * [w0] ww = 0 for W = 0
94 * [w1 ] ww = 1 for W = 1
95 * [wig] ww = 2 for W don't care (always assembled as 0)
96 * [ww] ww = 3 for W used as REX.W
H. Peter Anvinbd420c72008-05-22 11:24:35 -070097 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070098 * t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
H. Peter Anvind85d2502008-05-04 17:53:31 -070099 *
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700100 * \274..\277 - a signed byte immediate operand, from operand 0..3,
101 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
103 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -0700104 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +0000105 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -0800106 * \314 - (disassembler only) invalid with REX.B
107 * \315 - (disassembler only) invalid with REX.X
108 * \316 - (disassembler only) invalid with REX.R
109 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
111 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
112 * \322 - indicates that this instruction is only valid when the
113 * operand size is the default (instruction to disassembler,
114 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000115 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000116 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400117 * \325 - instruction which always uses spl/bpl/sil/dil
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118 * \330 - a literal byte follows in the code stream, to be added
119 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000120 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000121 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700122 * \332 - REP prefix (0xF2 byte) used as opcode extension.
123 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700124 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700125 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700126 * \336 - force a REP(E) prefix (0xF2) even if not specified.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400127 * \337 - force a REPNE prefix (0xF3) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700128 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000129 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400131 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700132 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
133 * (POP is never used for CS) depending on operand 0
134 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
135 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400136 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700137 * \361 - 66 SSE prefix (== \366\331)
138 * \362 - F2 SSE prefix (== \364\332)
139 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000140 * \364 - operand-size prefix (0x66) not permitted
141 * \365 - address-size prefix (0x67) not permitted
142 * \366 - operand-size prefix (0x66) used as opcode extension
143 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000144 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400145 * 370 is used for Jcc, 371 is used for JMP.
146 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
147 * used for conditional jump over longer jump
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700148 * \374 - this instruction takes an XMM VSIB memory EA
149 * \375 - this instruction takes an YMM VSIB memory EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000150 */
151
H. Peter Anvinfe501952007-10-02 21:53:51 -0700152#include "compiler.h"
153
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000154#include <stdio.h>
155#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000156#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000157
158#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000159#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000160#include "assemble.h"
161#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700162#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000163
H. Peter Anvin65289e82009-07-25 17:25:11 -0700164enum match_result {
165 /*
166 * Matching errors. These should be sorted so that more specific
167 * errors come later in the sequence.
168 */
169 MERR_INVALOP,
170 MERR_OPSIZEMISSING,
171 MERR_OPSIZEMISMATCH,
172 MERR_BADCPU,
173 MERR_BADMODE,
174 /*
175 * Matching success; the conditional ones first
176 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400177 MOK_JUMP, /* Matching OK but needs jmp_match() */
178 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700179};
180
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000181typedef struct {
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700182 enum ea_type type; /* what kind of EA is this? */
183 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,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400197 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700198static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400199 insn *instruction,
200 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700201static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700202static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000203static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700204static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000205static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700206static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000207
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700208static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
209
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700210static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000211{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700212 return ins->prefixes[pos] == prefix;
213}
214
215static void assert_no_prefix(insn * ins, enum prefix_pos pos)
216{
217 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400218 errfunc(ERR_NONFATAL, "invalid %s prefix",
219 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700220}
221
222static const char *size_name(int size)
223{
224 switch (size) {
225 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400226 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700227 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400228 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700229 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400230 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700231 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400232 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700233 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400234 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700235 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400236 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700237 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400238 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700239 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400240 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000241 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700242}
243
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400244static void warn_overflow(int pass, int size)
245{
246 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
247 "%s data exceeds bounds", size_name(size));
248}
249
250static void warn_overflow_const(int64_t data, int size)
251{
252 if (overflow_general(data, size))
253 warn_overflow(ERR_PASS1, size);
254}
255
256static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700257{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100258 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400259 if (overflow_general(o->offset, size))
260 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700261 }
262}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400263
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000264/*
265 * This routine wrappers the real output format's output routine,
266 * in order to pass a copy of the data off to the listing file
267 * generator at the same time.
268 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800269static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800270 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400271 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000272{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000273 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000274 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800275 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000276
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800277 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400278 /*
279 * This is a non-relocated address, and we're going to
280 * convert it into RAWDATA format.
281 */
282 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800283
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400284 if (size > 8) {
285 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
286 return;
287 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700288
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400289 WRITEADDR(q, *(int64_t *)data, size);
290 data = p;
291 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000292 }
293
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800294 list->output(offset, data, type, size);
295
Frank Kotlerabebb082003-09-06 04:45:37 +0000296 /*
297 * this call to src_get determines when we call the
298 * debug-format-specific "linenum" function
299 * it updates lineno and lnfname to the current values
300 * returning 0 if "same as last time", -2 if lnfname
301 * changed, and the amount by which lineno changed,
302 * if it did. thus, these variables must be static
303 */
304
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400305 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000306 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000307
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800308 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000309}
310
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700311static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700312 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800314 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000315 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000316
Charles Craynef1aefd82008-09-30 16:11:32 -0700317 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700318 return false;
319 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400320 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700321 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400322 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700323
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100325
Victor van den Elzen154e5922009-02-25 17:32:00 +0100326 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100327 /* Be optimistic in pass 1 */
328 return true;
329
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700331 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000332
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700333 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
334 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000336
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800337int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400338 insn * instruction, struct ofmt *output, efunc error,
339 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000340{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000341 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700343 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800344 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000345 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800346 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300347 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000348
H. Peter Anvine2c80182005-01-15 22:15:51 +0000349 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000350 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000351 outfmt = output; /* likewise */
352 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000353
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300354 wsize = idata_bytes(instruction->opcode);
355 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000357
H. Peter Anvineba20a72002-04-30 20:53:55 +0000358 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000360 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 if (t < 0)
362 errfunc(ERR_PANIC,
363 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000364
H. Peter Anvine2c80182005-01-15 22:15:51 +0000365 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400366 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400368 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700369 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400370 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000371 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700372 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800374 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400375 offset += wsize;
376 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700377 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400378 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000380
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800382 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000383 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000384
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 if (align) {
386 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100387 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800388 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 }
390 offset += e->stringlen + align;
391 }
392 }
393 if (t > 0 && t == instruction->times - 1) {
394 /*
395 * Dummy call to list->output to give the offset to the
396 * listing module.
397 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800398 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 list->uplevel(LIST_TIMES);
400 }
401 }
402 if (instruction->times > 1)
403 list->downlevel(LIST_TIMES);
404 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000405 }
406
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700408 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000410
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400411 fp = fopen(fname, "rb");
412 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
414 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400415 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000416 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
417 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400418 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700419 static char buf[4096];
420 size_t t = instruction->times;
421 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400422 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000423
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 len = ftell(fp);
425 if (instruction->eops->next) {
426 base = instruction->eops->next->offset;
427 len -= base;
428 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700429 len > (size_t)instruction->eops->next->next->offset)
430 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 }
432 /*
433 * Dummy call to list->output to give the offset to the
434 * listing module.
435 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800436 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000437 list->uplevel(LIST_INCBIN);
438 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700439 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000440
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 fseek(fp, base, SEEK_SET);
442 l = len;
443 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700444 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400445 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 if (!m) {
447 /*
448 * This shouldn't happen unless the file
449 * actually changes while we are reading
450 * it.
451 */
452 error(ERR_NONFATAL,
453 "`incbin': unexpected EOF while"
454 " reading file `%s'", fname);
455 t = 0; /* Try to exit cleanly */
456 break;
457 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800458 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000459 NO_SEG, NO_SEG);
460 l -= m;
461 }
462 }
463 list->downlevel(LIST_INCBIN);
464 if (instruction->times > 1) {
465 /*
466 * Dummy call to list->output to give the offset to the
467 * listing module.
468 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800469 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000470 list->uplevel(LIST_TIMES);
471 list->downlevel(LIST_TIMES);
472 }
473 fclose(fp);
474 return instruction->times * len;
475 }
476 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000477 }
478
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700479 /* Check to see if we need an address-size prefix */
480 add_asp(instruction, bits);
481
H. Peter Anvin23595f52009-07-25 17:44:25 -0700482 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700483
H. Peter Anvin23595f52009-07-25 17:44:25 -0700484 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400485 /* Matches! */
486 int64_t insn_size = calcsize(segment, offset, bits,
487 instruction, temp->code);
488 itimes = instruction->times;
489 if (insn_size < 0) /* shouldn't be, on pass two */
490 error(ERR_PANIC, "errors made it through from pass one");
491 else
492 while (itimes--) {
493 for (j = 0; j < MAXPREFIX; j++) {
494 uint8_t c = 0;
495 switch (instruction->prefixes[j]) {
496 case P_WAIT:
497 c = 0x9B;
498 break;
499 case P_LOCK:
500 c = 0xF0;
501 break;
502 case P_REPNE:
503 case P_REPNZ:
504 c = 0xF2;
505 break;
506 case P_REPE:
507 case P_REPZ:
508 case P_REP:
509 c = 0xF3;
510 break;
511 case R_CS:
512 if (bits == 64) {
513 error(ERR_WARNING | ERR_PASS2,
514 "cs segment base generated, but will be ignored in 64-bit mode");
515 }
516 c = 0x2E;
517 break;
518 case R_DS:
519 if (bits == 64) {
520 error(ERR_WARNING | ERR_PASS2,
521 "ds segment base generated, but will be ignored in 64-bit mode");
522 }
523 c = 0x3E;
524 break;
525 case R_ES:
526 if (bits == 64) {
527 error(ERR_WARNING | ERR_PASS2,
528 "es segment base generated, but will be ignored in 64-bit mode");
529 }
530 c = 0x26;
531 break;
532 case R_FS:
533 c = 0x64;
534 break;
535 case R_GS:
536 c = 0x65;
537 break;
538 case R_SS:
539 if (bits == 64) {
540 error(ERR_WARNING | ERR_PASS2,
541 "ss segment base generated, but will be ignored in 64-bit mode");
542 }
543 c = 0x36;
544 break;
545 case R_SEGR6:
546 case R_SEGR7:
547 error(ERR_NONFATAL,
548 "segr6 and segr7 cannot be used as prefixes");
549 break;
550 case P_A16:
551 if (bits == 64) {
552 error(ERR_NONFATAL,
553 "16-bit addressing is not supported "
554 "in 64-bit mode");
555 } else if (bits != 16)
556 c = 0x67;
557 break;
558 case P_A32:
559 if (bits != 32)
560 c = 0x67;
561 break;
562 case P_A64:
563 if (bits != 64) {
564 error(ERR_NONFATAL,
565 "64-bit addressing is only supported "
566 "in 64-bit mode");
567 }
568 break;
569 case P_ASP:
570 c = 0x67;
571 break;
572 case P_O16:
573 if (bits != 16)
574 c = 0x66;
575 break;
576 case P_O32:
577 if (bits == 16)
578 c = 0x66;
579 break;
580 case P_O64:
581 /* REX.W */
582 break;
583 case P_OSP:
584 c = 0x66;
585 break;
586 case P_none:
587 break;
588 default:
589 error(ERR_PANIC, "invalid instruction prefix");
590 }
591 if (c != 0) {
592 out(offset, segment, &c, OUT_RAWDATA, 1,
593 NO_SEG, NO_SEG);
594 offset++;
595 }
596 }
597 insn_end = offset + insn_size;
598 gencode(segment, offset, bits, instruction,
599 temp, insn_end);
600 offset += insn_size;
601 if (itimes > 0 && itimes == instruction->times - 1) {
602 /*
603 * Dummy call to list->output to give the offset to the
604 * listing module.
605 */
606 list->output(offset, NULL, OUT_RAWDATA, 0);
607 list->uplevel(LIST_TIMES);
608 }
609 }
610 if (instruction->times > 1)
611 list->downlevel(LIST_TIMES);
612 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700613 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400614 /* No match */
615 switch (m) {
616 case MERR_OPSIZEMISSING:
617 error(ERR_NONFATAL, "operation size not specified");
618 break;
619 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400621 break;
622 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400624 break;
625 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800626 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400627 bits);
628 break;
629 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000630 error(ERR_NONFATAL,
631 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400632 break;
633 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000634 }
635 return 0;
636}
637
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800638int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400639 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000640{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000641 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700642 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000643
H. Peter Anvine2c80182005-01-15 22:15:51 +0000644 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000645 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400647 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000648 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000649
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700650 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
651 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400652 instruction->opcode == I_DT || instruction->opcode == I_DO ||
653 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000654 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300655 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300658 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400660 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000661 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400664 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000665 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400666 warn_overflow_const(e->offset, wsize);
667 } else if (e->type == EOT_DB_STRING ||
668 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 align = (-osize) % wsize;
672 if (align < 0)
673 align += wsize;
674 isize += osize + align;
675 }
676 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000677 }
678
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400680 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300682 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700683 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000684
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400685 fp = fopen(fname, "rb");
686 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
688 fname);
689 else if (fseek(fp, 0L, SEEK_END) < 0)
690 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
691 fname);
692 else {
693 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000694 if (instruction->eops->next) {
695 len -= instruction->eops->next->offset;
696 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700697 len > (size_t)instruction->eops->next->next->offset) {
698 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000699 }
700 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300701 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300703 if (fp)
704 fclose(fp);
705 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000706 }
707
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700708 /* Check to see if we need an address-size prefix */
709 add_asp(instruction, bits);
710
H. Peter Anvin23595f52009-07-25 17:44:25 -0700711 m = find_match(&temp, instruction, segment, offset, bits);
712 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400713 /* we've matched an instruction. */
714 int64_t isize;
715 const uint8_t *codes = temp->code;
716 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100717
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400718 isize = calcsize(segment, offset, bits, instruction, codes);
719 if (isize < 0)
720 return -1;
721 for (j = 0; j < MAXPREFIX; j++) {
722 switch (instruction->prefixes[j]) {
723 case P_A16:
724 if (bits != 16)
725 isize++;
726 break;
727 case P_A32:
728 if (bits != 32)
729 isize++;
730 break;
731 case P_O16:
732 if (bits != 16)
733 isize++;
734 break;
735 case P_O32:
736 if (bits == 16)
737 isize++;
738 break;
739 case P_A64:
740 case P_O64:
741 case P_none:
742 break;
743 default:
744 isize++;
745 break;
746 }
747 }
748 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700749 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400750 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000751 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000752}
753
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700754static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000755{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700756 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400757 !(o->opflags & OPFLAG_UNKNOWN) &&
758 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000759}
760
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700761/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700762static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700763{
764 int16_t v;
765
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700766 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400767 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700768
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700769 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700770 return v >= -128 && v <= 127;
771}
772
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700773static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774{
775 int32_t v;
776
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700777 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400778 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700779
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700780 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700781 return v >= -128 && v <= 127;
782}
783
H. Peter Anvin507ae032008-10-09 15:37:10 -0700784/* Common construct */
785#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
786
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800787static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400788 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000789{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800790 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000791 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000792 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700793 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700794 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700795 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700796 enum ea_type eat;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000797
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700798 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700799 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700800
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700801 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400802 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700803
H. Peter Anvine2c80182005-01-15 22:15:51 +0000804 (void)segment; /* Don't warn that this parameter is unused */
805 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000806
H. Peter Anvin839eca22007-10-29 23:12:47 -0700807 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400808 c = *codes++;
809 op1 = (c & 3) + ((opex & 1) << 2);
810 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
811 opx = &ins->oprs[op1];
812 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700813
H. Peter Anvin839eca22007-10-29 23:12:47 -0700814 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 case 01:
816 case 02:
817 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400818 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000819 codes += c, length += c;
820 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700821
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400822 case 05:
823 case 06:
824 case 07:
825 opex = c;
826 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700827
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400828 case4(010):
829 ins->rex |=
830 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000831 codes++, length++;
832 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700833
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400834 case4(014):
835 case4(020):
836 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 length++;
838 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700839
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400840 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000841 length += 2;
842 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700843
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400844 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700845 if (opx->type & (BITS16 | BITS32 | BITS64))
846 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 else
848 length += (bits == 16) ? 2 : 4;
849 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700850
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400851 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000852 length += 4;
853 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700854
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400855 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700856 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700858
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400859 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000860 length++;
861 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700862
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400863 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000864 length += 8; /* MOV reg64/imm */
865 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700866
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400867 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 length += 2;
869 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700870
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400871 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700872 if (opx->type & (BITS16 | BITS32 | BITS64))
873 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 else
875 length += (bits == 16) ? 2 : 4;
876 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700877
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400878 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 length += 4;
880 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700881
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400882 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700883 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000884 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700885
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400886 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700887 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700889
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400890 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800891 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000892 length++;
893 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700894
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400895 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700896 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700897 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700898
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400899 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800900 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700901 length++;
902 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700903
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400904 case 0172:
905 case 0173:
906 case 0174:
907 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700908 length++;
909 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700910
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400911 case4(0250):
912 length += is_sbyte32(opx) ? 1 : 4;
913 break;
914
915 case4(0254):
916 length += 4;
917 break;
918
919 case4(0260):
920 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700921 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400922 ins->vex_cm = *codes++;
923 ins->vex_wlp = *codes++;
924 break;
925
926 case 0270:
927 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700928 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400929 ins->vex_cm = *codes++;
930 ins->vex_wlp = *codes++;
931 break;
932
933 case4(0274):
934 length++;
935 break;
936
937 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000938 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700939
H. Peter Anvine2c80182005-01-15 22:15:51 +0000940 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400941 if (bits == 64)
942 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700943 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000944 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700945
H. Peter Anvine2c80182005-01-15 22:15:51 +0000946 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700947 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000948 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700949
H. Peter Anvine2c80182005-01-15 22:15:51 +0000950 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700951 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700952
Keith Kaniosb7a89542007-04-12 02:40:54 +0000953 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400954 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
955 has_prefix(ins, PPS_ASIZE, P_A32))
956 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700958
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400959 case4(0314):
960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
H. Peter Anvine2c80182005-01-15 22:15:51 +0000962 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000963 {
964 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
965 if (pfx == P_O16)
966 break;
967 if (pfx != P_none)
968 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
969 else
970 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000971 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000972 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700973
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000975 {
976 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
977 if (pfx == P_O32)
978 break;
979 if (pfx != P_none)
980 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
981 else
982 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000983 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000984 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700985
H. Peter Anvine2c80182005-01-15 22:15:51 +0000986 case 0322:
987 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700988
Keith Kaniosb7a89542007-04-12 02:40:54 +0000989 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000990 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000991 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700992
Keith Kaniosb7a89542007-04-12 02:40:54 +0000993 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400994 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000995 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700996
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400997 case 0325:
998 ins->rex |= REX_NH;
999 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001000
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 case 0330:
1002 codes++, length++;
1003 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001004
H. Peter Anvine2c80182005-01-15 22:15:51 +00001005 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001006 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001007
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001008 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001009 case 0333:
1010 length++;
1011 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001012
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001013 case 0334:
1014 ins->rex |= REX_L;
1015 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001016
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001017 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001018 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001019
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001020 case 0336:
1021 if (!ins->prefixes[PPS_LREP])
1022 ins->prefixes[PPS_LREP] = P_REP;
1023 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001024
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001025 case 0337:
1026 if (!ins->prefixes[PPS_LREP])
1027 ins->prefixes[PPS_LREP] = P_REPNE;
1028 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001029
H. Peter Anvine2c80182005-01-15 22:15:51 +00001030 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001031 if (ins->oprs[0].segment != NO_SEG)
1032 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1033 " quantity of BSS space");
1034 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001035 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001036 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001037
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001038 case 0341:
1039 if (!ins->prefixes[PPS_WAIT])
1040 ins->prefixes[PPS_WAIT] = P_WAIT;
1041 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001042
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001043 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001044 length++;
1045 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001046
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001047 case 0360:
1048 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001049
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001050 case 0361:
1051 case 0362:
1052 case 0363:
1053 length++;
1054 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001055
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001056 case 0364:
1057 case 0365:
1058 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001059
Keith Kanios48af1772007-08-17 07:37:52 +00001060 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001061 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001062 length++;
1063 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001064
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 case 0370:
1066 case 0371:
1067 case 0372:
1068 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001069
H. Peter Anvine2c80182005-01-15 22:15:51 +00001070 case 0373:
1071 length++;
1072 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001073
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001074 case 0374:
1075 eat = EA_XMMVSIB;
1076 break;
1077
1078 case 0375:
1079 eat = EA_YMMVSIB;
1080 break;
1081
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001082 case4(0100):
1083 case4(0110):
1084 case4(0120):
1085 case4(0130):
1086 case4(0200):
1087 case4(0204):
1088 case4(0210):
1089 case4(0214):
1090 case4(0220):
1091 case4(0224):
1092 case4(0230):
1093 case4(0234):
1094 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001095 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001096 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001097 opflags_t rflags;
1098 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001099
Keith Kaniosb7a89542007-04-12 02:40:54 +00001100 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001101
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001102 if (c <= 0177) {
1103 /* pick rfield from operand b (opx) */
1104 rflags = regflag(opx);
1105 rfield = nasm_regvals[opx->basereg];
1106 } else {
1107 rflags = 0;
1108 rfield = c & 7;
1109 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001110 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1111 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001112 errfunc(ERR_NONFATAL, "invalid effective address");
1113 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001114 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001115 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001116 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001117 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001118 }
1119 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001120
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001121 default:
1122 errfunc(ERR_PANIC, "internal instruction table corrupt"
1123 ": instruction code \\%o (0x%02X) given", c, c);
1124 break;
1125 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001126 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001127
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001128 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001129
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001130 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001131 if (ins->rex & REX_H) {
1132 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1133 return -1;
1134 }
1135 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001136 }
1137
H. Peter Anvind85d2502008-05-04 17:53:31 -07001138 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001139 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001140
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001141 if (ins->rex & REX_H) {
1142 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1143 return -1;
1144 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001145 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001146 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001147 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001148 ins->rex &= ~REX_W;
1149 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001150 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001151 ins->rex |= REX_W;
1152 bad32 &= ~REX_W;
1153 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001154 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001155 /* Follow REX_W */
1156 break;
1157 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001158
H. Peter Anvinfc561202011-07-07 16:58:22 -07001159 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001160 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1161 return -1;
1162 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001163 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001164 length += 3;
1165 else
1166 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001167 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001168 if (ins->rex & REX_H) {
1169 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1170 return -1;
1171 } else if (bits == 64) {
1172 length++;
1173 } else if ((ins->rex & REX_L) &&
1174 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1175 cpu >= IF_X86_64) {
1176 /* LOCK-as-REX.R */
1177 assert_no_prefix(ins, PPS_LREP);
1178 length++;
1179 } else {
1180 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1181 return -1;
1182 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001183 }
1184
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001185 return length;
1186}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001187
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001188#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001189 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001190 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1191 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1192 ins->rex = 0; \
1193 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001194 }
1195
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001196static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001197 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001198 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001199{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001200 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001201 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1202 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1203 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001204 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001205 uint8_t c;
1206 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001207 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001208 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001209 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001210 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001211 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001212 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001213 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001214
H. Peter Anvin839eca22007-10-29 23:12:47 -07001215 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001216 c = *codes++;
1217 op1 = (c & 3) + ((opex & 1) << 2);
1218 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1219 opx = &ins->oprs[op1];
1220 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001221
H. Peter Anvin839eca22007-10-29 23:12:47 -07001222 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001223 case 01:
1224 case 02:
1225 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001226 case 04:
1227 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001228 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001229 codes += c;
1230 offset += c;
1231 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001232
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001233 case 05:
1234 case 06:
1235 case 07:
1236 opex = c;
1237 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001238
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001239 case4(010):
1240 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001241 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001242 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001243 offset += 1;
1244 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001245
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001246 case4(014):
1247 /*
1248 * The test for BITS8 and SBYTE here is intended to avoid
1249 * warning on optimizer actions due to SBYTE, while still
1250 * warn on explicit BYTE directives. Also warn, obviously,
1251 * if the optimizer isn't enabled.
1252 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001253 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001254 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1255 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001256 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001257 "signed byte value exceeds bounds");
1258 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001259 if (opx->segment != NO_SEG) {
1260 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001261 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001262 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001263 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001264 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001265 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 NO_SEG);
1267 }
1268 offset += 1;
1269 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001270
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001271 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001272 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001273 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001274 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001275 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001276 if (opx->segment != NO_SEG) {
1277 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001278 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001280 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001282 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 NO_SEG);
1284 }
1285 offset += 1;
1286 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001287
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001288 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001289 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001290 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001291 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 if (opx->segment != NO_SEG) {
1293 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001294 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001295 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001296 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001298 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 NO_SEG);
1300 }
1301 offset += 1;
1302 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001303
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001304 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001305 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001307 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001309 offset += 2;
1310 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001311
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001312 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001313 if (opx->type & (BITS16 | BITS32))
1314 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001315 else
1316 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001317 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001318 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001319 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001320 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 offset += size;
1322 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001323
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001324 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001325 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001326 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001327 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001328 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001329 offset += 4;
1330 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001331
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001332 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001334 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001335 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001336 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001338 offset += size;
1339 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001340
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001341 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001342 if (opx->segment != segment) {
1343 data = opx->offset;
1344 out(offset, segment, &data,
1345 OUT_REL1ADR, insn_end - offset,
1346 opx->segment, opx->wrt);
1347 } else {
1348 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001349 if (data > 127 || data < -128)
1350 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001351 out(offset, segment, &data,
1352 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1353 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 offset += 1;
1355 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001356
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001357 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001358 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001359 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001360 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001361 offset += 8;
1362 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001363
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001364 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001365 if (opx->segment != segment) {
1366 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001367 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001368 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001373 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 }
1375 offset += 2;
1376 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001377
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001378 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001379 if (opx->type & (BITS16 | BITS32 | BITS64))
1380 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001381 else
1382 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001383 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001385 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001386 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1387 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001388 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001389 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001391 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001392 }
1393 offset += size;
1394 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001395
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001396 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001397 if (opx->segment != segment) {
1398 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001400 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001401 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001403 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001406 }
1407 offset += 4;
1408 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001409
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001410 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001411 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001412 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1413 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001414 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001415 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001416 outfmt->segbase(1 + opx->segment),
1417 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001418 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001420
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001421 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001422 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001423 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001424 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001425 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001426 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001427 NO_SEG);
1428 offset++;
1429 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001430 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001431 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001432 offset += 2;
1433 }
1434 break;
1435
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001436 case4(0144):
1437 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001438 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001439 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001440 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001441 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001442 offset++;
1443 break;
1444
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001445 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001446 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001447 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001448 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001449 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001450 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 NO_SEG);
1452 offset++;
1453 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001454 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001455 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001456 offset += 4;
1457 }
1458 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001459
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001460 case4(0154):
1461 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001463 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001465 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001466 offset++;
1467 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001468
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001469 case 0172:
1470 c = *codes++;
1471 opx = &ins->oprs[c >> 3];
1472 bytes[0] = nasm_regvals[opx->basereg] << 4;
1473 opx = &ins->oprs[c & 7];
1474 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1475 errfunc(ERR_NONFATAL,
1476 "non-absolute expression not permitted as argument %d",
1477 c & 7);
1478 } else {
1479 if (opx->offset & ~15) {
1480 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1481 "four-bit argument exceeds bounds");
1482 }
1483 bytes[0] |= opx->offset & 15;
1484 }
1485 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1486 offset++;
1487 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001488
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001489 case 0173:
1490 c = *codes++;
1491 opx = &ins->oprs[c >> 4];
1492 bytes[0] = nasm_regvals[opx->basereg] << 4;
1493 bytes[0] |= c & 15;
1494 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1495 offset++;
1496 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001497
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001498 case 0174:
1499 c = *codes++;
1500 opx = &ins->oprs[c];
1501 bytes[0] = nasm_regvals[opx->basereg] << 4;
1502 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1503 offset++;
1504 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001505
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001506 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001507 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001508 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1509 (int32_t)data != (int64_t)data) {
1510 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1511 "signed dword immediate exceeds bounds");
1512 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001513 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001514 bytes[0] = data;
1515 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1516 NO_SEG);
1517 offset++;
1518 } else {
1519 out(offset, segment, &data, OUT_ADDRESS, 4,
1520 opx->segment, opx->wrt);
1521 offset += 4;
1522 }
1523 break;
1524
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001525 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001526 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001527 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1528 (int32_t)data != (int64_t)data) {
1529 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1530 "signed dword immediate exceeds bounds");
1531 }
1532 out(offset, segment, &data, OUT_ADDRESS, 4,
1533 opx->segment, opx->wrt);
1534 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001535 break;
1536
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001537 case4(0260):
1538 case 0270:
1539 codes += 2;
1540 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1541 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1542 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1543 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001544 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001545 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1546 offset += 3;
1547 } else {
1548 bytes[0] = 0xc5;
1549 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001550 ((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001551 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1552 offset += 2;
1553 }
1554 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001555
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001556 case4(0274):
1557 {
1558 uint64_t uv, um;
1559 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001560
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001561 if (ins->rex & REX_W)
1562 s = 64;
1563 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1564 s = 16;
1565 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1566 s = 32;
1567 else
1568 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001569
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001570 um = (uint64_t)2 << (s-1);
1571 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001572
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001573 if (uv > 127 && uv < (uint64_t)-128 &&
1574 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001575 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001576 "signed byte value exceeds bounds");
1577 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001578 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001579 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001580 out(offset, segment, &data, OUT_ADDRESS, 1,
1581 opx->segment, opx->wrt);
1582 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001583 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001584 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1585 NO_SEG);
1586 }
1587 offset += 1;
1588 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001589 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001590
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001591 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001592 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001593
H. Peter Anvine2c80182005-01-15 22:15:51 +00001594 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001595 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001596 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001597 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001598 offset += 1;
1599 } else
1600 offset += 0;
1601 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001602
H. Peter Anvine2c80182005-01-15 22:15:51 +00001603 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001604 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001605 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001606 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001607 offset += 1;
1608 } else
1609 offset += 0;
1610 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001611
H. Peter Anvine2c80182005-01-15 22:15:51 +00001612 case 0312:
1613 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001614
Keith Kaniosb7a89542007-04-12 02:40:54 +00001615 case 0313:
1616 ins->rex = 0;
1617 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001618
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001619 case4(0314):
1620 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001621
H. Peter Anvine2c80182005-01-15 22:15:51 +00001622 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001623 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001624 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001625
H. Peter Anvine2c80182005-01-15 22:15:51 +00001626 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001627 case 0323:
1628 break;
1629
Keith Kaniosb7a89542007-04-12 02:40:54 +00001630 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001631 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001632 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001633
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001634 case 0325:
1635 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001636
H. Peter Anvine2c80182005-01-15 22:15:51 +00001637 case 0330:
1638 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001639 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001640 offset += 1;
1641 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001642
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001644 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001645
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001646 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001648 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001649 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 offset += 1;
1651 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001652
Keith Kanios48af1772007-08-17 07:37:52 +00001653 case 0334:
1654 if (ins->rex & REX_R) {
1655 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001656 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001657 offset += 1;
1658 }
1659 ins->rex &= ~(REX_L|REX_R);
1660 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001661
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001662 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001663 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001664
H. Peter Anvin962e3052008-08-28 17:47:16 -07001665 case 0336:
1666 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001667 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001668
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 if (ins->oprs[0].segment != NO_SEG)
1671 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1672 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001673 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 if (size > 0)
1675 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001676 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001677 offset += size;
1678 }
1679 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001680
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001681 case 0341:
1682 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001683
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001684 case 0344:
1685 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001686 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001687 switch (ins->oprs[0].basereg) {
1688 case R_CS:
1689 bytes[0] += 0x0E;
1690 break;
1691 case R_DS:
1692 bytes[0] += 0x1E;
1693 break;
1694 case R_ES:
1695 bytes[0] += 0x06;
1696 break;
1697 case R_SS:
1698 bytes[0] += 0x16;
1699 break;
1700 default:
1701 errfunc(ERR_PANIC,
1702 "bizarre 8086 segment register received");
1703 }
1704 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1705 offset++;
1706 break;
1707
1708 case 0346:
1709 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001710 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001711 switch (ins->oprs[0].basereg) {
1712 case R_FS:
1713 bytes[0] += 0xA0;
1714 break;
1715 case R_GS:
1716 bytes[0] += 0xA8;
1717 break;
1718 default:
1719 errfunc(ERR_PANIC,
1720 "bizarre 386 segment register received");
1721 }
1722 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1723 offset++;
1724 break;
1725
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001726 case 0360:
1727 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001728
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001729 case 0361:
1730 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001731 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1732 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001733 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001734
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001735 case 0362:
1736 case 0363:
1737 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001738 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1739 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001740 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001741
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001742 case 0364:
1743 case 0365:
1744 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001745
Keith Kanios48af1772007-08-17 07:37:52 +00001746 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001747 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001748 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001749 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001750 offset += 1;
1751 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001752
H. Peter Anvine2c80182005-01-15 22:15:51 +00001753 case 0370:
1754 case 0371:
1755 case 0372:
1756 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001757
H. Peter Anvine2c80182005-01-15 22:15:51 +00001758 case 0373:
1759 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001760 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001761 offset += 1;
1762 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001763
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001764 case 0374:
1765 eat = EA_XMMVSIB;
1766 break;
1767
1768 case 0375:
1769 eat = EA_YMMVSIB;
1770 break;
1771
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001772 case4(0100):
1773 case4(0110):
1774 case4(0120):
1775 case4(0130):
1776 case4(0200):
1777 case4(0204):
1778 case4(0210):
1779 case4(0214):
1780 case4(0220):
1781 case4(0224):
1782 case4(0230):
1783 case4(0234):
1784 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001785 ea ea_data;
1786 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001787 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001788 uint8_t *p;
1789 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001790 enum out_type type;
1791 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001792
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001793 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001794 /* pick rfield from operand b (opx) */
1795 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001796 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001797 } else {
1798 /* rfield is constant */
1799 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001800 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001801 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001802
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001803 if (process_ea(opy, &ea_data, bits, ins->addr_size,
1804 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001805 errfunc(ERR_NONFATAL, "invalid effective address");
1806 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001807
Charles Crayne7e975552007-11-03 22:06:13 -07001808
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 p = bytes;
1810 *p++ = ea_data.modrm;
1811 if (ea_data.sib_present)
1812 *p++ = ea_data.sib;
1813
1814 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001815 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001816
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001817 /*
1818 * Make sure the address gets the right offset in case
1819 * the line breaks in the .lst file (BR 1197827)
1820 */
1821 offset += s;
1822 s = 0;
1823
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 switch (ea_data.bytes) {
1825 case 0:
1826 break;
1827 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001828 case 2:
1829 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001830 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001831 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001832 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001833 if (ea_data.rip) {
1834 if (opy->segment == segment) {
1835 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001836 if (overflow_signed(data, ea_data.bytes))
1837 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001838 out(offset, segment, &data, OUT_ADDRESS,
1839 ea_data.bytes, NO_SEG, NO_SEG);
1840 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001841 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001842 out(offset, segment, &data, OUT_REL4ADR,
1843 insn_end - offset, opy->segment, opy->wrt);
1844 }
1845 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001846 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1847 signed_bits(opy->offset, ins->addr_size) !=
1848 signed_bits(opy->offset, ea_data.bytes * 8))
1849 warn_overflow(ERR_PASS2, ea_data.bytes);
1850
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001851 type = OUT_ADDRESS;
1852 out(offset, segment, &data, OUT_ADDRESS,
1853 ea_data.bytes, opy->segment, opy->wrt);
1854 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001855 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001856 default:
1857 /* Impossible! */
1858 errfunc(ERR_PANIC,
1859 "Invalid amount of bytes (%d) for offset?!",
1860 ea_data.bytes);
1861 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001862 }
1863 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001864 }
1865 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001866
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001867 default:
1868 errfunc(ERR_PANIC, "internal instruction table corrupt"
1869 ": instruction code \\%o (0x%02X) given", c, c);
1870 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001871 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001872 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001873}
1874
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001875static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001876{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001877 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001878 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001879 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001880}
1881
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001882static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001883{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001884 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001885 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001886 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001887}
1888
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001889static int op_rexflags(const operand * o, int mask)
1890{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001891 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001892 int val;
1893
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001894 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001895 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001896
H. Peter Anvina4835d42008-05-20 14:21:29 -07001897 flags = nasm_reg_flags[o->basereg];
1898 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001899
1900 return rexflags(val, flags, mask);
1901}
1902
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001903static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001904{
1905 int rex = 0;
1906
1907 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001908 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001909 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001910 rex |= REX_W;
1911 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1912 rex |= REX_H;
1913 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1914 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001915
1916 return rex & mask;
1917}
1918
H. Peter Anvin23595f52009-07-25 17:44:25 -07001919static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001920 insn *instruction,
1921 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001922{
1923 const struct itemplate *temp;
1924 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001925 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001926 bool opsizemissing = false;
1927 int i;
1928
1929 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001930 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001931
1932 merr = MERR_INVALOP;
1933
1934 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001935 temp->opcode != I_none; temp++) {
1936 m = matches(temp, instruction, bits);
1937 if (m == MOK_JUMP) {
1938 if (jmp_match(segment, offset, bits, instruction, temp->code))
1939 m = MOK_GOOD;
1940 else
1941 m = MERR_INVALOP;
1942 } else if (m == MERR_OPSIZEMISSING &&
1943 (temp->flags & IF_SMASK) != IF_SX) {
1944 /*
1945 * Missing operand size and a candidate for fuzzy matching...
1946 */
1947 for (i = 0; i < temp->operands; i++) {
1948 if ((temp->opd[i] & SAME_AS) == 0)
1949 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1950 }
1951 opsizemissing = true;
1952 }
1953 if (m > merr)
1954 merr = m;
1955 if (merr == MOK_GOOD)
1956 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001957 }
1958
1959 /* No match, but see if we can get a fuzzy operand size match... */
1960 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001961 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001962
1963 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001964 /*
1965 * We ignore extrinsic operand sizes on registers, so we should
1966 * never try to fuzzy-match on them. This also resolves the case
1967 * when we have e.g. "xmmrm128" in two different positions.
1968 */
1969 if (is_class(REGISTER, instruction->oprs[i].type))
1970 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001971
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001972 /* This tests if xsizeflags[i] has more than one bit set */
1973 if ((xsizeflags[i] & (xsizeflags[i]-1)))
1974 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001975
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001976 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001977 }
1978
1979 /* Try matching again... */
1980 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001981 temp->opcode != I_none; temp++) {
1982 m = matches(temp, instruction, bits);
1983 if (m == MOK_JUMP) {
1984 if (jmp_match(segment, offset, bits, instruction, temp->code))
1985 m = MOK_GOOD;
1986 else
1987 m = MERR_INVALOP;
1988 }
1989 if (m > merr)
1990 merr = m;
1991 if (merr == MOK_GOOD)
1992 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001993 }
1994
H. Peter Anvina81655b2009-07-25 18:15:28 -07001995done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07001996 *tempp = temp;
1997 return merr;
1998}
1999
H. Peter Anvin65289e82009-07-25 17:25:11 -07002000static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002001 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002002{
H. Peter Anvin60926242009-07-26 16:25:38 -07002003 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002004 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002005
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002006 /*
2007 * Check the opcode
2008 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002009 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002010 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002011
2012 /*
2013 * Count the operands
2014 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002015 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002016 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002017
2018 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002019 * Is it legal?
2020 */
2021 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2022 return MERR_INVALOP;
2023
2024 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002025 * Check that no spurious colons or TOs are present
2026 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002027 for (i = 0; i < itemp->operands; i++)
2028 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002029 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002030
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002031 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002032 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002033 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002034 switch (itemp->flags & IF_SMASK) {
2035 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002036 asize = BITS8;
2037 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002038 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002039 asize = BITS16;
2040 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002041 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002042 asize = BITS32;
2043 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002044 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002045 asize = BITS64;
2046 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002047 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002048 asize = BITS128;
2049 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002050 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002051 asize = BITS256;
2052 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002053 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002054 switch (bits) {
2055 case 16:
2056 asize = BITS16;
2057 break;
2058 case 32:
2059 asize = BITS32;
2060 break;
2061 case 64:
2062 asize = BITS64;
2063 break;
2064 default:
2065 asize = 0;
2066 break;
2067 }
2068 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002069 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002070 asize = 0;
2071 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002072 }
2073
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002074 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002075 /* S- flags only apply to a specific operand */
2076 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2077 memset(size, 0, sizeof size);
2078 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002079 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002080 /* S- flags apply to all operands */
2081 for (i = 0; i < MAX_OPERANDS; i++)
2082 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002083 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002084
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002085 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002086 * Check that the operand flags all match up,
2087 * it's a bit tricky so lets be verbose:
2088 *
2089 * 1) Find out the size of operand. If instruction
2090 * doesn't have one specified -- we're trying to
2091 * guess it either from template (IF_S* flag) or
2092 * from code bits.
2093 *
2094 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2095 * (ie the same operand as was specified somewhere in template, and
2096 * this referred operand index is being achieved via ~SAME_AS)
2097 * we are to be sure that both registers (in template and instruction)
2098 * do exactly match.
2099 *
2100 * 3) If template operand do not match the instruction OR
2101 * template has an operand size specified AND this size differ
2102 * from which instruction has (perhaps we got it from code bits)
2103 * we are:
2104 * a) Check that only size of instruction and operand is differ
2105 * other characteristics do match
2106 * b) Perhaps it's a register specified in instruction so
2107 * for such a case we just mark that operand as "size
2108 * missing" and this will turn on fuzzy operand size
2109 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002110 */
2111 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002112 opflags_t type = instruction->oprs[i].type;
2113 if (!(type & SIZE_MASK))
2114 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002115
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002116 if (itemp->opd[i] & SAME_AS) {
2117 int j = itemp->opd[i] & ~SAME_AS;
2118 if (type != instruction->oprs[j].type ||
2119 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2120 return MERR_INVALOP;
2121 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002122 ((itemp->opd[i] & SIZE_MASK) &&
2123 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002124 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002125 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002126 } else if (!is_class(REGISTER, type)) {
2127 /*
2128 * Note: we don't honor extrinsic operand sizes for registers,
2129 * so "missing operand size" for a register should be
2130 * considered a wildcard match rather than an error.
2131 */
2132 opsizemissing = true;
2133 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002134 }
2135 }
2136
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002137 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002138 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002139
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002140 /*
2141 * Check operand sizes
2142 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002143 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002144 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002145 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002146 asize = itemp->opd[i] & SIZE_MASK;
2147 if (asize) {
2148 for (i = 0; i < oprs; i++)
2149 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002150 break;
2151 }
2152 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002153 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002154 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002155 }
2156
Keith Kaniosb7a89542007-04-12 02:40:54 +00002157 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002158 if (!(itemp->opd[i] & SIZE_MASK) &&
2159 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002160 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002161 }
2162
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002163 /*
2164 * Check template is okay at the set cpu level
2165 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002166 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002167 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002168
Keith Kaniosb7a89542007-04-12 02:40:54 +00002169 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002170 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002171 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002172 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002173 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002174
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002175 /*
2176 * Check if special handling needed for Jumps
2177 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002178 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002179 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002180
H. Peter Anvin60926242009-07-26 16:25:38 -07002181 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002182}
2183
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002184static enum ea_type process_ea(operand * input, ea * output, int bits,
2185 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002186{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002187 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002188
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002189 output->type = EA_SCALAR;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002190 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002191
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002192 /* REX flags for the rfield operand */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002193 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002194
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002195 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002196 int i;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002197 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002198
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002199 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002200 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002201 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002202 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002203
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002204 if (REG_EA & ~f)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002205 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002206
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002207 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002208
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002209 output->sib_present = false; /* no SIB necessary */
2210 output->bytes = 0; /* no offset necessary either */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002211 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002212 } else { /* it's a memory reference */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002213 if (input->basereg == -1 &&
2214 (input->indexreg == -1 || input->scale == 0)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002215 /* it's a pure offset */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002216
2217 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2218 input->segment == NO_SEG) {
2219 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2220 input->type &= ~IP_REL;
2221 input->type |= MEMORY;
2222 }
2223
2224 if (input->eaflags & EAF_BYTEOFFS ||
2225 (input->eaflags & EAF_WORDOFFS &&
2226 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2227 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2228 }
2229
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002230 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002231 int scale, index, base;
2232 output->sib_present = true;
2233 scale = 0;
2234 index = 4;
2235 base = 5;
2236 output->sib = (scale << 6) | (index << 3) | base;
2237 output->bytes = 4;
2238 output->modrm = 4 | ((rfield & 7) << 3);
2239 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002240 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002241 output->sib_present = false;
2242 output->bytes = (addrbits != 16 ? 4 : 2);
2243 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
2244 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002245 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002246 } else { /* it's an indirection */
2247 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002248 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002249 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002250 int t, it, bt; /* register numbers */
2251 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002252
H. Peter Anvine2c80182005-01-15 22:15:51 +00002253 if (s == 0)
2254 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002255
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002256 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002257 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002258 ix = nasm_reg_flags[i];
2259 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002260 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002261 ix = 0;
2262 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002263
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002264 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002265 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002266 bx = nasm_reg_flags[b];
2267 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002268 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002269 bx = 0;
2270 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002271
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002272 /* if either one are a vector register... */
2273 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
2274 int32_t sok = BITS32 | BITS64;
2275 int32_t o = input->offset;
2276 int mod, scale, index, base;
2277
2278 printf("bt = %x, bx = %x, it = %x, ix = %x, s = %d\n",
2279 bt, bx, it, ix, s);
2280
2281 /*
2282 * For a vector SIB, one has to be a vector and the other,
2283 * if present, a GPR. The vector must be the index operand.
2284 */
2285 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2286 if (s == 0)
2287 s = 1;
2288 else if (s != 1)
2289 goto err;
2290
2291 t = bt, bt = it, it = t;
2292 x = bx, bx = ix, ix = x;
2293 }
2294
2295 if (bt != -1) {
2296 if (REG_GPR & ~bx)
2297 goto err;
2298 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2299 sok &= bx;
2300 else
2301 goto err;
2302 }
2303
2304 /*
2305 * While we're here, ensure the user didn't specify
2306 * WORD or QWORD
2307 */
2308 if (input->disp_size == 16 || input->disp_size == 64)
2309 goto err;
2310
2311 if (addrbits == 16 ||
2312 (addrbits == 32 && !(sok & BITS32)) ||
2313 (addrbits == 64 && !(sok & BITS64)))
2314 goto err;
2315
2316 output->type = (ix & YMMREG & ~REG_EA)
2317 ? EA_YMMVSIB : EA_XMMVSIB;
2318
2319 output->rex |= rexflags(it, ix, REX_X);
2320 output->rex |= rexflags(bt, bx, REX_B);
2321
2322 index = it & 7; /* it is known to be != -1 */
2323
2324 switch (s) {
2325 case 1:
2326 scale = 0;
2327 break;
2328 case 2:
2329 scale = 1;
2330 break;
2331 case 4:
2332 scale = 2;
2333 break;
2334 case 8:
2335 scale = 3;
2336 break;
2337 default: /* then what the smeg is it? */
2338 goto err; /* panic */
2339 }
2340
2341 if (bt == -1) {
2342 base = 5;
2343 mod = 0;
2344 } else {
2345 base = (bt & 7);
2346 if (base != REG_NUM_EBP && o == 0 &&
2347 seg == NO_SEG && !forw_ref &&
2348 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2349 mod = 0;
2350 else if (input->eaflags & EAF_BYTEOFFS ||
2351 (o >= -128 && o <= 127 &&
2352 seg == NO_SEG && !forw_ref &&
2353 !(input->eaflags & EAF_WORDOFFS)))
2354 mod = 1;
2355 else
2356 mod = 2;
2357 }
2358
2359 output->sib_present = true;
2360 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2361 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
2362 output->sib = (scale << 6) | (index << 3) | base;
2363 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002364 /*
2365 * it must be a 32/64-bit memory reference. Firstly we have
2366 * to check that all registers involved are type E/Rxx.
2367 */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002368 int32_t sok = BITS32 | BITS64;
2369 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002370
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002371 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002372 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2373 sok &= ix;
2374 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002375 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002376 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002377
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002378 if (bt != -1) {
2379 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002380 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002381 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002382 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002383 sok &= bx;
2384 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002385
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002386 /*
2387 * While we're here, ensure the user didn't specify
2388 * WORD or QWORD
2389 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002390 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002391 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002392
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002393 if (addrbits == 16 ||
2394 (addrbits == 32 && !(sok & BITS32)) ||
2395 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002396 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002397
Keith Kaniosb7a89542007-04-12 02:40:54 +00002398 /* now reorganize base/index */
2399 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002400 ((hb == b && ht == EAH_NOTBASE) ||
2401 (hb == i && ht == EAH_MAKEBASE))) {
2402 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002403 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002404 x = bx, bx = ix, ix = x;
2405 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002406 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002407 bt = -1, bx = 0, s++;
2408 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002409 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002410 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002411 }
2412 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2413 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002414 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002415 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2416 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002417 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002418 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002419 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002420 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002421 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002422 x = ix, ix = bx, bx = x;
2423 }
2424 if (it == REG_NUM_ESP ||
2425 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002426 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002427
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002428 output->rex |= rexflags(it, ix, REX_X);
2429 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002430
Keith Kanios48af1772007-08-17 07:37:52 +00002431 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002432 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002433 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002434
Keith Kaniosb7a89542007-04-12 02:40:54 +00002435 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002436 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002437 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002438 } else {
2439 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002440 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002441 seg == NO_SEG && !forw_ref &&
2442 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002443 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002444 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002445 (o >= -128 && o <= 127 &&
2446 seg == NO_SEG && !forw_ref &&
2447 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002448 mod = 1;
2449 else
2450 mod = 2;
2451 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002452
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002453 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002454 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2455 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002456 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002457 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002458 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002459
Keith Kaniosb7a89542007-04-12 02:40:54 +00002460 if (it == -1)
2461 index = 4, s = 1;
2462 else
2463 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002464
H. Peter Anvine2c80182005-01-15 22:15:51 +00002465 switch (s) {
2466 case 1:
2467 scale = 0;
2468 break;
2469 case 2:
2470 scale = 1;
2471 break;
2472 case 4:
2473 scale = 2;
2474 break;
2475 case 8:
2476 scale = 3;
2477 break;
2478 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002479 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002480 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002481
Keith Kaniosb7a89542007-04-12 02:40:54 +00002482 if (bt == -1) {
2483 base = 5;
2484 mod = 0;
2485 } else {
2486 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002487 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002488 seg == NO_SEG && !forw_ref &&
2489 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002490 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002491 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002492 (o >= -128 && o <= 127 &&
2493 seg == NO_SEG && !forw_ref &&
2494 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002495 mod = 1;
2496 else
2497 mod = 2;
2498 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002499
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002500 output->sib_present = true;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002501 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002502 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002503 output->sib = (scale << 6) | (index << 3) | base;
2504 }
2505 } else { /* it's 16-bit */
2506 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002507 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002508
Keith Kaniosb7a89542007-04-12 02:40:54 +00002509 /* check for 64-bit long mode */
2510 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002511 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002512
H. Peter Anvine2c80182005-01-15 22:15:51 +00002513 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002514 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2515 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002516 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002517
Keith Kaniosb7a89542007-04-12 02:40:54 +00002518 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002519 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002520 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002521
H. Peter Anvine2c80182005-01-15 22:15:51 +00002522 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002523 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002524 if (b == -1 && i != -1) {
2525 int tmp = b;
2526 b = i;
2527 i = tmp;
2528 } /* swap */
2529 if ((b == R_SI || b == R_DI) && i != -1) {
2530 int tmp = b;
2531 b = i;
2532 i = tmp;
2533 }
2534 /* have BX/BP as base, SI/DI index */
2535 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002536 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002537 if (i != -1 && b != -1 &&
2538 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002539 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002540 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002541 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002542
H. Peter Anvine2c80182005-01-15 22:15:51 +00002543 rm = -1;
2544 if (i != -1)
2545 switch (i * 256 + b) {
2546 case R_SI * 256 + R_BX:
2547 rm = 0;
2548 break;
2549 case R_DI * 256 + R_BX:
2550 rm = 1;
2551 break;
2552 case R_SI * 256 + R_BP:
2553 rm = 2;
2554 break;
2555 case R_DI * 256 + R_BP:
2556 rm = 3;
2557 break;
2558 } else
2559 switch (b) {
2560 case R_SI:
2561 rm = 4;
2562 break;
2563 case R_DI:
2564 rm = 5;
2565 break;
2566 case R_BP:
2567 rm = 6;
2568 break;
2569 case R_BX:
2570 rm = 7;
2571 break;
2572 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002573 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002574 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002575
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002576 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2577 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002578 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002579 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002580 (o >= -128 && o <= 127 && seg == NO_SEG &&
2581 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002582 mod = 1;
2583 else
2584 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002585
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002586 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002587 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002588 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002589 }
2590 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002591 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002592
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002593 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002594 return output->type;
2595
2596err:
2597 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002598}
2599
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002600static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002601{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002602 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002603 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002604
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002605 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002606
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002607 switch (ins->prefixes[PPS_ASIZE]) {
2608 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002609 valid &= 16;
2610 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002611 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002612 valid &= 32;
2613 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002614 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002615 valid &= 64;
2616 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002617 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002618 valid &= (addrbits == 32) ? 16 : 32;
2619 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002620 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002621 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002622 }
2623
2624 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002625 if (is_class(MEMORY, ins->oprs[j].type)) {
2626 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002627
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002628 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002629 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002630 i = 0;
2631 else
2632 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002633
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002634 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002635 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002636 b = 0;
2637 else
2638 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002639
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002640 if (ins->oprs[j].scale == 0)
2641 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002642
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002643 if (!i && !b) {
2644 int ds = ins->oprs[j].disp_size;
2645 if ((addrbits != 64 && ds > 8) ||
2646 (addrbits == 64 && ds == 16))
2647 valid &= ds;
2648 } else {
2649 if (!(REG16 & ~b))
2650 valid &= 16;
2651 if (!(REG32 & ~b))
2652 valid &= 32;
2653 if (!(REG64 & ~b))
2654 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002655
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002656 if (!(REG16 & ~i))
2657 valid &= 16;
2658 if (!(REG32 & ~i))
2659 valid &= 32;
2660 if (!(REG64 & ~i))
2661 valid &= 64;
2662 }
2663 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002664 }
2665
2666 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002667 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002668 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002669 /* Add an address size prefix */
2670 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2671 ins->prefixes[PPS_ASIZE] = pref;
2672 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002673 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002674 /* Impossible... */
2675 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2676 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002677 }
2678
2679 defdisp = ins->addr_size == 16 ? 16 : 32;
2680
2681 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002682 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2683 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2684 /*
2685 * mem_offs sizes must match the address size; if not,
2686 * strip the MEM_OFFS bit and match only EA instructions
2687 */
2688 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2689 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002690 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002691}