blob: eba1b32db664d9ca402f353588b130ac36a5bead [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 Anvin755f5212012-02-25 11:41:34 -0800130 * \336 - force a REP(E) prefix (0xF3) even if not specified.
131 * \337 - force a REPNE prefix (0xF2) 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 Anvin755f5212012-02-25 11:41:34 -0800148 * \370,\371 - 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 Anvin8cc8a1d2012-02-25 11:11:42 -0800204static int64_t calcsize(int32_t, int64_t, int, insn *,
205 const struct itemplate *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700206static void gencode(int32_t segment, int64_t offset, int bits,
207 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400208 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700209static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400210 insn *instruction,
211 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700212static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700213static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000214static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700215static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000216static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700217static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000218
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700219static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
220
Cyrill Gorcunov18914e62011-11-12 11:41:51 +0400221static int has_prefix(insn * ins, enum prefix_pos pos, int prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000222{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700223 return ins->prefixes[pos] == prefix;
224}
225
226static void assert_no_prefix(insn * ins, enum prefix_pos pos)
227{
228 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400229 errfunc(ERR_NONFATAL, "invalid %s prefix",
230 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700231}
232
233static const char *size_name(int size)
234{
235 switch (size) {
236 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400237 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700238 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400239 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700240 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400241 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700242 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400243 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700244 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400245 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700246 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400247 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700248 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400249 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700250 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400251 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000252 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700253}
254
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400255static void warn_overflow(int pass, int size)
256{
257 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
258 "%s data exceeds bounds", size_name(size));
259}
260
261static void warn_overflow_const(int64_t data, int size)
262{
263 if (overflow_general(data, size))
264 warn_overflow(ERR_PASS1, size);
265}
266
267static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700268{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100269 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400270 if (overflow_general(o->offset, size))
271 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700272 }
273}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400274
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000275/*
276 * This routine wrappers the real output format's output routine,
277 * in order to pass a copy of the data off to the listing file
278 * generator at the same time.
279 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800280static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800281 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400282 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000283{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000284 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000285 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800286 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000287
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800288 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400289 /*
290 * This is a non-relocated address, and we're going to
291 * convert it into RAWDATA format.
292 */
293 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800294
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400295 if (size > 8) {
296 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
297 return;
298 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700299
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400300 WRITEADDR(q, *(int64_t *)data, size);
301 data = p;
302 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000303 }
304
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800305 list->output(offset, data, type, size);
306
Frank Kotlerabebb082003-09-06 04:45:37 +0000307 /*
308 * this call to src_get determines when we call the
309 * debug-format-specific "linenum" function
310 * it updates lineno and lnfname to the current values
311 * returning 0 if "same as last time", -2 if lnfname
312 * changed, and the amount by which lineno changed,
313 * if it did. thus, these variables must be static
314 */
315
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400316 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000318
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800319 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000320}
321
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700322static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800323 insn * ins, const struct itemplate *temp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800325 int64_t isize;
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800326 const uint8_t *code = temp->code;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000327 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000328
H. Peter Anvin755f5212012-02-25 11:41:34 -0800329 if (((c & ~1) != 0370) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700330 return false;
331 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400332 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700333 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400334 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700335
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800336 isize = calcsize(segment, offset, bits, ins, temp);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100337
Victor van den Elzen154e5922009-02-25 17:32:00 +0100338 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100339 /* Be optimistic in pass 1 */
340 return true;
341
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700343 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000344
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700345 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
346 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000347}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000348
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800349int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400350 insn * instruction, struct ofmt *output, efunc error,
351 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000352{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000353 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700355 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800356 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000357 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800358 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300359 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000360
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000362 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000363 outfmt = output; /* likewise */
364 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000365
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300366 wsize = idata_bytes(instruction->opcode);
367 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000368 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000369
H. Peter Anvineba20a72002-04-30 20:53:55 +0000370 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000372 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 if (t < 0)
374 errfunc(ERR_PANIC,
375 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000376
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400378 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400380 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700381 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400382 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000383 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700384 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800386 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400387 offset += wsize;
388 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700389 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400390 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000392
H. Peter Anvine2c80182005-01-15 22:15:51 +0000393 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800394 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000395 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000396
H. Peter Anvine2c80182005-01-15 22:15:51 +0000397 if (align) {
398 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100399 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800400 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000401 }
402 offset += e->stringlen + align;
403 }
404 }
405 if (t > 0 && t == instruction->times - 1) {
406 /*
407 * Dummy call to list->output to give the offset to the
408 * listing module.
409 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800410 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000411 list->uplevel(LIST_TIMES);
412 }
413 }
414 if (instruction->times > 1)
415 list->downlevel(LIST_TIMES);
416 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000417 }
418
H. Peter Anvine2c80182005-01-15 22:15:51 +0000419 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700420 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000421 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000422
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400423 fp = fopen(fname, "rb");
424 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000425 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
426 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400427 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000428 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
429 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400430 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700431 static char buf[4096];
432 size_t t = instruction->times;
433 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400434 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000435
H. Peter Anvine2c80182005-01-15 22:15:51 +0000436 len = ftell(fp);
437 if (instruction->eops->next) {
438 base = instruction->eops->next->offset;
439 len -= base;
440 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700441 len > (size_t)instruction->eops->next->next->offset)
442 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000443 }
444 /*
445 * Dummy call to list->output to give the offset to the
446 * listing module.
447 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800448 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000449 list->uplevel(LIST_INCBIN);
450 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700451 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000452
H. Peter Anvine2c80182005-01-15 22:15:51 +0000453 fseek(fp, base, SEEK_SET);
454 l = len;
455 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700456 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400457 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000458 if (!m) {
459 /*
460 * This shouldn't happen unless the file
461 * actually changes while we are reading
462 * it.
463 */
464 error(ERR_NONFATAL,
465 "`incbin': unexpected EOF while"
466 " reading file `%s'", fname);
467 t = 0; /* Try to exit cleanly */
468 break;
469 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800470 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000471 NO_SEG, NO_SEG);
472 l -= m;
473 }
474 }
475 list->downlevel(LIST_INCBIN);
476 if (instruction->times > 1) {
477 /*
478 * Dummy call to list->output to give the offset to the
479 * listing module.
480 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800481 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000482 list->uplevel(LIST_TIMES);
483 list->downlevel(LIST_TIMES);
484 }
485 fclose(fp);
486 return instruction->times * len;
487 }
488 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000489 }
490
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700491 /* Check to see if we need an address-size prefix */
492 add_asp(instruction, bits);
493
H. Peter Anvin23595f52009-07-25 17:44:25 -0700494 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700495
H. Peter Anvin23595f52009-07-25 17:44:25 -0700496 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400497 /* Matches! */
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800498 int64_t insn_size = calcsize(segment, offset, bits, instruction, temp);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400499 itimes = instruction->times;
500 if (insn_size < 0) /* shouldn't be, on pass two */
501 error(ERR_PANIC, "errors made it through from pass one");
502 else
503 while (itimes--) {
504 for (j = 0; j < MAXPREFIX; j++) {
505 uint8_t c = 0;
506 switch (instruction->prefixes[j]) {
507 case P_WAIT:
508 c = 0x9B;
509 break;
510 case P_LOCK:
511 c = 0xF0;
512 break;
513 case P_REPNE:
514 case P_REPNZ:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800515 case P_XACQUIRE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400516 c = 0xF2;
517 break;
518 case P_REPE:
519 case P_REPZ:
520 case P_REP:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800521 case P_XRELEASE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400522 c = 0xF3;
523 break;
524 case R_CS:
525 if (bits == 64) {
526 error(ERR_WARNING | ERR_PASS2,
527 "cs segment base generated, but will be ignored in 64-bit mode");
528 }
529 c = 0x2E;
530 break;
531 case R_DS:
532 if (bits == 64) {
533 error(ERR_WARNING | ERR_PASS2,
534 "ds segment base generated, but will be ignored in 64-bit mode");
535 }
536 c = 0x3E;
537 break;
538 case R_ES:
539 if (bits == 64) {
540 error(ERR_WARNING | ERR_PASS2,
541 "es segment base generated, but will be ignored in 64-bit mode");
542 }
543 c = 0x26;
544 break;
545 case R_FS:
546 c = 0x64;
547 break;
548 case R_GS:
549 c = 0x65;
550 break;
551 case R_SS:
552 if (bits == 64) {
553 error(ERR_WARNING | ERR_PASS2,
554 "ss segment base generated, but will be ignored in 64-bit mode");
555 }
556 c = 0x36;
557 break;
558 case R_SEGR6:
559 case R_SEGR7:
560 error(ERR_NONFATAL,
561 "segr6 and segr7 cannot be used as prefixes");
562 break;
563 case P_A16:
564 if (bits == 64) {
565 error(ERR_NONFATAL,
566 "16-bit addressing is not supported "
567 "in 64-bit mode");
568 } else if (bits != 16)
569 c = 0x67;
570 break;
571 case P_A32:
572 if (bits != 32)
573 c = 0x67;
574 break;
575 case P_A64:
576 if (bits != 64) {
577 error(ERR_NONFATAL,
578 "64-bit addressing is only supported "
579 "in 64-bit mode");
580 }
581 break;
582 case P_ASP:
583 c = 0x67;
584 break;
585 case P_O16:
586 if (bits != 16)
587 c = 0x66;
588 break;
589 case P_O32:
590 if (bits == 16)
591 c = 0x66;
592 break;
593 case P_O64:
594 /* REX.W */
595 break;
596 case P_OSP:
597 c = 0x66;
598 break;
599 case P_none:
600 break;
601 default:
602 error(ERR_PANIC, "invalid instruction prefix");
603 }
604 if (c != 0) {
605 out(offset, segment, &c, OUT_RAWDATA, 1,
606 NO_SEG, NO_SEG);
607 offset++;
608 }
609 }
610 insn_end = offset + insn_size;
611 gencode(segment, offset, bits, instruction,
612 temp, insn_end);
613 offset += insn_size;
614 if (itimes > 0 && itimes == instruction->times - 1) {
615 /*
616 * Dummy call to list->output to give the offset to the
617 * listing module.
618 */
619 list->output(offset, NULL, OUT_RAWDATA, 0);
620 list->uplevel(LIST_TIMES);
621 }
622 }
623 if (instruction->times > 1)
624 list->downlevel(LIST_TIMES);
625 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700626 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400627 /* No match */
628 switch (m) {
629 case MERR_OPSIZEMISSING:
630 error(ERR_NONFATAL, "operation size not specified");
631 break;
632 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000633 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400634 break;
635 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000636 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400637 break;
638 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800639 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400640 bits);
641 break;
642 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000643 error(ERR_NONFATAL,
644 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400645 break;
646 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000647 }
648 return 0;
649}
650
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800651int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400652 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000653{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000654 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700655 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000658 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400660 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000661 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700663 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
664 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400665 instruction->opcode == I_DT || instruction->opcode == I_DO ||
666 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000667 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300668 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000669
H. Peter Anvine2c80182005-01-15 22:15:51 +0000670 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300671 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000672
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400673 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000674 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000675
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400677 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000678 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400679 warn_overflow_const(e->offset, wsize);
680 } else if (e->type == EOT_DB_STRING ||
681 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000682 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000683
H. Peter Anvine2c80182005-01-15 22:15:51 +0000684 align = (-osize) % wsize;
685 if (align < 0)
686 align += wsize;
687 isize += osize + align;
688 }
689 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000690 }
691
H. Peter Anvine2c80182005-01-15 22:15:51 +0000692 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400693 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000694 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300695 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700696 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000697
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400698 fp = fopen(fname, "rb");
699 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000700 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
701 fname);
702 else if (fseek(fp, 0L, SEEK_END) < 0)
703 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
704 fname);
705 else {
706 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000707 if (instruction->eops->next) {
708 len -= instruction->eops->next->offset;
709 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700710 len > (size_t)instruction->eops->next->next->offset) {
711 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000712 }
713 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300714 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000715 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300716 if (fp)
717 fclose(fp);
718 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000719 }
720
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700721 /* Check to see if we need an address-size prefix */
722 add_asp(instruction, bits);
723
H. Peter Anvin23595f52009-07-25 17:44:25 -0700724 m = find_match(&temp, instruction, segment, offset, bits);
725 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400726 /* we've matched an instruction. */
727 int64_t isize;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400728 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100729
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800730 isize = calcsize(segment, offset, bits, instruction, temp);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400731 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];
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800799 enum whatwarn { w_none, w_lock, w_inval } ww;
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800800 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
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800811 ww = warn[n][hleok];
812 if (!is_class(MEMORY, ins->oprs[0].type))
813 ww = w_inval; /* HLE requires operand 0 to be memory */
814
815 switch (ww) {
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800816 case w_none:
817 break;
818
819 case w_lock:
820 if (ins->prefixes[PPS_LOCK] != P_LOCK) {
821 errfunc(ERR_WARNING | ERR_PASS2,
822 "%s with this instruction requires lock",
823 prefix_name(rep_pfx));
824 }
825 break;
826
827 case w_inval:
828 errfunc(ERR_WARNING | ERR_PASS2,
829 "%s invalid with this instruction",
830 prefix_name(rep_pfx));
831 break;
832 }
833}
834
H. Peter Anvin507ae032008-10-09 15:37:10 -0700835/* Common construct */
836#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
837
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800838static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800839 insn * ins, const struct itemplate *temp)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000840{
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800841 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800842 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000843 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000844 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700845 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700846 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700847 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700848 enum ea_type eat;
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800849 uint8_t hleok = 0;
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800850 bool lockcheck = true;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000851
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700852 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700853 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700854
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700855 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400856 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700857
H. Peter Anvine2c80182005-01-15 22:15:51 +0000858 (void)segment; /* Don't warn that this parameter is unused */
859 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000860
H. Peter Anvin839eca22007-10-29 23:12:47 -0700861 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400862 c = *codes++;
863 op1 = (c & 3) + ((opex & 1) << 2);
864 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
865 opx = &ins->oprs[op1];
866 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700867
H. Peter Anvin839eca22007-10-29 23:12:47 -0700868 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000869 case 01:
870 case 02:
871 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400872 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000873 codes += c, length += c;
874 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700875
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400876 case 05:
877 case 06:
878 case 07:
879 opex = c;
880 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700881
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400882 case4(010):
883 ins->rex |=
884 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 codes++, length++;
886 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700887
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400888 case4(014):
889 case4(020):
890 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000891 length++;
892 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700893
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400894 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000895 length += 2;
896 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700897
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400898 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700899 if (opx->type & (BITS16 | BITS32 | BITS64))
900 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000901 else
902 length += (bits == 16) ? 2 : 4;
903 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700904
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400905 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000906 length += 4;
907 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700908
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400909 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700910 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700912
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400913 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000914 length++;
915 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700916
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400917 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000918 length += 8; /* MOV reg64/imm */
919 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700920
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400921 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000922 length += 2;
923 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700924
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400925 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700926 if (opx->type & (BITS16 | BITS32 | BITS64))
927 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000928 else
929 length += (bits == 16) ? 2 : 4;
930 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700931
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400932 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000933 length += 4;
934 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700935
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400936 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700937 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000938 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700939
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400940 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700941 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000942 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700943
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400944 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800945 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000946 length++;
947 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700948
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400949 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700950 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700951 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700952
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400953 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800954 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700955 length++;
956 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700957
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400958 case 0172:
959 case 0173:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400960 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700961 length++;
962 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700963
H. Peter Anvincffe61e2011-07-07 17:21:24 -0700964 case4(0174):
965 length++;
966 break;
967
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400968 case4(0250):
969 length += is_sbyte32(opx) ? 1 : 4;
970 break;
971
972 case4(0254):
973 length += 4;
974 break;
975
976 case4(0260):
977 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700978 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400979 ins->vex_cm = *codes++;
980 ins->vex_wlp = *codes++;
981 break;
982
H. Peter Anvin8ea22002012-02-25 10:24:24 -0800983 case 0264:
984 if (has_prefix(ins, PPS_REP, P_XACQUIRE) ||
985 has_prefix(ins, PPS_REP, P_XRELEASE))
986 return -1;
987 break;
988
989 case 0265:
990 case 0266:
991 case 0267:
992 hleok = c & 3;
993 break;
994
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400995 case 0270:
996 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700997 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400998 ins->vex_cm = *codes++;
999 ins->vex_wlp = *codes++;
1000 break;
1001
1002 case4(0274):
1003 length++;
1004 break;
1005
1006 case4(0300):
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 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001010 if (bits == 64)
1011 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001012 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001013 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001014
H. Peter Anvine2c80182005-01-15 22:15:51 +00001015 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001016 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001017 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001018
H. Peter Anvine2c80182005-01-15 22:15:51 +00001019 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001020 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001021
Keith Kaniosb7a89542007-04-12 02:40:54 +00001022 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001023 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1024 has_prefix(ins, PPS_ASIZE, P_A32))
1025 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001026 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001027
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001028 case4(0314):
1029 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001030
H. Peter Anvine2c80182005-01-15 22:15:51 +00001031 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001032 {
1033 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1034 if (pfx == P_O16)
1035 break;
1036 if (pfx != P_none)
1037 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
1038 else
1039 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001040 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001041 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001042
H. Peter Anvine2c80182005-01-15 22:15:51 +00001043 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001044 {
1045 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1046 if (pfx == P_O32)
1047 break;
1048 if (pfx != P_none)
1049 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
1050 else
1051 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001052 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001053 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001054
H. Peter Anvine2c80182005-01-15 22:15:51 +00001055 case 0322:
1056 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001057
Keith Kaniosb7a89542007-04-12 02:40:54 +00001058 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001059 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001060 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001061
Keith Kaniosb7a89542007-04-12 02:40:54 +00001062 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001063 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001064 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001065
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001066 case 0325:
1067 ins->rex |= REX_NH;
1068 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001069
H. Peter Anvine2c80182005-01-15 22:15:51 +00001070 case 0330:
1071 codes++, length++;
1072 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001073
H. Peter Anvine2c80182005-01-15 22:15:51 +00001074 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001075 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001076
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001077 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001078 case 0333:
1079 length++;
1080 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001081
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001082 case 0334:
1083 ins->rex |= REX_L;
1084 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001085
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001086 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001087 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001088
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001089 case 0336:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001090 if (!ins->prefixes[PPS_REP])
1091 ins->prefixes[PPS_REP] = P_REP;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001092 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001093
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001094 case 0337:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001095 if (!ins->prefixes[PPS_REP])
1096 ins->prefixes[PPS_REP] = P_REPNE;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001097 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001098
H. Peter Anvine2c80182005-01-15 22:15:51 +00001099 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001100 if (ins->oprs[0].segment != NO_SEG)
1101 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1102 " quantity of BSS space");
1103 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001104 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001105 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001106
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001107 case 0341:
1108 if (!ins->prefixes[PPS_WAIT])
1109 ins->prefixes[PPS_WAIT] = P_WAIT;
1110 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001111
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001112 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001113 length++;
1114 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001115
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001116 case 0360:
1117 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001118
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001119 case 0361:
1120 case 0362:
1121 case 0363:
1122 length++;
1123 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001124
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001125 case 0364:
1126 case 0365:
1127 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001128
Keith Kanios48af1772007-08-17 07:37:52 +00001129 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001130 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001131 length++;
1132 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001133
H. Peter Anvine2c80182005-01-15 22:15:51 +00001134 case 0370:
1135 case 0371:
1136 case 0372:
1137 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001138
H. Peter Anvine2c80182005-01-15 22:15:51 +00001139 case 0373:
1140 length++;
1141 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001142
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001143 case 0374:
1144 eat = EA_XMMVSIB;
1145 break;
1146
1147 case 0375:
1148 eat = EA_YMMVSIB;
1149 break;
1150
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001151 case4(0100):
1152 case4(0110):
1153 case4(0120):
1154 case4(0130):
1155 case4(0200):
1156 case4(0204):
1157 case4(0210):
1158 case4(0214):
1159 case4(0220):
1160 case4(0224):
1161 case4(0230):
1162 case4(0234):
1163 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001164 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001165 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001166 opflags_t rflags;
1167 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001168
Keith Kaniosb7a89542007-04-12 02:40:54 +00001169 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001170
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001171 if (c <= 0177) {
1172 /* pick rfield from operand b (opx) */
1173 rflags = regflag(opx);
1174 rfield = nasm_regvals[opx->basereg];
1175 } else {
1176 rflags = 0;
1177 rfield = c & 7;
1178 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001179 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1180 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001181 errfunc(ERR_NONFATAL, "invalid effective address");
1182 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001183 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001184 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001185 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001186 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001187 }
1188 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001189
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001190 default:
1191 errfunc(ERR_PANIC, "internal instruction table corrupt"
1192 ": instruction code \\%o (0x%02X) given", c, c);
1193 break;
1194 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001195 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001196
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001197 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001198
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001199 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001200 if (ins->rex & REX_H) {
1201 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1202 return -1;
1203 }
1204 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001205 }
1206
H. Peter Anvind85d2502008-05-04 17:53:31 -07001207 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001208 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001209
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001210 if (ins->rex & REX_H) {
1211 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1212 return -1;
1213 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001214 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001215 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001216 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001217 ins->rex &= ~REX_W;
1218 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001219 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001220 ins->rex |= REX_W;
1221 bad32 &= ~REX_W;
1222 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001223 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001224 /* Follow REX_W */
1225 break;
1226 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001227
H. Peter Anvinfc561202011-07-07 16:58:22 -07001228 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001229 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1230 return -1;
1231 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001232 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001233 length += 3;
1234 else
1235 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001236 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001237 if (ins->rex & REX_H) {
1238 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1239 return -1;
1240 } else if (bits == 64) {
1241 length++;
1242 } else if ((ins->rex & REX_L) &&
1243 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1244 cpu >= IF_X86_64) {
1245 /* LOCK-as-REX.R */
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001246 assert_no_prefix(ins, PPS_LOCK);
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08001247 lockcheck = false; /* Already errored, no need for warning */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001248 length++;
1249 } else {
1250 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1251 return -1;
1252 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001253 }
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08001254
1255 if (has_prefix(ins, PPS_LOCK, P_LOCK) && lockcheck &&
1256 (!(temp->flags & IF_LOCK) || !is_class(MEMORY, ins->oprs[0].type))) {
1257 errfunc(ERR_WARNING | ERR_PASS2,
1258 "instruction is not lockable");
1259 }
1260
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -08001261 bad_hle_warn(ins, hleok);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001262
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001263 return length;
1264}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001265
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001266#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001267 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001268 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1269 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1270 ins->rex = 0; \
1271 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001272 }
1273
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001274static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001275 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001276 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001277{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001278 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001279 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1280 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1281 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001282 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001283 uint8_t c;
1284 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001285 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001286 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001287 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001288 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001289 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001290 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001291 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001292
H. Peter Anvin839eca22007-10-29 23:12:47 -07001293 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001294 c = *codes++;
1295 op1 = (c & 3) + ((opex & 1) << 2);
1296 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1297 opx = &ins->oprs[op1];
1298 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001299
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 case 01:
1302 case 02:
1303 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001304 case 04:
1305 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001306 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001307 codes += c;
1308 offset += c;
1309 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001310
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001311 case 05:
1312 case 06:
1313 case 07:
1314 opex = c;
1315 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001316
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001317 case4(010):
1318 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001319 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001320 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 offset += 1;
1322 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001323
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001324 case4(014):
1325 /*
1326 * The test for BITS8 and SBYTE here is intended to avoid
1327 * warning on optimizer actions due to SBYTE, while still
1328 * warn on explicit BYTE directives. Also warn, obviously,
1329 * if the optimizer isn't enabled.
1330 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001331 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001332 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1333 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001334 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001335 "signed byte value exceeds bounds");
1336 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 if (opx->segment != NO_SEG) {
1338 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001342 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001343 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001344 NO_SEG);
1345 }
1346 offset += 1;
1347 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001348
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001349 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001351 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001352 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001353 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001354 if (opx->segment != NO_SEG) {
1355 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001356 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001358 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001360 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001361 NO_SEG);
1362 }
1363 offset += 1;
1364 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001365
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001366 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001368 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001369 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001370 if (opx->segment != NO_SEG) {
1371 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001372 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001373 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001375 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001376 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 NO_SEG);
1378 }
1379 offset += 1;
1380 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001381
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001382 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001383 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001385 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 offset += 2;
1388 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001389
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001390 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 if (opx->type & (BITS16 | BITS32))
1392 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 else
1394 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001395 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001396 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001397 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 offset += size;
1400 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001401
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001402 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001403 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001404 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 offset += 4;
1408 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001409
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001410 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001411 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001412 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001413 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001414 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001415 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001416 offset += size;
1417 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001418
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001419 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001420 if (opx->segment != segment) {
1421 data = opx->offset;
1422 out(offset, segment, &data,
1423 OUT_REL1ADR, insn_end - offset,
1424 opx->segment, opx->wrt);
1425 } else {
1426 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001427 if (data > 127 || data < -128)
1428 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001429 out(offset, segment, &data,
1430 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1431 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001432 offset += 1;
1433 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001434
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001435 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001436 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001437 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001438 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001439 offset += 8;
1440 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001441
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001442 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001443 if (opx->segment != segment) {
1444 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001445 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001446 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001447 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001448 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001449 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001450 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001451 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001452 }
1453 offset += 2;
1454 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001455
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001456 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001457 if (opx->type & (BITS16 | BITS32 | BITS64))
1458 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001459 else
1460 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001461 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001462 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001463 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001464 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1465 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001466 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001467 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001469 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001470 }
1471 offset += size;
1472 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001473
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001474 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001475 if (opx->segment != segment) {
1476 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001477 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001478 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001479 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001480 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001481 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001482 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001483 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001484 }
1485 offset += 4;
1486 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001487
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001488 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001489 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1491 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001492 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001493 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001494 outfmt->segbase(1 + opx->segment),
1495 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001496 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001497 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001498
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001499 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001500 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001501 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001502 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001503 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001504 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001505 NO_SEG);
1506 offset++;
1507 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001508 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001509 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001510 offset += 2;
1511 }
1512 break;
1513
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001514 case4(0144):
1515 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001516 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001517 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001518 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001519 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001520 offset++;
1521 break;
1522
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001523 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001524 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001525 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001526 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001527 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001528 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001529 NO_SEG);
1530 offset++;
1531 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001532 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001533 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001534 offset += 4;
1535 }
1536 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001537
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001538 case4(0154):
1539 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001540 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001541 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001542 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001543 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001544 offset++;
1545 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001546
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001547 case 0172:
1548 c = *codes++;
1549 opx = &ins->oprs[c >> 3];
1550 bytes[0] = nasm_regvals[opx->basereg] << 4;
1551 opx = &ins->oprs[c & 7];
1552 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1553 errfunc(ERR_NONFATAL,
1554 "non-absolute expression not permitted as argument %d",
1555 c & 7);
1556 } else {
1557 if (opx->offset & ~15) {
1558 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1559 "four-bit argument exceeds bounds");
1560 }
1561 bytes[0] |= opx->offset & 15;
1562 }
1563 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1564 offset++;
1565 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001566
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001567 case 0173:
1568 c = *codes++;
1569 opx = &ins->oprs[c >> 4];
1570 bytes[0] = nasm_regvals[opx->basereg] << 4;
1571 bytes[0] |= c & 15;
1572 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1573 offset++;
1574 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001575
H. Peter Anvincffe61e2011-07-07 17:21:24 -07001576 case4(0174):
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001577 bytes[0] = nasm_regvals[opx->basereg] << 4;
1578 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1579 offset++;
1580 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001581
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001582 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001583 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001584 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1585 (int32_t)data != (int64_t)data) {
1586 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1587 "signed dword immediate exceeds bounds");
1588 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001589 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001590 bytes[0] = data;
1591 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1592 NO_SEG);
1593 offset++;
1594 } else {
1595 out(offset, segment, &data, OUT_ADDRESS, 4,
1596 opx->segment, opx->wrt);
1597 offset += 4;
1598 }
1599 break;
1600
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001601 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001602 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001603 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1604 (int32_t)data != (int64_t)data) {
1605 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1606 "signed dword immediate exceeds bounds");
1607 }
1608 out(offset, segment, &data, OUT_ADDRESS, 4,
1609 opx->segment, opx->wrt);
1610 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001611 break;
1612
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001613 case4(0260):
1614 case 0270:
1615 codes += 2;
1616 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1617 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1618 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1619 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001620 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001621 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1622 offset += 3;
1623 } else {
1624 bytes[0] = 0xc5;
1625 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001626 ((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001627 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1628 offset += 2;
1629 }
1630 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001631
H. Peter Anvin8ea22002012-02-25 10:24:24 -08001632 case4(0264):
1633 break;
1634
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001635 case4(0274):
1636 {
1637 uint64_t uv, um;
1638 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001639
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001640 if (ins->rex & REX_W)
1641 s = 64;
1642 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1643 s = 16;
1644 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1645 s = 32;
1646 else
1647 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001648
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001649 um = (uint64_t)2 << (s-1);
1650 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001651
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001652 if (uv > 127 && uv < (uint64_t)-128 &&
1653 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001654 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001655 "signed byte value exceeds bounds");
1656 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001657 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001658 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001659 out(offset, segment, &data, OUT_ADDRESS, 1,
1660 opx->segment, opx->wrt);
1661 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001662 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001663 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1664 NO_SEG);
1665 }
1666 offset += 1;
1667 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001668 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001669
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001670 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001672
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001674 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001676 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001677 offset += 1;
1678 } else
1679 offset += 0;
1680 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001681
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001683 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001685 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001686 offset += 1;
1687 } else
1688 offset += 0;
1689 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001690
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 case 0312:
1692 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001693
Keith Kaniosb7a89542007-04-12 02:40:54 +00001694 case 0313:
1695 ins->rex = 0;
1696 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001697
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001698 case4(0314):
1699 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001700
H. Peter Anvine2c80182005-01-15 22:15:51 +00001701 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001702 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001703 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001704
H. Peter Anvine2c80182005-01-15 22:15:51 +00001705 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001706 case 0323:
1707 break;
1708
Keith Kaniosb7a89542007-04-12 02:40:54 +00001709 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001710 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001711 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001712
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001713 case 0325:
1714 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001715
H. Peter Anvine2c80182005-01-15 22:15:51 +00001716 case 0330:
1717 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001718 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001719 offset += 1;
1720 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001721
H. Peter Anvine2c80182005-01-15 22:15:51 +00001722 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001723 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001724
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001725 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001726 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001727 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001728 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001729 offset += 1;
1730 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001731
Keith Kanios48af1772007-08-17 07:37:52 +00001732 case 0334:
1733 if (ins->rex & REX_R) {
1734 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001735 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001736 offset += 1;
1737 }
1738 ins->rex &= ~(REX_L|REX_R);
1739 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001740
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001741 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001742 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001743
H. Peter Anvin962e3052008-08-28 17:47:16 -07001744 case 0336:
1745 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001746 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001747
H. Peter Anvine2c80182005-01-15 22:15:51 +00001748 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001749 if (ins->oprs[0].segment != NO_SEG)
1750 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1751 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001752 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001753 if (size > 0)
1754 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001755 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001756 offset += size;
1757 }
1758 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001759
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001760 case 0341:
1761 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001762
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001763 case 0344:
1764 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001765 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001766 switch (ins->oprs[0].basereg) {
1767 case R_CS:
1768 bytes[0] += 0x0E;
1769 break;
1770 case R_DS:
1771 bytes[0] += 0x1E;
1772 break;
1773 case R_ES:
1774 bytes[0] += 0x06;
1775 break;
1776 case R_SS:
1777 bytes[0] += 0x16;
1778 break;
1779 default:
1780 errfunc(ERR_PANIC,
1781 "bizarre 8086 segment register received");
1782 }
1783 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1784 offset++;
1785 break;
1786
1787 case 0346:
1788 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001789 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001790 switch (ins->oprs[0].basereg) {
1791 case R_FS:
1792 bytes[0] += 0xA0;
1793 break;
1794 case R_GS:
1795 bytes[0] += 0xA8;
1796 break;
1797 default:
1798 errfunc(ERR_PANIC,
1799 "bizarre 386 segment register received");
1800 }
1801 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1802 offset++;
1803 break;
1804
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001805 case 0360:
1806 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001807
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001808 case 0361:
1809 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001810 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1811 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001812 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001813
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001814 case 0362:
1815 case 0363:
1816 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001817 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1818 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001819 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001820
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001821 case 0364:
1822 case 0365:
1823 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001824
Keith Kanios48af1772007-08-17 07:37:52 +00001825 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001826 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001827 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001828 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001829 offset += 1;
1830 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001831
H. Peter Anvine2c80182005-01-15 22:15:51 +00001832 case 0370:
1833 case 0371:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001835
H. Peter Anvine2c80182005-01-15 22:15:51 +00001836 case 0373:
1837 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001838 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001839 offset += 1;
1840 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001841
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001842 case 0374:
1843 eat = EA_XMMVSIB;
1844 break;
1845
1846 case 0375:
1847 eat = EA_YMMVSIB;
1848 break;
1849
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001850 case4(0100):
1851 case4(0110):
1852 case4(0120):
1853 case4(0130):
1854 case4(0200):
1855 case4(0204):
1856 case4(0210):
1857 case4(0214):
1858 case4(0220):
1859 case4(0224):
1860 case4(0230):
1861 case4(0234):
1862 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001863 ea ea_data;
1864 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001865 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001866 uint8_t *p;
1867 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001868 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001869
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001870 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001871 /* pick rfield from operand b (opx) */
1872 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001873 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001874 } else {
1875 /* rfield is constant */
1876 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001877 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001878 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001879
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001880 if (process_ea(opy, &ea_data, bits, ins->addr_size,
Cyrill Gorcunovcdb8cd72011-08-28 16:33:39 +04001881 rfield, rflags) != eat)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001882 errfunc(ERR_NONFATAL, "invalid effective address");
Charles Crayne7e975552007-11-03 22:06:13 -07001883
H. Peter Anvine2c80182005-01-15 22:15:51 +00001884 p = bytes;
1885 *p++ = ea_data.modrm;
1886 if (ea_data.sib_present)
1887 *p++ = ea_data.sib;
1888
1889 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001890 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001891
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001892 /*
1893 * Make sure the address gets the right offset in case
1894 * the line breaks in the .lst file (BR 1197827)
1895 */
1896 offset += s;
1897 s = 0;
1898
H. Peter Anvine2c80182005-01-15 22:15:51 +00001899 switch (ea_data.bytes) {
1900 case 0:
1901 break;
1902 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001903 case 2:
1904 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001905 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001906 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001907 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001908 if (ea_data.rip) {
1909 if (opy->segment == segment) {
1910 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001911 if (overflow_signed(data, ea_data.bytes))
1912 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001913 out(offset, segment, &data, OUT_ADDRESS,
1914 ea_data.bytes, NO_SEG, NO_SEG);
1915 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001916 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001917 out(offset, segment, &data, OUT_REL4ADR,
1918 insn_end - offset, opy->segment, opy->wrt);
1919 }
1920 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001921 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1922 signed_bits(opy->offset, ins->addr_size) !=
1923 signed_bits(opy->offset, ea_data.bytes * 8))
1924 warn_overflow(ERR_PASS2, ea_data.bytes);
1925
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001926 out(offset, segment, &data, OUT_ADDRESS,
1927 ea_data.bytes, opy->segment, opy->wrt);
1928 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001929 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001930 default:
1931 /* Impossible! */
1932 errfunc(ERR_PANIC,
1933 "Invalid amount of bytes (%d) for offset?!",
1934 ea_data.bytes);
1935 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001936 }
1937 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001938 }
1939 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001940
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001941 default:
1942 errfunc(ERR_PANIC, "internal instruction table corrupt"
1943 ": instruction code \\%o (0x%02X) given", c, c);
1944 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001945 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001946 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001947}
1948
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001949static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001950{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001951 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001952 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001953 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001954}
1955
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001956static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001957{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001958 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001959 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001960 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001961}
1962
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001963static int op_rexflags(const operand * o, int mask)
1964{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001965 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001966 int val;
1967
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001968 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001969 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001970
H. Peter Anvina4835d42008-05-20 14:21:29 -07001971 flags = nasm_reg_flags[o->basereg];
1972 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001973
1974 return rexflags(val, flags, mask);
1975}
1976
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001977static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001978{
1979 int rex = 0;
1980
1981 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001982 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001983 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001984 rex |= REX_W;
1985 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1986 rex |= REX_H;
1987 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1988 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001989
1990 return rex & mask;
1991}
1992
H. Peter Anvin23595f52009-07-25 17:44:25 -07001993static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001994 insn *instruction,
1995 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001996{
1997 const struct itemplate *temp;
1998 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001999 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07002000 bool opsizemissing = false;
2001 int i;
2002
2003 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002004 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002005
2006 merr = MERR_INVALOP;
2007
2008 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002009 temp->opcode != I_none; temp++) {
2010 m = matches(temp, instruction, bits);
2011 if (m == MOK_JUMP) {
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08002012 if (jmp_match(segment, offset, bits, instruction, temp))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002013 m = MOK_GOOD;
2014 else
2015 m = MERR_INVALOP;
2016 } else if (m == MERR_OPSIZEMISSING &&
2017 (temp->flags & IF_SMASK) != IF_SX) {
2018 /*
2019 * Missing operand size and a candidate for fuzzy matching...
2020 */
2021 for (i = 0; i < temp->operands; i++) {
2022 if ((temp->opd[i] & SAME_AS) == 0)
2023 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
2024 }
2025 opsizemissing = true;
2026 }
2027 if (m > merr)
2028 merr = m;
2029 if (merr == MOK_GOOD)
2030 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002031 }
2032
2033 /* No match, but see if we can get a fuzzy operand size match... */
2034 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002035 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002036
2037 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002038 /*
2039 * We ignore extrinsic operand sizes on registers, so we should
2040 * never try to fuzzy-match on them. This also resolves the case
2041 * when we have e.g. "xmmrm128" in two different positions.
2042 */
2043 if (is_class(REGISTER, instruction->oprs[i].type))
2044 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002045
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002046 /* This tests if xsizeflags[i] has more than one bit set */
2047 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2048 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002049
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002050 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002051 }
2052
2053 /* Try matching again... */
2054 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002055 temp->opcode != I_none; temp++) {
2056 m = matches(temp, instruction, bits);
2057 if (m == MOK_JUMP) {
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08002058 if (jmp_match(segment, offset, bits, instruction, temp))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002059 m = MOK_GOOD;
2060 else
2061 m = MERR_INVALOP;
2062 }
2063 if (m > merr)
2064 merr = m;
2065 if (merr == MOK_GOOD)
2066 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002067 }
2068
H. Peter Anvina81655b2009-07-25 18:15:28 -07002069done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002070 *tempp = temp;
2071 return merr;
2072}
2073
H. Peter Anvin65289e82009-07-25 17:25:11 -07002074static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002075 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002076{
H. Peter Anvin60926242009-07-26 16:25:38 -07002077 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002078 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002079
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002080 /*
2081 * Check the opcode
2082 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002083 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002084 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002085
2086 /*
2087 * Count the operands
2088 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002089 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002090 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002091
2092 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002093 * Is it legal?
2094 */
2095 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2096 return MERR_INVALOP;
2097
2098 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002099 * Check that no spurious colons or TOs are present
2100 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002101 for (i = 0; i < itemp->operands; i++)
2102 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002103 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002104
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002105 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002106 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002107 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002108 switch (itemp->flags & IF_SMASK) {
2109 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002110 asize = BITS8;
2111 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002112 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002113 asize = BITS16;
2114 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002115 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002116 asize = BITS32;
2117 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002118 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002119 asize = BITS64;
2120 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002121 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002122 asize = BITS128;
2123 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002124 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002125 asize = BITS256;
2126 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002127 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002128 switch (bits) {
2129 case 16:
2130 asize = BITS16;
2131 break;
2132 case 32:
2133 asize = BITS32;
2134 break;
2135 case 64:
2136 asize = BITS64;
2137 break;
2138 default:
2139 asize = 0;
2140 break;
2141 }
2142 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002143 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002144 asize = 0;
2145 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002146 }
2147
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002148 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002149 /* S- flags only apply to a specific operand */
2150 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2151 memset(size, 0, sizeof size);
2152 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002153 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002154 /* S- flags apply to all operands */
2155 for (i = 0; i < MAX_OPERANDS; i++)
2156 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002157 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002158
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002159 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002160 * Check that the operand flags all match up,
2161 * it's a bit tricky so lets be verbose:
2162 *
2163 * 1) Find out the size of operand. If instruction
2164 * doesn't have one specified -- we're trying to
2165 * guess it either from template (IF_S* flag) or
2166 * from code bits.
2167 *
2168 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2169 * (ie the same operand as was specified somewhere in template, and
2170 * this referred operand index is being achieved via ~SAME_AS)
2171 * we are to be sure that both registers (in template and instruction)
2172 * do exactly match.
2173 *
2174 * 3) If template operand do not match the instruction OR
2175 * template has an operand size specified AND this size differ
2176 * from which instruction has (perhaps we got it from code bits)
2177 * we are:
2178 * a) Check that only size of instruction and operand is differ
2179 * other characteristics do match
2180 * b) Perhaps it's a register specified in instruction so
2181 * for such a case we just mark that operand as "size
2182 * missing" and this will turn on fuzzy operand size
2183 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002184 */
2185 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002186 opflags_t type = instruction->oprs[i].type;
2187 if (!(type & SIZE_MASK))
2188 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002189
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002190 if (itemp->opd[i] & SAME_AS) {
2191 int j = itemp->opd[i] & ~SAME_AS;
2192 if (type != instruction->oprs[j].type ||
2193 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2194 return MERR_INVALOP;
2195 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002196 ((itemp->opd[i] & SIZE_MASK) &&
2197 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002198 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002199 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002200 } else if (!is_class(REGISTER, type)) {
2201 /*
2202 * Note: we don't honor extrinsic operand sizes for registers,
2203 * so "missing operand size" for a register should be
2204 * considered a wildcard match rather than an error.
2205 */
2206 opsizemissing = true;
2207 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002208 }
2209 }
2210
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002211 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002212 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002213
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002214 /*
2215 * Check operand sizes
2216 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002217 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002218 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002219 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002220 asize = itemp->opd[i] & SIZE_MASK;
2221 if (asize) {
2222 for (i = 0; i < oprs; i++)
2223 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002224 break;
2225 }
2226 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002227 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002228 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002229 }
2230
Keith Kaniosb7a89542007-04-12 02:40:54 +00002231 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002232 if (!(itemp->opd[i] & SIZE_MASK) &&
2233 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002234 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002235 }
2236
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002237 /*
2238 * Check template is okay at the set cpu level
2239 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002240 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002241 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002242
Keith Kaniosb7a89542007-04-12 02:40:54 +00002243 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002244 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002245 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002246 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002247 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002248
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002249 /*
2250 * Check if special handling needed for Jumps
2251 */
H. Peter Anvin755f5212012-02-25 11:41:34 -08002252 if ((itemp->code[0] & ~1) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002253 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002254
H. Peter Anvin60926242009-07-26 16:25:38 -07002255 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002256}
2257
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002258static enum ea_type process_ea(operand *input, ea *output, int bits,
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002259 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002260{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002261 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002262
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002263 output->type = EA_SCALAR;
2264 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002265
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002266 /* REX flags for the rfield operand */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002267 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002268
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002269 if (is_class(REGISTER, input->type)) {
2270 /*
2271 * It's a direct register.
2272 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002273 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002274
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002275 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002276 goto err;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002277
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002278 f = regflag(input);
2279
2280 if (!is_class(REG_EA, f))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002281 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002282
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002283 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002284 output->sib_present = false; /* no SIB necessary */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002285 output->bytes = 0; /* no offset necessary either */
2286 output->modrm = GEN_MODRM(3, rfield, nasm_regvals[input->basereg]);
2287 } else {
2288 /*
2289 * It's a memory reference.
2290 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002291 if (input->basereg == -1 &&
2292 (input->indexreg == -1 || input->scale == 0)) {
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002293 /*
2294 * It's a pure offset.
2295 */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002296 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2297 input->segment == NO_SEG) {
2298 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2299 input->type &= ~IP_REL;
2300 input->type |= MEMORY;
2301 }
2302
2303 if (input->eaflags & EAF_BYTEOFFS ||
2304 (input->eaflags & EAF_WORDOFFS &&
2305 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2306 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2307 }
2308
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002309 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002310 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002311 output->sib = GEN_SIB(0, 4, 5);
2312 output->bytes = 4;
2313 output->modrm = GEN_MODRM(0, rfield, 4);
2314 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002315 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002316 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002317 output->bytes = (addrbits != 16 ? 4 : 2);
2318 output->modrm = GEN_MODRM(0, rfield, (addrbits != 16 ? 5 : 6));
2319 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002320 }
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002321 } else {
2322 /*
2323 * It's an indirection.
2324 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002325 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002326 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002327 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002328 int t, it, bt; /* register numbers */
2329 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002330
H. Peter Anvine2c80182005-01-15 22:15:51 +00002331 if (s == 0)
2332 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002333
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002334 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002335 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002336 ix = nasm_reg_flags[i];
2337 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002338 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002339 ix = 0;
2340 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002341
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002342 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002343 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002344 bx = nasm_reg_flags[b];
2345 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002346 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002347 bx = 0;
2348 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002349
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002350 /* if either one are a vector register... */
2351 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
2352 int32_t sok = BITS32 | BITS64;
2353 int32_t o = input->offset;
2354 int mod, scale, index, base;
2355
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002356 /*
2357 * For a vector SIB, one has to be a vector and the other,
2358 * if present, a GPR. The vector must be the index operand.
2359 */
2360 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2361 if (s == 0)
2362 s = 1;
2363 else if (s != 1)
2364 goto err;
2365
2366 t = bt, bt = it, it = t;
2367 x = bx, bx = ix, ix = x;
2368 }
2369
2370 if (bt != -1) {
2371 if (REG_GPR & ~bx)
2372 goto err;
2373 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2374 sok &= bx;
2375 else
2376 goto err;
2377 }
2378
2379 /*
2380 * While we're here, ensure the user didn't specify
2381 * WORD or QWORD
2382 */
2383 if (input->disp_size == 16 || input->disp_size == 64)
2384 goto err;
2385
2386 if (addrbits == 16 ||
2387 (addrbits == 32 && !(sok & BITS32)) ||
2388 (addrbits == 64 && !(sok & BITS64)))
2389 goto err;
2390
2391 output->type = (ix & YMMREG & ~REG_EA)
2392 ? EA_YMMVSIB : EA_XMMVSIB;
2393
2394 output->rex |= rexflags(it, ix, REX_X);
2395 output->rex |= rexflags(bt, bx, REX_B);
2396
2397 index = it & 7; /* it is known to be != -1 */
2398
2399 switch (s) {
2400 case 1:
2401 scale = 0;
2402 break;
2403 case 2:
2404 scale = 1;
2405 break;
2406 case 4:
2407 scale = 2;
2408 break;
2409 case 8:
2410 scale = 3;
2411 break;
2412 default: /* then what the smeg is it? */
2413 goto err; /* panic */
2414 }
2415
2416 if (bt == -1) {
2417 base = 5;
2418 mod = 0;
2419 } else {
2420 base = (bt & 7);
2421 if (base != REG_NUM_EBP && o == 0 &&
2422 seg == NO_SEG && !forw_ref &&
2423 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2424 mod = 0;
2425 else if (input->eaflags & EAF_BYTEOFFS ||
2426 (o >= -128 && o <= 127 &&
2427 seg == NO_SEG && !forw_ref &&
2428 !(input->eaflags & EAF_WORDOFFS)))
2429 mod = 1;
2430 else
2431 mod = 2;
2432 }
2433
2434 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002435 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2436 output->modrm = GEN_MODRM(mod, rfield, 4);
2437 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002438 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002439 /*
2440 * it must be a 32/64-bit memory reference. Firstly we have
2441 * to check that all registers involved are type E/Rxx.
2442 */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002443 int32_t sok = BITS32 | BITS64;
2444 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002445
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002446 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002447 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2448 sok &= ix;
2449 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002450 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002451 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002452
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002453 if (bt != -1) {
2454 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002455 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002456 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002457 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002458 sok &= bx;
2459 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002460
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002461 /*
2462 * While we're here, ensure the user didn't specify
2463 * WORD or QWORD
2464 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002465 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002466 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002467
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002468 if (addrbits == 16 ||
2469 (addrbits == 32 && !(sok & BITS32)) ||
2470 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002471 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002472
Keith Kaniosb7a89542007-04-12 02:40:54 +00002473 /* now reorganize base/index */
2474 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002475 ((hb == b && ht == EAH_NOTBASE) ||
2476 (hb == i && ht == EAH_MAKEBASE))) {
2477 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002478 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002479 x = bx, bx = ix, ix = x;
2480 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002481 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002482 bt = -1, bx = 0, s++;
2483 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002484 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002485 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002486 }
2487 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2488 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002489 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002490 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2491 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002492 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002493 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002494 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002495 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002496 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002497 x = ix, ix = bx, bx = x;
2498 }
2499 if (it == REG_NUM_ESP ||
2500 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002501 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002502
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002503 output->rex |= rexflags(it, ix, REX_X);
2504 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002505
Keith Kanios48af1772007-08-17 07:37:52 +00002506 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002507 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002508 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002509
Keith Kaniosb7a89542007-04-12 02:40:54 +00002510 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002511 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002512 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002513 } else {
2514 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002515 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002516 seg == NO_SEG && !forw_ref &&
2517 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002518 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002519 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002520 (o >= -128 && o <= 127 &&
2521 seg == NO_SEG && !forw_ref &&
2522 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002523 mod = 1;
2524 else
2525 mod = 2;
2526 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002527
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002528 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002529 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2530 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002531 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002532 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002533 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002534
Keith Kaniosb7a89542007-04-12 02:40:54 +00002535 if (it == -1)
2536 index = 4, s = 1;
2537 else
2538 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002539
H. Peter Anvine2c80182005-01-15 22:15:51 +00002540 switch (s) {
2541 case 1:
2542 scale = 0;
2543 break;
2544 case 2:
2545 scale = 1;
2546 break;
2547 case 4:
2548 scale = 2;
2549 break;
2550 case 8:
2551 scale = 3;
2552 break;
2553 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002554 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002555 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002556
Keith Kaniosb7a89542007-04-12 02:40:54 +00002557 if (bt == -1) {
2558 base = 5;
2559 mod = 0;
2560 } else {
2561 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002562 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002563 seg == NO_SEG && !forw_ref &&
2564 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002565 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002566 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002567 (o >= -128 && o <= 127 &&
2568 seg == NO_SEG && !forw_ref &&
2569 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002570 mod = 1;
2571 else
2572 mod = 2;
2573 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002574
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002575 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002576 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2577 output->modrm = GEN_MODRM(mod, rfield, 4);
2578 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002579 }
2580 } else { /* it's 16-bit */
2581 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002582 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002583
Keith Kaniosb7a89542007-04-12 02:40:54 +00002584 /* check for 64-bit long mode */
2585 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002586 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002587
H. Peter Anvine2c80182005-01-15 22:15:51 +00002588 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002589 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2590 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002591 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002592
Keith Kaniosb7a89542007-04-12 02:40:54 +00002593 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002594 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002595 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002596
H. Peter Anvine2c80182005-01-15 22:15:51 +00002597 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002598 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002599 if (b == -1 && i != -1) {
2600 int tmp = b;
2601 b = i;
2602 i = tmp;
2603 } /* swap */
2604 if ((b == R_SI || b == R_DI) && i != -1) {
2605 int tmp = b;
2606 b = i;
2607 i = tmp;
2608 }
2609 /* have BX/BP as base, SI/DI index */
2610 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002611 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002612 if (i != -1 && b != -1 &&
2613 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002614 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002615 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002616 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002617
H. Peter Anvine2c80182005-01-15 22:15:51 +00002618 rm = -1;
2619 if (i != -1)
2620 switch (i * 256 + b) {
2621 case R_SI * 256 + R_BX:
2622 rm = 0;
2623 break;
2624 case R_DI * 256 + R_BX:
2625 rm = 1;
2626 break;
2627 case R_SI * 256 + R_BP:
2628 rm = 2;
2629 break;
2630 case R_DI * 256 + R_BP:
2631 rm = 3;
2632 break;
2633 } else
2634 switch (b) {
2635 case R_SI:
2636 rm = 4;
2637 break;
2638 case R_DI:
2639 rm = 5;
2640 break;
2641 case R_BP:
2642 rm = 6;
2643 break;
2644 case R_BX:
2645 rm = 7;
2646 break;
2647 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002648 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002649 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002650
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002651 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2652 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002653 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002654 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002655 (o >= -128 && o <= 127 && seg == NO_SEG &&
2656 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002657 mod = 1;
2658 else
2659 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002660
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002661 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002662 output->bytes = mod; /* bytes of offset needed */
2663 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002664 }
2665 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002666 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002667
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002668 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002669 return output->type;
2670
2671err:
2672 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002673}
2674
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002675static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002676{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002677 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002678 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002679
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002680 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002681
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002682 switch (ins->prefixes[PPS_ASIZE]) {
2683 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002684 valid &= 16;
2685 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002686 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002687 valid &= 32;
2688 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002689 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002690 valid &= 64;
2691 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002692 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002693 valid &= (addrbits == 32) ? 16 : 32;
2694 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002695 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002696 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002697 }
2698
2699 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002700 if (is_class(MEMORY, ins->oprs[j].type)) {
2701 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002702
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002703 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002704 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002705 i = 0;
2706 else
2707 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002708
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002709 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002710 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002711 b = 0;
2712 else
2713 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002714
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002715 if (ins->oprs[j].scale == 0)
2716 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002717
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002718 if (!i && !b) {
2719 int ds = ins->oprs[j].disp_size;
2720 if ((addrbits != 64 && ds > 8) ||
2721 (addrbits == 64 && ds == 16))
2722 valid &= ds;
2723 } else {
2724 if (!(REG16 & ~b))
2725 valid &= 16;
2726 if (!(REG32 & ~b))
2727 valid &= 32;
2728 if (!(REG64 & ~b))
2729 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002730
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002731 if (!(REG16 & ~i))
2732 valid &= 16;
2733 if (!(REG32 & ~i))
2734 valid &= 32;
2735 if (!(REG64 & ~i))
2736 valid &= 64;
2737 }
2738 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002739 }
2740
2741 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002742 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002743 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002744 /* Add an address size prefix */
Cyrill Gorcunovd6851d42011-09-25 18:01:45 +04002745 ins->prefixes[PPS_ASIZE] = (addrbits == 32) ? P_A16 : P_A32;;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002746 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002747 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002748 /* Impossible... */
2749 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2750 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002751 }
2752
2753 defdisp = ins->addr_size == 16 ? 16 : 32;
2754
2755 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002756 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2757 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2758 /*
2759 * mem_offs sizes must match the address size; if not,
2760 * strip the MEM_OFFS bit and match only EA instructions
2761 */
2762 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2763 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002764 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002765}