blob: 1697ac7494e341c14198d34ac47999a76e8776a2 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -08003 * Copyright 1996-2012 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.
H. Peter Anvincffe61e2011-07-07 17:21:24 -070073 * \174..\177 - the register number from operand 0..3 in bits 7..4, and
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040074 * 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.
H. Peter Anvin8ea22002012-02-25 10:24:24 -080083 * \264 - skip this instruction pattern if HLE prefixes present
84 * \265 - instruction takes XRELEASE (F3) with or without lock
85 * \266 - instruction takes XACQUIRE/XRELEASE with or without lock
86 * \267 - instruction takes XACQUIRE/XRELEASE with lock only
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040087 * \270 - this instruction uses VEX/XOP rather than REX, with the
88 * V field set to 1111b.
H. Peter Anvind85d2502008-05-04 17:53:31 -070089 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070090 * VEX/XOP prefixes are followed by the sequence:
91 * \tmm\wlp where mm is the M field; and wlp is:
H. Peter Anvin421059c2010-08-16 14:56:33 -070092 * 00 wwl lpp
93 * [l0] ll = 0 for L = 0 (.128, .lz)
94 * [l1] ll = 1 for L = 1 (.256)
95 * [lig] ll = 2 for L don't care (always assembled as 0)
96 *
H. Peter Anvin978c2172010-08-16 13:48:43 -070097 * [w0] ww = 0 for W = 0
98 * [w1 ] ww = 1 for W = 1
99 * [wig] ww = 2 for W don't care (always assembled as 0)
100 * [ww] ww = 3 for W used as REX.W
H. Peter Anvinbd420c72008-05-22 11:24:35 -0700101 *
H. Peter Anvina04019c2009-05-03 21:42:34 -0700102 * t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
H. Peter Anvind85d2502008-05-04 17:53:31 -0700103 *
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700104 * \274..\277 - a signed byte immediate operand, from operand 0..3,
105 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000106 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
107 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -0700108 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +0000109 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -0800110 * \314 - (disassembler only) invalid with REX.B
111 * \315 - (disassembler only) invalid with REX.X
112 * \316 - (disassembler only) invalid with REX.R
113 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000114 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
115 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
116 * \322 - indicates that this instruction is only valid when the
117 * operand size is the default (instruction to disassembler,
118 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000119 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000120 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400121 * \325 - instruction which always uses spl/bpl/sil/dil
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000122 * \330 - a literal byte follows in the code stream, to be added
123 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000124 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000125 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700126 * \332 - REP prefix (0xF2 byte) used as opcode extension.
127 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700128 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700129 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700130 * \336 - force a REP(E) prefix (0xF2) even if not specified.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400131 * \337 - force a REPNE prefix (0xF3) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700132 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000133 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000134 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400135 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700136 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
137 * (POP is never used for CS) depending on operand 0
138 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
139 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400140 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700141 * \361 - 66 SSE prefix (== \366\331)
142 * \362 - F2 SSE prefix (== \364\332)
143 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000144 * \364 - operand-size prefix (0x66) not permitted
145 * \365 - address-size prefix (0x67) not permitted
146 * \366 - operand-size prefix (0x66) used as opcode extension
147 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000148 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400149 * 370 is used for Jcc, 371 is used for JMP.
150 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
151 * used for conditional jump over longer jump
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700152 * \374 - this instruction takes an XMM VSIB memory EA
153 * \375 - this instruction takes an YMM VSIB memory EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000154 */
155
H. Peter Anvinfe501952007-10-02 21:53:51 -0700156#include "compiler.h"
157
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000158#include <stdio.h>
159#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000160#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000161
162#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000163#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000164#include "assemble.h"
165#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700166#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000167
H. Peter Anvin65289e82009-07-25 17:25:11 -0700168enum match_result {
169 /*
170 * Matching errors. These should be sorted so that more specific
171 * errors come later in the sequence.
172 */
173 MERR_INVALOP,
174 MERR_OPSIZEMISSING,
175 MERR_OPSIZEMISMATCH,
176 MERR_BADCPU,
177 MERR_BADMODE,
178 /*
179 * Matching success; the conditional ones first
180 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400181 MOK_JUMP, /* Matching OK but needs jmp_match() */
182 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700183};
184
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000185typedef struct {
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700186 enum ea_type type; /* what kind of EA is this? */
187 int sib_present; /* is a SIB byte necessary? */
188 int bytes; /* # of bytes of offset needed */
189 int size; /* lazy - this is sib+bytes+1 */
190 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000191} ea;
192
Cyrill Gorcunov10734c72011-08-29 00:07:17 +0400193#define GEN_SIB(scale, index, base) \
194 (((scale) << 6) | ((index) << 3) | ((base)))
195
196#define GEN_MODRM(mod, reg, rm) \
197 (((mod) << 6) | (((reg) & 7) << 3) | ((rm) & 7))
198
Keith Kaniosb7a89542007-04-12 02:40:54 +0000199static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000200static efunc errfunc;
201static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000202static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000203
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700204static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700205static void gencode(int32_t segment, int64_t offset, int bits,
206 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400207 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700208static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400209 insn *instruction,
210 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700211static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700212static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000213static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700214static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000215static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700216static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000217
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700218static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
219
Cyrill Gorcunov18914e62011-11-12 11:41:51 +0400220static int has_prefix(insn * ins, enum prefix_pos pos, int prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000221{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700222 return ins->prefixes[pos] == prefix;
223}
224
225static void assert_no_prefix(insn * ins, enum prefix_pos pos)
226{
227 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400228 errfunc(ERR_NONFATAL, "invalid %s prefix",
229 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700230}
231
232static const char *size_name(int size)
233{
234 switch (size) {
235 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400236 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700237 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400238 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700239 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400240 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700241 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400242 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700243 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400244 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700245 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400246 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700247 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400248 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700249 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400250 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000251 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700252}
253
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400254static void warn_overflow(int pass, int size)
255{
256 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
257 "%s data exceeds bounds", size_name(size));
258}
259
260static void warn_overflow_const(int64_t data, int size)
261{
262 if (overflow_general(data, size))
263 warn_overflow(ERR_PASS1, size);
264}
265
266static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700267{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100268 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400269 if (overflow_general(o->offset, size))
270 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700271 }
272}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400273
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000274/*
275 * This routine wrappers the real output format's output routine,
276 * in order to pass a copy of the data off to the listing file
277 * generator at the same time.
278 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800279static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800280 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400281 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000282{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000283 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000284 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800285 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000286
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800287 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400288 /*
289 * This is a non-relocated address, and we're going to
290 * convert it into RAWDATA format.
291 */
292 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800293
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400294 if (size > 8) {
295 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
296 return;
297 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700298
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400299 WRITEADDR(q, *(int64_t *)data, size);
300 data = p;
301 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000302 }
303
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800304 list->output(offset, data, type, size);
305
Frank Kotlerabebb082003-09-06 04:45:37 +0000306 /*
307 * this call to src_get determines when we call the
308 * debug-format-specific "linenum" function
309 * it updates lineno and lnfname to the current values
310 * returning 0 if "same as last time", -2 if lnfname
311 * changed, and the amount by which lineno changed,
312 * if it did. thus, these variables must be static
313 */
314
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400315 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000317
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800318 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000319}
320
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700321static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700322 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000323{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800324 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000325 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000326
Charles Craynef1aefd82008-09-30 16:11:32 -0700327 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700328 return false;
329 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400330 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700331 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400332 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700333
H. Peter Anvine2c80182005-01-15 22:15:51 +0000334 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100335
Victor van den Elzen154e5922009-02-25 17:32:00 +0100336 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100337 /* Be optimistic in pass 1 */
338 return true;
339
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700341 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000342
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700343 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
344 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000346
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800347int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400348 insn * instruction, struct ofmt *output, efunc error,
349 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000350{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000351 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000352 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700353 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800354 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000355 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800356 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300357 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000358
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000360 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 outfmt = output; /* likewise */
362 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000363
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300364 wsize = idata_bytes(instruction->opcode);
365 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000367
H. Peter Anvineba20a72002-04-30 20:53:55 +0000368 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000369 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000370 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 if (t < 0)
372 errfunc(ERR_PANIC,
373 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000374
H. Peter Anvine2c80182005-01-15 22:15:51 +0000375 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400376 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400378 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700379 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400380 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000381 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700382 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000383 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800384 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400385 offset += wsize;
386 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700387 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400388 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000390
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800392 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000393 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000394
H. Peter Anvine2c80182005-01-15 22:15:51 +0000395 if (align) {
396 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100397 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800398 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 }
400 offset += e->stringlen + align;
401 }
402 }
403 if (t > 0 && t == instruction->times - 1) {
404 /*
405 * Dummy call to list->output to give the offset to the
406 * listing module.
407 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800408 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 list->uplevel(LIST_TIMES);
410 }
411 }
412 if (instruction->times > 1)
413 list->downlevel(LIST_TIMES);
414 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000415 }
416
H. Peter Anvine2c80182005-01-15 22:15:51 +0000417 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700418 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000419 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000420
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400421 fp = fopen(fname, "rb");
422 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000423 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
424 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400425 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000426 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
427 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400428 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700429 static char buf[4096];
430 size_t t = instruction->times;
431 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400432 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000433
H. Peter Anvine2c80182005-01-15 22:15:51 +0000434 len = ftell(fp);
435 if (instruction->eops->next) {
436 base = instruction->eops->next->offset;
437 len -= base;
438 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700439 len > (size_t)instruction->eops->next->next->offset)
440 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 }
442 /*
443 * Dummy call to list->output to give the offset to the
444 * listing module.
445 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800446 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000447 list->uplevel(LIST_INCBIN);
448 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700449 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000450
H. Peter Anvine2c80182005-01-15 22:15:51 +0000451 fseek(fp, base, SEEK_SET);
452 l = len;
453 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700454 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400455 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000456 if (!m) {
457 /*
458 * This shouldn't happen unless the file
459 * actually changes while we are reading
460 * it.
461 */
462 error(ERR_NONFATAL,
463 "`incbin': unexpected EOF while"
464 " reading file `%s'", fname);
465 t = 0; /* Try to exit cleanly */
466 break;
467 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800468 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000469 NO_SEG, NO_SEG);
470 l -= m;
471 }
472 }
473 list->downlevel(LIST_INCBIN);
474 if (instruction->times > 1) {
475 /*
476 * Dummy call to list->output to give the offset to the
477 * listing module.
478 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800479 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000480 list->uplevel(LIST_TIMES);
481 list->downlevel(LIST_TIMES);
482 }
483 fclose(fp);
484 return instruction->times * len;
485 }
486 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000487 }
488
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700489 /* Check to see if we need an address-size prefix */
490 add_asp(instruction, bits);
491
H. Peter Anvin23595f52009-07-25 17:44:25 -0700492 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700493
H. Peter Anvin23595f52009-07-25 17:44:25 -0700494 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400495 /* Matches! */
496 int64_t insn_size = calcsize(segment, offset, bits,
497 instruction, temp->code);
498 itimes = instruction->times;
499 if (insn_size < 0) /* shouldn't be, on pass two */
500 error(ERR_PANIC, "errors made it through from pass one");
501 else
502 while (itimes--) {
503 for (j = 0; j < MAXPREFIX; j++) {
504 uint8_t c = 0;
505 switch (instruction->prefixes[j]) {
506 case P_WAIT:
507 c = 0x9B;
508 break;
509 case P_LOCK:
510 c = 0xF0;
511 break;
512 case P_REPNE:
513 case P_REPNZ:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800514 case P_XACQUIRE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400515 c = 0xF2;
516 break;
517 case P_REPE:
518 case P_REPZ:
519 case P_REP:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800520 case P_XRELEASE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400521 c = 0xF3;
522 break;
523 case R_CS:
524 if (bits == 64) {
525 error(ERR_WARNING | ERR_PASS2,
526 "cs segment base generated, but will be ignored in 64-bit mode");
527 }
528 c = 0x2E;
529 break;
530 case R_DS:
531 if (bits == 64) {
532 error(ERR_WARNING | ERR_PASS2,
533 "ds segment base generated, but will be ignored in 64-bit mode");
534 }
535 c = 0x3E;
536 break;
537 case R_ES:
538 if (bits == 64) {
539 error(ERR_WARNING | ERR_PASS2,
540 "es segment base generated, but will be ignored in 64-bit mode");
541 }
542 c = 0x26;
543 break;
544 case R_FS:
545 c = 0x64;
546 break;
547 case R_GS:
548 c = 0x65;
549 break;
550 case R_SS:
551 if (bits == 64) {
552 error(ERR_WARNING | ERR_PASS2,
553 "ss segment base generated, but will be ignored in 64-bit mode");
554 }
555 c = 0x36;
556 break;
557 case R_SEGR6:
558 case R_SEGR7:
559 error(ERR_NONFATAL,
560 "segr6 and segr7 cannot be used as prefixes");
561 break;
562 case P_A16:
563 if (bits == 64) {
564 error(ERR_NONFATAL,
565 "16-bit addressing is not supported "
566 "in 64-bit mode");
567 } else if (bits != 16)
568 c = 0x67;
569 break;
570 case P_A32:
571 if (bits != 32)
572 c = 0x67;
573 break;
574 case P_A64:
575 if (bits != 64) {
576 error(ERR_NONFATAL,
577 "64-bit addressing is only supported "
578 "in 64-bit mode");
579 }
580 break;
581 case P_ASP:
582 c = 0x67;
583 break;
584 case P_O16:
585 if (bits != 16)
586 c = 0x66;
587 break;
588 case P_O32:
589 if (bits == 16)
590 c = 0x66;
591 break;
592 case P_O64:
593 /* REX.W */
594 break;
595 case P_OSP:
596 c = 0x66;
597 break;
598 case P_none:
599 break;
600 default:
601 error(ERR_PANIC, "invalid instruction prefix");
602 }
603 if (c != 0) {
604 out(offset, segment, &c, OUT_RAWDATA, 1,
605 NO_SEG, NO_SEG);
606 offset++;
607 }
608 }
609 insn_end = offset + insn_size;
610 gencode(segment, offset, bits, instruction,
611 temp, insn_end);
612 offset += insn_size;
613 if (itimes > 0 && itimes == instruction->times - 1) {
614 /*
615 * Dummy call to list->output to give the offset to the
616 * listing module.
617 */
618 list->output(offset, NULL, OUT_RAWDATA, 0);
619 list->uplevel(LIST_TIMES);
620 }
621 }
622 if (instruction->times > 1)
623 list->downlevel(LIST_TIMES);
624 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700625 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400626 /* No match */
627 switch (m) {
628 case MERR_OPSIZEMISSING:
629 error(ERR_NONFATAL, "operation size not specified");
630 break;
631 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000632 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400633 break;
634 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000635 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400636 break;
637 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800638 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400639 bits);
640 break;
641 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000642 error(ERR_NONFATAL,
643 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400644 break;
645 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646 }
647 return 0;
648}
649
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800650int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400651 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000652{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000653 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700654 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000655
H. Peter Anvine2c80182005-01-15 22:15:51 +0000656 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000657 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000658
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400659 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000661
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700662 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
663 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400664 instruction->opcode == I_DT || instruction->opcode == I_DO ||
665 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000666 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300667 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000668
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300670 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000671
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400672 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000673 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000674
H. Peter Anvine2c80182005-01-15 22:15:51 +0000675 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400676 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400678 warn_overflow_const(e->offset, wsize);
679 } else if (e->type == EOT_DB_STRING ||
680 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000682
H. Peter Anvine2c80182005-01-15 22:15:51 +0000683 align = (-osize) % wsize;
684 if (align < 0)
685 align += wsize;
686 isize += osize + align;
687 }
688 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000689 }
690
H. Peter Anvine2c80182005-01-15 22:15:51 +0000691 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400692 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300694 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700695 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000696
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400697 fp = fopen(fname, "rb");
698 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000699 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
700 fname);
701 else if (fseek(fp, 0L, SEEK_END) < 0)
702 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
703 fname);
704 else {
705 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000706 if (instruction->eops->next) {
707 len -= instruction->eops->next->offset;
708 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700709 len > (size_t)instruction->eops->next->next->offset) {
710 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000711 }
712 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300713 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000714 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300715 if (fp)
716 fclose(fp);
717 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000718 }
719
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700720 /* Check to see if we need an address-size prefix */
721 add_asp(instruction, bits);
722
H. Peter Anvin23595f52009-07-25 17:44:25 -0700723 m = find_match(&temp, instruction, segment, offset, bits);
724 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400725 /* we've matched an instruction. */
726 int64_t isize;
727 const uint8_t *codes = temp->code;
728 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100729
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400730 isize = calcsize(segment, offset, bits, instruction, codes);
731 if (isize < 0)
732 return -1;
733 for (j = 0; j < MAXPREFIX; j++) {
734 switch (instruction->prefixes[j]) {
735 case P_A16:
736 if (bits != 16)
737 isize++;
738 break;
739 case P_A32:
740 if (bits != 32)
741 isize++;
742 break;
743 case P_O16:
744 if (bits != 16)
745 isize++;
746 break;
747 case P_O32:
748 if (bits == 16)
749 isize++;
750 break;
751 case P_A64:
752 case P_O64:
753 case P_none:
754 break;
755 default:
756 isize++;
757 break;
758 }
759 }
760 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700761 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400762 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000763 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000764}
765
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700766static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000767{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700768 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400769 !(o->opflags & OPFLAG_UNKNOWN) &&
770 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000771}
772
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700773/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700774static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700775{
776 int16_t v;
777
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700778 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400779 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700780
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700781 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700782 return v >= -128 && v <= 127;
783}
784
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700785static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700786{
787 int32_t v;
788
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700789 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400790 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700791
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700792 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700793 return v >= -128 && v <= 127;
794}
795
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800796static void bad_hle_warn(const insn * ins, uint8_t hleok)
797{
798 enum prefixes rep_pfx = ins->prefixes[PPS_REP];
799 enum whatwarn { w_none, w_lock, w_inval };
800 static const enum whatwarn warn[2][4] =
801 {
802 { w_inval, w_inval, w_none, w_lock }, /* XACQUIRE */
803 { w_inval, w_none, w_none, w_lock }, /* XRELEASE */
804 };
805 unsigned int n;
806
807 n = (unsigned int)rep_pfx - P_XACQUIRE;
808 if (n > 1)
809 return; /* Not XACQUIRE/XRELEASE */
810
811 switch (warn[n][hleok]) {
812 case w_none:
813 break;
814
815 case w_lock:
816 if (ins->prefixes[PPS_LOCK] != P_LOCK) {
817 errfunc(ERR_WARNING | ERR_PASS2,
818 "%s with this instruction requires lock",
819 prefix_name(rep_pfx));
820 }
821 break;
822
823 case w_inval:
824 errfunc(ERR_WARNING | ERR_PASS2,
825 "%s invalid with this instruction",
826 prefix_name(rep_pfx));
827 break;
828 }
829}
830
H. Peter Anvin507ae032008-10-09 15:37:10 -0700831/* Common construct */
832#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
833
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800834static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400835 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000836{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800837 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000838 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000839 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700840 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700841 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700842 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700843 enum ea_type eat;
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800844 uint8_t hleok = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000845
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700846 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700847 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700848
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700849 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400850 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700851
H. Peter Anvine2c80182005-01-15 22:15:51 +0000852 (void)segment; /* Don't warn that this parameter is unused */
853 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000854
H. Peter Anvin839eca22007-10-29 23:12:47 -0700855 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400856 c = *codes++;
857 op1 = (c & 3) + ((opex & 1) << 2);
858 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
859 opx = &ins->oprs[op1];
860 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700861
H. Peter Anvin839eca22007-10-29 23:12:47 -0700862 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000863 case 01:
864 case 02:
865 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400866 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 codes += c, length += c;
868 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700869
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400870 case 05:
871 case 06:
872 case 07:
873 opex = c;
874 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700875
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400876 case4(010):
877 ins->rex |=
878 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 codes++, length++;
880 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700881
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400882 case4(014):
883 case4(020):
884 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 length++;
886 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700887
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400888 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 length += 2;
890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400892 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700893 if (opx->type & (BITS16 | BITS32 | BITS64))
894 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000895 else
896 length += (bits == 16) ? 2 : 4;
897 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700898
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400899 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 length += 4;
901 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700902
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400903 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700904 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000905 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700906
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400907 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000908 length++;
909 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700910
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400911 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000912 length += 8; /* MOV reg64/imm */
913 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700914
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400915 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000916 length += 2;
917 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700918
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400919 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700920 if (opx->type & (BITS16 | BITS32 | BITS64))
921 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000922 else
923 length += (bits == 16) ? 2 : 4;
924 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700925
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400926 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000927 length += 4;
928 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700929
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400930 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700931 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000932 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700933
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400934 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700935 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000936 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700937
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400938 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800939 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000940 length++;
941 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700942
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400943 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700944 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700945 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700946
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400947 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800948 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700949 length++;
950 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700951
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400952 case 0172:
953 case 0173:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400954 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700955 length++;
956 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700957
H. Peter Anvincffe61e2011-07-07 17:21:24 -0700958 case4(0174):
959 length++;
960 break;
961
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400962 case4(0250):
963 length += is_sbyte32(opx) ? 1 : 4;
964 break;
965
966 case4(0254):
967 length += 4;
968 break;
969
970 case4(0260):
971 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700972 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400973 ins->vex_cm = *codes++;
974 ins->vex_wlp = *codes++;
975 break;
976
H. Peter Anvin8ea22002012-02-25 10:24:24 -0800977 case 0264:
978 if (has_prefix(ins, PPS_REP, P_XACQUIRE) ||
979 has_prefix(ins, PPS_REP, P_XRELEASE))
980 return -1;
981 break;
982
983 case 0265:
984 case 0266:
985 case 0267:
986 hleok = c & 3;
987 break;
988
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400989 case 0270:
990 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700991 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400992 ins->vex_cm = *codes++;
993 ins->vex_wlp = *codes++;
994 break;
995
996 case4(0274):
997 length++;
998 break;
999
1000 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001002
H. Peter Anvine2c80182005-01-15 22:15:51 +00001003 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001004 if (bits == 64)
1005 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001006 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001007 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001008
H. Peter Anvine2c80182005-01-15 22:15:51 +00001009 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001010 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001011 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001012
H. Peter Anvine2c80182005-01-15 22:15:51 +00001013 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001014 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001015
Keith Kaniosb7a89542007-04-12 02:40:54 +00001016 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001017 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1018 has_prefix(ins, PPS_ASIZE, P_A32))
1019 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001020 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001021
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001022 case4(0314):
1023 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001024
H. Peter Anvine2c80182005-01-15 22:15:51 +00001025 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001026 {
1027 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1028 if (pfx == P_O16)
1029 break;
1030 if (pfx != P_none)
1031 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
1032 else
1033 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001034 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001035 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001036
H. Peter Anvine2c80182005-01-15 22:15:51 +00001037 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001038 {
1039 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1040 if (pfx == P_O32)
1041 break;
1042 if (pfx != P_none)
1043 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
1044 else
1045 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001046 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001047 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001048
H. Peter Anvine2c80182005-01-15 22:15:51 +00001049 case 0322:
1050 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001051
Keith Kaniosb7a89542007-04-12 02:40:54 +00001052 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001053 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001054 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001055
Keith Kaniosb7a89542007-04-12 02:40:54 +00001056 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001057 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001058 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001059
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001060 case 0325:
1061 ins->rex |= REX_NH;
1062 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001063
H. Peter Anvine2c80182005-01-15 22:15:51 +00001064 case 0330:
1065 codes++, length++;
1066 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001067
H. Peter Anvine2c80182005-01-15 22:15:51 +00001068 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001069 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001070
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001071 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001072 case 0333:
1073 length++;
1074 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001075
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001076 case 0334:
1077 ins->rex |= REX_L;
1078 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001079
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001080 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001081 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001082
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001083 case 0336:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001084 if (!ins->prefixes[PPS_REP])
1085 ins->prefixes[PPS_REP] = P_REP;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001086 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001087
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001088 case 0337:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001089 if (!ins->prefixes[PPS_REP])
1090 ins->prefixes[PPS_REP] = P_REPNE;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001091 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001092
H. Peter Anvine2c80182005-01-15 22:15:51 +00001093 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001094 if (ins->oprs[0].segment != NO_SEG)
1095 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1096 " quantity of BSS space");
1097 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001098 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001099 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001100
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001101 case 0341:
1102 if (!ins->prefixes[PPS_WAIT])
1103 ins->prefixes[PPS_WAIT] = P_WAIT;
1104 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001105
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001106 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001107 length++;
1108 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001109
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001110 case 0360:
1111 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001112
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001113 case 0361:
1114 case 0362:
1115 case 0363:
1116 length++;
1117 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001118
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001119 case 0364:
1120 case 0365:
1121 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001122
Keith Kanios48af1772007-08-17 07:37:52 +00001123 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001124 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001125 length++;
1126 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001127
H. Peter Anvine2c80182005-01-15 22:15:51 +00001128 case 0370:
1129 case 0371:
1130 case 0372:
1131 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001132
H. Peter Anvine2c80182005-01-15 22:15:51 +00001133 case 0373:
1134 length++;
1135 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001136
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001137 case 0374:
1138 eat = EA_XMMVSIB;
1139 break;
1140
1141 case 0375:
1142 eat = EA_YMMVSIB;
1143 break;
1144
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001145 case4(0100):
1146 case4(0110):
1147 case4(0120):
1148 case4(0130):
1149 case4(0200):
1150 case4(0204):
1151 case4(0210):
1152 case4(0214):
1153 case4(0220):
1154 case4(0224):
1155 case4(0230):
1156 case4(0234):
1157 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001158 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001159 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001160 opflags_t rflags;
1161 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001162
Keith Kaniosb7a89542007-04-12 02:40:54 +00001163 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001164
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001165 if (c <= 0177) {
1166 /* pick rfield from operand b (opx) */
1167 rflags = regflag(opx);
1168 rfield = nasm_regvals[opx->basereg];
1169 } else {
1170 rflags = 0;
1171 rfield = c & 7;
1172 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001173 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1174 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001175 errfunc(ERR_NONFATAL, "invalid effective address");
1176 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001177 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001178 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001179 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001180 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001181 }
1182 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001183
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001184 default:
1185 errfunc(ERR_PANIC, "internal instruction table corrupt"
1186 ": instruction code \\%o (0x%02X) given", c, c);
1187 break;
1188 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001189 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001190
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001191 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001192
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001193 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001194 if (ins->rex & REX_H) {
1195 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1196 return -1;
1197 }
1198 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001199 }
1200
H. Peter Anvind85d2502008-05-04 17:53:31 -07001201 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001202 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001203
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001204 if (ins->rex & REX_H) {
1205 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1206 return -1;
1207 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001208 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001209 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001210 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001211 ins->rex &= ~REX_W;
1212 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001213 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001214 ins->rex |= REX_W;
1215 bad32 &= ~REX_W;
1216 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001217 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001218 /* Follow REX_W */
1219 break;
1220 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001221
H. Peter Anvinfc561202011-07-07 16:58:22 -07001222 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001223 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1224 return -1;
1225 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001226 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001227 length += 3;
1228 else
1229 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001230 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001231 if (ins->rex & REX_H) {
1232 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1233 return -1;
1234 } else if (bits == 64) {
1235 length++;
1236 } else if ((ins->rex & REX_L) &&
1237 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1238 cpu >= IF_X86_64) {
1239 /* LOCK-as-REX.R */
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001240 assert_no_prefix(ins, PPS_LOCK);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001241 length++;
1242 } else {
1243 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1244 return -1;
1245 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001246 }
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -08001247
1248 bad_hle_warn(ins, hleok);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001249
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001250 return length;
1251}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001252
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001253#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001254 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001255 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1256 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1257 ins->rex = 0; \
1258 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001259 }
1260
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001261static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001262 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001263 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001264{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001265 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1267 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1268 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001269 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001270 uint8_t c;
1271 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001272 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001273 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001274 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001275 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001276 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001277 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001278 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001279
H. Peter Anvin839eca22007-10-29 23:12:47 -07001280 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001281 c = *codes++;
1282 op1 = (c & 3) + ((opex & 1) << 2);
1283 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1284 opx = &ins->oprs[op1];
1285 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001286
H. Peter Anvin839eca22007-10-29 23:12:47 -07001287 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001288 case 01:
1289 case 02:
1290 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001291 case 04:
1292 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001293 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001294 codes += c;
1295 offset += c;
1296 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001297
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001298 case 05:
1299 case 06:
1300 case 07:
1301 opex = c;
1302 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001303
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001304 case4(010):
1305 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001306 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001307 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001308 offset += 1;
1309 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001310
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001311 case4(014):
1312 /*
1313 * The test for BITS8 and SBYTE here is intended to avoid
1314 * warning on optimizer actions due to SBYTE, while still
1315 * warn on explicit BYTE directives. Also warn, obviously,
1316 * if the optimizer isn't enabled.
1317 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001318 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001319 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1320 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001321 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001322 "signed byte value exceeds bounds");
1323 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001324 if (opx->segment != NO_SEG) {
1325 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001326 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001327 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001330 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001331 NO_SEG);
1332 }
1333 offset += 1;
1334 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001335
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001336 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001338 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001339 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001341 if (opx->segment != NO_SEG) {
1342 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001343 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001344 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001345 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001346 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001347 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001348 NO_SEG);
1349 }
1350 offset += 1;
1351 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001352
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001353 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001354 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001355 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001356 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 if (opx->segment != NO_SEG) {
1358 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001359 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001360 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001361 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001362 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001363 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001364 NO_SEG);
1365 }
1366 offset += 1;
1367 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001368
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001369 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001370 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001372 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001373 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 offset += 2;
1375 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001376
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001377 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 if (opx->type & (BITS16 | BITS32))
1379 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 else
1381 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001382 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001383 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001384 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001385 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001386 offset += size;
1387 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001388
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001389 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001390 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001392 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001393 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001394 offset += 4;
1395 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001396
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001397 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001399 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001400 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001401 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001402 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001403 offset += size;
1404 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001405
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001406 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001407 if (opx->segment != segment) {
1408 data = opx->offset;
1409 out(offset, segment, &data,
1410 OUT_REL1ADR, insn_end - offset,
1411 opx->segment, opx->wrt);
1412 } else {
1413 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001414 if (data > 127 || data < -128)
1415 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001416 out(offset, segment, &data,
1417 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1418 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 offset += 1;
1420 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001421
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001422 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001424 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001425 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001426 offset += 8;
1427 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001428
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001429 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001430 if (opx->segment != segment) {
1431 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001432 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001433 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001435 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001436 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001437 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001438 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 }
1440 offset += 2;
1441 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001442
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001443 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001444 if (opx->type & (BITS16 | BITS32 | BITS64))
1445 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 else
1447 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001448 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001449 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001450 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001451 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1452 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001453 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001454 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001455 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001456 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001457 }
1458 offset += size;
1459 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001460
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001461 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001462 if (opx->segment != segment) {
1463 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001465 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001468 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001470 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001471 }
1472 offset += 4;
1473 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001474
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001475 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001476 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001477 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1478 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001479 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001480 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001481 outfmt->segbase(1 + opx->segment),
1482 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001483 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001484 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001485
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001486 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001487 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001488 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001489 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001491 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001492 NO_SEG);
1493 offset++;
1494 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001495 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001496 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001497 offset += 2;
1498 }
1499 break;
1500
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001501 case4(0144):
1502 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001503 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001504 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001505 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001506 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001507 offset++;
1508 break;
1509
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001510 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001511 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001512 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001513 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001514 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001515 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001516 NO_SEG);
1517 offset++;
1518 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001519 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001520 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001521 offset += 4;
1522 }
1523 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001524
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001525 case4(0154):
1526 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001527 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001528 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001529 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001530 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001531 offset++;
1532 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001533
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001534 case 0172:
1535 c = *codes++;
1536 opx = &ins->oprs[c >> 3];
1537 bytes[0] = nasm_regvals[opx->basereg] << 4;
1538 opx = &ins->oprs[c & 7];
1539 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1540 errfunc(ERR_NONFATAL,
1541 "non-absolute expression not permitted as argument %d",
1542 c & 7);
1543 } else {
1544 if (opx->offset & ~15) {
1545 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1546 "four-bit argument exceeds bounds");
1547 }
1548 bytes[0] |= opx->offset & 15;
1549 }
1550 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1551 offset++;
1552 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001553
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001554 case 0173:
1555 c = *codes++;
1556 opx = &ins->oprs[c >> 4];
1557 bytes[0] = nasm_regvals[opx->basereg] << 4;
1558 bytes[0] |= c & 15;
1559 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1560 offset++;
1561 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001562
H. Peter Anvincffe61e2011-07-07 17:21:24 -07001563 case4(0174):
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001564 bytes[0] = nasm_regvals[opx->basereg] << 4;
1565 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1566 offset++;
1567 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001568
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001569 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001570 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001571 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1572 (int32_t)data != (int64_t)data) {
1573 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1574 "signed dword immediate exceeds bounds");
1575 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001576 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001577 bytes[0] = data;
1578 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1579 NO_SEG);
1580 offset++;
1581 } else {
1582 out(offset, segment, &data, OUT_ADDRESS, 4,
1583 opx->segment, opx->wrt);
1584 offset += 4;
1585 }
1586 break;
1587
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001588 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001589 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001590 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1591 (int32_t)data != (int64_t)data) {
1592 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1593 "signed dword immediate exceeds bounds");
1594 }
1595 out(offset, segment, &data, OUT_ADDRESS, 4,
1596 opx->segment, opx->wrt);
1597 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001598 break;
1599
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001600 case4(0260):
1601 case 0270:
1602 codes += 2;
1603 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1604 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1605 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1606 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001607 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001608 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1609 offset += 3;
1610 } else {
1611 bytes[0] = 0xc5;
1612 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001613 ((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001614 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1615 offset += 2;
1616 }
1617 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001618
H. Peter Anvin8ea22002012-02-25 10:24:24 -08001619 case4(0264):
1620 break;
1621
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001622 case4(0274):
1623 {
1624 uint64_t uv, um;
1625 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001626
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001627 if (ins->rex & REX_W)
1628 s = 64;
1629 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1630 s = 16;
1631 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1632 s = 32;
1633 else
1634 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001635
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001636 um = (uint64_t)2 << (s-1);
1637 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001638
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001639 if (uv > 127 && uv < (uint64_t)-128 &&
1640 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001641 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001642 "signed byte value exceeds bounds");
1643 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001644 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001645 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001646 out(offset, segment, &data, OUT_ADDRESS, 1,
1647 opx->segment, opx->wrt);
1648 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001649 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001650 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1651 NO_SEG);
1652 }
1653 offset += 1;
1654 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001655 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001656
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001657 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001659
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001661 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001662 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001663 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001664 offset += 1;
1665 } else
1666 offset += 0;
1667 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001668
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001670 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001672 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 offset += 1;
1674 } else
1675 offset += 0;
1676 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001677
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 case 0312:
1679 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001680
Keith Kaniosb7a89542007-04-12 02:40:54 +00001681 case 0313:
1682 ins->rex = 0;
1683 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001684
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001685 case4(0314):
1686 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001687
H. Peter Anvine2c80182005-01-15 22:15:51 +00001688 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001689 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001690 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001691
H. Peter Anvine2c80182005-01-15 22:15:51 +00001692 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001693 case 0323:
1694 break;
1695
Keith Kaniosb7a89542007-04-12 02:40:54 +00001696 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001697 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001698 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001699
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001700 case 0325:
1701 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001702
H. Peter Anvine2c80182005-01-15 22:15:51 +00001703 case 0330:
1704 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001705 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001706 offset += 1;
1707 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001708
H. Peter Anvine2c80182005-01-15 22:15:51 +00001709 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001710 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001711
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001712 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001713 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001714 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001715 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001716 offset += 1;
1717 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001718
Keith Kanios48af1772007-08-17 07:37:52 +00001719 case 0334:
1720 if (ins->rex & REX_R) {
1721 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001722 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001723 offset += 1;
1724 }
1725 ins->rex &= ~(REX_L|REX_R);
1726 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001727
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001728 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001729 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001730
H. Peter Anvin962e3052008-08-28 17:47:16 -07001731 case 0336:
1732 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001733 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001734
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001736 if (ins->oprs[0].segment != NO_SEG)
1737 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1738 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001739 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001740 if (size > 0)
1741 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001742 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001743 offset += size;
1744 }
1745 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001746
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001747 case 0341:
1748 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001749
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001750 case 0344:
1751 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001752 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001753 switch (ins->oprs[0].basereg) {
1754 case R_CS:
1755 bytes[0] += 0x0E;
1756 break;
1757 case R_DS:
1758 bytes[0] += 0x1E;
1759 break;
1760 case R_ES:
1761 bytes[0] += 0x06;
1762 break;
1763 case R_SS:
1764 bytes[0] += 0x16;
1765 break;
1766 default:
1767 errfunc(ERR_PANIC,
1768 "bizarre 8086 segment register received");
1769 }
1770 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1771 offset++;
1772 break;
1773
1774 case 0346:
1775 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001776 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001777 switch (ins->oprs[0].basereg) {
1778 case R_FS:
1779 bytes[0] += 0xA0;
1780 break;
1781 case R_GS:
1782 bytes[0] += 0xA8;
1783 break;
1784 default:
1785 errfunc(ERR_PANIC,
1786 "bizarre 386 segment register received");
1787 }
1788 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1789 offset++;
1790 break;
1791
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001792 case 0360:
1793 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001794
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001795 case 0361:
1796 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001797 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1798 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001799 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001800
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001801 case 0362:
1802 case 0363:
1803 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001804 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1805 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001806 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001807
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001808 case 0364:
1809 case 0365:
1810 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001811
Keith Kanios48af1772007-08-17 07:37:52 +00001812 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001813 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001814 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001815 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001816 offset += 1;
1817 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001818
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 case 0370:
1820 case 0371:
1821 case 0372:
1822 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001823
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 case 0373:
1825 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001826 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001827 offset += 1;
1828 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001829
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001830 case 0374:
1831 eat = EA_XMMVSIB;
1832 break;
1833
1834 case 0375:
1835 eat = EA_YMMVSIB;
1836 break;
1837
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001838 case4(0100):
1839 case4(0110):
1840 case4(0120):
1841 case4(0130):
1842 case4(0200):
1843 case4(0204):
1844 case4(0210):
1845 case4(0214):
1846 case4(0220):
1847 case4(0224):
1848 case4(0230):
1849 case4(0234):
1850 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001851 ea ea_data;
1852 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001853 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001854 uint8_t *p;
1855 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001856 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001857
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001858 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001859 /* pick rfield from operand b (opx) */
1860 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001861 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001862 } else {
1863 /* rfield is constant */
1864 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001865 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001866 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001867
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001868 if (process_ea(opy, &ea_data, bits, ins->addr_size,
Cyrill Gorcunovcdb8cd72011-08-28 16:33:39 +04001869 rfield, rflags) != eat)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001870 errfunc(ERR_NONFATAL, "invalid effective address");
Charles Crayne7e975552007-11-03 22:06:13 -07001871
H. Peter Anvine2c80182005-01-15 22:15:51 +00001872 p = bytes;
1873 *p++ = ea_data.modrm;
1874 if (ea_data.sib_present)
1875 *p++ = ea_data.sib;
1876
1877 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001878 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001879
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001880 /*
1881 * Make sure the address gets the right offset in case
1882 * the line breaks in the .lst file (BR 1197827)
1883 */
1884 offset += s;
1885 s = 0;
1886
H. Peter Anvine2c80182005-01-15 22:15:51 +00001887 switch (ea_data.bytes) {
1888 case 0:
1889 break;
1890 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001891 case 2:
1892 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001893 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001894 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001895 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001896 if (ea_data.rip) {
1897 if (opy->segment == segment) {
1898 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001899 if (overflow_signed(data, ea_data.bytes))
1900 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001901 out(offset, segment, &data, OUT_ADDRESS,
1902 ea_data.bytes, NO_SEG, NO_SEG);
1903 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001904 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001905 out(offset, segment, &data, OUT_REL4ADR,
1906 insn_end - offset, opy->segment, opy->wrt);
1907 }
1908 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001909 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1910 signed_bits(opy->offset, ins->addr_size) !=
1911 signed_bits(opy->offset, ea_data.bytes * 8))
1912 warn_overflow(ERR_PASS2, ea_data.bytes);
1913
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001914 out(offset, segment, &data, OUT_ADDRESS,
1915 ea_data.bytes, opy->segment, opy->wrt);
1916 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001917 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001918 default:
1919 /* Impossible! */
1920 errfunc(ERR_PANIC,
1921 "Invalid amount of bytes (%d) for offset?!",
1922 ea_data.bytes);
1923 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001924 }
1925 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001926 }
1927 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001928
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001929 default:
1930 errfunc(ERR_PANIC, "internal instruction table corrupt"
1931 ": instruction code \\%o (0x%02X) given", c, c);
1932 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001933 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001934 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001935}
1936
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001937static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001938{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001939 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001940 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001941 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001942}
1943
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001944static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001945{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001946 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001947 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001948 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001949}
1950
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001951static int op_rexflags(const operand * o, int mask)
1952{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001953 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001954 int val;
1955
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001956 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001957 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001958
H. Peter Anvina4835d42008-05-20 14:21:29 -07001959 flags = nasm_reg_flags[o->basereg];
1960 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001961
1962 return rexflags(val, flags, mask);
1963}
1964
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001965static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001966{
1967 int rex = 0;
1968
1969 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001970 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001971 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001972 rex |= REX_W;
1973 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1974 rex |= REX_H;
1975 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1976 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001977
1978 return rex & mask;
1979}
1980
H. Peter Anvin23595f52009-07-25 17:44:25 -07001981static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001982 insn *instruction,
1983 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001984{
1985 const struct itemplate *temp;
1986 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001987 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001988 bool opsizemissing = false;
1989 int i;
1990
1991 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001992 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001993
1994 merr = MERR_INVALOP;
1995
1996 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001997 temp->opcode != I_none; temp++) {
1998 m = matches(temp, instruction, bits);
1999 if (m == MOK_JUMP) {
2000 if (jmp_match(segment, offset, bits, instruction, temp->code))
2001 m = MOK_GOOD;
2002 else
2003 m = MERR_INVALOP;
2004 } else if (m == MERR_OPSIZEMISSING &&
2005 (temp->flags & IF_SMASK) != IF_SX) {
2006 /*
2007 * Missing operand size and a candidate for fuzzy matching...
2008 */
2009 for (i = 0; i < temp->operands; i++) {
2010 if ((temp->opd[i] & SAME_AS) == 0)
2011 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
2012 }
2013 opsizemissing = true;
2014 }
2015 if (m > merr)
2016 merr = m;
2017 if (merr == MOK_GOOD)
2018 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002019 }
2020
2021 /* No match, but see if we can get a fuzzy operand size match... */
2022 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002023 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002024
2025 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002026 /*
2027 * We ignore extrinsic operand sizes on registers, so we should
2028 * never try to fuzzy-match on them. This also resolves the case
2029 * when we have e.g. "xmmrm128" in two different positions.
2030 */
2031 if (is_class(REGISTER, instruction->oprs[i].type))
2032 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002033
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002034 /* This tests if xsizeflags[i] has more than one bit set */
2035 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2036 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002037
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002038 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002039 }
2040
2041 /* Try matching again... */
2042 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002043 temp->opcode != I_none; temp++) {
2044 m = matches(temp, instruction, bits);
2045 if (m == MOK_JUMP) {
2046 if (jmp_match(segment, offset, bits, instruction, temp->code))
2047 m = MOK_GOOD;
2048 else
2049 m = MERR_INVALOP;
2050 }
2051 if (m > merr)
2052 merr = m;
2053 if (merr == MOK_GOOD)
2054 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002055 }
2056
H. Peter Anvina81655b2009-07-25 18:15:28 -07002057done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002058 *tempp = temp;
2059 return merr;
2060}
2061
H. Peter Anvin65289e82009-07-25 17:25:11 -07002062static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002063 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002064{
H. Peter Anvin60926242009-07-26 16:25:38 -07002065 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002066 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002067
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002068 /*
2069 * Check the opcode
2070 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002071 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002072 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002073
2074 /*
2075 * Count the operands
2076 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002077 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002078 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002079
2080 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002081 * Is it legal?
2082 */
2083 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2084 return MERR_INVALOP;
2085
2086 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002087 * Check that no spurious colons or TOs are present
2088 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002089 for (i = 0; i < itemp->operands; i++)
2090 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002091 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002092
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002093 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002094 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002095 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002096 switch (itemp->flags & IF_SMASK) {
2097 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002098 asize = BITS8;
2099 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002100 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002101 asize = BITS16;
2102 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002103 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002104 asize = BITS32;
2105 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002106 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002107 asize = BITS64;
2108 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002109 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002110 asize = BITS128;
2111 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002112 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002113 asize = BITS256;
2114 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002115 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002116 switch (bits) {
2117 case 16:
2118 asize = BITS16;
2119 break;
2120 case 32:
2121 asize = BITS32;
2122 break;
2123 case 64:
2124 asize = BITS64;
2125 break;
2126 default:
2127 asize = 0;
2128 break;
2129 }
2130 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002131 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002132 asize = 0;
2133 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002134 }
2135
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002136 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002137 /* S- flags only apply to a specific operand */
2138 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2139 memset(size, 0, sizeof size);
2140 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002141 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002142 /* S- flags apply to all operands */
2143 for (i = 0; i < MAX_OPERANDS; i++)
2144 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002145 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002146
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002147 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002148 * Check that the operand flags all match up,
2149 * it's a bit tricky so lets be verbose:
2150 *
2151 * 1) Find out the size of operand. If instruction
2152 * doesn't have one specified -- we're trying to
2153 * guess it either from template (IF_S* flag) or
2154 * from code bits.
2155 *
2156 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2157 * (ie the same operand as was specified somewhere in template, and
2158 * this referred operand index is being achieved via ~SAME_AS)
2159 * we are to be sure that both registers (in template and instruction)
2160 * do exactly match.
2161 *
2162 * 3) If template operand do not match the instruction OR
2163 * template has an operand size specified AND this size differ
2164 * from which instruction has (perhaps we got it from code bits)
2165 * we are:
2166 * a) Check that only size of instruction and operand is differ
2167 * other characteristics do match
2168 * b) Perhaps it's a register specified in instruction so
2169 * for such a case we just mark that operand as "size
2170 * missing" and this will turn on fuzzy operand size
2171 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002172 */
2173 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002174 opflags_t type = instruction->oprs[i].type;
2175 if (!(type & SIZE_MASK))
2176 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002177
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002178 if (itemp->opd[i] & SAME_AS) {
2179 int j = itemp->opd[i] & ~SAME_AS;
2180 if (type != instruction->oprs[j].type ||
2181 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2182 return MERR_INVALOP;
2183 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002184 ((itemp->opd[i] & SIZE_MASK) &&
2185 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002186 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002187 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002188 } else if (!is_class(REGISTER, type)) {
2189 /*
2190 * Note: we don't honor extrinsic operand sizes for registers,
2191 * so "missing operand size" for a register should be
2192 * considered a wildcard match rather than an error.
2193 */
2194 opsizemissing = true;
2195 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002196 }
2197 }
2198
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002199 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002200 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002201
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002202 /*
2203 * Check operand sizes
2204 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002205 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002206 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002207 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002208 asize = itemp->opd[i] & SIZE_MASK;
2209 if (asize) {
2210 for (i = 0; i < oprs; i++)
2211 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002212 break;
2213 }
2214 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002215 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002216 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002217 }
2218
Keith Kaniosb7a89542007-04-12 02:40:54 +00002219 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002220 if (!(itemp->opd[i] & SIZE_MASK) &&
2221 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002222 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002223 }
2224
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002225 /*
2226 * Check template is okay at the set cpu level
2227 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002228 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002229 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002230
Keith Kaniosb7a89542007-04-12 02:40:54 +00002231 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002232 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002233 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002234 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002235 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002236
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002237 /*
2238 * Check if special handling needed for Jumps
2239 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002240 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002241 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002242
H. Peter Anvin60926242009-07-26 16:25:38 -07002243 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002244}
2245
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002246static enum ea_type process_ea(operand *input, ea *output, int bits,
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002247 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002248{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002249 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002250
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002251 output->type = EA_SCALAR;
2252 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002253
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002254 /* REX flags for the rfield operand */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002255 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002256
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002257 if (is_class(REGISTER, input->type)) {
2258 /*
2259 * It's a direct register.
2260 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002261 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002262
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002263 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002264 goto err;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002265
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002266 f = regflag(input);
2267
2268 if (!is_class(REG_EA, f))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002269 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002270
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002271 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002272 output->sib_present = false; /* no SIB necessary */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002273 output->bytes = 0; /* no offset necessary either */
2274 output->modrm = GEN_MODRM(3, rfield, nasm_regvals[input->basereg]);
2275 } else {
2276 /*
2277 * It's a memory reference.
2278 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002279 if (input->basereg == -1 &&
2280 (input->indexreg == -1 || input->scale == 0)) {
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002281 /*
2282 * It's a pure offset.
2283 */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002284 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2285 input->segment == NO_SEG) {
2286 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2287 input->type &= ~IP_REL;
2288 input->type |= MEMORY;
2289 }
2290
2291 if (input->eaflags & EAF_BYTEOFFS ||
2292 (input->eaflags & EAF_WORDOFFS &&
2293 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2294 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2295 }
2296
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002297 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002298 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002299 output->sib = GEN_SIB(0, 4, 5);
2300 output->bytes = 4;
2301 output->modrm = GEN_MODRM(0, rfield, 4);
2302 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002303 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002304 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002305 output->bytes = (addrbits != 16 ? 4 : 2);
2306 output->modrm = GEN_MODRM(0, rfield, (addrbits != 16 ? 5 : 6));
2307 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002308 }
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002309 } else {
2310 /*
2311 * It's an indirection.
2312 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002313 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002314 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002315 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002316 int t, it, bt; /* register numbers */
2317 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002318
H. Peter Anvine2c80182005-01-15 22:15:51 +00002319 if (s == 0)
2320 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002321
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002322 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002323 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002324 ix = nasm_reg_flags[i];
2325 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002326 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002327 ix = 0;
2328 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002329
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002330 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002331 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002332 bx = nasm_reg_flags[b];
2333 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002334 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002335 bx = 0;
2336 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002337
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002338 /* if either one are a vector register... */
2339 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
2340 int32_t sok = BITS32 | BITS64;
2341 int32_t o = input->offset;
2342 int mod, scale, index, base;
2343
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002344 /*
2345 * For a vector SIB, one has to be a vector and the other,
2346 * if present, a GPR. The vector must be the index operand.
2347 */
2348 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2349 if (s == 0)
2350 s = 1;
2351 else if (s != 1)
2352 goto err;
2353
2354 t = bt, bt = it, it = t;
2355 x = bx, bx = ix, ix = x;
2356 }
2357
2358 if (bt != -1) {
2359 if (REG_GPR & ~bx)
2360 goto err;
2361 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2362 sok &= bx;
2363 else
2364 goto err;
2365 }
2366
2367 /*
2368 * While we're here, ensure the user didn't specify
2369 * WORD or QWORD
2370 */
2371 if (input->disp_size == 16 || input->disp_size == 64)
2372 goto err;
2373
2374 if (addrbits == 16 ||
2375 (addrbits == 32 && !(sok & BITS32)) ||
2376 (addrbits == 64 && !(sok & BITS64)))
2377 goto err;
2378
2379 output->type = (ix & YMMREG & ~REG_EA)
2380 ? EA_YMMVSIB : EA_XMMVSIB;
2381
2382 output->rex |= rexflags(it, ix, REX_X);
2383 output->rex |= rexflags(bt, bx, REX_B);
2384
2385 index = it & 7; /* it is known to be != -1 */
2386
2387 switch (s) {
2388 case 1:
2389 scale = 0;
2390 break;
2391 case 2:
2392 scale = 1;
2393 break;
2394 case 4:
2395 scale = 2;
2396 break;
2397 case 8:
2398 scale = 3;
2399 break;
2400 default: /* then what the smeg is it? */
2401 goto err; /* panic */
2402 }
2403
2404 if (bt == -1) {
2405 base = 5;
2406 mod = 0;
2407 } else {
2408 base = (bt & 7);
2409 if (base != REG_NUM_EBP && o == 0 &&
2410 seg == NO_SEG && !forw_ref &&
2411 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2412 mod = 0;
2413 else if (input->eaflags & EAF_BYTEOFFS ||
2414 (o >= -128 && o <= 127 &&
2415 seg == NO_SEG && !forw_ref &&
2416 !(input->eaflags & EAF_WORDOFFS)))
2417 mod = 1;
2418 else
2419 mod = 2;
2420 }
2421
2422 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002423 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2424 output->modrm = GEN_MODRM(mod, rfield, 4);
2425 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002426 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002427 /*
2428 * it must be a 32/64-bit memory reference. Firstly we have
2429 * to check that all registers involved are type E/Rxx.
2430 */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002431 int32_t sok = BITS32 | BITS64;
2432 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002433
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002434 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002435 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2436 sok &= ix;
2437 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002438 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002439 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002440
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002441 if (bt != -1) {
2442 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002443 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002444 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002445 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002446 sok &= bx;
2447 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002448
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002449 /*
2450 * While we're here, ensure the user didn't specify
2451 * WORD or QWORD
2452 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002453 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002454 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002455
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002456 if (addrbits == 16 ||
2457 (addrbits == 32 && !(sok & BITS32)) ||
2458 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002459 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002460
Keith Kaniosb7a89542007-04-12 02:40:54 +00002461 /* now reorganize base/index */
2462 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002463 ((hb == b && ht == EAH_NOTBASE) ||
2464 (hb == i && ht == EAH_MAKEBASE))) {
2465 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002466 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002467 x = bx, bx = ix, ix = x;
2468 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002469 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002470 bt = -1, bx = 0, s++;
2471 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002472 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002473 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002474 }
2475 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2476 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002477 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002478 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2479 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002480 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002481 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002482 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002483 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002484 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002485 x = ix, ix = bx, bx = x;
2486 }
2487 if (it == REG_NUM_ESP ||
2488 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002489 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002490
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002491 output->rex |= rexflags(it, ix, REX_X);
2492 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002493
Keith Kanios48af1772007-08-17 07:37:52 +00002494 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002495 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002496 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002497
Keith Kaniosb7a89542007-04-12 02:40:54 +00002498 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002499 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002500 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002501 } else {
2502 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002503 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002504 seg == NO_SEG && !forw_ref &&
2505 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002506 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002507 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002508 (o >= -128 && o <= 127 &&
2509 seg == NO_SEG && !forw_ref &&
2510 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002511 mod = 1;
2512 else
2513 mod = 2;
2514 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002515
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002516 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002517 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2518 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002519 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002520 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002521 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002522
Keith Kaniosb7a89542007-04-12 02:40:54 +00002523 if (it == -1)
2524 index = 4, s = 1;
2525 else
2526 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002527
H. Peter Anvine2c80182005-01-15 22:15:51 +00002528 switch (s) {
2529 case 1:
2530 scale = 0;
2531 break;
2532 case 2:
2533 scale = 1;
2534 break;
2535 case 4:
2536 scale = 2;
2537 break;
2538 case 8:
2539 scale = 3;
2540 break;
2541 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002542 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002543 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002544
Keith Kaniosb7a89542007-04-12 02:40:54 +00002545 if (bt == -1) {
2546 base = 5;
2547 mod = 0;
2548 } else {
2549 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002550 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002551 seg == NO_SEG && !forw_ref &&
2552 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002553 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002554 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002555 (o >= -128 && o <= 127 &&
2556 seg == NO_SEG && !forw_ref &&
2557 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002558 mod = 1;
2559 else
2560 mod = 2;
2561 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002562
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002563 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002564 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2565 output->modrm = GEN_MODRM(mod, rfield, 4);
2566 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002567 }
2568 } else { /* it's 16-bit */
2569 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002570 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002571
Keith Kaniosb7a89542007-04-12 02:40:54 +00002572 /* check for 64-bit long mode */
2573 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002574 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002575
H. Peter Anvine2c80182005-01-15 22:15:51 +00002576 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002577 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2578 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002579 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002580
Keith Kaniosb7a89542007-04-12 02:40:54 +00002581 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002582 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002583 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002584
H. Peter Anvine2c80182005-01-15 22:15:51 +00002585 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002586 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002587 if (b == -1 && i != -1) {
2588 int tmp = b;
2589 b = i;
2590 i = tmp;
2591 } /* swap */
2592 if ((b == R_SI || b == R_DI) && i != -1) {
2593 int tmp = b;
2594 b = i;
2595 i = tmp;
2596 }
2597 /* have BX/BP as base, SI/DI index */
2598 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002599 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002600 if (i != -1 && b != -1 &&
2601 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002602 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002603 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002604 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002605
H. Peter Anvine2c80182005-01-15 22:15:51 +00002606 rm = -1;
2607 if (i != -1)
2608 switch (i * 256 + b) {
2609 case R_SI * 256 + R_BX:
2610 rm = 0;
2611 break;
2612 case R_DI * 256 + R_BX:
2613 rm = 1;
2614 break;
2615 case R_SI * 256 + R_BP:
2616 rm = 2;
2617 break;
2618 case R_DI * 256 + R_BP:
2619 rm = 3;
2620 break;
2621 } else
2622 switch (b) {
2623 case R_SI:
2624 rm = 4;
2625 break;
2626 case R_DI:
2627 rm = 5;
2628 break;
2629 case R_BP:
2630 rm = 6;
2631 break;
2632 case R_BX:
2633 rm = 7;
2634 break;
2635 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002636 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002637 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002638
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002639 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2640 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002641 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002642 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002643 (o >= -128 && o <= 127 && seg == NO_SEG &&
2644 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002645 mod = 1;
2646 else
2647 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002648
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002649 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002650 output->bytes = mod; /* bytes of offset needed */
2651 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002652 }
2653 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002654 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002655
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002656 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002657 return output->type;
2658
2659err:
2660 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002661}
2662
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002663static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002664{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002665 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002666 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002667
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002668 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002669
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002670 switch (ins->prefixes[PPS_ASIZE]) {
2671 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002672 valid &= 16;
2673 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002674 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002675 valid &= 32;
2676 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002677 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002678 valid &= 64;
2679 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002680 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002681 valid &= (addrbits == 32) ? 16 : 32;
2682 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002683 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002684 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002685 }
2686
2687 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002688 if (is_class(MEMORY, ins->oprs[j].type)) {
2689 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002690
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002691 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002692 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002693 i = 0;
2694 else
2695 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002696
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002697 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002698 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002699 b = 0;
2700 else
2701 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002702
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002703 if (ins->oprs[j].scale == 0)
2704 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002705
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002706 if (!i && !b) {
2707 int ds = ins->oprs[j].disp_size;
2708 if ((addrbits != 64 && ds > 8) ||
2709 (addrbits == 64 && ds == 16))
2710 valid &= ds;
2711 } else {
2712 if (!(REG16 & ~b))
2713 valid &= 16;
2714 if (!(REG32 & ~b))
2715 valid &= 32;
2716 if (!(REG64 & ~b))
2717 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002718
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002719 if (!(REG16 & ~i))
2720 valid &= 16;
2721 if (!(REG32 & ~i))
2722 valid &= 32;
2723 if (!(REG64 & ~i))
2724 valid &= 64;
2725 }
2726 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002727 }
2728
2729 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002730 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002731 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002732 /* Add an address size prefix */
Cyrill Gorcunovd6851d42011-09-25 18:01:45 +04002733 ins->prefixes[PPS_ASIZE] = (addrbits == 32) ? P_A16 : P_A32;;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002734 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002735 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002736 /* Impossible... */
2737 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2738 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002739 }
2740
2741 defdisp = ins->addr_size == 16 ? 16 : 32;
2742
2743 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002744 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2745 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2746 /*
2747 * mem_offs sizes must match the address size; if not,
2748 * strip the MEM_OFFS bit and match only EA instructions
2749 */
2750 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2751 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002752 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002753}