blob: 7374139f26fd66e6416f32ab56bf9c7d010c6d17 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07003 * Copyright 1996-2011 The NASM Authors - All Rights Reserved
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07004 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
Cyrill Gorcunov1de95002009-11-06 00:08:38 +030017 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -070018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * assemble.c code generation for the Netwide Assembler
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036 *
37 * the actual codes (C syntax, i.e. octal):
38 * \0 - terminates the code. (Unless it's a literal of course.)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040039 * \1..\4 - that many literal bytes follow in the code stream
H. Peter Anvindcffe4b2008-10-10 22:10:31 -070040 * \5 - add 4 to the primary operand number (b, low octdigit)
41 * \6 - add 4 to the secondary operand number (a, middle octdigit)
42 * \7 - add 4 to both the primary and the secondary operand number
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070043 * \10..\13 - a literal byte follows in the code stream, to be added
44 * to the register value of operand 0..3
45 * \14..\17 - a signed byte immediate operand, from operand 0..3
46 * \20..\23 - a byte immediate operand, from operand 0..3
47 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
48 * \30..\33 - a word immediate operand, from operand 0..3
49 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000050 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070051 * \40..\43 - a long immediate operand, from operand 0..3
52 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040053 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070054 * \50..\53 - a byte relative operand, from operand 0..3
55 * \54..\57 - a qword immediate operand, from operand 0..3
56 * \60..\63 - a word relative operand, from operand 0..3
57 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000058 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070059 * \70..\73 - a long relative operand, from operand 0..3
H. Peter Anvinc1377e92008-10-06 23:40:31 -070060 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000061 * \1ab - a ModRM, calculated on EA in operand a, with the spare
62 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070063 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080064 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040065 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvinc1377e92008-10-06 23:40:31 -070066 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080067 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040068 * is a signed byte rather than a dword. Opcode byte follows.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040069 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070070 * the 4-bit immediate from operand b in bits 3..0.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040071 * \173\xab - the register number from operand a in bits 7..4, with
72 * the value b in bits 3..0.
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 Anvinc1377e92008-10-06 23:40:31 -0700100 * \274..\277 - a signed byte immediate operand, from operand 0..3,
101 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
103 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -0700104 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +0000105 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -0800106 * \314 - (disassembler only) invalid with REX.B
107 * \315 - (disassembler only) invalid with REX.X
108 * \316 - (disassembler only) invalid with REX.R
109 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
111 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
112 * \322 - indicates that this instruction is only valid when the
113 * operand size is the default (instruction to disassembler,
114 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000115 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000116 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400117 * \325 - instruction which always uses spl/bpl/sil/dil
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118 * \330 - a literal byte follows in the code stream, to be added
119 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000120 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000121 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700122 * \332 - REP prefix (0xF2 byte) used as opcode extension.
123 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700124 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700125 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700126 * \336 - force a REP(E) prefix (0xF2) even if not specified.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400127 * \337 - force a REPNE prefix (0xF3) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700128 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000129 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400131 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700132 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
133 * (POP is never used for CS) depending on operand 0
134 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
135 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400136 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700137 * \361 - 66 SSE prefix (== \366\331)
138 * \362 - F2 SSE prefix (== \364\332)
139 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000140 * \364 - operand-size prefix (0x66) not permitted
141 * \365 - address-size prefix (0x67) not permitted
142 * \366 - operand-size prefix (0x66) used as opcode extension
143 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000144 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400145 * 370 is used for Jcc, 371 is used for JMP.
146 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
147 * used for conditional jump over longer jump
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700148 * \374 - this instruction takes an XMM VSIB memory EA
149 * \375 - this instruction takes an YMM VSIB memory EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000150 */
151
H. Peter Anvinfe501952007-10-02 21:53:51 -0700152#include "compiler.h"
153
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000154#include <stdio.h>
155#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000156#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000157
158#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000159#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000160#include "assemble.h"
161#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700162#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000163
H. Peter Anvin65289e82009-07-25 17:25:11 -0700164enum match_result {
165 /*
166 * Matching errors. These should be sorted so that more specific
167 * errors come later in the sequence.
168 */
169 MERR_INVALOP,
170 MERR_OPSIZEMISSING,
171 MERR_OPSIZEMISMATCH,
172 MERR_BADCPU,
173 MERR_BADMODE,
174 /*
175 * Matching success; the conditional ones first
176 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400177 MOK_JUMP, /* Matching OK but needs jmp_match() */
178 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700179};
180
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000181typedef struct {
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700182 enum ea_type type; /* what kind of EA is this? */
183 int sib_present; /* is a SIB byte necessary? */
184 int bytes; /* # of bytes of offset needed */
185 int size; /* lazy - this is sib+bytes+1 */
186 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000187} ea;
188
Cyrill Gorcunov10734c72011-08-29 00:07:17 +0400189#define GEN_SIB(scale, index, base) \
190 (((scale) << 6) | ((index) << 3) | ((base)))
191
192#define GEN_MODRM(mod, reg, rm) \
193 (((mod) << 6) | (((reg) & 7) << 3) | ((rm) & 7))
194
Keith Kaniosb7a89542007-04-12 02:40:54 +0000195static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000196static efunc errfunc;
197static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000198static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000199
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700200static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700201static void gencode(int32_t segment, int64_t offset, int bits,
202 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400203 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700204static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400205 insn *instruction,
206 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700207static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700208static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000209static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700210static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000211static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700212static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000213
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700214static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
215
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700216static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000217{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700218 return ins->prefixes[pos] == prefix;
219}
220
221static void assert_no_prefix(insn * ins, enum prefix_pos pos)
222{
223 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400224 errfunc(ERR_NONFATAL, "invalid %s prefix",
225 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700226}
227
228static const char *size_name(int size)
229{
230 switch (size) {
231 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400232 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700233 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400234 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700235 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400236 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700237 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400238 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700239 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400240 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700241 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400242 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700243 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400244 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700245 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400246 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000247 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700248}
249
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400250static void warn_overflow(int pass, int size)
251{
252 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
253 "%s data exceeds bounds", size_name(size));
254}
255
256static void warn_overflow_const(int64_t data, int size)
257{
258 if (overflow_general(data, size))
259 warn_overflow(ERR_PASS1, size);
260}
261
262static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700263{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100264 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400265 if (overflow_general(o->offset, size))
266 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700267 }
268}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400269
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000270/*
271 * This routine wrappers the real output format's output routine,
272 * in order to pass a copy of the data off to the listing file
273 * generator at the same time.
274 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800275static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800276 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400277 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000278{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000279 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000280 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800281 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000282
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800283 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400284 /*
285 * This is a non-relocated address, and we're going to
286 * convert it into RAWDATA format.
287 */
288 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800289
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400290 if (size > 8) {
291 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
292 return;
293 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700294
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400295 WRITEADDR(q, *(int64_t *)data, size);
296 data = p;
297 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000298 }
299
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800300 list->output(offset, data, type, size);
301
Frank Kotlerabebb082003-09-06 04:45:37 +0000302 /*
303 * this call to src_get determines when we call the
304 * debug-format-specific "linenum" function
305 * it updates lineno and lnfname to the current values
306 * returning 0 if "same as last time", -2 if lnfname
307 * changed, and the amount by which lineno changed,
308 * if it did. thus, these variables must be static
309 */
310
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400311 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000312 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000313
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800314 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000315}
316
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700317static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700318 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000319{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800320 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000321 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000322
Charles Craynef1aefd82008-09-30 16:11:32 -0700323 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700324 return false;
325 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400326 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700327 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400328 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700329
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100331
Victor van den Elzen154e5922009-02-25 17:32:00 +0100332 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100333 /* Be optimistic in pass 1 */
334 return true;
335
H. Peter Anvine2c80182005-01-15 22:15:51 +0000336 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700337 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000338
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700339 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
340 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000341}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000342
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800343int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400344 insn * instruction, struct ofmt *output, efunc error,
345 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000346{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000347 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700349 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800350 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000351 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800352 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300353 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000354
H. Peter Anvine2c80182005-01-15 22:15:51 +0000355 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000356 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000357 outfmt = output; /* likewise */
358 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000359
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300360 wsize = idata_bytes(instruction->opcode);
361 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000362 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000363
H. Peter Anvineba20a72002-04-30 20:53:55 +0000364 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000365 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000366 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 if (t < 0)
368 errfunc(ERR_PANIC,
369 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000370
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400372 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400374 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700375 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400376 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000377 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700378 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800380 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400381 offset += wsize;
382 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700383 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400384 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000386
H. Peter Anvine2c80182005-01-15 22:15:51 +0000387 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800388 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000390
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 if (align) {
392 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100393 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800394 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000395 }
396 offset += e->stringlen + align;
397 }
398 }
399 if (t > 0 && t == instruction->times - 1) {
400 /*
401 * Dummy call to list->output to give the offset to the
402 * listing module.
403 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800404 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000405 list->uplevel(LIST_TIMES);
406 }
407 }
408 if (instruction->times > 1)
409 list->downlevel(LIST_TIMES);
410 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000411 }
412
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700414 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000415 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000416
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400417 fp = fopen(fname, "rb");
418 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000419 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
420 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400421 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
423 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400424 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700425 static char buf[4096];
426 size_t t = instruction->times;
427 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400428 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000429
H. Peter Anvine2c80182005-01-15 22:15:51 +0000430 len = ftell(fp);
431 if (instruction->eops->next) {
432 base = instruction->eops->next->offset;
433 len -= base;
434 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700435 len > (size_t)instruction->eops->next->next->offset)
436 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000437 }
438 /*
439 * Dummy call to list->output to give the offset to the
440 * listing module.
441 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800442 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000443 list->uplevel(LIST_INCBIN);
444 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700445 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000446
H. Peter Anvine2c80182005-01-15 22:15:51 +0000447 fseek(fp, base, SEEK_SET);
448 l = len;
449 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700450 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400451 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000452 if (!m) {
453 /*
454 * This shouldn't happen unless the file
455 * actually changes while we are reading
456 * it.
457 */
458 error(ERR_NONFATAL,
459 "`incbin': unexpected EOF while"
460 " reading file `%s'", fname);
461 t = 0; /* Try to exit cleanly */
462 break;
463 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800464 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000465 NO_SEG, NO_SEG);
466 l -= m;
467 }
468 }
469 list->downlevel(LIST_INCBIN);
470 if (instruction->times > 1) {
471 /*
472 * Dummy call to list->output to give the offset to the
473 * listing module.
474 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800475 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000476 list->uplevel(LIST_TIMES);
477 list->downlevel(LIST_TIMES);
478 }
479 fclose(fp);
480 return instruction->times * len;
481 }
482 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000483 }
484
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700485 /* Check to see if we need an address-size prefix */
486 add_asp(instruction, bits);
487
H. Peter Anvin23595f52009-07-25 17:44:25 -0700488 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700489
H. Peter Anvin23595f52009-07-25 17:44:25 -0700490 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400491 /* Matches! */
492 int64_t insn_size = calcsize(segment, offset, bits,
493 instruction, temp->code);
494 itimes = instruction->times;
495 if (insn_size < 0) /* shouldn't be, on pass two */
496 error(ERR_PANIC, "errors made it through from pass one");
497 else
498 while (itimes--) {
499 for (j = 0; j < MAXPREFIX; j++) {
500 uint8_t c = 0;
501 switch (instruction->prefixes[j]) {
502 case P_WAIT:
503 c = 0x9B;
504 break;
505 case P_LOCK:
506 c = 0xF0;
507 break;
508 case P_REPNE:
509 case P_REPNZ:
510 c = 0xF2;
511 break;
512 case P_REPE:
513 case P_REPZ:
514 case P_REP:
515 c = 0xF3;
516 break;
517 case R_CS:
518 if (bits == 64) {
519 error(ERR_WARNING | ERR_PASS2,
520 "cs segment base generated, but will be ignored in 64-bit mode");
521 }
522 c = 0x2E;
523 break;
524 case R_DS:
525 if (bits == 64) {
526 error(ERR_WARNING | ERR_PASS2,
527 "ds segment base generated, but will be ignored in 64-bit mode");
528 }
529 c = 0x3E;
530 break;
531 case R_ES:
532 if (bits == 64) {
533 error(ERR_WARNING | ERR_PASS2,
534 "es segment base generated, but will be ignored in 64-bit mode");
535 }
536 c = 0x26;
537 break;
538 case R_FS:
539 c = 0x64;
540 break;
541 case R_GS:
542 c = 0x65;
543 break;
544 case R_SS:
545 if (bits == 64) {
546 error(ERR_WARNING | ERR_PASS2,
547 "ss segment base generated, but will be ignored in 64-bit mode");
548 }
549 c = 0x36;
550 break;
551 case R_SEGR6:
552 case R_SEGR7:
553 error(ERR_NONFATAL,
554 "segr6 and segr7 cannot be used as prefixes");
555 break;
556 case P_A16:
557 if (bits == 64) {
558 error(ERR_NONFATAL,
559 "16-bit addressing is not supported "
560 "in 64-bit mode");
561 } else if (bits != 16)
562 c = 0x67;
563 break;
564 case P_A32:
565 if (bits != 32)
566 c = 0x67;
567 break;
568 case P_A64:
569 if (bits != 64) {
570 error(ERR_NONFATAL,
571 "64-bit addressing is only supported "
572 "in 64-bit mode");
573 }
574 break;
575 case P_ASP:
576 c = 0x67;
577 break;
578 case P_O16:
579 if (bits != 16)
580 c = 0x66;
581 break;
582 case P_O32:
583 if (bits == 16)
584 c = 0x66;
585 break;
586 case P_O64:
587 /* REX.W */
588 break;
589 case P_OSP:
590 c = 0x66;
591 break;
592 case P_none:
593 break;
594 default:
595 error(ERR_PANIC, "invalid instruction prefix");
596 }
597 if (c != 0) {
598 out(offset, segment, &c, OUT_RAWDATA, 1,
599 NO_SEG, NO_SEG);
600 offset++;
601 }
602 }
603 insn_end = offset + insn_size;
604 gencode(segment, offset, bits, instruction,
605 temp, insn_end);
606 offset += insn_size;
607 if (itimes > 0 && itimes == instruction->times - 1) {
608 /*
609 * Dummy call to list->output to give the offset to the
610 * listing module.
611 */
612 list->output(offset, NULL, OUT_RAWDATA, 0);
613 list->uplevel(LIST_TIMES);
614 }
615 }
616 if (instruction->times > 1)
617 list->downlevel(LIST_TIMES);
618 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700619 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400620 /* No match */
621 switch (m) {
622 case MERR_OPSIZEMISSING:
623 error(ERR_NONFATAL, "operation size not specified");
624 break;
625 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000626 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400627 break;
628 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000629 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400630 break;
631 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800632 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400633 bits);
634 break;
635 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000636 error(ERR_NONFATAL,
637 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400638 break;
639 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000640 }
641 return 0;
642}
643
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800644int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400645 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000646{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000647 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700648 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000649
H. Peter Anvine2c80182005-01-15 22:15:51 +0000650 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000651 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000652
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400653 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000654 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000655
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700656 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
657 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400658 instruction->opcode == I_DT || instruction->opcode == I_DO ||
659 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300661 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300664 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000665
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400666 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000667 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000668
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400670 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400672 warn_overflow_const(e->offset, wsize);
673 } else if (e->type == EOT_DB_STRING ||
674 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000675 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000676
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 align = (-osize) % wsize;
678 if (align < 0)
679 align += wsize;
680 isize += osize + align;
681 }
682 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000683 }
684
H. Peter Anvine2c80182005-01-15 22:15:51 +0000685 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400686 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300688 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700689 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000690
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400691 fp = fopen(fname, "rb");
692 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
694 fname);
695 else if (fseek(fp, 0L, SEEK_END) < 0)
696 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
697 fname);
698 else {
699 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000700 if (instruction->eops->next) {
701 len -= instruction->eops->next->offset;
702 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700703 len > (size_t)instruction->eops->next->next->offset) {
704 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000705 }
706 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300707 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000708 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300709 if (fp)
710 fclose(fp);
711 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000712 }
713
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700714 /* Check to see if we need an address-size prefix */
715 add_asp(instruction, bits);
716
H. Peter Anvin23595f52009-07-25 17:44:25 -0700717 m = find_match(&temp, instruction, segment, offset, bits);
718 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400719 /* we've matched an instruction. */
720 int64_t isize;
721 const uint8_t *codes = temp->code;
722 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100723
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400724 isize = calcsize(segment, offset, bits, instruction, codes);
725 if (isize < 0)
726 return -1;
727 for (j = 0; j < MAXPREFIX; j++) {
728 switch (instruction->prefixes[j]) {
729 case P_A16:
730 if (bits != 16)
731 isize++;
732 break;
733 case P_A32:
734 if (bits != 32)
735 isize++;
736 break;
737 case P_O16:
738 if (bits != 16)
739 isize++;
740 break;
741 case P_O32:
742 if (bits == 16)
743 isize++;
744 break;
745 case P_A64:
746 case P_O64:
747 case P_none:
748 break;
749 default:
750 isize++;
751 break;
752 }
753 }
754 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700755 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400756 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000757 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000758}
759
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700760static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000761{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700762 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400763 !(o->opflags & OPFLAG_UNKNOWN) &&
764 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000765}
766
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700767/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700768static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700769{
770 int16_t v;
771
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700772 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400773 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700775 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700776 return v >= -128 && v <= 127;
777}
778
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700779static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700780{
781 int32_t v;
782
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700783 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400784 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700785
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700786 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700787 return v >= -128 && v <= 127;
788}
789
H. Peter Anvin507ae032008-10-09 15:37:10 -0700790/* Common construct */
791#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
792
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800793static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400794 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000795{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800796 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000797 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000798 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700799 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700800 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700801 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700802 enum ea_type eat;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000803
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700804 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700805 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700806
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700807 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400808 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700809
H. Peter Anvine2c80182005-01-15 22:15:51 +0000810 (void)segment; /* Don't warn that this parameter is unused */
811 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000812
H. Peter Anvin839eca22007-10-29 23:12:47 -0700813 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400814 c = *codes++;
815 op1 = (c & 3) + ((opex & 1) << 2);
816 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
817 opx = &ins->oprs[op1];
818 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700819
H. Peter Anvin839eca22007-10-29 23:12:47 -0700820 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000821 case 01:
822 case 02:
823 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400824 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000825 codes += c, length += c;
826 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700827
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400828 case 05:
829 case 06:
830 case 07:
831 opex = c;
832 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700833
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400834 case4(010):
835 ins->rex |=
836 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 codes++, length++;
838 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700839
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400840 case4(014):
841 case4(020):
842 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000843 length++;
844 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700845
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400846 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 length += 2;
848 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700849
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400850 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700851 if (opx->type & (BITS16 | BITS32 | BITS64))
852 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000853 else
854 length += (bits == 16) ? 2 : 4;
855 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700856
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400857 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000858 length += 4;
859 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700860
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400861 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700862 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000863 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700864
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400865 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000866 length++;
867 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700868
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400869 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000870 length += 8; /* MOV reg64/imm */
871 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700872
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400873 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 length += 2;
875 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700876
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400877 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700878 if (opx->type & (BITS16 | BITS32 | BITS64))
879 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000880 else
881 length += (bits == 16) ? 2 : 4;
882 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700883
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400884 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 length += 4;
886 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700887
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400888 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700889 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400892 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700893 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700895
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400896 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800897 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000898 length++;
899 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700900
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400901 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700902 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700903 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700904
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400905 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800906 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700907 length++;
908 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700909
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400910 case 0172:
911 case 0173:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400912 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700913 length++;
914 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700915
H. Peter Anvincffe61e2011-07-07 17:21:24 -0700916 case4(0174):
917 length++;
918 break;
919
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400920 case4(0250):
921 length += is_sbyte32(opx) ? 1 : 4;
922 break;
923
924 case4(0254):
925 length += 4;
926 break;
927
928 case4(0260):
929 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700930 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400931 ins->vex_cm = *codes++;
932 ins->vex_wlp = *codes++;
933 break;
934
935 case 0270:
936 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700937 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400938 ins->vex_cm = *codes++;
939 ins->vex_wlp = *codes++;
940 break;
941
942 case4(0274):
943 length++;
944 break;
945
946 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000947 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700948
H. Peter Anvine2c80182005-01-15 22:15:51 +0000949 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400950 if (bits == 64)
951 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700952 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000953 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700954
H. Peter Anvine2c80182005-01-15 22:15:51 +0000955 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700956 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700958
H. Peter Anvine2c80182005-01-15 22:15:51 +0000959 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
Keith Kaniosb7a89542007-04-12 02:40:54 +0000962 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400963 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
964 has_prefix(ins, PPS_ASIZE, P_A32))
965 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000966 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700967
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400968 case4(0314):
969 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700970
H. Peter Anvine2c80182005-01-15 22:15:51 +0000971 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000972 {
973 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
974 if (pfx == P_O16)
975 break;
976 if (pfx != P_none)
977 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
978 else
979 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000980 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000981 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700982
H. Peter Anvine2c80182005-01-15 22:15:51 +0000983 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000984 {
985 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
986 if (pfx == P_O32)
987 break;
988 if (pfx != P_none)
989 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
990 else
991 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000992 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000993 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700994
H. Peter Anvine2c80182005-01-15 22:15:51 +0000995 case 0322:
996 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700997
Keith Kaniosb7a89542007-04-12 02:40:54 +0000998 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000999 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001000 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001001
Keith Kaniosb7a89542007-04-12 02:40:54 +00001002 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001003 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001004 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001005
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001006 case 0325:
1007 ins->rex |= REX_NH;
1008 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001009
H. Peter Anvine2c80182005-01-15 22:15:51 +00001010 case 0330:
1011 codes++, length++;
1012 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001013
H. Peter Anvine2c80182005-01-15 22:15:51 +00001014 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001015 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001016
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001017 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001018 case 0333:
1019 length++;
1020 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001021
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001022 case 0334:
1023 ins->rex |= REX_L;
1024 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001025
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001026 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001027 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001028
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001029 case 0336:
1030 if (!ins->prefixes[PPS_LREP])
1031 ins->prefixes[PPS_LREP] = P_REP;
1032 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001033
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001034 case 0337:
1035 if (!ins->prefixes[PPS_LREP])
1036 ins->prefixes[PPS_LREP] = P_REPNE;
1037 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001038
H. Peter Anvine2c80182005-01-15 22:15:51 +00001039 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001040 if (ins->oprs[0].segment != NO_SEG)
1041 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1042 " quantity of BSS space");
1043 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001044 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001046
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001047 case 0341:
1048 if (!ins->prefixes[PPS_WAIT])
1049 ins->prefixes[PPS_WAIT] = P_WAIT;
1050 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001051
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001052 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001053 length++;
1054 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001055
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001056 case 0360:
1057 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001058
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001059 case 0361:
1060 case 0362:
1061 case 0363:
1062 length++;
1063 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001064
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001065 case 0364:
1066 case 0365:
1067 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001068
Keith Kanios48af1772007-08-17 07:37:52 +00001069 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001070 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001071 length++;
1072 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001073
H. Peter Anvine2c80182005-01-15 22:15:51 +00001074 case 0370:
1075 case 0371:
1076 case 0372:
1077 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001078
H. Peter Anvine2c80182005-01-15 22:15:51 +00001079 case 0373:
1080 length++;
1081 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001082
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001083 case 0374:
1084 eat = EA_XMMVSIB;
1085 break;
1086
1087 case 0375:
1088 eat = EA_YMMVSIB;
1089 break;
1090
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001091 case4(0100):
1092 case4(0110):
1093 case4(0120):
1094 case4(0130):
1095 case4(0200):
1096 case4(0204):
1097 case4(0210):
1098 case4(0214):
1099 case4(0220):
1100 case4(0224):
1101 case4(0230):
1102 case4(0234):
1103 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001104 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001105 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001106 opflags_t rflags;
1107 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001108
Keith Kaniosb7a89542007-04-12 02:40:54 +00001109 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001110
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001111 if (c <= 0177) {
1112 /* pick rfield from operand b (opx) */
1113 rflags = regflag(opx);
1114 rfield = nasm_regvals[opx->basereg];
1115 } else {
1116 rflags = 0;
1117 rfield = c & 7;
1118 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001119 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1120 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001121 errfunc(ERR_NONFATAL, "invalid effective address");
1122 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001123 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001124 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001125 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001126 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001127 }
1128 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001129
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001130 default:
1131 errfunc(ERR_PANIC, "internal instruction table corrupt"
1132 ": instruction code \\%o (0x%02X) given", c, c);
1133 break;
1134 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001135 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001136
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001137 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001138
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001139 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001140 if (ins->rex & REX_H) {
1141 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1142 return -1;
1143 }
1144 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001145 }
1146
H. Peter Anvind85d2502008-05-04 17:53:31 -07001147 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001148 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001149
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001150 if (ins->rex & REX_H) {
1151 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1152 return -1;
1153 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001154 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001155 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001156 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001157 ins->rex &= ~REX_W;
1158 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001159 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001160 ins->rex |= REX_W;
1161 bad32 &= ~REX_W;
1162 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001163 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001164 /* Follow REX_W */
1165 break;
1166 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001167
H. Peter Anvinfc561202011-07-07 16:58:22 -07001168 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001169 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1170 return -1;
1171 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001172 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001173 length += 3;
1174 else
1175 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001176 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001177 if (ins->rex & REX_H) {
1178 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1179 return -1;
1180 } else if (bits == 64) {
1181 length++;
1182 } else if ((ins->rex & REX_L) &&
1183 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1184 cpu >= IF_X86_64) {
1185 /* LOCK-as-REX.R */
1186 assert_no_prefix(ins, PPS_LREP);
1187 length++;
1188 } else {
1189 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1190 return -1;
1191 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001192 }
1193
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001194 return length;
1195}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001196
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001197#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001198 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001199 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1200 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1201 ins->rex = 0; \
1202 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001203 }
1204
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001205static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001206 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001207 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001208{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001209 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001210 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1211 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1212 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001213 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001214 uint8_t c;
1215 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001216 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001217 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001218 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001219 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001220 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001221 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001222 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001223
H. Peter Anvin839eca22007-10-29 23:12:47 -07001224 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001225 c = *codes++;
1226 op1 = (c & 3) + ((opex & 1) << 2);
1227 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1228 opx = &ins->oprs[op1];
1229 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001230
H. Peter Anvin839eca22007-10-29 23:12:47 -07001231 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001232 case 01:
1233 case 02:
1234 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001235 case 04:
1236 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001237 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001238 codes += c;
1239 offset += c;
1240 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001241
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001242 case 05:
1243 case 06:
1244 case 07:
1245 opex = c;
1246 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001247
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001248 case4(010):
1249 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001250 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001251 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001252 offset += 1;
1253 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001254
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001255 case4(014):
1256 /*
1257 * The test for BITS8 and SBYTE here is intended to avoid
1258 * warning on optimizer actions due to SBYTE, while still
1259 * warn on explicit BYTE directives. Also warn, obviously,
1260 * if the optimizer isn't enabled.
1261 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001262 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001263 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1264 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001265 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001266 "signed byte value exceeds bounds");
1267 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 if (opx->segment != NO_SEG) {
1269 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001270 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001271 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001272 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001273 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001274 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001275 NO_SEG);
1276 }
1277 offset += 1;
1278 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001279
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001280 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001282 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001283 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001285 if (opx->segment != NO_SEG) {
1286 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001287 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001288 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001289 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001291 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001292 NO_SEG);
1293 }
1294 offset += 1;
1295 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001296
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001297 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001298 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001299 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001300 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001301 if (opx->segment != NO_SEG) {
1302 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001303 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001304 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001305 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001307 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001308 NO_SEG);
1309 }
1310 offset += 1;
1311 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001312
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001313 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001314 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001315 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001316 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 offset += 2;
1319 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001320
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001321 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 if (opx->type & (BITS16 | BITS32))
1323 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 else
1325 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001326 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001327 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001328 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001330 offset += size;
1331 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001332
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001333 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001334 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001335 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001336 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001338 offset += 4;
1339 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001340
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001341 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001342 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001343 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001344 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001345 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001346 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001347 offset += size;
1348 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001349
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001350 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001351 if (opx->segment != segment) {
1352 data = opx->offset;
1353 out(offset, segment, &data,
1354 OUT_REL1ADR, insn_end - offset,
1355 opx->segment, opx->wrt);
1356 } else {
1357 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001358 if (data > 127 || data < -128)
1359 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001360 out(offset, segment, &data,
1361 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1362 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001363 offset += 1;
1364 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001365
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001366 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001368 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001370 offset += 8;
1371 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001372
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001373 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001374 if (opx->segment != segment) {
1375 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001376 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001377 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001379 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001380 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001381 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001382 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001383 }
1384 offset += 2;
1385 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001386
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001387 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001388 if (opx->type & (BITS16 | BITS32 | BITS64))
1389 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 else
1391 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001392 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001393 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001394 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001395 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1396 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001397 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001400 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001401 }
1402 offset += size;
1403 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001404
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001405 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 if (opx->segment != segment) {
1407 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001408 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001409 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001410 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001411 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001412 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001413 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001414 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001415 }
1416 offset += 4;
1417 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001418
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001419 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001421 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1422 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001423 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001424 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001425 outfmt->segbase(1 + opx->segment),
1426 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001427 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001429
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001430 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001431 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001432 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001433 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001434 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001435 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001436 NO_SEG);
1437 offset++;
1438 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001439 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001440 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001441 offset += 2;
1442 }
1443 break;
1444
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001445 case4(0144):
1446 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001447 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001448 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001449 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001450 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001451 offset++;
1452 break;
1453
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001454 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001455 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001456 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001457 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001458 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001459 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 NO_SEG);
1461 offset++;
1462 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001463 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001464 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001465 offset += 4;
1466 }
1467 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001468
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001469 case4(0154):
1470 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001471 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001472 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001473 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001474 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001475 offset++;
1476 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001477
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001478 case 0172:
1479 c = *codes++;
1480 opx = &ins->oprs[c >> 3];
1481 bytes[0] = nasm_regvals[opx->basereg] << 4;
1482 opx = &ins->oprs[c & 7];
1483 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1484 errfunc(ERR_NONFATAL,
1485 "non-absolute expression not permitted as argument %d",
1486 c & 7);
1487 } else {
1488 if (opx->offset & ~15) {
1489 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1490 "four-bit argument exceeds bounds");
1491 }
1492 bytes[0] |= opx->offset & 15;
1493 }
1494 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1495 offset++;
1496 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001497
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001498 case 0173:
1499 c = *codes++;
1500 opx = &ins->oprs[c >> 4];
1501 bytes[0] = nasm_regvals[opx->basereg] << 4;
1502 bytes[0] |= c & 15;
1503 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1504 offset++;
1505 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001506
H. Peter Anvincffe61e2011-07-07 17:21:24 -07001507 case4(0174):
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001508 bytes[0] = nasm_regvals[opx->basereg] << 4;
1509 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1510 offset++;
1511 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001512
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001513 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001514 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001515 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1516 (int32_t)data != (int64_t)data) {
1517 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1518 "signed dword immediate exceeds bounds");
1519 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001520 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001521 bytes[0] = data;
1522 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1523 NO_SEG);
1524 offset++;
1525 } else {
1526 out(offset, segment, &data, OUT_ADDRESS, 4,
1527 opx->segment, opx->wrt);
1528 offset += 4;
1529 }
1530 break;
1531
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001532 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001533 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001534 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1535 (int32_t)data != (int64_t)data) {
1536 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1537 "signed dword immediate exceeds bounds");
1538 }
1539 out(offset, segment, &data, OUT_ADDRESS, 4,
1540 opx->segment, opx->wrt);
1541 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001542 break;
1543
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001544 case4(0260):
1545 case 0270:
1546 codes += 2;
1547 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1548 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1549 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1550 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001551 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001552 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1553 offset += 3;
1554 } else {
1555 bytes[0] = 0xc5;
1556 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001557 ((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001558 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1559 offset += 2;
1560 }
1561 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001562
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001563 case4(0274):
1564 {
1565 uint64_t uv, um;
1566 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001567
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001568 if (ins->rex & REX_W)
1569 s = 64;
1570 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1571 s = 16;
1572 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1573 s = 32;
1574 else
1575 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001576
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001577 um = (uint64_t)2 << (s-1);
1578 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001579
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001580 if (uv > 127 && uv < (uint64_t)-128 &&
1581 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001582 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001583 "signed byte value exceeds bounds");
1584 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001585 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001586 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001587 out(offset, segment, &data, OUT_ADDRESS, 1,
1588 opx->segment, opx->wrt);
1589 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001590 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001591 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1592 NO_SEG);
1593 }
1594 offset += 1;
1595 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001596 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001597
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001598 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001599 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001600
H. Peter Anvine2c80182005-01-15 22:15:51 +00001601 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001602 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001603 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001604 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001605 offset += 1;
1606 } else
1607 offset += 0;
1608 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001609
H. Peter Anvine2c80182005-01-15 22:15:51 +00001610 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001611 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001612 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001613 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001614 offset += 1;
1615 } else
1616 offset += 0;
1617 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001618
H. Peter Anvine2c80182005-01-15 22:15:51 +00001619 case 0312:
1620 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001621
Keith Kaniosb7a89542007-04-12 02:40:54 +00001622 case 0313:
1623 ins->rex = 0;
1624 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001625
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001626 case4(0314):
1627 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001628
H. Peter Anvine2c80182005-01-15 22:15:51 +00001629 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001630 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001631 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001632
H. Peter Anvine2c80182005-01-15 22:15:51 +00001633 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001634 case 0323:
1635 break;
1636
Keith Kaniosb7a89542007-04-12 02:40:54 +00001637 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001638 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001639 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001640
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001641 case 0325:
1642 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001643
H. Peter Anvine2c80182005-01-15 22:15:51 +00001644 case 0330:
1645 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001646 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 offset += 1;
1648 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001649
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001651 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001652
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001653 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001654 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001655 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001656 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001657 offset += 1;
1658 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001659
Keith Kanios48af1772007-08-17 07:37:52 +00001660 case 0334:
1661 if (ins->rex & REX_R) {
1662 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001663 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001664 offset += 1;
1665 }
1666 ins->rex &= ~(REX_L|REX_R);
1667 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001668
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001669 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001670 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001671
H. Peter Anvin962e3052008-08-28 17:47:16 -07001672 case 0336:
1673 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001674 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001675
H. Peter Anvine2c80182005-01-15 22:15:51 +00001676 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001677 if (ins->oprs[0].segment != NO_SEG)
1678 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1679 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001680 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001681 if (size > 0)
1682 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001683 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 offset += size;
1685 }
1686 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001687
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001688 case 0341:
1689 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001690
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001691 case 0344:
1692 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001693 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001694 switch (ins->oprs[0].basereg) {
1695 case R_CS:
1696 bytes[0] += 0x0E;
1697 break;
1698 case R_DS:
1699 bytes[0] += 0x1E;
1700 break;
1701 case R_ES:
1702 bytes[0] += 0x06;
1703 break;
1704 case R_SS:
1705 bytes[0] += 0x16;
1706 break;
1707 default:
1708 errfunc(ERR_PANIC,
1709 "bizarre 8086 segment register received");
1710 }
1711 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1712 offset++;
1713 break;
1714
1715 case 0346:
1716 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001717 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001718 switch (ins->oprs[0].basereg) {
1719 case R_FS:
1720 bytes[0] += 0xA0;
1721 break;
1722 case R_GS:
1723 bytes[0] += 0xA8;
1724 break;
1725 default:
1726 errfunc(ERR_PANIC,
1727 "bizarre 386 segment register received");
1728 }
1729 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1730 offset++;
1731 break;
1732
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001733 case 0360:
1734 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001735
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001736 case 0361:
1737 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001738 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1739 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001740 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001741
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001742 case 0362:
1743 case 0363:
1744 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001745 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1746 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001747 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001748
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001749 case 0364:
1750 case 0365:
1751 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001752
Keith Kanios48af1772007-08-17 07:37:52 +00001753 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001754 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001755 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001756 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001757 offset += 1;
1758 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001759
H. Peter Anvine2c80182005-01-15 22:15:51 +00001760 case 0370:
1761 case 0371:
1762 case 0372:
1763 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001764
H. Peter Anvine2c80182005-01-15 22:15:51 +00001765 case 0373:
1766 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001767 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001768 offset += 1;
1769 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001770
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001771 case 0374:
1772 eat = EA_XMMVSIB;
1773 break;
1774
1775 case 0375:
1776 eat = EA_YMMVSIB;
1777 break;
1778
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001779 case4(0100):
1780 case4(0110):
1781 case4(0120):
1782 case4(0130):
1783 case4(0200):
1784 case4(0204):
1785 case4(0210):
1786 case4(0214):
1787 case4(0220):
1788 case4(0224):
1789 case4(0230):
1790 case4(0234):
1791 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001792 ea ea_data;
1793 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001794 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001795 uint8_t *p;
1796 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001797 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001798
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001799 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001800 /* pick rfield from operand b (opx) */
1801 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001802 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001803 } else {
1804 /* rfield is constant */
1805 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001807 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001808
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001809 if (process_ea(opy, &ea_data, bits, ins->addr_size,
Cyrill Gorcunovcdb8cd72011-08-28 16:33:39 +04001810 rfield, rflags) != eat)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811 errfunc(ERR_NONFATAL, "invalid effective address");
Charles Crayne7e975552007-11-03 22:06:13 -07001812
H. Peter Anvine2c80182005-01-15 22:15:51 +00001813 p = bytes;
1814 *p++ = ea_data.modrm;
1815 if (ea_data.sib_present)
1816 *p++ = ea_data.sib;
1817
1818 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001819 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001820
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001821 /*
1822 * Make sure the address gets the right offset in case
1823 * the line breaks in the .lst file (BR 1197827)
1824 */
1825 offset += s;
1826 s = 0;
1827
H. Peter Anvine2c80182005-01-15 22:15:51 +00001828 switch (ea_data.bytes) {
1829 case 0:
1830 break;
1831 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001832 case 2:
1833 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001834 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001835 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001836 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001837 if (ea_data.rip) {
1838 if (opy->segment == segment) {
1839 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001840 if (overflow_signed(data, ea_data.bytes))
1841 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001842 out(offset, segment, &data, OUT_ADDRESS,
1843 ea_data.bytes, NO_SEG, NO_SEG);
1844 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001845 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001846 out(offset, segment, &data, OUT_REL4ADR,
1847 insn_end - offset, opy->segment, opy->wrt);
1848 }
1849 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001850 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1851 signed_bits(opy->offset, ins->addr_size) !=
1852 signed_bits(opy->offset, ea_data.bytes * 8))
1853 warn_overflow(ERR_PASS2, ea_data.bytes);
1854
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001855 out(offset, segment, &data, OUT_ADDRESS,
1856 ea_data.bytes, opy->segment, opy->wrt);
1857 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001858 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001859 default:
1860 /* Impossible! */
1861 errfunc(ERR_PANIC,
1862 "Invalid amount of bytes (%d) for offset?!",
1863 ea_data.bytes);
1864 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001865 }
1866 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001867 }
1868 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001869
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001870 default:
1871 errfunc(ERR_PANIC, "internal instruction table corrupt"
1872 ": instruction code \\%o (0x%02X) given", c, c);
1873 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001874 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001875 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001876}
1877
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001878static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001880 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001881 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001882 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001883}
1884
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001885static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001886{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001887 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001888 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001889 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001890}
1891
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001892static int op_rexflags(const operand * o, int mask)
1893{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001894 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001895 int val;
1896
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001897 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001898 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001899
H. Peter Anvina4835d42008-05-20 14:21:29 -07001900 flags = nasm_reg_flags[o->basereg];
1901 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001902
1903 return rexflags(val, flags, mask);
1904}
1905
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001906static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001907{
1908 int rex = 0;
1909
1910 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001911 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001912 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001913 rex |= REX_W;
1914 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1915 rex |= REX_H;
1916 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1917 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001918
1919 return rex & mask;
1920}
1921
H. Peter Anvin23595f52009-07-25 17:44:25 -07001922static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001923 insn *instruction,
1924 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001925{
1926 const struct itemplate *temp;
1927 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001928 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001929 bool opsizemissing = false;
1930 int i;
1931
1932 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001933 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001934
1935 merr = MERR_INVALOP;
1936
1937 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001938 temp->opcode != I_none; temp++) {
1939 m = matches(temp, instruction, bits);
1940 if (m == MOK_JUMP) {
1941 if (jmp_match(segment, offset, bits, instruction, temp->code))
1942 m = MOK_GOOD;
1943 else
1944 m = MERR_INVALOP;
1945 } else if (m == MERR_OPSIZEMISSING &&
1946 (temp->flags & IF_SMASK) != IF_SX) {
1947 /*
1948 * Missing operand size and a candidate for fuzzy matching...
1949 */
1950 for (i = 0; i < temp->operands; i++) {
1951 if ((temp->opd[i] & SAME_AS) == 0)
1952 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1953 }
1954 opsizemissing = true;
1955 }
1956 if (m > merr)
1957 merr = m;
1958 if (merr == MOK_GOOD)
1959 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001960 }
1961
1962 /* No match, but see if we can get a fuzzy operand size match... */
1963 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001964 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001965
1966 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001967 /*
1968 * We ignore extrinsic operand sizes on registers, so we should
1969 * never try to fuzzy-match on them. This also resolves the case
1970 * when we have e.g. "xmmrm128" in two different positions.
1971 */
1972 if (is_class(REGISTER, instruction->oprs[i].type))
1973 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001974
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001975 /* This tests if xsizeflags[i] has more than one bit set */
1976 if ((xsizeflags[i] & (xsizeflags[i]-1)))
1977 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001978
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001979 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001980 }
1981
1982 /* Try matching again... */
1983 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001984 temp->opcode != I_none; temp++) {
1985 m = matches(temp, instruction, bits);
1986 if (m == MOK_JUMP) {
1987 if (jmp_match(segment, offset, bits, instruction, temp->code))
1988 m = MOK_GOOD;
1989 else
1990 m = MERR_INVALOP;
1991 }
1992 if (m > merr)
1993 merr = m;
1994 if (merr == MOK_GOOD)
1995 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001996 }
1997
H. Peter Anvina81655b2009-07-25 18:15:28 -07001998done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07001999 *tempp = temp;
2000 return merr;
2001}
2002
H. Peter Anvin65289e82009-07-25 17:25:11 -07002003static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002004 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002005{
H. Peter Anvin60926242009-07-26 16:25:38 -07002006 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002007 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002008
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002009 /*
2010 * Check the opcode
2011 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002012 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002013 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002014
2015 /*
2016 * Count the operands
2017 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002018 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002019 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002020
2021 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002022 * Is it legal?
2023 */
2024 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2025 return MERR_INVALOP;
2026
2027 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002028 * Check that no spurious colons or TOs are present
2029 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002030 for (i = 0; i < itemp->operands; i++)
2031 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002032 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002033
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002034 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002035 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002036 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002037 switch (itemp->flags & IF_SMASK) {
2038 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002039 asize = BITS8;
2040 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002041 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002042 asize = BITS16;
2043 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002044 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002045 asize = BITS32;
2046 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002047 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002048 asize = BITS64;
2049 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002050 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002051 asize = BITS128;
2052 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002053 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002054 asize = BITS256;
2055 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002056 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002057 switch (bits) {
2058 case 16:
2059 asize = BITS16;
2060 break;
2061 case 32:
2062 asize = BITS32;
2063 break;
2064 case 64:
2065 asize = BITS64;
2066 break;
2067 default:
2068 asize = 0;
2069 break;
2070 }
2071 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002072 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002073 asize = 0;
2074 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002075 }
2076
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002077 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002078 /* S- flags only apply to a specific operand */
2079 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2080 memset(size, 0, sizeof size);
2081 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002082 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002083 /* S- flags apply to all operands */
2084 for (i = 0; i < MAX_OPERANDS; i++)
2085 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002086 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002087
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002088 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002089 * Check that the operand flags all match up,
2090 * it's a bit tricky so lets be verbose:
2091 *
2092 * 1) Find out the size of operand. If instruction
2093 * doesn't have one specified -- we're trying to
2094 * guess it either from template (IF_S* flag) or
2095 * from code bits.
2096 *
2097 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2098 * (ie the same operand as was specified somewhere in template, and
2099 * this referred operand index is being achieved via ~SAME_AS)
2100 * we are to be sure that both registers (in template and instruction)
2101 * do exactly match.
2102 *
2103 * 3) If template operand do not match the instruction OR
2104 * template has an operand size specified AND this size differ
2105 * from which instruction has (perhaps we got it from code bits)
2106 * we are:
2107 * a) Check that only size of instruction and operand is differ
2108 * other characteristics do match
2109 * b) Perhaps it's a register specified in instruction so
2110 * for such a case we just mark that operand as "size
2111 * missing" and this will turn on fuzzy operand size
2112 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002113 */
2114 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002115 opflags_t type = instruction->oprs[i].type;
2116 if (!(type & SIZE_MASK))
2117 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002118
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002119 if (itemp->opd[i] & SAME_AS) {
2120 int j = itemp->opd[i] & ~SAME_AS;
2121 if (type != instruction->oprs[j].type ||
2122 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2123 return MERR_INVALOP;
2124 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002125 ((itemp->opd[i] & SIZE_MASK) &&
2126 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002127 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002128 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002129 } else if (!is_class(REGISTER, type)) {
2130 /*
2131 * Note: we don't honor extrinsic operand sizes for registers,
2132 * so "missing operand size" for a register should be
2133 * considered a wildcard match rather than an error.
2134 */
2135 opsizemissing = true;
2136 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002137 }
2138 }
2139
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002140 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002141 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002142
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002143 /*
2144 * Check operand sizes
2145 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002146 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002147 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002148 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002149 asize = itemp->opd[i] & SIZE_MASK;
2150 if (asize) {
2151 for (i = 0; i < oprs; i++)
2152 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002153 break;
2154 }
2155 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002156 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002157 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002158 }
2159
Keith Kaniosb7a89542007-04-12 02:40:54 +00002160 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002161 if (!(itemp->opd[i] & SIZE_MASK) &&
2162 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002163 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002164 }
2165
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002166 /*
2167 * Check template is okay at the set cpu level
2168 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002169 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002170 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002171
Keith Kaniosb7a89542007-04-12 02:40:54 +00002172 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002173 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002174 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002175 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002176 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002177
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002178 /*
2179 * Check if special handling needed for Jumps
2180 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002181 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002182 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002183
H. Peter Anvin60926242009-07-26 16:25:38 -07002184 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002185}
2186
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002187static enum ea_type process_ea(operand *input, ea *output, int bits,
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002188 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002189{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002190 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002191
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002192 output->type = EA_SCALAR;
2193 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002194
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002195 /* REX flags for the rfield operand */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002196 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002197
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002198 if (is_class(REGISTER, input->type)) {
2199 /*
2200 * It's a direct register.
2201 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002202 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002203
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002204 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002205 goto err;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002206
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002207 f = regflag(input);
2208
2209 if (!is_class(REG_EA, f))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002210 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002211
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002212 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002213 output->sib_present = false; /* no SIB necessary */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002214 output->bytes = 0; /* no offset necessary either */
2215 output->modrm = GEN_MODRM(3, rfield, nasm_regvals[input->basereg]);
2216 } else {
2217 /*
2218 * It's a memory reference.
2219 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002220 if (input->basereg == -1 &&
2221 (input->indexreg == -1 || input->scale == 0)) {
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002222 /*
2223 * It's a pure offset.
2224 */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002225 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2226 input->segment == NO_SEG) {
2227 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2228 input->type &= ~IP_REL;
2229 input->type |= MEMORY;
2230 }
2231
2232 if (input->eaflags & EAF_BYTEOFFS ||
2233 (input->eaflags & EAF_WORDOFFS &&
2234 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2235 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2236 }
2237
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002238 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002239 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002240 output->sib = GEN_SIB(0, 4, 5);
2241 output->bytes = 4;
2242 output->modrm = GEN_MODRM(0, rfield, 4);
2243 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002244 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002245 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002246 output->bytes = (addrbits != 16 ? 4 : 2);
2247 output->modrm = GEN_MODRM(0, rfield, (addrbits != 16 ? 5 : 6));
2248 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002249 }
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002250 } else {
2251 /*
2252 * It's an indirection.
2253 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002254 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002255 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002256 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002257 int t, it, bt; /* register numbers */
2258 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002259
H. Peter Anvine2c80182005-01-15 22:15:51 +00002260 if (s == 0)
2261 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002262
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002263 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002264 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002265 ix = nasm_reg_flags[i];
2266 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002267 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002268 ix = 0;
2269 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002270
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002271 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002272 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002273 bx = nasm_reg_flags[b];
2274 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002275 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002276 bx = 0;
2277 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002278
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002279 /* if either one are a vector register... */
2280 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
2281 int32_t sok = BITS32 | BITS64;
2282 int32_t o = input->offset;
2283 int mod, scale, index, base;
2284
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002285 /*
2286 * For a vector SIB, one has to be a vector and the other,
2287 * if present, a GPR. The vector must be the index operand.
2288 */
2289 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2290 if (s == 0)
2291 s = 1;
2292 else if (s != 1)
2293 goto err;
2294
2295 t = bt, bt = it, it = t;
2296 x = bx, bx = ix, ix = x;
2297 }
2298
2299 if (bt != -1) {
2300 if (REG_GPR & ~bx)
2301 goto err;
2302 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2303 sok &= bx;
2304 else
2305 goto err;
2306 }
2307
2308 /*
2309 * While we're here, ensure the user didn't specify
2310 * WORD or QWORD
2311 */
2312 if (input->disp_size == 16 || input->disp_size == 64)
2313 goto err;
2314
2315 if (addrbits == 16 ||
2316 (addrbits == 32 && !(sok & BITS32)) ||
2317 (addrbits == 64 && !(sok & BITS64)))
2318 goto err;
2319
2320 output->type = (ix & YMMREG & ~REG_EA)
2321 ? EA_YMMVSIB : EA_XMMVSIB;
2322
2323 output->rex |= rexflags(it, ix, REX_X);
2324 output->rex |= rexflags(bt, bx, REX_B);
2325
2326 index = it & 7; /* it is known to be != -1 */
2327
2328 switch (s) {
2329 case 1:
2330 scale = 0;
2331 break;
2332 case 2:
2333 scale = 1;
2334 break;
2335 case 4:
2336 scale = 2;
2337 break;
2338 case 8:
2339 scale = 3;
2340 break;
2341 default: /* then what the smeg is it? */
2342 goto err; /* panic */
2343 }
2344
2345 if (bt == -1) {
2346 base = 5;
2347 mod = 0;
2348 } else {
2349 base = (bt & 7);
2350 if (base != REG_NUM_EBP && o == 0 &&
2351 seg == NO_SEG && !forw_ref &&
2352 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2353 mod = 0;
2354 else if (input->eaflags & EAF_BYTEOFFS ||
2355 (o >= -128 && o <= 127 &&
2356 seg == NO_SEG && !forw_ref &&
2357 !(input->eaflags & EAF_WORDOFFS)))
2358 mod = 1;
2359 else
2360 mod = 2;
2361 }
2362
2363 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002364 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2365 output->modrm = GEN_MODRM(mod, rfield, 4);
2366 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002367 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002368 /*
2369 * it must be a 32/64-bit memory reference. Firstly we have
2370 * to check that all registers involved are type E/Rxx.
2371 */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002372 int32_t sok = BITS32 | BITS64;
2373 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002374
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002375 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002376 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2377 sok &= ix;
2378 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002379 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002380 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002381
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002382 if (bt != -1) {
2383 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002384 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002385 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002386 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002387 sok &= bx;
2388 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002389
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002390 /*
2391 * While we're here, ensure the user didn't specify
2392 * WORD or QWORD
2393 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002394 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002395 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002396
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002397 if (addrbits == 16 ||
2398 (addrbits == 32 && !(sok & BITS32)) ||
2399 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002400 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002401
Keith Kaniosb7a89542007-04-12 02:40:54 +00002402 /* now reorganize base/index */
2403 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002404 ((hb == b && ht == EAH_NOTBASE) ||
2405 (hb == i && ht == EAH_MAKEBASE))) {
2406 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002407 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002408 x = bx, bx = ix, ix = x;
2409 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002410 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002411 bt = -1, bx = 0, s++;
2412 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002413 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002414 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002415 }
2416 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2417 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002418 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002419 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2420 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002421 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002422 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002423 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002424 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002425 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002426 x = ix, ix = bx, bx = x;
2427 }
2428 if (it == REG_NUM_ESP ||
2429 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002430 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002431
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002432 output->rex |= rexflags(it, ix, REX_X);
2433 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002434
Keith Kanios48af1772007-08-17 07:37:52 +00002435 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002436 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002437 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002438
Keith Kaniosb7a89542007-04-12 02:40:54 +00002439 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002440 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002441 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002442 } else {
2443 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002444 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002445 seg == NO_SEG && !forw_ref &&
2446 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002447 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002448 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002449 (o >= -128 && o <= 127 &&
2450 seg == NO_SEG && !forw_ref &&
2451 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002452 mod = 1;
2453 else
2454 mod = 2;
2455 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002456
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002457 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002458 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2459 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002460 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002461 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002462 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002463
Keith Kaniosb7a89542007-04-12 02:40:54 +00002464 if (it == -1)
2465 index = 4, s = 1;
2466 else
2467 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002468
H. Peter Anvine2c80182005-01-15 22:15:51 +00002469 switch (s) {
2470 case 1:
2471 scale = 0;
2472 break;
2473 case 2:
2474 scale = 1;
2475 break;
2476 case 4:
2477 scale = 2;
2478 break;
2479 case 8:
2480 scale = 3;
2481 break;
2482 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002483 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002484 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002485
Keith Kaniosb7a89542007-04-12 02:40:54 +00002486 if (bt == -1) {
2487 base = 5;
2488 mod = 0;
2489 } else {
2490 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002491 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002492 seg == NO_SEG && !forw_ref &&
2493 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002494 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002495 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002496 (o >= -128 && o <= 127 &&
2497 seg == NO_SEG && !forw_ref &&
2498 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002499 mod = 1;
2500 else
2501 mod = 2;
2502 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002503
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002504 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002505 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2506 output->modrm = GEN_MODRM(mod, rfield, 4);
2507 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002508 }
2509 } else { /* it's 16-bit */
2510 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002511 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002512
Keith Kaniosb7a89542007-04-12 02:40:54 +00002513 /* check for 64-bit long mode */
2514 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002515 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002516
H. Peter Anvine2c80182005-01-15 22:15:51 +00002517 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002518 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2519 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002520 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002521
Keith Kaniosb7a89542007-04-12 02:40:54 +00002522 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002523 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002524 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002525
H. Peter Anvine2c80182005-01-15 22:15:51 +00002526 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002527 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002528 if (b == -1 && i != -1) {
2529 int tmp = b;
2530 b = i;
2531 i = tmp;
2532 } /* swap */
2533 if ((b == R_SI || b == R_DI) && i != -1) {
2534 int tmp = b;
2535 b = i;
2536 i = tmp;
2537 }
2538 /* have BX/BP as base, SI/DI index */
2539 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002540 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002541 if (i != -1 && b != -1 &&
2542 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002543 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002544 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002545 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002546
H. Peter Anvine2c80182005-01-15 22:15:51 +00002547 rm = -1;
2548 if (i != -1)
2549 switch (i * 256 + b) {
2550 case R_SI * 256 + R_BX:
2551 rm = 0;
2552 break;
2553 case R_DI * 256 + R_BX:
2554 rm = 1;
2555 break;
2556 case R_SI * 256 + R_BP:
2557 rm = 2;
2558 break;
2559 case R_DI * 256 + R_BP:
2560 rm = 3;
2561 break;
2562 } else
2563 switch (b) {
2564 case R_SI:
2565 rm = 4;
2566 break;
2567 case R_DI:
2568 rm = 5;
2569 break;
2570 case R_BP:
2571 rm = 6;
2572 break;
2573 case R_BX:
2574 rm = 7;
2575 break;
2576 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002577 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002578 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002579
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002580 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2581 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002582 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002583 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002584 (o >= -128 && o <= 127 && seg == NO_SEG &&
2585 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002586 mod = 1;
2587 else
2588 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002589
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002590 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002591 output->bytes = mod; /* bytes of offset needed */
2592 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002593 }
2594 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002595 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002596
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002597 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002598 return output->type;
2599
2600err:
2601 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002602}
2603
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002604static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002605{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002606 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002607 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002608
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002609 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002610
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002611 switch (ins->prefixes[PPS_ASIZE]) {
2612 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002613 valid &= 16;
2614 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002615 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002616 valid &= 32;
2617 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002618 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002619 valid &= 64;
2620 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002621 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002622 valid &= (addrbits == 32) ? 16 : 32;
2623 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002624 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002625 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002626 }
2627
2628 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002629 if (is_class(MEMORY, ins->oprs[j].type)) {
2630 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002631
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002632 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002633 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002634 i = 0;
2635 else
2636 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002637
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002638 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002639 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002640 b = 0;
2641 else
2642 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002643
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002644 if (ins->oprs[j].scale == 0)
2645 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002646
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002647 if (!i && !b) {
2648 int ds = ins->oprs[j].disp_size;
2649 if ((addrbits != 64 && ds > 8) ||
2650 (addrbits == 64 && ds == 16))
2651 valid &= ds;
2652 } else {
2653 if (!(REG16 & ~b))
2654 valid &= 16;
2655 if (!(REG32 & ~b))
2656 valid &= 32;
2657 if (!(REG64 & ~b))
2658 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002659
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002660 if (!(REG16 & ~i))
2661 valid &= 16;
2662 if (!(REG32 & ~i))
2663 valid &= 32;
2664 if (!(REG64 & ~i))
2665 valid &= 64;
2666 }
2667 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002668 }
2669
2670 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002671 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002672 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002673 /* Add an address size prefix */
Cyrill Gorcunovd6851d42011-09-25 18:01:45 +04002674 ins->prefixes[PPS_ASIZE] = (addrbits == 32) ? P_A16 : P_A32;;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002675 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002676 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002677 /* Impossible... */
2678 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2679 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002680 }
2681
2682 defdisp = ins->addr_size == 16 ? 16 : 32;
2683
2684 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002685 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2686 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2687 /*
2688 * mem_offs sizes must match the address size; if not,
2689 * strip the MEM_OFFS bit and match only EA instructions
2690 */
2691 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2692 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002693 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002694}