blob: 5a50e1986fd47bb409d213f51d8bbf3a18a9866a [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
Keith Kaniosb7a89542007-04-12 02:40:54 +0000189static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000190static efunc errfunc;
191static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000192static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000193
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700194static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700195static void gencode(int32_t segment, int64_t offset, int bits,
196 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400197 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700198static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400199 insn *instruction,
200 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700201static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700202static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000203static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700204static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000205static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700206static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000207
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700208static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
209
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700210static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000211{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700212 return ins->prefixes[pos] == prefix;
213}
214
215static void assert_no_prefix(insn * ins, enum prefix_pos pos)
216{
217 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400218 errfunc(ERR_NONFATAL, "invalid %s prefix",
219 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700220}
221
222static const char *size_name(int size)
223{
224 switch (size) {
225 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400226 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700227 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400228 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700229 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400230 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700231 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400232 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700233 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400234 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700235 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400236 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700237 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400238 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700239 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400240 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000241 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700242}
243
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400244static void warn_overflow(int pass, int size)
245{
246 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
247 "%s data exceeds bounds", size_name(size));
248}
249
250static void warn_overflow_const(int64_t data, int size)
251{
252 if (overflow_general(data, size))
253 warn_overflow(ERR_PASS1, size);
254}
255
256static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700257{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100258 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400259 if (overflow_general(o->offset, size))
260 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700261 }
262}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400263
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000264/*
265 * This routine wrappers the real output format's output routine,
266 * in order to pass a copy of the data off to the listing file
267 * generator at the same time.
268 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800269static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800270 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400271 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000272{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000273 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000274 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800275 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000276
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800277 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400278 /*
279 * This is a non-relocated address, and we're going to
280 * convert it into RAWDATA format.
281 */
282 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800283
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400284 if (size > 8) {
285 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
286 return;
287 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700288
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400289 WRITEADDR(q, *(int64_t *)data, size);
290 data = p;
291 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000292 }
293
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800294 list->output(offset, data, type, size);
295
Frank Kotlerabebb082003-09-06 04:45:37 +0000296 /*
297 * this call to src_get determines when we call the
298 * debug-format-specific "linenum" function
299 * it updates lineno and lnfname to the current values
300 * returning 0 if "same as last time", -2 if lnfname
301 * changed, and the amount by which lineno changed,
302 * if it did. thus, these variables must be static
303 */
304
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400305 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000306 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000307
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800308 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000309}
310
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700311static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700312 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800314 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000315 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000316
Charles Craynef1aefd82008-09-30 16:11:32 -0700317 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700318 return false;
319 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400320 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700321 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400322 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700323
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100325
Victor van den Elzen154e5922009-02-25 17:32:00 +0100326 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100327 /* Be optimistic in pass 1 */
328 return true;
329
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700331 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000332
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700333 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
334 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000336
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800337int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400338 insn * instruction, struct ofmt *output, efunc error,
339 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000340{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000341 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700343 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800344 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000345 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800346 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300347 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000348
H. Peter Anvine2c80182005-01-15 22:15:51 +0000349 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000350 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000351 outfmt = output; /* likewise */
352 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000353
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300354 wsize = idata_bytes(instruction->opcode);
355 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000357
H. Peter Anvineba20a72002-04-30 20:53:55 +0000358 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000360 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 if (t < 0)
362 errfunc(ERR_PANIC,
363 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000364
H. Peter Anvine2c80182005-01-15 22:15:51 +0000365 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400366 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400368 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700369 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400370 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000371 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700372 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800374 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400375 offset += wsize;
376 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700377 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400378 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000380
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800382 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000383 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000384
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 if (align) {
386 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100387 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800388 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 }
390 offset += e->stringlen + align;
391 }
392 }
393 if (t > 0 && t == instruction->times - 1) {
394 /*
395 * Dummy call to list->output to give the offset to the
396 * listing module.
397 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800398 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 list->uplevel(LIST_TIMES);
400 }
401 }
402 if (instruction->times > 1)
403 list->downlevel(LIST_TIMES);
404 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000405 }
406
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700408 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000410
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400411 fp = fopen(fname, "rb");
412 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
414 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400415 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000416 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
417 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400418 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700419 static char buf[4096];
420 size_t t = instruction->times;
421 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400422 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000423
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 len = ftell(fp);
425 if (instruction->eops->next) {
426 base = instruction->eops->next->offset;
427 len -= base;
428 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700429 len > (size_t)instruction->eops->next->next->offset)
430 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 }
432 /*
433 * Dummy call to list->output to give the offset to the
434 * listing module.
435 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800436 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000437 list->uplevel(LIST_INCBIN);
438 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700439 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000440
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 fseek(fp, base, SEEK_SET);
442 l = len;
443 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700444 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400445 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 if (!m) {
447 /*
448 * This shouldn't happen unless the file
449 * actually changes while we are reading
450 * it.
451 */
452 error(ERR_NONFATAL,
453 "`incbin': unexpected EOF while"
454 " reading file `%s'", fname);
455 t = 0; /* Try to exit cleanly */
456 break;
457 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800458 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000459 NO_SEG, NO_SEG);
460 l -= m;
461 }
462 }
463 list->downlevel(LIST_INCBIN);
464 if (instruction->times > 1) {
465 /*
466 * Dummy call to list->output to give the offset to the
467 * listing module.
468 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800469 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000470 list->uplevel(LIST_TIMES);
471 list->downlevel(LIST_TIMES);
472 }
473 fclose(fp);
474 return instruction->times * len;
475 }
476 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000477 }
478
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700479 /* Check to see if we need an address-size prefix */
480 add_asp(instruction, bits);
481
H. Peter Anvin23595f52009-07-25 17:44:25 -0700482 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700483
H. Peter Anvin23595f52009-07-25 17:44:25 -0700484 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400485 /* Matches! */
486 int64_t insn_size = calcsize(segment, offset, bits,
487 instruction, temp->code);
488 itimes = instruction->times;
489 if (insn_size < 0) /* shouldn't be, on pass two */
490 error(ERR_PANIC, "errors made it through from pass one");
491 else
492 while (itimes--) {
493 for (j = 0; j < MAXPREFIX; j++) {
494 uint8_t c = 0;
495 switch (instruction->prefixes[j]) {
496 case P_WAIT:
497 c = 0x9B;
498 break;
499 case P_LOCK:
500 c = 0xF0;
501 break;
502 case P_REPNE:
503 case P_REPNZ:
504 c = 0xF2;
505 break;
506 case P_REPE:
507 case P_REPZ:
508 case P_REP:
509 c = 0xF3;
510 break;
511 case R_CS:
512 if (bits == 64) {
513 error(ERR_WARNING | ERR_PASS2,
514 "cs segment base generated, but will be ignored in 64-bit mode");
515 }
516 c = 0x2E;
517 break;
518 case R_DS:
519 if (bits == 64) {
520 error(ERR_WARNING | ERR_PASS2,
521 "ds segment base generated, but will be ignored in 64-bit mode");
522 }
523 c = 0x3E;
524 break;
525 case R_ES:
526 if (bits == 64) {
527 error(ERR_WARNING | ERR_PASS2,
528 "es segment base generated, but will be ignored in 64-bit mode");
529 }
530 c = 0x26;
531 break;
532 case R_FS:
533 c = 0x64;
534 break;
535 case R_GS:
536 c = 0x65;
537 break;
538 case R_SS:
539 if (bits == 64) {
540 error(ERR_WARNING | ERR_PASS2,
541 "ss segment base generated, but will be ignored in 64-bit mode");
542 }
543 c = 0x36;
544 break;
545 case R_SEGR6:
546 case R_SEGR7:
547 error(ERR_NONFATAL,
548 "segr6 and segr7 cannot be used as prefixes");
549 break;
550 case P_A16:
551 if (bits == 64) {
552 error(ERR_NONFATAL,
553 "16-bit addressing is not supported "
554 "in 64-bit mode");
555 } else if (bits != 16)
556 c = 0x67;
557 break;
558 case P_A32:
559 if (bits != 32)
560 c = 0x67;
561 break;
562 case P_A64:
563 if (bits != 64) {
564 error(ERR_NONFATAL,
565 "64-bit addressing is only supported "
566 "in 64-bit mode");
567 }
568 break;
569 case P_ASP:
570 c = 0x67;
571 break;
572 case P_O16:
573 if (bits != 16)
574 c = 0x66;
575 break;
576 case P_O32:
577 if (bits == 16)
578 c = 0x66;
579 break;
580 case P_O64:
581 /* REX.W */
582 break;
583 case P_OSP:
584 c = 0x66;
585 break;
586 case P_none:
587 break;
588 default:
589 error(ERR_PANIC, "invalid instruction prefix");
590 }
591 if (c != 0) {
592 out(offset, segment, &c, OUT_RAWDATA, 1,
593 NO_SEG, NO_SEG);
594 offset++;
595 }
596 }
597 insn_end = offset + insn_size;
598 gencode(segment, offset, bits, instruction,
599 temp, insn_end);
600 offset += insn_size;
601 if (itimes > 0 && itimes == instruction->times - 1) {
602 /*
603 * Dummy call to list->output to give the offset to the
604 * listing module.
605 */
606 list->output(offset, NULL, OUT_RAWDATA, 0);
607 list->uplevel(LIST_TIMES);
608 }
609 }
610 if (instruction->times > 1)
611 list->downlevel(LIST_TIMES);
612 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700613 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400614 /* No match */
615 switch (m) {
616 case MERR_OPSIZEMISSING:
617 error(ERR_NONFATAL, "operation size not specified");
618 break;
619 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400621 break;
622 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400624 break;
625 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800626 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400627 bits);
628 break;
629 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000630 error(ERR_NONFATAL,
631 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400632 break;
633 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000634 }
635 return 0;
636}
637
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800638int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400639 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000640{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000641 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700642 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000643
H. Peter Anvine2c80182005-01-15 22:15:51 +0000644 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000645 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400647 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000648 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000649
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700650 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
651 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400652 instruction->opcode == I_DT || instruction->opcode == I_DO ||
653 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000654 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300655 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300658 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400660 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000661 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400664 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000665 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400666 warn_overflow_const(e->offset, wsize);
667 } else if (e->type == EOT_DB_STRING ||
668 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 align = (-osize) % wsize;
672 if (align < 0)
673 align += wsize;
674 isize += osize + align;
675 }
676 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000677 }
678
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400680 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300682 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700683 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000684
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400685 fp = fopen(fname, "rb");
686 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
688 fname);
689 else if (fseek(fp, 0L, SEEK_END) < 0)
690 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
691 fname);
692 else {
693 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000694 if (instruction->eops->next) {
695 len -= instruction->eops->next->offset;
696 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700697 len > (size_t)instruction->eops->next->next->offset) {
698 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000699 }
700 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300701 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300703 if (fp)
704 fclose(fp);
705 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000706 }
707
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700708 /* Check to see if we need an address-size prefix */
709 add_asp(instruction, bits);
710
H. Peter Anvin23595f52009-07-25 17:44:25 -0700711 m = find_match(&temp, instruction, segment, offset, bits);
712 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400713 /* we've matched an instruction. */
714 int64_t isize;
715 const uint8_t *codes = temp->code;
716 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100717
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400718 isize = calcsize(segment, offset, bits, instruction, codes);
719 if (isize < 0)
720 return -1;
721 for (j = 0; j < MAXPREFIX; j++) {
722 switch (instruction->prefixes[j]) {
723 case P_A16:
724 if (bits != 16)
725 isize++;
726 break;
727 case P_A32:
728 if (bits != 32)
729 isize++;
730 break;
731 case P_O16:
732 if (bits != 16)
733 isize++;
734 break;
735 case P_O32:
736 if (bits == 16)
737 isize++;
738 break;
739 case P_A64:
740 case P_O64:
741 case P_none:
742 break;
743 default:
744 isize++;
745 break;
746 }
747 }
748 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700749 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400750 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000751 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000752}
753
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700754static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000755{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700756 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400757 !(o->opflags & OPFLAG_UNKNOWN) &&
758 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000759}
760
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700761/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700762static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700763{
764 int16_t v;
765
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700766 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400767 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700768
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700769 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700770 return v >= -128 && v <= 127;
771}
772
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700773static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774{
775 int32_t v;
776
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700777 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400778 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700779
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700780 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700781 return v >= -128 && v <= 127;
782}
783
H. Peter Anvin507ae032008-10-09 15:37:10 -0700784/* Common construct */
785#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
786
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800787static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400788 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000789{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800790 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000791 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000792 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700793 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700794 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700795 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700796 enum ea_type eat;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000797
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700798 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700799 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700800
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700801 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400802 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700803
H. Peter Anvine2c80182005-01-15 22:15:51 +0000804 (void)segment; /* Don't warn that this parameter is unused */
805 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000806
H. Peter Anvin839eca22007-10-29 23:12:47 -0700807 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400808 c = *codes++;
809 op1 = (c & 3) + ((opex & 1) << 2);
810 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
811 opx = &ins->oprs[op1];
812 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700813
H. Peter Anvin839eca22007-10-29 23:12:47 -0700814 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 case 01:
816 case 02:
817 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400818 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000819 codes += c, length += c;
820 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700821
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400822 case 05:
823 case 06:
824 case 07:
825 opex = c;
826 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700827
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400828 case4(010):
829 ins->rex |=
830 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000831 codes++, length++;
832 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700833
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400834 case4(014):
835 case4(020):
836 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 length++;
838 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700839
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400840 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000841 length += 2;
842 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700843
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400844 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700845 if (opx->type & (BITS16 | BITS32 | BITS64))
846 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 else
848 length += (bits == 16) ? 2 : 4;
849 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700850
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400851 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000852 length += 4;
853 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700854
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400855 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700856 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700858
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400859 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000860 length++;
861 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700862
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400863 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000864 length += 8; /* MOV reg64/imm */
865 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700866
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400867 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 length += 2;
869 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700870
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400871 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700872 if (opx->type & (BITS16 | BITS32 | BITS64))
873 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 else
875 length += (bits == 16) ? 2 : 4;
876 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700877
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400878 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 length += 4;
880 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700881
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400882 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700883 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000884 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700885
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400886 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700887 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700889
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400890 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800891 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000892 length++;
893 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700894
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400895 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700896 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700897 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700898
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400899 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800900 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700901 length++;
902 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700903
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400904 case 0172:
905 case 0173:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400906 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700907 length++;
908 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700909
H. Peter Anvincffe61e2011-07-07 17:21:24 -0700910 case4(0174):
911 length++;
912 break;
913
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400914 case4(0250):
915 length += is_sbyte32(opx) ? 1 : 4;
916 break;
917
918 case4(0254):
919 length += 4;
920 break;
921
922 case4(0260):
923 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700924 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400925 ins->vex_cm = *codes++;
926 ins->vex_wlp = *codes++;
927 break;
928
929 case 0270:
930 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700931 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400932 ins->vex_cm = *codes++;
933 ins->vex_wlp = *codes++;
934 break;
935
936 case4(0274):
937 length++;
938 break;
939
940 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000941 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700942
H. Peter Anvine2c80182005-01-15 22:15:51 +0000943 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400944 if (bits == 64)
945 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700946 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
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 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700950 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000951 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700952
H. Peter Anvine2c80182005-01-15 22:15:51 +0000953 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700954 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700955
Keith Kaniosb7a89542007-04-12 02:40:54 +0000956 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400957 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
958 has_prefix(ins, PPS_ASIZE, P_A32))
959 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400962 case4(0314):
963 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700964
H. Peter Anvine2c80182005-01-15 22:15:51 +0000965 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000966 {
967 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
968 if (pfx == P_O16)
969 break;
970 if (pfx != P_none)
971 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
972 else
973 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000975 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700976
H. Peter Anvine2c80182005-01-15 22:15:51 +0000977 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000978 {
979 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
980 if (pfx == P_O32)
981 break;
982 if (pfx != P_none)
983 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
984 else
985 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000986 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000987 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700988
H. Peter Anvine2c80182005-01-15 22:15:51 +0000989 case 0322:
990 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700991
Keith Kaniosb7a89542007-04-12 02:40:54 +0000992 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000993 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000994 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700995
Keith Kaniosb7a89542007-04-12 02:40:54 +0000996 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400997 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000998 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700999
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001000 case 0325:
1001 ins->rex |= REX_NH;
1002 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001003
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 case 0330:
1005 codes++, length++;
1006 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001007
H. Peter Anvine2c80182005-01-15 22:15:51 +00001008 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001009 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001010
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001011 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001012 case 0333:
1013 length++;
1014 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001015
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001016 case 0334:
1017 ins->rex |= REX_L;
1018 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001019
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001020 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001021 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001022
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001023 case 0336:
1024 if (!ins->prefixes[PPS_LREP])
1025 ins->prefixes[PPS_LREP] = P_REP;
1026 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001027
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001028 case 0337:
1029 if (!ins->prefixes[PPS_LREP])
1030 ins->prefixes[PPS_LREP] = P_REPNE;
1031 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001032
H. Peter Anvine2c80182005-01-15 22:15:51 +00001033 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001034 if (ins->oprs[0].segment != NO_SEG)
1035 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1036 " quantity of BSS space");
1037 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001038 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001039 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001040
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001041 case 0341:
1042 if (!ins->prefixes[PPS_WAIT])
1043 ins->prefixes[PPS_WAIT] = P_WAIT;
1044 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001045
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001046 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001047 length++;
1048 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001049
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001050 case 0360:
1051 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001052
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001053 case 0361:
1054 case 0362:
1055 case 0363:
1056 length++;
1057 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001058
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001059 case 0364:
1060 case 0365:
1061 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001062
Keith Kanios48af1772007-08-17 07:37:52 +00001063 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001064 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001065 length++;
1066 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001067
H. Peter Anvine2c80182005-01-15 22:15:51 +00001068 case 0370:
1069 case 0371:
1070 case 0372:
1071 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001072
H. Peter Anvine2c80182005-01-15 22:15:51 +00001073 case 0373:
1074 length++;
1075 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001076
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001077 case 0374:
1078 eat = EA_XMMVSIB;
1079 break;
1080
1081 case 0375:
1082 eat = EA_YMMVSIB;
1083 break;
1084
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001085 case4(0100):
1086 case4(0110):
1087 case4(0120):
1088 case4(0130):
1089 case4(0200):
1090 case4(0204):
1091 case4(0210):
1092 case4(0214):
1093 case4(0220):
1094 case4(0224):
1095 case4(0230):
1096 case4(0234):
1097 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001098 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001099 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001100 opflags_t rflags;
1101 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001102
Keith Kaniosb7a89542007-04-12 02:40:54 +00001103 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001104
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001105 if (c <= 0177) {
1106 /* pick rfield from operand b (opx) */
1107 rflags = regflag(opx);
1108 rfield = nasm_regvals[opx->basereg];
1109 } else {
1110 rflags = 0;
1111 rfield = c & 7;
1112 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001113 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1114 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001115 errfunc(ERR_NONFATAL, "invalid effective address");
1116 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001117 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001118 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001119 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001120 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001121 }
1122 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001123
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001124 default:
1125 errfunc(ERR_PANIC, "internal instruction table corrupt"
1126 ": instruction code \\%o (0x%02X) given", c, c);
1127 break;
1128 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001129 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001130
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001131 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001132
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001133 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001134 if (ins->rex & REX_H) {
1135 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1136 return -1;
1137 }
1138 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001139 }
1140
H. Peter Anvind85d2502008-05-04 17:53:31 -07001141 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001142 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001143
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001144 if (ins->rex & REX_H) {
1145 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1146 return -1;
1147 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001148 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001149 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001150 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001151 ins->rex &= ~REX_W;
1152 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001153 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001154 ins->rex |= REX_W;
1155 bad32 &= ~REX_W;
1156 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001157 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001158 /* Follow REX_W */
1159 break;
1160 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001161
H. Peter Anvinfc561202011-07-07 16:58:22 -07001162 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001163 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1164 return -1;
1165 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001166 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001167 length += 3;
1168 else
1169 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001170 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001171 if (ins->rex & REX_H) {
1172 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1173 return -1;
1174 } else if (bits == 64) {
1175 length++;
1176 } else if ((ins->rex & REX_L) &&
1177 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1178 cpu >= IF_X86_64) {
1179 /* LOCK-as-REX.R */
1180 assert_no_prefix(ins, PPS_LREP);
1181 length++;
1182 } else {
1183 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1184 return -1;
1185 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001186 }
1187
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001188 return length;
1189}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001190
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001191#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001192 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001193 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1194 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1195 ins->rex = 0; \
1196 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001197 }
1198
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001199static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001200 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001201 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001202{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001203 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001204 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1205 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1206 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001207 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001208 uint8_t c;
1209 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001210 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001211 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001212 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001213 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001214 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001215 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001216 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001217
H. Peter Anvin839eca22007-10-29 23:12:47 -07001218 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001219 c = *codes++;
1220 op1 = (c & 3) + ((opex & 1) << 2);
1221 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1222 opx = &ins->oprs[op1];
1223 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001224
H. Peter Anvin839eca22007-10-29 23:12:47 -07001225 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001226 case 01:
1227 case 02:
1228 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001229 case 04:
1230 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001231 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001232 codes += c;
1233 offset += c;
1234 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001235
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001236 case 05:
1237 case 06:
1238 case 07:
1239 opex = c;
1240 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001241
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001242 case4(010):
1243 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001244 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001245 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001246 offset += 1;
1247 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001248
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001249 case4(014):
1250 /*
1251 * The test for BITS8 and SBYTE here is intended to avoid
1252 * warning on optimizer actions due to SBYTE, while still
1253 * warn on explicit BYTE directives. Also warn, obviously,
1254 * if the optimizer isn't enabled.
1255 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001256 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001257 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1258 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001259 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001260 "signed byte value exceeds bounds");
1261 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001262 if (opx->segment != NO_SEG) {
1263 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001264 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001267 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001268 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 NO_SEG);
1270 }
1271 offset += 1;
1272 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001273
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001274 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001275 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001276 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001277 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001278 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 if (opx->segment != NO_SEG) {
1280 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001281 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001285 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 NO_SEG);
1287 }
1288 offset += 1;
1289 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001290
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001291 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001293 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001294 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001295 if (opx->segment != NO_SEG) {
1296 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001297 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001298 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001301 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001302 NO_SEG);
1303 }
1304 offset += 1;
1305 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001306
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001307 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001308 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001310 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001311 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001312 offset += 2;
1313 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001314
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001315 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001316 if (opx->type & (BITS16 | BITS32))
1317 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 else
1319 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001320 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001322 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001323 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 offset += size;
1325 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001326
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001327 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001328 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001330 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 offset += 4;
1333 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001334
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001335 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001336 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001337 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001338 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 offset += size;
1342 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001343
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001344 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001345 if (opx->segment != segment) {
1346 data = opx->offset;
1347 out(offset, segment, &data,
1348 OUT_REL1ADR, insn_end - offset,
1349 opx->segment, opx->wrt);
1350 } else {
1351 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001352 if (data > 127 || data < -128)
1353 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001354 out(offset, segment, &data,
1355 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1356 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001357 offset += 1;
1358 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001359
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001360 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001362 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001364 offset += 8;
1365 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001366
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001367 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001368 if (opx->segment != segment) {
1369 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001371 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001372 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001374 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001375 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001376 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 }
1378 offset += 2;
1379 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001380
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001381 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001382 if (opx->type & (BITS16 | BITS32 | BITS64))
1383 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001384 else
1385 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001387 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001388 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001389 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1390 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001392 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001394 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001395 }
1396 offset += size;
1397 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001398
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001399 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001400 if (opx->segment != segment) {
1401 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001403 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001404 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001405 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001408 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001409 }
1410 offset += 4;
1411 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001412
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001413 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001414 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001415 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1416 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001417 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001418 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001419 outfmt->segbase(1 + opx->segment),
1420 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001421 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001423
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001424 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001425 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001426 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001427 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001428 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001429 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001430 NO_SEG);
1431 offset++;
1432 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001433 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001435 offset += 2;
1436 }
1437 break;
1438
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001439 case4(0144):
1440 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001441 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001442 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001443 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001444 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001445 offset++;
1446 break;
1447
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001448 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001449 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001450 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001451 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001452 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001453 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001454 NO_SEG);
1455 offset++;
1456 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001457 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001458 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001459 offset += 4;
1460 }
1461 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001462
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001463 case4(0154):
1464 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001465 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001466 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001468 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 offset++;
1470 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001471
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001472 case 0172:
1473 c = *codes++;
1474 opx = &ins->oprs[c >> 3];
1475 bytes[0] = nasm_regvals[opx->basereg] << 4;
1476 opx = &ins->oprs[c & 7];
1477 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1478 errfunc(ERR_NONFATAL,
1479 "non-absolute expression not permitted as argument %d",
1480 c & 7);
1481 } else {
1482 if (opx->offset & ~15) {
1483 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1484 "four-bit argument exceeds bounds");
1485 }
1486 bytes[0] |= opx->offset & 15;
1487 }
1488 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1489 offset++;
1490 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001491
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001492 case 0173:
1493 c = *codes++;
1494 opx = &ins->oprs[c >> 4];
1495 bytes[0] = nasm_regvals[opx->basereg] << 4;
1496 bytes[0] |= c & 15;
1497 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1498 offset++;
1499 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001500
H. Peter Anvincffe61e2011-07-07 17:21:24 -07001501 case4(0174):
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001502 bytes[0] = nasm_regvals[opx->basereg] << 4;
1503 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1504 offset++;
1505 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001506
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001507 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001508 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001509 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1510 (int32_t)data != (int64_t)data) {
1511 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1512 "signed dword immediate exceeds bounds");
1513 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001514 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001515 bytes[0] = data;
1516 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1517 NO_SEG);
1518 offset++;
1519 } else {
1520 out(offset, segment, &data, OUT_ADDRESS, 4,
1521 opx->segment, opx->wrt);
1522 offset += 4;
1523 }
1524 break;
1525
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001526 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001527 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001528 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1529 (int32_t)data != (int64_t)data) {
1530 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1531 "signed dword immediate exceeds bounds");
1532 }
1533 out(offset, segment, &data, OUT_ADDRESS, 4,
1534 opx->segment, opx->wrt);
1535 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001536 break;
1537
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001538 case4(0260):
1539 case 0270:
1540 codes += 2;
1541 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1542 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1543 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1544 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001545 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001546 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1547 offset += 3;
1548 } else {
1549 bytes[0] = 0xc5;
1550 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
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, 2, NO_SEG, NO_SEG);
1553 offset += 2;
1554 }
1555 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001556
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001557 case4(0274):
1558 {
1559 uint64_t uv, um;
1560 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001561
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001562 if (ins->rex & REX_W)
1563 s = 64;
1564 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1565 s = 16;
1566 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1567 s = 32;
1568 else
1569 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001570
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001571 um = (uint64_t)2 << (s-1);
1572 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001573
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001574 if (uv > 127 && uv < (uint64_t)-128 &&
1575 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001576 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001577 "signed byte value exceeds bounds");
1578 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001579 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001580 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001581 out(offset, segment, &data, OUT_ADDRESS, 1,
1582 opx->segment, opx->wrt);
1583 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001584 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001585 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1586 NO_SEG);
1587 }
1588 offset += 1;
1589 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001590 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001591
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001592 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001593 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001594
H. Peter Anvine2c80182005-01-15 22:15:51 +00001595 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001596 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001597 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001598 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001599 offset += 1;
1600 } else
1601 offset += 0;
1602 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001603
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001605 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001606 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001607 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001608 offset += 1;
1609 } else
1610 offset += 0;
1611 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001612
H. Peter Anvine2c80182005-01-15 22:15:51 +00001613 case 0312:
1614 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001615
Keith Kaniosb7a89542007-04-12 02:40:54 +00001616 case 0313:
1617 ins->rex = 0;
1618 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001619
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001620 case4(0314):
1621 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001622
H. Peter Anvine2c80182005-01-15 22:15:51 +00001623 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001624 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001626
H. Peter Anvine2c80182005-01-15 22:15:51 +00001627 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001628 case 0323:
1629 break;
1630
Keith Kaniosb7a89542007-04-12 02:40:54 +00001631 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001632 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001633 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001634
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001635 case 0325:
1636 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001637
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 case 0330:
1639 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001640 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001641 offset += 1;
1642 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001643
H. Peter Anvine2c80182005-01-15 22:15:51 +00001644 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001646
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001647 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001648 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001649 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001650 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001651 offset += 1;
1652 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001653
Keith Kanios48af1772007-08-17 07:37:52 +00001654 case 0334:
1655 if (ins->rex & REX_R) {
1656 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001657 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001658 offset += 1;
1659 }
1660 ins->rex &= ~(REX_L|REX_R);
1661 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001662
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001663 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001664 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001665
H. Peter Anvin962e3052008-08-28 17:47:16 -07001666 case 0336:
1667 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001668 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001669
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 if (ins->oprs[0].segment != NO_SEG)
1672 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1673 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001674 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 if (size > 0)
1676 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001677 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 offset += size;
1679 }
1680 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001681
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001682 case 0341:
1683 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001684
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001685 case 0344:
1686 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001687 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001688 switch (ins->oprs[0].basereg) {
1689 case R_CS:
1690 bytes[0] += 0x0E;
1691 break;
1692 case R_DS:
1693 bytes[0] += 0x1E;
1694 break;
1695 case R_ES:
1696 bytes[0] += 0x06;
1697 break;
1698 case R_SS:
1699 bytes[0] += 0x16;
1700 break;
1701 default:
1702 errfunc(ERR_PANIC,
1703 "bizarre 8086 segment register received");
1704 }
1705 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1706 offset++;
1707 break;
1708
1709 case 0346:
1710 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001711 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001712 switch (ins->oprs[0].basereg) {
1713 case R_FS:
1714 bytes[0] += 0xA0;
1715 break;
1716 case R_GS:
1717 bytes[0] += 0xA8;
1718 break;
1719 default:
1720 errfunc(ERR_PANIC,
1721 "bizarre 386 segment register received");
1722 }
1723 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1724 offset++;
1725 break;
1726
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001727 case 0360:
1728 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001729
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001730 case 0361:
1731 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001732 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1733 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001734 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001735
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001736 case 0362:
1737 case 0363:
1738 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001739 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1740 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001741 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001742
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001743 case 0364:
1744 case 0365:
1745 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001746
Keith Kanios48af1772007-08-17 07:37:52 +00001747 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001748 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001749 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001750 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001751 offset += 1;
1752 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001753
H. Peter Anvine2c80182005-01-15 22:15:51 +00001754 case 0370:
1755 case 0371:
1756 case 0372:
1757 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001758
H. Peter Anvine2c80182005-01-15 22:15:51 +00001759 case 0373:
1760 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001761 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001762 offset += 1;
1763 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001764
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001765 case 0374:
1766 eat = EA_XMMVSIB;
1767 break;
1768
1769 case 0375:
1770 eat = EA_YMMVSIB;
1771 break;
1772
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001773 case4(0100):
1774 case4(0110):
1775 case4(0120):
1776 case4(0130):
1777 case4(0200):
1778 case4(0204):
1779 case4(0210):
1780 case4(0214):
1781 case4(0220):
1782 case4(0224):
1783 case4(0230):
1784 case4(0234):
1785 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001786 ea ea_data;
1787 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001788 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001789 uint8_t *p;
1790 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001791 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001792
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001793 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001794 /* pick rfield from operand b (opx) */
1795 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001796 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001797 } else {
1798 /* rfield is constant */
1799 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001800 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001801 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001802
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001803 if (process_ea(opy, &ea_data, bits, ins->addr_size,
1804 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001805 errfunc(ERR_NONFATAL, "invalid effective address");
1806 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001807
Charles Crayne7e975552007-11-03 22:06:13 -07001808
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 p = bytes;
1810 *p++ = ea_data.modrm;
1811 if (ea_data.sib_present)
1812 *p++ = ea_data.sib;
1813
1814 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001815 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001816
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001817 /*
1818 * Make sure the address gets the right offset in case
1819 * the line breaks in the .lst file (BR 1197827)
1820 */
1821 offset += s;
1822 s = 0;
1823
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 switch (ea_data.bytes) {
1825 case 0:
1826 break;
1827 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001828 case 2:
1829 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001830 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001831 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001832 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001833 if (ea_data.rip) {
1834 if (opy->segment == segment) {
1835 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001836 if (overflow_signed(data, ea_data.bytes))
1837 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001838 out(offset, segment, &data, OUT_ADDRESS,
1839 ea_data.bytes, NO_SEG, NO_SEG);
1840 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001841 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001842 out(offset, segment, &data, OUT_REL4ADR,
1843 insn_end - offset, opy->segment, opy->wrt);
1844 }
1845 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001846 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1847 signed_bits(opy->offset, ins->addr_size) !=
1848 signed_bits(opy->offset, ea_data.bytes * 8))
1849 warn_overflow(ERR_PASS2, ea_data.bytes);
1850
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001851 out(offset, segment, &data, OUT_ADDRESS,
1852 ea_data.bytes, opy->segment, opy->wrt);
1853 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001854 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001855 default:
1856 /* Impossible! */
1857 errfunc(ERR_PANIC,
1858 "Invalid amount of bytes (%d) for offset?!",
1859 ea_data.bytes);
1860 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001861 }
1862 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001863 }
1864 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001865
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001866 default:
1867 errfunc(ERR_PANIC, "internal instruction table corrupt"
1868 ": instruction code \\%o (0x%02X) given", c, c);
1869 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001870 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001871 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001872}
1873
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001874static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001875{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001876 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001877 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001878 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879}
1880
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001881static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001882{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001883 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001884 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001885 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001886}
1887
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001888static int op_rexflags(const operand * o, int mask)
1889{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001890 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001891 int val;
1892
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001893 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001894 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001895
H. Peter Anvina4835d42008-05-20 14:21:29 -07001896 flags = nasm_reg_flags[o->basereg];
1897 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001898
1899 return rexflags(val, flags, mask);
1900}
1901
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001902static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001903{
1904 int rex = 0;
1905
1906 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001907 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001908 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001909 rex |= REX_W;
1910 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1911 rex |= REX_H;
1912 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1913 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001914
1915 return rex & mask;
1916}
1917
H. Peter Anvin23595f52009-07-25 17:44:25 -07001918static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001919 insn *instruction,
1920 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001921{
1922 const struct itemplate *temp;
1923 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001924 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001925 bool opsizemissing = false;
1926 int i;
1927
1928 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001929 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001930
1931 merr = MERR_INVALOP;
1932
1933 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001934 temp->opcode != I_none; temp++) {
1935 m = matches(temp, instruction, bits);
1936 if (m == MOK_JUMP) {
1937 if (jmp_match(segment, offset, bits, instruction, temp->code))
1938 m = MOK_GOOD;
1939 else
1940 m = MERR_INVALOP;
1941 } else if (m == MERR_OPSIZEMISSING &&
1942 (temp->flags & IF_SMASK) != IF_SX) {
1943 /*
1944 * Missing operand size and a candidate for fuzzy matching...
1945 */
1946 for (i = 0; i < temp->operands; i++) {
1947 if ((temp->opd[i] & SAME_AS) == 0)
1948 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1949 }
1950 opsizemissing = true;
1951 }
1952 if (m > merr)
1953 merr = m;
1954 if (merr == MOK_GOOD)
1955 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001956 }
1957
1958 /* No match, but see if we can get a fuzzy operand size match... */
1959 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001960 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001961
1962 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001963 /*
1964 * We ignore extrinsic operand sizes on registers, so we should
1965 * never try to fuzzy-match on them. This also resolves the case
1966 * when we have e.g. "xmmrm128" in two different positions.
1967 */
1968 if (is_class(REGISTER, instruction->oprs[i].type))
1969 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001970
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001971 /* This tests if xsizeflags[i] has more than one bit set */
1972 if ((xsizeflags[i] & (xsizeflags[i]-1)))
1973 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001974
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001975 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001976 }
1977
1978 /* Try matching again... */
1979 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001980 temp->opcode != I_none; temp++) {
1981 m = matches(temp, instruction, bits);
1982 if (m == MOK_JUMP) {
1983 if (jmp_match(segment, offset, bits, instruction, temp->code))
1984 m = MOK_GOOD;
1985 else
1986 m = MERR_INVALOP;
1987 }
1988 if (m > merr)
1989 merr = m;
1990 if (merr == MOK_GOOD)
1991 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001992 }
1993
H. Peter Anvina81655b2009-07-25 18:15:28 -07001994done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07001995 *tempp = temp;
1996 return merr;
1997}
1998
H. Peter Anvin65289e82009-07-25 17:25:11 -07001999static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002000 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002001{
H. Peter Anvin60926242009-07-26 16:25:38 -07002002 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002003 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002004
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002005 /*
2006 * Check the opcode
2007 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002008 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002009 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002010
2011 /*
2012 * Count the operands
2013 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002014 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002015 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002016
2017 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002018 * Is it legal?
2019 */
2020 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2021 return MERR_INVALOP;
2022
2023 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002024 * Check that no spurious colons or TOs are present
2025 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002026 for (i = 0; i < itemp->operands; i++)
2027 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002028 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002029
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002030 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002031 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002032 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002033 switch (itemp->flags & IF_SMASK) {
2034 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002035 asize = BITS8;
2036 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002037 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002038 asize = BITS16;
2039 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002040 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002041 asize = BITS32;
2042 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002043 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002044 asize = BITS64;
2045 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002046 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002047 asize = BITS128;
2048 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002049 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002050 asize = BITS256;
2051 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002052 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002053 switch (bits) {
2054 case 16:
2055 asize = BITS16;
2056 break;
2057 case 32:
2058 asize = BITS32;
2059 break;
2060 case 64:
2061 asize = BITS64;
2062 break;
2063 default:
2064 asize = 0;
2065 break;
2066 }
2067 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002068 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002069 asize = 0;
2070 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002071 }
2072
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002073 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002074 /* S- flags only apply to a specific operand */
2075 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2076 memset(size, 0, sizeof size);
2077 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002078 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002079 /* S- flags apply to all operands */
2080 for (i = 0; i < MAX_OPERANDS; i++)
2081 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002082 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002083
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002084 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002085 * Check that the operand flags all match up,
2086 * it's a bit tricky so lets be verbose:
2087 *
2088 * 1) Find out the size of operand. If instruction
2089 * doesn't have one specified -- we're trying to
2090 * guess it either from template (IF_S* flag) or
2091 * from code bits.
2092 *
2093 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2094 * (ie the same operand as was specified somewhere in template, and
2095 * this referred operand index is being achieved via ~SAME_AS)
2096 * we are to be sure that both registers (in template and instruction)
2097 * do exactly match.
2098 *
2099 * 3) If template operand do not match the instruction OR
2100 * template has an operand size specified AND this size differ
2101 * from which instruction has (perhaps we got it from code bits)
2102 * we are:
2103 * a) Check that only size of instruction and operand is differ
2104 * other characteristics do match
2105 * b) Perhaps it's a register specified in instruction so
2106 * for such a case we just mark that operand as "size
2107 * missing" and this will turn on fuzzy operand size
2108 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002109 */
2110 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002111 opflags_t type = instruction->oprs[i].type;
2112 if (!(type & SIZE_MASK))
2113 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002114
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002115 if (itemp->opd[i] & SAME_AS) {
2116 int j = itemp->opd[i] & ~SAME_AS;
2117 if (type != instruction->oprs[j].type ||
2118 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2119 return MERR_INVALOP;
2120 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002121 ((itemp->opd[i] & SIZE_MASK) &&
2122 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002123 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002124 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002125 } else if (!is_class(REGISTER, type)) {
2126 /*
2127 * Note: we don't honor extrinsic operand sizes for registers,
2128 * so "missing operand size" for a register should be
2129 * considered a wildcard match rather than an error.
2130 */
2131 opsizemissing = true;
2132 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002133 }
2134 }
2135
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002136 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002137 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002138
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002139 /*
2140 * Check operand sizes
2141 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002142 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002143 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002144 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002145 asize = itemp->opd[i] & SIZE_MASK;
2146 if (asize) {
2147 for (i = 0; i < oprs; i++)
2148 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002149 break;
2150 }
2151 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002152 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002153 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002154 }
2155
Keith Kaniosb7a89542007-04-12 02:40:54 +00002156 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002157 if (!(itemp->opd[i] & SIZE_MASK) &&
2158 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002159 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002160 }
2161
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002162 /*
2163 * Check template is okay at the set cpu level
2164 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002165 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002166 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002167
Keith Kaniosb7a89542007-04-12 02:40:54 +00002168 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002169 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002170 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002171 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002172 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002173
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002174 /*
2175 * Check if special handling needed for Jumps
2176 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002177 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002178 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002179
H. Peter Anvin60926242009-07-26 16:25:38 -07002180 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002181}
2182
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002183static enum ea_type process_ea(operand * input, ea * output, int bits,
2184 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002185{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002186 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002187
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002188 output->type = EA_SCALAR;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002189 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002190
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002191 /* REX flags for the rfield operand */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002192 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002193
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002194 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002195 int i;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002196 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002197
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002198 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002199 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002200 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002201 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002202
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002203 if (REG_EA & ~f)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002204 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002205
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002206 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002207
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002208 output->sib_present = false; /* no SIB necessary */
2209 output->bytes = 0; /* no offset necessary either */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002210 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002211 } else { /* it's a memory reference */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002212 if (input->basereg == -1 &&
2213 (input->indexreg == -1 || input->scale == 0)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002214 /* it's a pure offset */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002215
2216 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2217 input->segment == NO_SEG) {
2218 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2219 input->type &= ~IP_REL;
2220 input->type |= MEMORY;
2221 }
2222
2223 if (input->eaflags & EAF_BYTEOFFS ||
2224 (input->eaflags & EAF_WORDOFFS &&
2225 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2226 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2227 }
2228
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002229 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002230 int scale, index, base;
2231 output->sib_present = true;
2232 scale = 0;
2233 index = 4;
2234 base = 5;
2235 output->sib = (scale << 6) | (index << 3) | base;
2236 output->bytes = 4;
2237 output->modrm = 4 | ((rfield & 7) << 3);
2238 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002239 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002240 output->sib_present = false;
2241 output->bytes = (addrbits != 16 ? 4 : 2);
2242 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
2243 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002244 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002245 } else { /* it's an indirection */
2246 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002247 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002248 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002249 int t, it, bt; /* register numbers */
2250 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002251
H. Peter Anvine2c80182005-01-15 22:15:51 +00002252 if (s == 0)
2253 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002254
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002255 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002256 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002257 ix = nasm_reg_flags[i];
2258 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002259 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002260 ix = 0;
2261 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002262
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002263 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002264 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002265 bx = nasm_reg_flags[b];
2266 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002267 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002268 bx = 0;
2269 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002270
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002271 /* if either one are a vector register... */
2272 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
2273 int32_t sok = BITS32 | BITS64;
2274 int32_t o = input->offset;
2275 int mod, scale, index, base;
2276
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002277 /*
2278 * For a vector SIB, one has to be a vector and the other,
2279 * if present, a GPR. The vector must be the index operand.
2280 */
2281 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2282 if (s == 0)
2283 s = 1;
2284 else if (s != 1)
2285 goto err;
2286
2287 t = bt, bt = it, it = t;
2288 x = bx, bx = ix, ix = x;
2289 }
2290
2291 if (bt != -1) {
2292 if (REG_GPR & ~bx)
2293 goto err;
2294 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2295 sok &= bx;
2296 else
2297 goto err;
2298 }
2299
2300 /*
2301 * While we're here, ensure the user didn't specify
2302 * WORD or QWORD
2303 */
2304 if (input->disp_size == 16 || input->disp_size == 64)
2305 goto err;
2306
2307 if (addrbits == 16 ||
2308 (addrbits == 32 && !(sok & BITS32)) ||
2309 (addrbits == 64 && !(sok & BITS64)))
2310 goto err;
2311
2312 output->type = (ix & YMMREG & ~REG_EA)
2313 ? EA_YMMVSIB : EA_XMMVSIB;
2314
2315 output->rex |= rexflags(it, ix, REX_X);
2316 output->rex |= rexflags(bt, bx, REX_B);
2317
2318 index = it & 7; /* it is known to be != -1 */
2319
2320 switch (s) {
2321 case 1:
2322 scale = 0;
2323 break;
2324 case 2:
2325 scale = 1;
2326 break;
2327 case 4:
2328 scale = 2;
2329 break;
2330 case 8:
2331 scale = 3;
2332 break;
2333 default: /* then what the smeg is it? */
2334 goto err; /* panic */
2335 }
2336
2337 if (bt == -1) {
2338 base = 5;
2339 mod = 0;
2340 } else {
2341 base = (bt & 7);
2342 if (base != REG_NUM_EBP && o == 0 &&
2343 seg == NO_SEG && !forw_ref &&
2344 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2345 mod = 0;
2346 else if (input->eaflags & EAF_BYTEOFFS ||
2347 (o >= -128 && o <= 127 &&
2348 seg == NO_SEG && !forw_ref &&
2349 !(input->eaflags & EAF_WORDOFFS)))
2350 mod = 1;
2351 else
2352 mod = 2;
2353 }
2354
2355 output->sib_present = true;
2356 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2357 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
2358 output->sib = (scale << 6) | (index << 3) | base;
2359 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002360 /*
2361 * it must be a 32/64-bit memory reference. Firstly we have
2362 * to check that all registers involved are type E/Rxx.
2363 */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002364 int32_t sok = BITS32 | BITS64;
2365 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002366
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002367 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002368 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2369 sok &= ix;
2370 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002371 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002372 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002373
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002374 if (bt != -1) {
2375 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002376 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002377 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002378 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002379 sok &= bx;
2380 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002381
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002382 /*
2383 * While we're here, ensure the user didn't specify
2384 * WORD or QWORD
2385 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002386 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002387 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002388
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002389 if (addrbits == 16 ||
2390 (addrbits == 32 && !(sok & BITS32)) ||
2391 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002392 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002393
Keith Kaniosb7a89542007-04-12 02:40:54 +00002394 /* now reorganize base/index */
2395 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002396 ((hb == b && ht == EAH_NOTBASE) ||
2397 (hb == i && ht == EAH_MAKEBASE))) {
2398 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002399 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002400 x = bx, bx = ix, ix = x;
2401 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002402 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002403 bt = -1, bx = 0, s++;
2404 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002405 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002406 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002407 }
2408 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2409 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002410 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002411 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2412 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002413 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002414 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002415 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002416 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002417 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002418 x = ix, ix = bx, bx = x;
2419 }
2420 if (it == REG_NUM_ESP ||
2421 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002422 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002423
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002424 output->rex |= rexflags(it, ix, REX_X);
2425 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002426
Keith Kanios48af1772007-08-17 07:37:52 +00002427 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002428 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002429 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002430
Keith Kaniosb7a89542007-04-12 02:40:54 +00002431 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002432 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002433 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002434 } else {
2435 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002436 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002437 seg == NO_SEG && !forw_ref &&
2438 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002439 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002440 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002441 (o >= -128 && o <= 127 &&
2442 seg == NO_SEG && !forw_ref &&
2443 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002444 mod = 1;
2445 else
2446 mod = 2;
2447 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002448
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002449 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002450 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2451 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002452 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002453 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002454 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002455
Keith Kaniosb7a89542007-04-12 02:40:54 +00002456 if (it == -1)
2457 index = 4, s = 1;
2458 else
2459 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002460
H. Peter Anvine2c80182005-01-15 22:15:51 +00002461 switch (s) {
2462 case 1:
2463 scale = 0;
2464 break;
2465 case 2:
2466 scale = 1;
2467 break;
2468 case 4:
2469 scale = 2;
2470 break;
2471 case 8:
2472 scale = 3;
2473 break;
2474 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002475 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002476 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002477
Keith Kaniosb7a89542007-04-12 02:40:54 +00002478 if (bt == -1) {
2479 base = 5;
2480 mod = 0;
2481 } else {
2482 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002483 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002484 seg == NO_SEG && !forw_ref &&
2485 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002486 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002487 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002488 (o >= -128 && o <= 127 &&
2489 seg == NO_SEG && !forw_ref &&
2490 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002491 mod = 1;
2492 else
2493 mod = 2;
2494 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002495
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002496 output->sib_present = true;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002497 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002498 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002499 output->sib = (scale << 6) | (index << 3) | base;
2500 }
2501 } else { /* it's 16-bit */
2502 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002503 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002504
Keith Kaniosb7a89542007-04-12 02:40:54 +00002505 /* check for 64-bit long mode */
2506 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002507 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002508
H. Peter Anvine2c80182005-01-15 22:15:51 +00002509 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002510 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2511 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002512 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002513
Keith Kaniosb7a89542007-04-12 02:40:54 +00002514 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002515 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002516 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002517
H. Peter Anvine2c80182005-01-15 22:15:51 +00002518 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002519 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002520 if (b == -1 && i != -1) {
2521 int tmp = b;
2522 b = i;
2523 i = tmp;
2524 } /* swap */
2525 if ((b == R_SI || b == R_DI) && i != -1) {
2526 int tmp = b;
2527 b = i;
2528 i = tmp;
2529 }
2530 /* have BX/BP as base, SI/DI index */
2531 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002532 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002533 if (i != -1 && b != -1 &&
2534 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002535 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002536 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002537 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002538
H. Peter Anvine2c80182005-01-15 22:15:51 +00002539 rm = -1;
2540 if (i != -1)
2541 switch (i * 256 + b) {
2542 case R_SI * 256 + R_BX:
2543 rm = 0;
2544 break;
2545 case R_DI * 256 + R_BX:
2546 rm = 1;
2547 break;
2548 case R_SI * 256 + R_BP:
2549 rm = 2;
2550 break;
2551 case R_DI * 256 + R_BP:
2552 rm = 3;
2553 break;
2554 } else
2555 switch (b) {
2556 case R_SI:
2557 rm = 4;
2558 break;
2559 case R_DI:
2560 rm = 5;
2561 break;
2562 case R_BP:
2563 rm = 6;
2564 break;
2565 case R_BX:
2566 rm = 7;
2567 break;
2568 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002569 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002570 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002571
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002572 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2573 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002574 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002575 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002576 (o >= -128 && o <= 127 && seg == NO_SEG &&
2577 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002578 mod = 1;
2579 else
2580 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002581
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002582 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002583 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002584 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002585 }
2586 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002587 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002588
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002589 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002590 return output->type;
2591
2592err:
2593 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002594}
2595
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002596static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002597{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002598 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002599 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002600
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002601 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002602
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002603 switch (ins->prefixes[PPS_ASIZE]) {
2604 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002605 valid &= 16;
2606 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002607 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002608 valid &= 32;
2609 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002610 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002611 valid &= 64;
2612 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002613 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002614 valid &= (addrbits == 32) ? 16 : 32;
2615 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002616 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002617 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002618 }
2619
2620 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002621 if (is_class(MEMORY, ins->oprs[j].type)) {
2622 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002623
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002624 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002625 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002626 i = 0;
2627 else
2628 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002629
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002630 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002631 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002632 b = 0;
2633 else
2634 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002635
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002636 if (ins->oprs[j].scale == 0)
2637 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002638
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002639 if (!i && !b) {
2640 int ds = ins->oprs[j].disp_size;
2641 if ((addrbits != 64 && ds > 8) ||
2642 (addrbits == 64 && ds == 16))
2643 valid &= ds;
2644 } else {
2645 if (!(REG16 & ~b))
2646 valid &= 16;
2647 if (!(REG32 & ~b))
2648 valid &= 32;
2649 if (!(REG64 & ~b))
2650 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002651
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002652 if (!(REG16 & ~i))
2653 valid &= 16;
2654 if (!(REG32 & ~i))
2655 valid &= 32;
2656 if (!(REG64 & ~i))
2657 valid &= 64;
2658 }
2659 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002660 }
2661
2662 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002663 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002664 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002665 /* Add an address size prefix */
2666 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2667 ins->prefixes[PPS_ASIZE] = pref;
2668 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002669 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002670 /* Impossible... */
2671 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2672 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002673 }
2674
2675 defdisp = ins->addr_size == 16 ? 16 : 32;
2676
2677 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002678 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2679 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2680 /*
2681 * mem_offs sizes must match the address size; if not,
2682 * strip the MEM_OFFS bit and match only EA instructions
2683 */
2684 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2685 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002686 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002687}