blob: 06fba53b6243924fd923617df056405aeb067e1b [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.
83 * \270 - this instruction uses VEX/XOP rather than REX, with the
84 * V field set to 1111b.
H. Peter Anvind85d2502008-05-04 17:53:31 -070085 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070086 * VEX/XOP prefixes are followed by the sequence:
87 * \tmm\wlp where mm is the M field; and wlp is:
H. Peter Anvin421059c2010-08-16 14:56:33 -070088 * 00 wwl lpp
89 * [l0] ll = 0 for L = 0 (.128, .lz)
90 * [l1] ll = 1 for L = 1 (.256)
91 * [lig] ll = 2 for L don't care (always assembled as 0)
92 *
H. Peter Anvin978c2172010-08-16 13:48:43 -070093 * [w0] ww = 0 for W = 0
94 * [w1 ] ww = 1 for W = 1
95 * [wig] ww = 2 for W don't care (always assembled as 0)
96 * [ww] ww = 3 for W used as REX.W
H. Peter Anvinbd420c72008-05-22 11:24:35 -070097 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070098 * t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
H. Peter Anvind85d2502008-05-04 17:53:31 -070099 *
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800100 * \271 - instruction takes XRELEASE (F3) with or without lock
101 * \272 - instruction takes XACQUIRE/XRELEASE with or without lock
102 * \273 - instruction takes XACQUIRE/XRELEASE with lock only
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700103 * \274..\277 - a signed byte immediate operand, from operand 0..3,
104 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000105 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
106 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -0700107 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +0000108 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -0800109 * \314 - (disassembler only) invalid with REX.B
110 * \315 - (disassembler only) invalid with REX.X
111 * \316 - (disassembler only) invalid with REX.R
112 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
114 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
115 * \322 - indicates that this instruction is only valid when the
116 * operand size is the default (instruction to disassembler,
117 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000118 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000119 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400120 * \325 - instruction which always uses spl/bpl/sil/dil
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000121 * \330 - a literal byte follows in the code stream, to be added
122 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000123 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000124 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700125 * \332 - REP prefix (0xF2 byte) used as opcode extension.
126 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700127 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700128 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700129 * \336 - force a REP(E) prefix (0xF2) even if not specified.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400130 * \337 - force a REPNE prefix (0xF3) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700131 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000132 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000133 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400134 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700135 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
136 * (POP is never used for CS) depending on operand 0
137 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
138 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400139 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700140 * \361 - 66 SSE prefix (== \366\331)
141 * \362 - F2 SSE prefix (== \364\332)
142 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000143 * \364 - operand-size prefix (0x66) not permitted
144 * \365 - address-size prefix (0x67) not permitted
145 * \366 - operand-size prefix (0x66) used as opcode extension
146 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000147 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400148 * 370 is used for Jcc, 371 is used for JMP.
149 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
150 * used for conditional jump over longer jump
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700151 * \374 - this instruction takes an XMM VSIB memory EA
152 * \375 - this instruction takes an YMM VSIB memory EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000153 */
154
H. Peter Anvinfe501952007-10-02 21:53:51 -0700155#include "compiler.h"
156
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000157#include <stdio.h>
158#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000159#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000160
161#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000162#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000163#include "assemble.h"
164#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700165#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000166
H. Peter Anvin65289e82009-07-25 17:25:11 -0700167enum match_result {
168 /*
169 * Matching errors. These should be sorted so that more specific
170 * errors come later in the sequence.
171 */
172 MERR_INVALOP,
173 MERR_OPSIZEMISSING,
174 MERR_OPSIZEMISMATCH,
175 MERR_BADCPU,
176 MERR_BADMODE,
177 /*
178 * Matching success; the conditional ones first
179 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400180 MOK_JUMP, /* Matching OK but needs jmp_match() */
181 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700182};
183
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000184typedef struct {
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700185 enum ea_type type; /* what kind of EA is this? */
186 int sib_present; /* is a SIB byte necessary? */
187 int bytes; /* # of bytes of offset needed */
188 int size; /* lazy - this is sib+bytes+1 */
189 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000190} ea;
191
Cyrill Gorcunov10734c72011-08-29 00:07:17 +0400192#define GEN_SIB(scale, index, base) \
193 (((scale) << 6) | ((index) << 3) | ((base)))
194
195#define GEN_MODRM(mod, reg, rm) \
196 (((mod) << 6) | (((reg) & 7) << 3) | ((rm) & 7))
197
Keith Kaniosb7a89542007-04-12 02:40:54 +0000198static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000199static efunc errfunc;
200static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000201static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000202
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700203static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700204static void gencode(int32_t segment, int64_t offset, int bits,
205 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400206 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700207static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400208 insn *instruction,
209 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700210static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700211static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000212static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700213static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000214static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700215static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000216
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700217static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
218
Cyrill Gorcunov18914e62011-11-12 11:41:51 +0400219static int has_prefix(insn * ins, enum prefix_pos pos, int prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000220{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700221 return ins->prefixes[pos] == prefix;
222}
223
224static void assert_no_prefix(insn * ins, enum prefix_pos pos)
225{
226 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400227 errfunc(ERR_NONFATAL, "invalid %s prefix",
228 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700229}
230
231static const char *size_name(int size)
232{
233 switch (size) {
234 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400235 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700236 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400237 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700238 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400239 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700240 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400241 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700242 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400243 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700244 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400245 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700246 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400247 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700248 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400249 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000250 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700251}
252
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400253static void warn_overflow(int pass, int size)
254{
255 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
256 "%s data exceeds bounds", size_name(size));
257}
258
259static void warn_overflow_const(int64_t data, int size)
260{
261 if (overflow_general(data, size))
262 warn_overflow(ERR_PASS1, size);
263}
264
265static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700266{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100267 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400268 if (overflow_general(o->offset, size))
269 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700270 }
271}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400272
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000273/*
274 * This routine wrappers the real output format's output routine,
275 * in order to pass a copy of the data off to the listing file
276 * generator at the same time.
277 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800278static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800279 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400280 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000281{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000282 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000283 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800284 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000285
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800286 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400287 /*
288 * This is a non-relocated address, and we're going to
289 * convert it into RAWDATA format.
290 */
291 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800292
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400293 if (size > 8) {
294 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
295 return;
296 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700297
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400298 WRITEADDR(q, *(int64_t *)data, size);
299 data = p;
300 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000301 }
302
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800303 list->output(offset, data, type, size);
304
Frank Kotlerabebb082003-09-06 04:45:37 +0000305 /*
306 * this call to src_get determines when we call the
307 * debug-format-specific "linenum" function
308 * it updates lineno and lnfname to the current values
309 * returning 0 if "same as last time", -2 if lnfname
310 * changed, and the amount by which lineno changed,
311 * if it did. thus, these variables must be static
312 */
313
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400314 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000315 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000316
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800317 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000318}
319
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700320static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700321 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000322{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800323 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000324 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000325
Charles Craynef1aefd82008-09-30 16:11:32 -0700326 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700327 return false;
328 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400329 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700330 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400331 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700332
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100334
Victor van den Elzen154e5922009-02-25 17:32:00 +0100335 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100336 /* Be optimistic in pass 1 */
337 return true;
338
H. Peter Anvine2c80182005-01-15 22:15:51 +0000339 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700340 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000341
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700342 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
343 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000344}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000345
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800346int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400347 insn * instruction, struct ofmt *output, efunc error,
348 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000349{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000350 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000351 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700352 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800353 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000354 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800355 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300356 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000357
H. Peter Anvine2c80182005-01-15 22:15:51 +0000358 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000359 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000360 outfmt = output; /* likewise */
361 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000362
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300363 wsize = idata_bytes(instruction->opcode);
364 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000365 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000366
H. Peter Anvineba20a72002-04-30 20:53:55 +0000367 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000368 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000369 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 if (t < 0)
371 errfunc(ERR_PANIC,
372 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000373
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400375 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400377 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700378 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400379 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000380 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700381 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800383 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400384 offset += wsize;
385 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700386 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400387 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000388 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000389
H. Peter Anvine2c80182005-01-15 22:15:51 +0000390 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800391 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000392 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000393
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 if (align) {
395 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100396 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800397 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 }
399 offset += e->stringlen + align;
400 }
401 }
402 if (t > 0 && t == instruction->times - 1) {
403 /*
404 * Dummy call to list->output to give the offset to the
405 * listing module.
406 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800407 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000408 list->uplevel(LIST_TIMES);
409 }
410 }
411 if (instruction->times > 1)
412 list->downlevel(LIST_TIMES);
413 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000414 }
415
H. Peter Anvine2c80182005-01-15 22:15:51 +0000416 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700417 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000418 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000419
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400420 fp = fopen(fname, "rb");
421 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
423 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400424 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000425 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
426 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400427 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700428 static char buf[4096];
429 size_t t = instruction->times;
430 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400431 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000432
H. Peter Anvine2c80182005-01-15 22:15:51 +0000433 len = ftell(fp);
434 if (instruction->eops->next) {
435 base = instruction->eops->next->offset;
436 len -= base;
437 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700438 len > (size_t)instruction->eops->next->next->offset)
439 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000440 }
441 /*
442 * Dummy call to list->output to give the offset to the
443 * listing module.
444 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800445 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 list->uplevel(LIST_INCBIN);
447 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700448 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000449
H. Peter Anvine2c80182005-01-15 22:15:51 +0000450 fseek(fp, base, SEEK_SET);
451 l = len;
452 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700453 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400454 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000455 if (!m) {
456 /*
457 * This shouldn't happen unless the file
458 * actually changes while we are reading
459 * it.
460 */
461 error(ERR_NONFATAL,
462 "`incbin': unexpected EOF while"
463 " reading file `%s'", fname);
464 t = 0; /* Try to exit cleanly */
465 break;
466 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800467 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000468 NO_SEG, NO_SEG);
469 l -= m;
470 }
471 }
472 list->downlevel(LIST_INCBIN);
473 if (instruction->times > 1) {
474 /*
475 * Dummy call to list->output to give the offset to the
476 * listing module.
477 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800478 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000479 list->uplevel(LIST_TIMES);
480 list->downlevel(LIST_TIMES);
481 }
482 fclose(fp);
483 return instruction->times * len;
484 }
485 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000486 }
487
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700488 /* Check to see if we need an address-size prefix */
489 add_asp(instruction, bits);
490
H. Peter Anvin23595f52009-07-25 17:44:25 -0700491 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700492
H. Peter Anvin23595f52009-07-25 17:44:25 -0700493 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400494 /* Matches! */
495 int64_t insn_size = calcsize(segment, offset, bits,
496 instruction, temp->code);
497 itimes = instruction->times;
498 if (insn_size < 0) /* shouldn't be, on pass two */
499 error(ERR_PANIC, "errors made it through from pass one");
500 else
501 while (itimes--) {
502 for (j = 0; j < MAXPREFIX; j++) {
503 uint8_t c = 0;
504 switch (instruction->prefixes[j]) {
505 case P_WAIT:
506 c = 0x9B;
507 break;
508 case P_LOCK:
509 c = 0xF0;
510 break;
511 case P_REPNE:
512 case P_REPNZ:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800513 case P_XACQUIRE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400514 c = 0xF2;
515 break;
516 case P_REPE:
517 case P_REPZ:
518 case P_REP:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800519 case P_XRELEASE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400520 c = 0xF3;
521 break;
522 case R_CS:
523 if (bits == 64) {
524 error(ERR_WARNING | ERR_PASS2,
525 "cs segment base generated, but will be ignored in 64-bit mode");
526 }
527 c = 0x2E;
528 break;
529 case R_DS:
530 if (bits == 64) {
531 error(ERR_WARNING | ERR_PASS2,
532 "ds segment base generated, but will be ignored in 64-bit mode");
533 }
534 c = 0x3E;
535 break;
536 case R_ES:
537 if (bits == 64) {
538 error(ERR_WARNING | ERR_PASS2,
539 "es segment base generated, but will be ignored in 64-bit mode");
540 }
541 c = 0x26;
542 break;
543 case R_FS:
544 c = 0x64;
545 break;
546 case R_GS:
547 c = 0x65;
548 break;
549 case R_SS:
550 if (bits == 64) {
551 error(ERR_WARNING | ERR_PASS2,
552 "ss segment base generated, but will be ignored in 64-bit mode");
553 }
554 c = 0x36;
555 break;
556 case R_SEGR6:
557 case R_SEGR7:
558 error(ERR_NONFATAL,
559 "segr6 and segr7 cannot be used as prefixes");
560 break;
561 case P_A16:
562 if (bits == 64) {
563 error(ERR_NONFATAL,
564 "16-bit addressing is not supported "
565 "in 64-bit mode");
566 } else if (bits != 16)
567 c = 0x67;
568 break;
569 case P_A32:
570 if (bits != 32)
571 c = 0x67;
572 break;
573 case P_A64:
574 if (bits != 64) {
575 error(ERR_NONFATAL,
576 "64-bit addressing is only supported "
577 "in 64-bit mode");
578 }
579 break;
580 case P_ASP:
581 c = 0x67;
582 break;
583 case P_O16:
584 if (bits != 16)
585 c = 0x66;
586 break;
587 case P_O32:
588 if (bits == 16)
589 c = 0x66;
590 break;
591 case P_O64:
592 /* REX.W */
593 break;
594 case P_OSP:
595 c = 0x66;
596 break;
597 case P_none:
598 break;
599 default:
600 error(ERR_PANIC, "invalid instruction prefix");
601 }
602 if (c != 0) {
603 out(offset, segment, &c, OUT_RAWDATA, 1,
604 NO_SEG, NO_SEG);
605 offset++;
606 }
607 }
608 insn_end = offset + insn_size;
609 gencode(segment, offset, bits, instruction,
610 temp, insn_end);
611 offset += insn_size;
612 if (itimes > 0 && itimes == instruction->times - 1) {
613 /*
614 * Dummy call to list->output to give the offset to the
615 * listing module.
616 */
617 list->output(offset, NULL, OUT_RAWDATA, 0);
618 list->uplevel(LIST_TIMES);
619 }
620 }
621 if (instruction->times > 1)
622 list->downlevel(LIST_TIMES);
623 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700624 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400625 /* No match */
626 switch (m) {
627 case MERR_OPSIZEMISSING:
628 error(ERR_NONFATAL, "operation size not specified");
629 break;
630 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000631 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400632 break;
633 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000634 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400635 break;
636 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800637 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400638 bits);
639 break;
640 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000641 error(ERR_NONFATAL,
642 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400643 break;
644 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000645 }
646 return 0;
647}
648
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800649int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400650 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000651{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000652 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700653 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000654
H. Peter Anvine2c80182005-01-15 22:15:51 +0000655 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000656 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000657
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400658 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000659 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000660
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700661 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
662 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400663 instruction->opcode == I_DT || instruction->opcode == I_DO ||
664 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000665 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300666 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000667
H. Peter Anvine2c80182005-01-15 22:15:51 +0000668 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300669 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000670
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400671 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000672 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000673
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400675 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400677 warn_overflow_const(e->offset, wsize);
678 } else if (e->type == EOT_DB_STRING ||
679 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000681
H. Peter Anvine2c80182005-01-15 22:15:51 +0000682 align = (-osize) % wsize;
683 if (align < 0)
684 align += wsize;
685 isize += osize + align;
686 }
687 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000688 }
689
H. Peter Anvine2c80182005-01-15 22:15:51 +0000690 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400691 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000692 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300693 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700694 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000695
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400696 fp = fopen(fname, "rb");
697 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000698 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
699 fname);
700 else if (fseek(fp, 0L, SEEK_END) < 0)
701 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
702 fname);
703 else {
704 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000705 if (instruction->eops->next) {
706 len -= instruction->eops->next->offset;
707 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700708 len > (size_t)instruction->eops->next->next->offset) {
709 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000710 }
711 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300712 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000713 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300714 if (fp)
715 fclose(fp);
716 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000717 }
718
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700719 /* Check to see if we need an address-size prefix */
720 add_asp(instruction, bits);
721
H. Peter Anvin23595f52009-07-25 17:44:25 -0700722 m = find_match(&temp, instruction, segment, offset, bits);
723 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400724 /* we've matched an instruction. */
725 int64_t isize;
726 const uint8_t *codes = temp->code;
727 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100728
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400729 isize = calcsize(segment, offset, bits, instruction, codes);
730 if (isize < 0)
731 return -1;
732 for (j = 0; j < MAXPREFIX; j++) {
733 switch (instruction->prefixes[j]) {
734 case P_A16:
735 if (bits != 16)
736 isize++;
737 break;
738 case P_A32:
739 if (bits != 32)
740 isize++;
741 break;
742 case P_O16:
743 if (bits != 16)
744 isize++;
745 break;
746 case P_O32:
747 if (bits == 16)
748 isize++;
749 break;
750 case P_A64:
751 case P_O64:
752 case P_none:
753 break;
754 default:
755 isize++;
756 break;
757 }
758 }
759 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700760 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400761 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000762 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000763}
764
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700765static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000766{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700767 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400768 !(o->opflags & OPFLAG_UNKNOWN) &&
769 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000770}
771
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700772/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700773static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774{
775 int16_t v;
776
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700777 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400778 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700779
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700780 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700781 return v >= -128 && v <= 127;
782}
783
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700784static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700785{
786 int32_t v;
787
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700788 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400789 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700790
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700791 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700792 return v >= -128 && v <= 127;
793}
794
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800795static void bad_hle_warn(const insn * ins, uint8_t hleok)
796{
797 enum prefixes rep_pfx = ins->prefixes[PPS_REP];
798 enum whatwarn { w_none, w_lock, w_inval };
799 static const enum whatwarn warn[2][4] =
800 {
801 { w_inval, w_inval, w_none, w_lock }, /* XACQUIRE */
802 { w_inval, w_none, w_none, w_lock }, /* XRELEASE */
803 };
804 unsigned int n;
805
806 n = (unsigned int)rep_pfx - P_XACQUIRE;
807 if (n > 1)
808 return; /* Not XACQUIRE/XRELEASE */
809
810 switch (warn[n][hleok]) {
811 case w_none:
812 break;
813
814 case w_lock:
815 if (ins->prefixes[PPS_LOCK] != P_LOCK) {
816 errfunc(ERR_WARNING | ERR_PASS2,
817 "%s with this instruction requires lock",
818 prefix_name(rep_pfx));
819 }
820 break;
821
822 case w_inval:
823 errfunc(ERR_WARNING | ERR_PASS2,
824 "%s invalid with this instruction",
825 prefix_name(rep_pfx));
826 break;
827 }
828}
829
H. Peter Anvin507ae032008-10-09 15:37:10 -0700830/* Common construct */
831#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
832
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800833static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400834 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000835{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800836 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000837 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000838 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700839 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700840 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700841 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700842 enum ea_type eat;
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800843 uint8_t hleok = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000844
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700845 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700846 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700847
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700848 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400849 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700850
H. Peter Anvine2c80182005-01-15 22:15:51 +0000851 (void)segment; /* Don't warn that this parameter is unused */
852 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000853
H. Peter Anvin839eca22007-10-29 23:12:47 -0700854 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400855 c = *codes++;
856 op1 = (c & 3) + ((opex & 1) << 2);
857 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
858 opx = &ins->oprs[op1];
859 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700860
H. Peter Anvin839eca22007-10-29 23:12:47 -0700861 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000862 case 01:
863 case 02:
864 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400865 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000866 codes += c, length += c;
867 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700868
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400869 case 05:
870 case 06:
871 case 07:
872 opex = c;
873 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700874
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400875 case4(010):
876 ins->rex |=
877 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 codes++, length++;
879 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700880
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400881 case4(014):
882 case4(020):
883 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000884 length++;
885 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700886
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400887 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 length += 2;
889 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700890
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400891 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700892 if (opx->type & (BITS16 | BITS32 | BITS64))
893 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 else
895 length += (bits == 16) ? 2 : 4;
896 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700897
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400898 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000899 length += 4;
900 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700901
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400902 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700903 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000904 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700905
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400906 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000907 length++;
908 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700909
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400910 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000911 length += 8; /* MOV reg64/imm */
912 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700913
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400914 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000915 length += 2;
916 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700917
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400918 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700919 if (opx->type & (BITS16 | BITS32 | BITS64))
920 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000921 else
922 length += (bits == 16) ? 2 : 4;
923 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700924
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400925 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000926 length += 4;
927 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700928
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400929 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700930 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000931 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700932
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400933 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700934 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000935 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700936
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400937 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800938 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000939 length++;
940 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700941
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400942 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700943 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700944 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700945
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400946 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800947 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700948 length++;
949 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700950
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400951 case 0172:
952 case 0173:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400953 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700954 length++;
955 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700956
H. Peter Anvincffe61e2011-07-07 17:21:24 -0700957 case4(0174):
958 length++;
959 break;
960
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400961 case4(0250):
962 length += is_sbyte32(opx) ? 1 : 4;
963 break;
964
965 case4(0254):
966 length += 4;
967 break;
968
969 case4(0260):
970 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700971 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400972 ins->vex_cm = *codes++;
973 ins->vex_wlp = *codes++;
974 break;
975
976 case 0270:
977 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700978 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400979 ins->vex_cm = *codes++;
980 ins->vex_wlp = *codes++;
981 break;
982
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800983 case 0271:
984 case 0272:
985 case 0273:
986 hleok = c & 3;
987 break;
988
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400989 case4(0274):
990 length++;
991 break;
992
993 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000994 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700995
H. Peter Anvine2c80182005-01-15 22:15:51 +0000996 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400997 if (bits == 64)
998 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700999 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001000 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001001
H. Peter Anvine2c80182005-01-15 22:15:51 +00001002 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001003 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001005
H. Peter Anvine2c80182005-01-15 22:15:51 +00001006 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001007 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001008
Keith Kaniosb7a89542007-04-12 02:40:54 +00001009 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001010 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1011 has_prefix(ins, PPS_ASIZE, P_A32))
1012 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001013 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001014
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001015 case4(0314):
1016 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001017
H. Peter Anvine2c80182005-01-15 22:15:51 +00001018 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001019 {
1020 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1021 if (pfx == P_O16)
1022 break;
1023 if (pfx != P_none)
1024 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
1025 else
1026 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001027 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001028 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001029
H. Peter Anvine2c80182005-01-15 22:15:51 +00001030 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001031 {
1032 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1033 if (pfx == P_O32)
1034 break;
1035 if (pfx != P_none)
1036 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
1037 else
1038 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001039 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +00001040 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001041
H. Peter Anvine2c80182005-01-15 22:15:51 +00001042 case 0322:
1043 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001044
Keith Kaniosb7a89542007-04-12 02:40:54 +00001045 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001046 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001047 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001048
Keith Kaniosb7a89542007-04-12 02:40:54 +00001049 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001050 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001051 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001052
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001053 case 0325:
1054 ins->rex |= REX_NH;
1055 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001056
H. Peter Anvine2c80182005-01-15 22:15:51 +00001057 case 0330:
1058 codes++, length++;
1059 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001060
H. Peter Anvine2c80182005-01-15 22:15:51 +00001061 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001062 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001063
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001064 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 case 0333:
1066 length++;
1067 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001068
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001069 case 0334:
1070 ins->rex |= REX_L;
1071 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001072
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001073 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001074 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001075
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001076 case 0336:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001077 if (!ins->prefixes[PPS_REP])
1078 ins->prefixes[PPS_REP] = P_REP;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001079 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001080
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001081 case 0337:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001082 if (!ins->prefixes[PPS_REP])
1083 ins->prefixes[PPS_REP] = P_REPNE;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001084 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001085
H. Peter Anvine2c80182005-01-15 22:15:51 +00001086 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001087 if (ins->oprs[0].segment != NO_SEG)
1088 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1089 " quantity of BSS space");
1090 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001091 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001092 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001093
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001094 case 0341:
1095 if (!ins->prefixes[PPS_WAIT])
1096 ins->prefixes[PPS_WAIT] = P_WAIT;
1097 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001098
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001099 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001100 length++;
1101 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001102
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001103 case 0360:
1104 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001105
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001106 case 0361:
1107 case 0362:
1108 case 0363:
1109 length++;
1110 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001111
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001112 case 0364:
1113 case 0365:
1114 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001115
Keith Kanios48af1772007-08-17 07:37:52 +00001116 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001117 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001118 length++;
1119 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001120
H. Peter Anvine2c80182005-01-15 22:15:51 +00001121 case 0370:
1122 case 0371:
1123 case 0372:
1124 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001125
H. Peter Anvine2c80182005-01-15 22:15:51 +00001126 case 0373:
1127 length++;
1128 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001129
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001130 case 0374:
1131 eat = EA_XMMVSIB;
1132 break;
1133
1134 case 0375:
1135 eat = EA_YMMVSIB;
1136 break;
1137
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001138 case4(0100):
1139 case4(0110):
1140 case4(0120):
1141 case4(0130):
1142 case4(0200):
1143 case4(0204):
1144 case4(0210):
1145 case4(0214):
1146 case4(0220):
1147 case4(0224):
1148 case4(0230):
1149 case4(0234):
1150 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001151 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001152 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001153 opflags_t rflags;
1154 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001155
Keith Kaniosb7a89542007-04-12 02:40:54 +00001156 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001157
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001158 if (c <= 0177) {
1159 /* pick rfield from operand b (opx) */
1160 rflags = regflag(opx);
1161 rfield = nasm_regvals[opx->basereg];
1162 } else {
1163 rflags = 0;
1164 rfield = c & 7;
1165 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001166 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1167 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001168 errfunc(ERR_NONFATAL, "invalid effective address");
1169 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001170 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001171 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001172 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001173 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001174 }
1175 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001176
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001177 default:
1178 errfunc(ERR_PANIC, "internal instruction table corrupt"
1179 ": instruction code \\%o (0x%02X) given", c, c);
1180 break;
1181 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001182 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001183
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001184 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001185
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001186 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001187 if (ins->rex & REX_H) {
1188 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1189 return -1;
1190 }
1191 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001192 }
1193
H. Peter Anvind85d2502008-05-04 17:53:31 -07001194 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001195 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001196
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001197 if (ins->rex & REX_H) {
1198 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1199 return -1;
1200 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001201 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001202 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001203 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001204 ins->rex &= ~REX_W;
1205 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001206 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001207 ins->rex |= REX_W;
1208 bad32 &= ~REX_W;
1209 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001210 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001211 /* Follow REX_W */
1212 break;
1213 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001214
H. Peter Anvinfc561202011-07-07 16:58:22 -07001215 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001216 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1217 return -1;
1218 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001219 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001220 length += 3;
1221 else
1222 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001223 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001224 if (ins->rex & REX_H) {
1225 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1226 return -1;
1227 } else if (bits == 64) {
1228 length++;
1229 } else if ((ins->rex & REX_L) &&
1230 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1231 cpu >= IF_X86_64) {
1232 /* LOCK-as-REX.R */
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001233 assert_no_prefix(ins, PPS_LOCK);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001234 length++;
1235 } else {
1236 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1237 return -1;
1238 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001239 }
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -08001240
1241 bad_hle_warn(ins, hleok);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001242
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001243 return length;
1244}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001245
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001246#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001247 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001248 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1249 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1250 ins->rex = 0; \
1251 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001252 }
1253
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001254static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001255 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001256 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001257{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001258 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001259 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1260 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1261 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001262 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001263 uint8_t c;
1264 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001265 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001266 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001267 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001269 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001270 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001271 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001272
H. Peter Anvin839eca22007-10-29 23:12:47 -07001273 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001274 c = *codes++;
1275 op1 = (c & 3) + ((opex & 1) << 2);
1276 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1277 opx = &ins->oprs[op1];
1278 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001279
H. Peter Anvin839eca22007-10-29 23:12:47 -07001280 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 case 01:
1282 case 02:
1283 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001284 case 04:
1285 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001286 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001287 codes += c;
1288 offset += c;
1289 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001290
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001291 case 05:
1292 case 06:
1293 case 07:
1294 opex = c;
1295 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001296
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001297 case4(010):
1298 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001299 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001300 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 offset += 1;
1302 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001303
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001304 case4(014):
1305 /*
1306 * The test for BITS8 and SBYTE here is intended to avoid
1307 * warning on optimizer actions due to SBYTE, while still
1308 * warn on explicit BYTE directives. Also warn, obviously,
1309 * if the optimizer isn't enabled.
1310 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001311 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001312 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1313 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001314 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001315 "signed byte value exceeds bounds");
1316 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 if (opx->segment != NO_SEG) {
1318 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001319 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001320 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001323 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 NO_SEG);
1325 }
1326 offset += 1;
1327 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001328
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001329 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001331 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001332 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001333 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001334 if (opx->segment != NO_SEG) {
1335 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001336 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001338 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001339 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001340 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 NO_SEG);
1342 }
1343 offset += 1;
1344 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001345
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001346 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001348 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001349 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 if (opx->segment != NO_SEG) {
1351 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001352 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001355 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001356 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001357 NO_SEG);
1358 }
1359 offset += 1;
1360 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001361
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001362 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001363 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001364 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001365 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001366 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001367 offset += 2;
1368 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001369
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001370 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 if (opx->type & (BITS16 | BITS32))
1372 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 else
1374 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001375 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001376 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001377 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001379 offset += size;
1380 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001381
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001382 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001383 warn_overflow_opd(opx, 4);
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, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 offset += 4;
1388 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001389
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001390 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001392 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001393 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001394 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001396 offset += size;
1397 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001398
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001399 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001400 if (opx->segment != segment) {
1401 data = opx->offset;
1402 out(offset, segment, &data,
1403 OUT_REL1ADR, insn_end - offset,
1404 opx->segment, opx->wrt);
1405 } else {
1406 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001407 if (data > 127 || data < -128)
1408 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001409 out(offset, segment, &data,
1410 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1411 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001412 offset += 1;
1413 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001414
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001415 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001416 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001417 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001419 offset += 8;
1420 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001421
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001422 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 if (opx->segment != segment) {
1424 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001426 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001427 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001429 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001430 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001431 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001432 }
1433 offset += 2;
1434 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001435
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001436 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001437 if (opx->type & (BITS16 | BITS32 | BITS64))
1438 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 else
1440 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001441 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001442 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001443 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001444 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1445 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001447 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001448 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001449 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001450 }
1451 offset += size;
1452 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001453
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001454 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001455 if (opx->segment != segment) {
1456 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001457 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001458 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001459 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001461 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001463 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 }
1465 offset += 4;
1466 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001467
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001468 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001469 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001470 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1471 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001472 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001473 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001474 outfmt->segbase(1 + opx->segment),
1475 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001476 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001477 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001478
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001479 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001480 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001481 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001482 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001483 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001484 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001485 NO_SEG);
1486 offset++;
1487 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001488 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001489 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 offset += 2;
1491 }
1492 break;
1493
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001494 case4(0144):
1495 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001496 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001497 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001498 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001499 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001500 offset++;
1501 break;
1502
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001503 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001504 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001505 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001506 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001507 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001508 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001509 NO_SEG);
1510 offset++;
1511 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001512 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001513 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001514 offset += 4;
1515 }
1516 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001517
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001518 case4(0154):
1519 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001520 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001521 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001522 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001523 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001524 offset++;
1525 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001526
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001527 case 0172:
1528 c = *codes++;
1529 opx = &ins->oprs[c >> 3];
1530 bytes[0] = nasm_regvals[opx->basereg] << 4;
1531 opx = &ins->oprs[c & 7];
1532 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1533 errfunc(ERR_NONFATAL,
1534 "non-absolute expression not permitted as argument %d",
1535 c & 7);
1536 } else {
1537 if (opx->offset & ~15) {
1538 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1539 "four-bit argument exceeds bounds");
1540 }
1541 bytes[0] |= opx->offset & 15;
1542 }
1543 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1544 offset++;
1545 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001546
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001547 case 0173:
1548 c = *codes++;
1549 opx = &ins->oprs[c >> 4];
1550 bytes[0] = nasm_regvals[opx->basereg] << 4;
1551 bytes[0] |= c & 15;
1552 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1553 offset++;
1554 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001555
H. Peter Anvincffe61e2011-07-07 17:21:24 -07001556 case4(0174):
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001557 bytes[0] = nasm_regvals[opx->basereg] << 4;
1558 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1559 offset++;
1560 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001561
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001562 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001563 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001564 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1565 (int32_t)data != (int64_t)data) {
1566 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1567 "signed dword immediate exceeds bounds");
1568 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001569 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001570 bytes[0] = data;
1571 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1572 NO_SEG);
1573 offset++;
1574 } else {
1575 out(offset, segment, &data, OUT_ADDRESS, 4,
1576 opx->segment, opx->wrt);
1577 offset += 4;
1578 }
1579 break;
1580
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001581 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001582 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001583 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1584 (int32_t)data != (int64_t)data) {
1585 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1586 "signed dword immediate exceeds bounds");
1587 }
1588 out(offset, segment, &data, OUT_ADDRESS, 4,
1589 opx->segment, opx->wrt);
1590 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001591 break;
1592
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001593 case4(0260):
1594 case 0270:
1595 codes += 2;
1596 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1597 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1598 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1599 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001600 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001601 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1602 offset += 3;
1603 } else {
1604 bytes[0] = 0xc5;
1605 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001606 ((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001607 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1608 offset += 2;
1609 }
1610 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001611
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001612 case4(0274):
1613 {
1614 uint64_t uv, um;
1615 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001616
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001617 if (ins->rex & REX_W)
1618 s = 64;
1619 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1620 s = 16;
1621 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1622 s = 32;
1623 else
1624 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001625
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001626 um = (uint64_t)2 << (s-1);
1627 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001628
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001629 if (uv > 127 && uv < (uint64_t)-128 &&
1630 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001631 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001632 "signed byte value exceeds bounds");
1633 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001634 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001635 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001636 out(offset, segment, &data, OUT_ADDRESS, 1,
1637 opx->segment, opx->wrt);
1638 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001639 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001640 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1641 NO_SEG);
1642 }
1643 offset += 1;
1644 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001645 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001646
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001647 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001648 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001649
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001651 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001653 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001654 offset += 1;
1655 } else
1656 offset += 0;
1657 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001658
H. Peter Anvine2c80182005-01-15 22:15:51 +00001659 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001660 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001661 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001662 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001663 offset += 1;
1664 } else
1665 offset += 0;
1666 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001667
H. Peter Anvine2c80182005-01-15 22:15:51 +00001668 case 0312:
1669 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001670
Keith Kaniosb7a89542007-04-12 02:40:54 +00001671 case 0313:
1672 ins->rex = 0;
1673 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001674
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001675 case4(0314):
1676 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001677
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001679 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001681
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001683 case 0323:
1684 break;
1685
Keith Kaniosb7a89542007-04-12 02:40:54 +00001686 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001687 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001688 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001689
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001690 case 0325:
1691 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001692
H. Peter Anvine2c80182005-01-15 22:15:51 +00001693 case 0330:
1694 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001695 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001696 offset += 1;
1697 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001698
H. Peter Anvine2c80182005-01-15 22:15:51 +00001699 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001700 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001701
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001702 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001703 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001704 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001705 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001706 offset += 1;
1707 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001708
Keith Kanios48af1772007-08-17 07:37:52 +00001709 case 0334:
1710 if (ins->rex & REX_R) {
1711 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001712 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001713 offset += 1;
1714 }
1715 ins->rex &= ~(REX_L|REX_R);
1716 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001717
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001718 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001719 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001720
H. Peter Anvin962e3052008-08-28 17:47:16 -07001721 case 0336:
1722 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001723 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001724
H. Peter Anvine2c80182005-01-15 22:15:51 +00001725 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001726 if (ins->oprs[0].segment != NO_SEG)
1727 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1728 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001729 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001730 if (size > 0)
1731 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001732 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001733 offset += size;
1734 }
1735 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001736
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001737 case 0341:
1738 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001739
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001740 case 0344:
1741 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001742 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001743 switch (ins->oprs[0].basereg) {
1744 case R_CS:
1745 bytes[0] += 0x0E;
1746 break;
1747 case R_DS:
1748 bytes[0] += 0x1E;
1749 break;
1750 case R_ES:
1751 bytes[0] += 0x06;
1752 break;
1753 case R_SS:
1754 bytes[0] += 0x16;
1755 break;
1756 default:
1757 errfunc(ERR_PANIC,
1758 "bizarre 8086 segment register received");
1759 }
1760 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1761 offset++;
1762 break;
1763
1764 case 0346:
1765 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001766 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001767 switch (ins->oprs[0].basereg) {
1768 case R_FS:
1769 bytes[0] += 0xA0;
1770 break;
1771 case R_GS:
1772 bytes[0] += 0xA8;
1773 break;
1774 default:
1775 errfunc(ERR_PANIC,
1776 "bizarre 386 segment register received");
1777 }
1778 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1779 offset++;
1780 break;
1781
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001782 case 0360:
1783 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001784
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001785 case 0361:
1786 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001787 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1788 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001789 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001790
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001791 case 0362:
1792 case 0363:
1793 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001794 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1795 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001796 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001797
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001798 case 0364:
1799 case 0365:
1800 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001801
Keith Kanios48af1772007-08-17 07:37:52 +00001802 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001803 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001804 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001805 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001806 offset += 1;
1807 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001808
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 case 0370:
1810 case 0371:
1811 case 0372:
1812 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001813
H. Peter Anvine2c80182005-01-15 22:15:51 +00001814 case 0373:
1815 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001816 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001817 offset += 1;
1818 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001819
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001820 case 0374:
1821 eat = EA_XMMVSIB;
1822 break;
1823
1824 case 0375:
1825 eat = EA_YMMVSIB;
1826 break;
1827
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001828 case4(0100):
1829 case4(0110):
1830 case4(0120):
1831 case4(0130):
1832 case4(0200):
1833 case4(0204):
1834 case4(0210):
1835 case4(0214):
1836 case4(0220):
1837 case4(0224):
1838 case4(0230):
1839 case4(0234):
1840 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001841 ea ea_data;
1842 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001843 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001844 uint8_t *p;
1845 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001846 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001847
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001848 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001849 /* pick rfield from operand b (opx) */
1850 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001851 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001852 } else {
1853 /* rfield is constant */
1854 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001855 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001856 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001857
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001858 if (process_ea(opy, &ea_data, bits, ins->addr_size,
Cyrill Gorcunovcdb8cd72011-08-28 16:33:39 +04001859 rfield, rflags) != eat)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001860 errfunc(ERR_NONFATAL, "invalid effective address");
Charles Crayne7e975552007-11-03 22:06:13 -07001861
H. Peter Anvine2c80182005-01-15 22:15:51 +00001862 p = bytes;
1863 *p++ = ea_data.modrm;
1864 if (ea_data.sib_present)
1865 *p++ = ea_data.sib;
1866
1867 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001868 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001869
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001870 /*
1871 * Make sure the address gets the right offset in case
1872 * the line breaks in the .lst file (BR 1197827)
1873 */
1874 offset += s;
1875 s = 0;
1876
H. Peter Anvine2c80182005-01-15 22:15:51 +00001877 switch (ea_data.bytes) {
1878 case 0:
1879 break;
1880 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001881 case 2:
1882 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001883 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001884 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001885 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001886 if (ea_data.rip) {
1887 if (opy->segment == segment) {
1888 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001889 if (overflow_signed(data, ea_data.bytes))
1890 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001891 out(offset, segment, &data, OUT_ADDRESS,
1892 ea_data.bytes, NO_SEG, NO_SEG);
1893 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001894 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001895 out(offset, segment, &data, OUT_REL4ADR,
1896 insn_end - offset, opy->segment, opy->wrt);
1897 }
1898 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001899 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1900 signed_bits(opy->offset, ins->addr_size) !=
1901 signed_bits(opy->offset, ea_data.bytes * 8))
1902 warn_overflow(ERR_PASS2, ea_data.bytes);
1903
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001904 out(offset, segment, &data, OUT_ADDRESS,
1905 ea_data.bytes, opy->segment, opy->wrt);
1906 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001907 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001908 default:
1909 /* Impossible! */
1910 errfunc(ERR_PANIC,
1911 "Invalid amount of bytes (%d) for offset?!",
1912 ea_data.bytes);
1913 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001914 }
1915 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001916 }
1917 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001918
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001919 default:
1920 errfunc(ERR_PANIC, "internal instruction table corrupt"
1921 ": instruction code \\%o (0x%02X) given", c, c);
1922 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001923 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001924 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001925}
1926
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001927static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001928{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001929 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001930 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001931 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001932}
1933
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001934static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001935{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001936 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001937 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001938 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001939}
1940
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001941static int op_rexflags(const operand * o, int mask)
1942{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001943 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001944 int val;
1945
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001946 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001947 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001948
H. Peter Anvina4835d42008-05-20 14:21:29 -07001949 flags = nasm_reg_flags[o->basereg];
1950 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001951
1952 return rexflags(val, flags, mask);
1953}
1954
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001955static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001956{
1957 int rex = 0;
1958
1959 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001960 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001961 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001962 rex |= REX_W;
1963 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1964 rex |= REX_H;
1965 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1966 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001967
1968 return rex & mask;
1969}
1970
H. Peter Anvin23595f52009-07-25 17:44:25 -07001971static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001972 insn *instruction,
1973 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001974{
1975 const struct itemplate *temp;
1976 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001977 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001978 bool opsizemissing = false;
1979 int i;
1980
1981 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001982 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001983
1984 merr = MERR_INVALOP;
1985
1986 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001987 temp->opcode != I_none; temp++) {
1988 m = matches(temp, instruction, bits);
1989 if (m == MOK_JUMP) {
1990 if (jmp_match(segment, offset, bits, instruction, temp->code))
1991 m = MOK_GOOD;
1992 else
1993 m = MERR_INVALOP;
1994 } else if (m == MERR_OPSIZEMISSING &&
1995 (temp->flags & IF_SMASK) != IF_SX) {
1996 /*
1997 * Missing operand size and a candidate for fuzzy matching...
1998 */
1999 for (i = 0; i < temp->operands; i++) {
2000 if ((temp->opd[i] & SAME_AS) == 0)
2001 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
2002 }
2003 opsizemissing = true;
2004 }
2005 if (m > merr)
2006 merr = m;
2007 if (merr == MOK_GOOD)
2008 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002009 }
2010
2011 /* No match, but see if we can get a fuzzy operand size match... */
2012 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002013 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002014
2015 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002016 /*
2017 * We ignore extrinsic operand sizes on registers, so we should
2018 * never try to fuzzy-match on them. This also resolves the case
2019 * when we have e.g. "xmmrm128" in two different positions.
2020 */
2021 if (is_class(REGISTER, instruction->oprs[i].type))
2022 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002023
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002024 /* This tests if xsizeflags[i] has more than one bit set */
2025 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2026 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002027
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002028 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002029 }
2030
2031 /* Try matching again... */
2032 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002033 temp->opcode != I_none; temp++) {
2034 m = matches(temp, instruction, bits);
2035 if (m == MOK_JUMP) {
2036 if (jmp_match(segment, offset, bits, instruction, temp->code))
2037 m = MOK_GOOD;
2038 else
2039 m = MERR_INVALOP;
2040 }
2041 if (m > merr)
2042 merr = m;
2043 if (merr == MOK_GOOD)
2044 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002045 }
2046
H. Peter Anvina81655b2009-07-25 18:15:28 -07002047done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002048 *tempp = temp;
2049 return merr;
2050}
2051
H. Peter Anvin65289e82009-07-25 17:25:11 -07002052static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002053 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002054{
H. Peter Anvin60926242009-07-26 16:25:38 -07002055 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002056 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002057
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002058 /*
2059 * Check the opcode
2060 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002061 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002062 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002063
2064 /*
2065 * Count the operands
2066 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002067 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002068 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002069
2070 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002071 * Is it legal?
2072 */
2073 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2074 return MERR_INVALOP;
2075
2076 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002077 * Check that no spurious colons or TOs are present
2078 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002079 for (i = 0; i < itemp->operands; i++)
2080 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002081 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002082
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002083 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002084 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002085 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002086 switch (itemp->flags & IF_SMASK) {
2087 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002088 asize = BITS8;
2089 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002090 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002091 asize = BITS16;
2092 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002093 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002094 asize = BITS32;
2095 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002096 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002097 asize = BITS64;
2098 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002099 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002100 asize = BITS128;
2101 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002102 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002103 asize = BITS256;
2104 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002105 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002106 switch (bits) {
2107 case 16:
2108 asize = BITS16;
2109 break;
2110 case 32:
2111 asize = BITS32;
2112 break;
2113 case 64:
2114 asize = BITS64;
2115 break;
2116 default:
2117 asize = 0;
2118 break;
2119 }
2120 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002121 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002122 asize = 0;
2123 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002124 }
2125
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002126 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002127 /* S- flags only apply to a specific operand */
2128 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2129 memset(size, 0, sizeof size);
2130 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002131 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002132 /* S- flags apply to all operands */
2133 for (i = 0; i < MAX_OPERANDS; i++)
2134 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002135 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002136
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002137 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002138 * Check that the operand flags all match up,
2139 * it's a bit tricky so lets be verbose:
2140 *
2141 * 1) Find out the size of operand. If instruction
2142 * doesn't have one specified -- we're trying to
2143 * guess it either from template (IF_S* flag) or
2144 * from code bits.
2145 *
2146 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2147 * (ie the same operand as was specified somewhere in template, and
2148 * this referred operand index is being achieved via ~SAME_AS)
2149 * we are to be sure that both registers (in template and instruction)
2150 * do exactly match.
2151 *
2152 * 3) If template operand do not match the instruction OR
2153 * template has an operand size specified AND this size differ
2154 * from which instruction has (perhaps we got it from code bits)
2155 * we are:
2156 * a) Check that only size of instruction and operand is differ
2157 * other characteristics do match
2158 * b) Perhaps it's a register specified in instruction so
2159 * for such a case we just mark that operand as "size
2160 * missing" and this will turn on fuzzy operand size
2161 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002162 */
2163 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002164 opflags_t type = instruction->oprs[i].type;
2165 if (!(type & SIZE_MASK))
2166 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002167
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002168 if (itemp->opd[i] & SAME_AS) {
2169 int j = itemp->opd[i] & ~SAME_AS;
2170 if (type != instruction->oprs[j].type ||
2171 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2172 return MERR_INVALOP;
2173 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002174 ((itemp->opd[i] & SIZE_MASK) &&
2175 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002176 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002177 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002178 } else if (!is_class(REGISTER, type)) {
2179 /*
2180 * Note: we don't honor extrinsic operand sizes for registers,
2181 * so "missing operand size" for a register should be
2182 * considered a wildcard match rather than an error.
2183 */
2184 opsizemissing = true;
2185 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002186 }
2187 }
2188
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002189 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002190 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002191
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002192 /*
2193 * Check operand sizes
2194 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002195 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002196 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002197 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002198 asize = itemp->opd[i] & SIZE_MASK;
2199 if (asize) {
2200 for (i = 0; i < oprs; i++)
2201 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002202 break;
2203 }
2204 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002205 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002206 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002207 }
2208
Keith Kaniosb7a89542007-04-12 02:40:54 +00002209 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002210 if (!(itemp->opd[i] & SIZE_MASK) &&
2211 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002212 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002213 }
2214
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002215 /*
2216 * Check template is okay at the set cpu level
2217 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002218 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002219 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002220
Keith Kaniosb7a89542007-04-12 02:40:54 +00002221 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002222 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002223 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002224 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002225 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002226
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002227 /*
2228 * Check if special handling needed for Jumps
2229 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002230 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002231 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002232
H. Peter Anvin60926242009-07-26 16:25:38 -07002233 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002234}
2235
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002236static enum ea_type process_ea(operand *input, ea *output, int bits,
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002237 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002238{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002239 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002240
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002241 output->type = EA_SCALAR;
2242 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002243
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002244 /* REX flags for the rfield operand */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002245 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002246
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002247 if (is_class(REGISTER, input->type)) {
2248 /*
2249 * It's a direct register.
2250 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002251 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002252
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002253 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002254 goto err;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002255
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002256 f = regflag(input);
2257
2258 if (!is_class(REG_EA, f))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002259 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002260
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002261 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002262 output->sib_present = false; /* no SIB necessary */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002263 output->bytes = 0; /* no offset necessary either */
2264 output->modrm = GEN_MODRM(3, rfield, nasm_regvals[input->basereg]);
2265 } else {
2266 /*
2267 * It's a memory reference.
2268 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002269 if (input->basereg == -1 &&
2270 (input->indexreg == -1 || input->scale == 0)) {
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002271 /*
2272 * It's a pure offset.
2273 */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002274 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2275 input->segment == NO_SEG) {
2276 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2277 input->type &= ~IP_REL;
2278 input->type |= MEMORY;
2279 }
2280
2281 if (input->eaflags & EAF_BYTEOFFS ||
2282 (input->eaflags & EAF_WORDOFFS &&
2283 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2284 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2285 }
2286
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002287 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002288 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002289 output->sib = GEN_SIB(0, 4, 5);
2290 output->bytes = 4;
2291 output->modrm = GEN_MODRM(0, rfield, 4);
2292 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002293 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002294 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002295 output->bytes = (addrbits != 16 ? 4 : 2);
2296 output->modrm = GEN_MODRM(0, rfield, (addrbits != 16 ? 5 : 6));
2297 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002298 }
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002299 } else {
2300 /*
2301 * It's an indirection.
2302 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002303 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002304 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002305 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002306 int t, it, bt; /* register numbers */
2307 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002308
H. Peter Anvine2c80182005-01-15 22:15:51 +00002309 if (s == 0)
2310 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002311
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002312 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002313 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002314 ix = nasm_reg_flags[i];
2315 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002316 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002317 ix = 0;
2318 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002319
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002320 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002321 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002322 bx = nasm_reg_flags[b];
2323 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002324 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002325 bx = 0;
2326 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002327
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002328 /* if either one are a vector register... */
2329 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
2330 int32_t sok = BITS32 | BITS64;
2331 int32_t o = input->offset;
2332 int mod, scale, index, base;
2333
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002334 /*
2335 * For a vector SIB, one has to be a vector and the other,
2336 * if present, a GPR. The vector must be the index operand.
2337 */
2338 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2339 if (s == 0)
2340 s = 1;
2341 else if (s != 1)
2342 goto err;
2343
2344 t = bt, bt = it, it = t;
2345 x = bx, bx = ix, ix = x;
2346 }
2347
2348 if (bt != -1) {
2349 if (REG_GPR & ~bx)
2350 goto err;
2351 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2352 sok &= bx;
2353 else
2354 goto err;
2355 }
2356
2357 /*
2358 * While we're here, ensure the user didn't specify
2359 * WORD or QWORD
2360 */
2361 if (input->disp_size == 16 || input->disp_size == 64)
2362 goto err;
2363
2364 if (addrbits == 16 ||
2365 (addrbits == 32 && !(sok & BITS32)) ||
2366 (addrbits == 64 && !(sok & BITS64)))
2367 goto err;
2368
2369 output->type = (ix & YMMREG & ~REG_EA)
2370 ? EA_YMMVSIB : EA_XMMVSIB;
2371
2372 output->rex |= rexflags(it, ix, REX_X);
2373 output->rex |= rexflags(bt, bx, REX_B);
2374
2375 index = it & 7; /* it is known to be != -1 */
2376
2377 switch (s) {
2378 case 1:
2379 scale = 0;
2380 break;
2381 case 2:
2382 scale = 1;
2383 break;
2384 case 4:
2385 scale = 2;
2386 break;
2387 case 8:
2388 scale = 3;
2389 break;
2390 default: /* then what the smeg is it? */
2391 goto err; /* panic */
2392 }
2393
2394 if (bt == -1) {
2395 base = 5;
2396 mod = 0;
2397 } else {
2398 base = (bt & 7);
2399 if (base != REG_NUM_EBP && o == 0 &&
2400 seg == NO_SEG && !forw_ref &&
2401 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2402 mod = 0;
2403 else if (input->eaflags & EAF_BYTEOFFS ||
2404 (o >= -128 && o <= 127 &&
2405 seg == NO_SEG && !forw_ref &&
2406 !(input->eaflags & EAF_WORDOFFS)))
2407 mod = 1;
2408 else
2409 mod = 2;
2410 }
2411
2412 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002413 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2414 output->modrm = GEN_MODRM(mod, rfield, 4);
2415 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002416 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002417 /*
2418 * it must be a 32/64-bit memory reference. Firstly we have
2419 * to check that all registers involved are type E/Rxx.
2420 */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002421 int32_t sok = BITS32 | BITS64;
2422 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002423
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002424 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002425 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2426 sok &= ix;
2427 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002428 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002429 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002430
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002431 if (bt != -1) {
2432 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002433 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002434 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002435 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002436 sok &= bx;
2437 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002438
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002439 /*
2440 * While we're here, ensure the user didn't specify
2441 * WORD or QWORD
2442 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002443 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002444 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002445
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002446 if (addrbits == 16 ||
2447 (addrbits == 32 && !(sok & BITS32)) ||
2448 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002449 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002450
Keith Kaniosb7a89542007-04-12 02:40:54 +00002451 /* now reorganize base/index */
2452 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002453 ((hb == b && ht == EAH_NOTBASE) ||
2454 (hb == i && ht == EAH_MAKEBASE))) {
2455 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002456 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002457 x = bx, bx = ix, ix = x;
2458 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002459 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002460 bt = -1, bx = 0, s++;
2461 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002462 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002463 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002464 }
2465 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2466 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002467 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002468 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2469 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002470 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002471 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002472 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002473 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002474 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002475 x = ix, ix = bx, bx = x;
2476 }
2477 if (it == REG_NUM_ESP ||
2478 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002479 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002480
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002481 output->rex |= rexflags(it, ix, REX_X);
2482 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002483
Keith Kanios48af1772007-08-17 07:37:52 +00002484 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002485 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002486 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002487
Keith Kaniosb7a89542007-04-12 02:40:54 +00002488 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002489 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002490 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002491 } else {
2492 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002493 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002494 seg == NO_SEG && !forw_ref &&
2495 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002496 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002497 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002498 (o >= -128 && o <= 127 &&
2499 seg == NO_SEG && !forw_ref &&
2500 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002501 mod = 1;
2502 else
2503 mod = 2;
2504 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002505
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002506 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002507 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2508 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002509 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002510 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002511 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002512
Keith Kaniosb7a89542007-04-12 02:40:54 +00002513 if (it == -1)
2514 index = 4, s = 1;
2515 else
2516 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002517
H. Peter Anvine2c80182005-01-15 22:15:51 +00002518 switch (s) {
2519 case 1:
2520 scale = 0;
2521 break;
2522 case 2:
2523 scale = 1;
2524 break;
2525 case 4:
2526 scale = 2;
2527 break;
2528 case 8:
2529 scale = 3;
2530 break;
2531 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002532 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002533 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002534
Keith Kaniosb7a89542007-04-12 02:40:54 +00002535 if (bt == -1) {
2536 base = 5;
2537 mod = 0;
2538 } else {
2539 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002540 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002541 seg == NO_SEG && !forw_ref &&
2542 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002543 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002544 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002545 (o >= -128 && o <= 127 &&
2546 seg == NO_SEG && !forw_ref &&
2547 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002548 mod = 1;
2549 else
2550 mod = 2;
2551 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002552
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002553 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002554 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2555 output->modrm = GEN_MODRM(mod, rfield, 4);
2556 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002557 }
2558 } else { /* it's 16-bit */
2559 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002560 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002561
Keith Kaniosb7a89542007-04-12 02:40:54 +00002562 /* check for 64-bit long mode */
2563 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002564 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002565
H. Peter Anvine2c80182005-01-15 22:15:51 +00002566 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002567 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2568 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002569 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002570
Keith Kaniosb7a89542007-04-12 02:40:54 +00002571 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002572 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002573 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002574
H. Peter Anvine2c80182005-01-15 22:15:51 +00002575 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002576 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002577 if (b == -1 && i != -1) {
2578 int tmp = b;
2579 b = i;
2580 i = tmp;
2581 } /* swap */
2582 if ((b == R_SI || b == R_DI) && i != -1) {
2583 int tmp = b;
2584 b = i;
2585 i = tmp;
2586 }
2587 /* have BX/BP as base, SI/DI index */
2588 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002589 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002590 if (i != -1 && b != -1 &&
2591 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002592 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002593 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002594 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002595
H. Peter Anvine2c80182005-01-15 22:15:51 +00002596 rm = -1;
2597 if (i != -1)
2598 switch (i * 256 + b) {
2599 case R_SI * 256 + R_BX:
2600 rm = 0;
2601 break;
2602 case R_DI * 256 + R_BX:
2603 rm = 1;
2604 break;
2605 case R_SI * 256 + R_BP:
2606 rm = 2;
2607 break;
2608 case R_DI * 256 + R_BP:
2609 rm = 3;
2610 break;
2611 } else
2612 switch (b) {
2613 case R_SI:
2614 rm = 4;
2615 break;
2616 case R_DI:
2617 rm = 5;
2618 break;
2619 case R_BP:
2620 rm = 6;
2621 break;
2622 case R_BX:
2623 rm = 7;
2624 break;
2625 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002626 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002627 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002628
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002629 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2630 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002631 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002632 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002633 (o >= -128 && o <= 127 && seg == NO_SEG &&
2634 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002635 mod = 1;
2636 else
2637 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002638
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002639 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002640 output->bytes = mod; /* bytes of offset needed */
2641 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002642 }
2643 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002644 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002645
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002646 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002647 return output->type;
2648
2649err:
2650 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002651}
2652
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002653static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002654{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002655 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002656 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002657
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002658 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002659
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002660 switch (ins->prefixes[PPS_ASIZE]) {
2661 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002662 valid &= 16;
2663 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002664 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002665 valid &= 32;
2666 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002667 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002668 valid &= 64;
2669 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002670 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002671 valid &= (addrbits == 32) ? 16 : 32;
2672 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002673 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002674 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002675 }
2676
2677 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002678 if (is_class(MEMORY, ins->oprs[j].type)) {
2679 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002680
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002681 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002682 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002683 i = 0;
2684 else
2685 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002686
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002687 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002688 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002689 b = 0;
2690 else
2691 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002692
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002693 if (ins->oprs[j].scale == 0)
2694 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002695
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002696 if (!i && !b) {
2697 int ds = ins->oprs[j].disp_size;
2698 if ((addrbits != 64 && ds > 8) ||
2699 (addrbits == 64 && ds == 16))
2700 valid &= ds;
2701 } else {
2702 if (!(REG16 & ~b))
2703 valid &= 16;
2704 if (!(REG32 & ~b))
2705 valid &= 32;
2706 if (!(REG64 & ~b))
2707 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002708
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002709 if (!(REG16 & ~i))
2710 valid &= 16;
2711 if (!(REG32 & ~i))
2712 valid &= 32;
2713 if (!(REG64 & ~i))
2714 valid &= 64;
2715 }
2716 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002717 }
2718
2719 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002720 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002721 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002722 /* Add an address size prefix */
Cyrill Gorcunovd6851d42011-09-25 18:01:45 +04002723 ins->prefixes[PPS_ASIZE] = (addrbits == 32) ? P_A16 : P_A32;;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002724 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002725 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002726 /* Impossible... */
2727 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2728 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002729 }
2730
2731 defdisp = ins->addr_size == 16 ? 16 : 32;
2732
2733 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002734 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2735 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2736 /*
2737 * mem_offs sizes must match the address size; if not,
2738 * strip the MEM_OFFS bit and match only EA instructions
2739 */
2740 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2741 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002742 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002743}