blob: 1a7dc8e085e95d4db338c3e68c84eb055e657be5 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvinfea84d72010-05-06 15:32:20 -07003 * Copyright 1996-2010 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.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070069 * \160..\163 - this instruction uses DREX rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040070 * OC0 field set to 0, and the dest field taken from
H. Peter Anvin401c07e2007-09-17 16:55:04 -070071 * operand 0..3.
72 * \164..\167 - this instruction uses DREX rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040073 * OC0 field set to 1, and the dest field taken from
H. Peter Anvin401c07e2007-09-17 16:55:04 -070074 * operand 0..3.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040075 * \171 - placement of DREX suffix in the absence of an EA
76 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070077 * the 4-bit immediate from operand b in bits 3..0.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040078 * \173\xab - the register number from operand a in bits 7..4, with
79 * the value b in bits 3..0.
80 * \174\a - the register number from operand a in bits 7..4, and
81 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000082 * \2ab - a ModRM, calculated on EA in operand a, with the spare
83 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070084 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
85 * is not equal to the truncated and sign-extended 32-bit
86 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvin588df782008-10-07 10:05:10 -070087 * \254..\257 - a signed 32-bit operand to be extended to 64 bits.
H. Peter Anvina04019c2009-05-03 21:42:34 -070088 * \260..\263 - this instruction uses VEX/XOP rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040089 * V field taken from operand 0..3.
90 * \270 - this instruction uses VEX/XOP rather than REX, with the
91 * V field set to 1111b.
H. Peter Anvind85d2502008-05-04 17:53:31 -070092 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070093 * VEX/XOP prefixes are followed by the sequence:
94 * \tmm\wlp where mm is the M field; and wlp is:
H. Peter Anvin421059c2010-08-16 14:56:33 -070095 * 00 wwl lpp
96 * [l0] ll = 0 for L = 0 (.128, .lz)
97 * [l1] ll = 1 for L = 1 (.256)
98 * [lig] ll = 2 for L don't care (always assembled as 0)
99 *
H. Peter Anvin978c2172010-08-16 13:48:43 -0700100 * [w0] ww = 0 for W = 0
101 * [w1 ] ww = 1 for W = 1
102 * [wig] ww = 2 for W don't care (always assembled as 0)
103 * [ww] ww = 3 for W used as REX.W
H. Peter Anvinbd420c72008-05-22 11:24:35 -0700104 *
H. Peter Anvina04019c2009-05-03 21:42:34 -0700105 * t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
H. Peter Anvind85d2502008-05-04 17:53:31 -0700106 *
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700107 * \274..\277 - a signed byte immediate operand, from operand 0..3,
108 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000109 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
110 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -0700111 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +0000112 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -0800113 * \314 - (disassembler only) invalid with REX.B
114 * \315 - (disassembler only) invalid with REX.X
115 * \316 - (disassembler only) invalid with REX.R
116 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000117 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
118 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
119 * \322 - indicates that this instruction is only valid when the
120 * operand size is the default (instruction to disassembler,
121 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000122 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000123 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400124 * \325 - instruction which always uses spl/bpl/sil/dil
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000125 * \330 - a literal byte follows in the code stream, to be added
126 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000127 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000128 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700129 * \332 - REP prefix (0xF2 byte) used as opcode extension.
130 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700131 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700132 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700133 * \336 - force a REP(E) prefix (0xF2) even if not specified.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400134 * \337 - force a REPNE prefix (0xF3) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700135 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000136 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000137 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400138 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700139 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
140 * (POP is never used for CS) depending on operand 0
141 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
142 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400143 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700144 * \361 - 66 SSE prefix (== \366\331)
145 * \362 - F2 SSE prefix (== \364\332)
146 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000147 * \364 - operand-size prefix (0x66) not permitted
148 * \365 - address-size prefix (0x67) not permitted
149 * \366 - operand-size prefix (0x66) used as opcode extension
150 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000151 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400152 * 370 is used for Jcc, 371 is used for JMP.
153 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
154 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000155 */
156
H. Peter Anvinfe501952007-10-02 21:53:51 -0700157#include "compiler.h"
158
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000159#include <stdio.h>
160#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000161#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000162
163#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000164#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000165#include "assemble.h"
166#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700167#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000168
H. Peter Anvin65289e82009-07-25 17:25:11 -0700169enum match_result {
170 /*
171 * Matching errors. These should be sorted so that more specific
172 * errors come later in the sequence.
173 */
174 MERR_INVALOP,
175 MERR_OPSIZEMISSING,
176 MERR_OPSIZEMISMATCH,
177 MERR_BADCPU,
178 MERR_BADMODE,
179 /*
180 * Matching success; the conditional ones first
181 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400182 MOK_JUMP, /* Matching OK but needs jmp_match() */
183 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700184};
185
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000186typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000187 int sib_present; /* is a SIB byte necessary? */
188 int bytes; /* # of bytes of offset needed */
189 int size; /* lazy - this is sib+bytes+1 */
190 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000191} ea;
192
Keith Kaniosb7a89542007-04-12 02:40:54 +0000193static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000194static efunc errfunc;
195static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000196static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000197
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700198static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700199static void gencode(int32_t segment, int64_t offset, int bits,
200 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400201 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700202static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400203 insn *instruction,
204 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700205static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700206static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000207static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700208static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000209static int op_rexflags(const operand *, int);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700210static ea *process_ea(operand *, ea *, int, int, int, opflags_t);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700211static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000212
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700213static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000214{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700215 return ins->prefixes[pos] == prefix;
216}
217
218static void assert_no_prefix(insn * ins, enum prefix_pos pos)
219{
220 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400221 errfunc(ERR_NONFATAL, "invalid %s prefix",
222 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700223}
224
225static const char *size_name(int size)
226{
227 switch (size) {
228 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400229 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700230 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400231 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700232 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400233 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700234 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400235 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700236 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400237 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700238 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400239 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700240 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400241 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700242 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400243 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000244 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700245}
246
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400247static void warn_overflow(int pass, int size)
248{
249 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
250 "%s data exceeds bounds", size_name(size));
251}
252
253static void warn_overflow_const(int64_t data, int size)
254{
255 if (overflow_general(data, size))
256 warn_overflow(ERR_PASS1, size);
257}
258
259static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700260{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100261 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400262 if (overflow_general(o->offset, size))
263 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700264 }
265}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400266
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000267/*
268 * This routine wrappers the real output format's output routine,
269 * in order to pass a copy of the data off to the listing file
270 * generator at the same time.
271 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800272static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800273 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400274 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000275{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000276 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000277 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800278 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000279
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800280 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400281 /*
282 * This is a non-relocated address, and we're going to
283 * convert it into RAWDATA format.
284 */
285 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800286
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400287 if (size > 8) {
288 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
289 return;
290 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700291
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400292 WRITEADDR(q, *(int64_t *)data, size);
293 data = p;
294 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000295 }
296
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800297 list->output(offset, data, type, size);
298
Frank Kotlerabebb082003-09-06 04:45:37 +0000299 /*
300 * this call to src_get determines when we call the
301 * debug-format-specific "linenum" function
302 * it updates lineno and lnfname to the current values
303 * returning 0 if "same as last time", -2 if lnfname
304 * changed, and the amount by which lineno changed,
305 * if it did. thus, these variables must be static
306 */
307
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400308 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000309 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000310
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800311 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000312}
313
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700314static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700315 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800317 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000318 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000319
Charles Craynef1aefd82008-09-30 16:11:32 -0700320 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700321 return false;
322 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400323 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700324 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400325 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700326
H. Peter Anvine2c80182005-01-15 22:15:51 +0000327 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100328
Victor van den Elzen154e5922009-02-25 17:32:00 +0100329 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100330 /* Be optimistic in pass 1 */
331 return true;
332
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700334 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000335
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700336 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
337 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000339
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800340int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400341 insn * instruction, struct ofmt *output, efunc error,
342 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000343{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000344 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700346 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800347 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000348 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800349 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300350 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000351
H. Peter Anvine2c80182005-01-15 22:15:51 +0000352 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000353 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 outfmt = output; /* likewise */
355 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000356
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300357 wsize = idata_bytes(instruction->opcode);
358 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000360
H. Peter Anvineba20a72002-04-30 20:53:55 +0000361 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000362 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000363 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000364 if (t < 0)
365 errfunc(ERR_PANIC,
366 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000367
H. Peter Anvine2c80182005-01-15 22:15:51 +0000368 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400369 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400371 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700372 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400373 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000374 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700375 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800377 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400378 offset += wsize;
379 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700380 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400381 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000383
H. Peter Anvine2c80182005-01-15 22:15:51 +0000384 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800385 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000386 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000387
H. Peter Anvine2c80182005-01-15 22:15:51 +0000388 if (align) {
389 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100390 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800391 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000392 }
393 offset += e->stringlen + align;
394 }
395 }
396 if (t > 0 && t == instruction->times - 1) {
397 /*
398 * Dummy call to list->output to give the offset to the
399 * listing module.
400 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800401 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000402 list->uplevel(LIST_TIMES);
403 }
404 }
405 if (instruction->times > 1)
406 list->downlevel(LIST_TIMES);
407 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000408 }
409
H. Peter Anvine2c80182005-01-15 22:15:51 +0000410 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700411 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000412 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000413
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400414 fp = fopen(fname, "rb");
415 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000416 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
417 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400418 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000419 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
420 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400421 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700422 static char buf[4096];
423 size_t t = instruction->times;
424 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400425 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000426
H. Peter Anvine2c80182005-01-15 22:15:51 +0000427 len = ftell(fp);
428 if (instruction->eops->next) {
429 base = instruction->eops->next->offset;
430 len -= base;
431 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700432 len > (size_t)instruction->eops->next->next->offset)
433 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000434 }
435 /*
436 * Dummy call to list->output to give the offset to the
437 * listing module.
438 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800439 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000440 list->uplevel(LIST_INCBIN);
441 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700442 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000443
H. Peter Anvine2c80182005-01-15 22:15:51 +0000444 fseek(fp, base, SEEK_SET);
445 l = len;
446 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700447 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400448 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000449 if (!m) {
450 /*
451 * This shouldn't happen unless the file
452 * actually changes while we are reading
453 * it.
454 */
455 error(ERR_NONFATAL,
456 "`incbin': unexpected EOF while"
457 " reading file `%s'", fname);
458 t = 0; /* Try to exit cleanly */
459 break;
460 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800461 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000462 NO_SEG, NO_SEG);
463 l -= m;
464 }
465 }
466 list->downlevel(LIST_INCBIN);
467 if (instruction->times > 1) {
468 /*
469 * Dummy call to list->output to give the offset to the
470 * listing module.
471 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800472 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000473 list->uplevel(LIST_TIMES);
474 list->downlevel(LIST_TIMES);
475 }
476 fclose(fp);
477 return instruction->times * len;
478 }
479 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000480 }
481
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700482 /* Check to see if we need an address-size prefix */
483 add_asp(instruction, bits);
484
H. Peter Anvin23595f52009-07-25 17:44:25 -0700485 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700486
H. Peter Anvin23595f52009-07-25 17:44:25 -0700487 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400488 /* Matches! */
489 int64_t insn_size = calcsize(segment, offset, bits,
490 instruction, temp->code);
491 itimes = instruction->times;
492 if (insn_size < 0) /* shouldn't be, on pass two */
493 error(ERR_PANIC, "errors made it through from pass one");
494 else
495 while (itimes--) {
496 for (j = 0; j < MAXPREFIX; j++) {
497 uint8_t c = 0;
498 switch (instruction->prefixes[j]) {
499 case P_WAIT:
500 c = 0x9B;
501 break;
502 case P_LOCK:
503 c = 0xF0;
504 break;
505 case P_REPNE:
506 case P_REPNZ:
507 c = 0xF2;
508 break;
509 case P_REPE:
510 case P_REPZ:
511 case P_REP:
512 c = 0xF3;
513 break;
514 case R_CS:
515 if (bits == 64) {
516 error(ERR_WARNING | ERR_PASS2,
517 "cs segment base generated, but will be ignored in 64-bit mode");
518 }
519 c = 0x2E;
520 break;
521 case R_DS:
522 if (bits == 64) {
523 error(ERR_WARNING | ERR_PASS2,
524 "ds segment base generated, but will be ignored in 64-bit mode");
525 }
526 c = 0x3E;
527 break;
528 case R_ES:
529 if (bits == 64) {
530 error(ERR_WARNING | ERR_PASS2,
531 "es segment base generated, but will be ignored in 64-bit mode");
532 }
533 c = 0x26;
534 break;
535 case R_FS:
536 c = 0x64;
537 break;
538 case R_GS:
539 c = 0x65;
540 break;
541 case R_SS:
542 if (bits == 64) {
543 error(ERR_WARNING | ERR_PASS2,
544 "ss segment base generated, but will be ignored in 64-bit mode");
545 }
546 c = 0x36;
547 break;
548 case R_SEGR6:
549 case R_SEGR7:
550 error(ERR_NONFATAL,
551 "segr6 and segr7 cannot be used as prefixes");
552 break;
553 case P_A16:
554 if (bits == 64) {
555 error(ERR_NONFATAL,
556 "16-bit addressing is not supported "
557 "in 64-bit mode");
558 } else if (bits != 16)
559 c = 0x67;
560 break;
561 case P_A32:
562 if (bits != 32)
563 c = 0x67;
564 break;
565 case P_A64:
566 if (bits != 64) {
567 error(ERR_NONFATAL,
568 "64-bit addressing is only supported "
569 "in 64-bit mode");
570 }
571 break;
572 case P_ASP:
573 c = 0x67;
574 break;
575 case P_O16:
576 if (bits != 16)
577 c = 0x66;
578 break;
579 case P_O32:
580 if (bits == 16)
581 c = 0x66;
582 break;
583 case P_O64:
584 /* REX.W */
585 break;
586 case P_OSP:
587 c = 0x66;
588 break;
589 case P_none:
590 break;
591 default:
592 error(ERR_PANIC, "invalid instruction prefix");
593 }
594 if (c != 0) {
595 out(offset, segment, &c, OUT_RAWDATA, 1,
596 NO_SEG, NO_SEG);
597 offset++;
598 }
599 }
600 insn_end = offset + insn_size;
601 gencode(segment, offset, bits, instruction,
602 temp, insn_end);
603 offset += insn_size;
604 if (itimes > 0 && itimes == instruction->times - 1) {
605 /*
606 * Dummy call to list->output to give the offset to the
607 * listing module.
608 */
609 list->output(offset, NULL, OUT_RAWDATA, 0);
610 list->uplevel(LIST_TIMES);
611 }
612 }
613 if (instruction->times > 1)
614 list->downlevel(LIST_TIMES);
615 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700616 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400617 /* No match */
618 switch (m) {
619 case MERR_OPSIZEMISSING:
620 error(ERR_NONFATAL, "operation size not specified");
621 break;
622 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400624 break;
625 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000626 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400627 break;
628 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800629 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400630 bits);
631 break;
632 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000633 error(ERR_NONFATAL,
634 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400635 break;
636 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000637 }
638 return 0;
639}
640
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800641int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400642 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000643{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000644 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700645 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
H. Peter Anvine2c80182005-01-15 22:15:51 +0000647 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000648 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000649
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400650 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000651 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000652
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700653 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
654 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400655 instruction->opcode == I_DT || instruction->opcode == I_DO ||
656 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300658 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300661 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400663 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000664 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000665
H. Peter Anvine2c80182005-01-15 22:15:51 +0000666 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400667 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000668 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400669 warn_overflow_const(e->offset, wsize);
670 } else if (e->type == EOT_DB_STRING ||
671 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000673
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 align = (-osize) % wsize;
675 if (align < 0)
676 align += wsize;
677 isize += osize + align;
678 }
679 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000680 }
681
H. Peter Anvine2c80182005-01-15 22:15:51 +0000682 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400683 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000684 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300685 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700686 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000687
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400688 fp = fopen(fname, "rb");
689 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000690 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
691 fname);
692 else if (fseek(fp, 0L, SEEK_END) < 0)
693 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
694 fname);
695 else {
696 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000697 if (instruction->eops->next) {
698 len -= instruction->eops->next->offset;
699 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700700 len > (size_t)instruction->eops->next->next->offset) {
701 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 }
703 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300704 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000705 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300706 if (fp)
707 fclose(fp);
708 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000709 }
710
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700711 /* Check to see if we need an address-size prefix */
712 add_asp(instruction, bits);
713
H. Peter Anvin23595f52009-07-25 17:44:25 -0700714 m = find_match(&temp, instruction, segment, offset, bits);
715 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400716 /* we've matched an instruction. */
717 int64_t isize;
718 const uint8_t *codes = temp->code;
719 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100720
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400721 isize = calcsize(segment, offset, bits, instruction, codes);
722 if (isize < 0)
723 return -1;
724 for (j = 0; j < MAXPREFIX; j++) {
725 switch (instruction->prefixes[j]) {
726 case P_A16:
727 if (bits != 16)
728 isize++;
729 break;
730 case P_A32:
731 if (bits != 32)
732 isize++;
733 break;
734 case P_O16:
735 if (bits != 16)
736 isize++;
737 break;
738 case P_O32:
739 if (bits == 16)
740 isize++;
741 break;
742 case P_A64:
743 case P_O64:
744 case P_none:
745 break;
746 default:
747 isize++;
748 break;
749 }
750 }
751 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700752 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400753 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000754 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000755}
756
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700757static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000758{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700759 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400760 !(o->opflags & OPFLAG_UNKNOWN) &&
761 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000762}
763
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700764/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700765static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700766{
767 int16_t v;
768
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700769 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400770 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700771
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700772 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700773 return v >= -128 && v <= 127;
774}
775
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700776static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700777{
778 int32_t v;
779
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700780 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400781 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700782
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700783 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700784 return v >= -128 && v <= 127;
785}
786
H. Peter Anvin507ae032008-10-09 15:37:10 -0700787/* Common construct */
788#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
789
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800790static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400791 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000792{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800793 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000794 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000795 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700796 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700797 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700798 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000799
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700800 ins->rex = 0; /* Ensure REX is reset */
801
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700802 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400803 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700804
H. Peter Anvine2c80182005-01-15 22:15:51 +0000805 (void)segment; /* Don't warn that this parameter is unused */
806 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000807
H. Peter Anvin839eca22007-10-29 23:12:47 -0700808 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400809 c = *codes++;
810 op1 = (c & 3) + ((opex & 1) << 2);
811 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
812 opx = &ins->oprs[op1];
813 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700814
H. Peter Anvin839eca22007-10-29 23:12:47 -0700815 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000816 case 01:
817 case 02:
818 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400819 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000820 codes += c, length += c;
821 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700822
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400823 case 05:
824 case 06:
825 case 07:
826 opex = c;
827 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700828
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400829 case4(010):
830 ins->rex |=
831 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000832 codes++, length++;
833 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700834
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400835 case4(014):
836 case4(020):
837 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000838 length++;
839 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700840
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400841 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000842 length += 2;
843 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700844
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400845 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700846 if (opx->type & (BITS16 | BITS32 | BITS64))
847 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000848 else
849 length += (bits == 16) ? 2 : 4;
850 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700851
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400852 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000853 length += 4;
854 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700855
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400856 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700857 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000858 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700859
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400860 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 length++;
862 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700863
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400864 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000865 length += 8; /* MOV reg64/imm */
866 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700867
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400868 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000869 length += 2;
870 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700871
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400872 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700873 if (opx->type & (BITS16 | BITS32 | BITS64))
874 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000875 else
876 length += (bits == 16) ? 2 : 4;
877 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700878
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400879 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000880 length += 4;
881 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700882
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400883 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700884 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700886
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400887 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700888 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700890
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400891 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800892 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000893 length++;
894 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700895
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400896 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700897 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700898 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700899
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400900 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800901 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700902 length++;
903 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700904
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400905 case4(0160):
906 length++;
907 ins->rex |= REX_D;
908 ins->drexdst = regval(opx);
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700909 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700910
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400911 case4(0164):
912 length++;
913 ins->rex |= REX_D|REX_OC;
914 ins->drexdst = regval(opx);
915 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700916
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400917 case 0171:
918 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700919
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400920 case 0172:
921 case 0173:
922 case 0174:
923 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700924 length++;
925 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700926
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400927 case4(0250):
928 length += is_sbyte32(opx) ? 1 : 4;
929 break;
930
931 case4(0254):
932 length += 4;
933 break;
934
935 case4(0260):
936 ins->rex |= REX_V;
937 ins->drexdst = regval(opx);
938 ins->vex_cm = *codes++;
939 ins->vex_wlp = *codes++;
940 break;
941
942 case 0270:
943 ins->rex |= REX_V;
944 ins->drexdst = 0;
945 ins->vex_cm = *codes++;
946 ins->vex_wlp = *codes++;
947 break;
948
949 case4(0274):
950 length++;
951 break;
952
953 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000954 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700955
H. Peter Anvine2c80182005-01-15 22:15:51 +0000956 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400957 if (bits == 64)
958 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700959 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
H. Peter Anvine2c80182005-01-15 22:15:51 +0000962 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700963 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000964 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700965
H. Peter Anvine2c80182005-01-15 22:15:51 +0000966 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700967 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700968
Keith Kaniosb7a89542007-04-12 02:40:54 +0000969 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400970 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
971 has_prefix(ins, PPS_ASIZE, P_A32))
972 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000973 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700974
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400975 case4(0314):
976 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700977
H. Peter Anvine2c80182005-01-15 22:15:51 +0000978 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000979 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000980 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700981
H. Peter Anvine2c80182005-01-15 22:15:51 +0000982 case 0321:
983 length += (bits == 16);
984 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700985
H. Peter Anvine2c80182005-01-15 22:15:51 +0000986 case 0322:
987 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700988
Keith Kaniosb7a89542007-04-12 02:40:54 +0000989 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000990 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000991 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700992
Keith Kaniosb7a89542007-04-12 02:40:54 +0000993 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400994 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000995 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700996
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400997 case 0325:
998 ins->rex |= REX_NH;
999 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001000
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 case 0330:
1002 codes++, length++;
1003 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001004
H. Peter Anvine2c80182005-01-15 22:15:51 +00001005 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001006 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001007
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001008 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001009 case 0333:
1010 length++;
1011 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001012
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001013 case 0334:
1014 ins->rex |= REX_L;
1015 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001016
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001017 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001018 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001019
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001020 case 0336:
1021 if (!ins->prefixes[PPS_LREP])
1022 ins->prefixes[PPS_LREP] = P_REP;
1023 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001024
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001025 case 0337:
1026 if (!ins->prefixes[PPS_LREP])
1027 ins->prefixes[PPS_LREP] = P_REPNE;
1028 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001029
H. Peter Anvine2c80182005-01-15 22:15:51 +00001030 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001031 if (ins->oprs[0].segment != NO_SEG)
1032 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1033 " quantity of BSS space");
1034 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001035 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001036 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001037
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001038 case 0341:
1039 if (!ins->prefixes[PPS_WAIT])
1040 ins->prefixes[PPS_WAIT] = P_WAIT;
1041 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001042
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001043 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001044 length++;
1045 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001046
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001047 case 0360:
1048 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001049
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001050 case 0361:
1051 case 0362:
1052 case 0363:
1053 length++;
1054 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001055
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001056 case 0364:
1057 case 0365:
1058 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001059
Keith Kanios48af1772007-08-17 07:37:52 +00001060 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001061 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001062 length++;
1063 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001064
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 case 0370:
1066 case 0371:
1067 case 0372:
1068 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001069
H. Peter Anvine2c80182005-01-15 22:15:51 +00001070 case 0373:
1071 length++;
1072 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001073
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001074 case4(0100):
1075 case4(0110):
1076 case4(0120):
1077 case4(0130):
1078 case4(0200):
1079 case4(0204):
1080 case4(0210):
1081 case4(0214):
1082 case4(0220):
1083 case4(0224):
1084 case4(0230):
1085 case4(0234):
1086 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001087 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001088 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001089 opflags_t rflags;
1090 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001091
Keith Kaniosb7a89542007-04-12 02:40:54 +00001092 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001093
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001094 if (c <= 0177) {
1095 /* pick rfield from operand b (opx) */
1096 rflags = regflag(opx);
1097 rfield = nasm_regvals[opx->basereg];
1098 } else {
1099 rflags = 0;
1100 rfield = c & 7;
1101 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001102 if (!process_ea(opy, &ea_data, bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001103 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001104 errfunc(ERR_NONFATAL, "invalid effective address");
1105 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001106 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001107 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001108 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001109 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001110 }
1111 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001112
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001113 default:
1114 errfunc(ERR_PANIC, "internal instruction table corrupt"
1115 ": instruction code \\%o (0x%02X) given", c, c);
1116 break;
1117 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001118 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001119
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001120 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001121
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001122 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001123 if (ins->rex & REX_H) {
1124 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1125 return -1;
1126 }
1127 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001128 }
1129
H. Peter Anvind85d2502008-05-04 17:53:31 -07001130 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001131 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001132
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001133 if (ins->rex & REX_H) {
1134 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1135 return -1;
1136 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001137 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001138 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001139 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001140 ins->rex &= ~REX_W;
1141 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001142 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001143 ins->rex |= REX_W;
1144 bad32 &= ~REX_W;
1145 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001146 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001147 /* Follow REX_W */
1148 break;
1149 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001150
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001151 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1152 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1153 return -1;
1154 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001155 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001156 length += 3;
1157 else
1158 length += 2;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001159 } else if (ins->rex & REX_D) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001160 if (ins->rex & REX_H) {
1161 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1162 return -1;
1163 }
1164 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
1165 ins->drexdst > 7)) {
1166 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1167 return -1;
1168 }
1169 length++;
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 Anvind85d2502008-05-04 17:53:31 -07001192 if (!(ins->rex & (REX_D|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{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001203 static 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 Anvin70653092007-10-19 14:42:29 -07001216
H. Peter Anvin839eca22007-10-29 23:12:47 -07001217 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001218 c = *codes++;
1219 op1 = (c & 3) + ((opex & 1) << 2);
1220 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1221 opx = &ins->oprs[op1];
1222 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001223
H. Peter Anvin839eca22007-10-29 23:12:47 -07001224 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001225 case 01:
1226 case 02:
1227 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001228 case 04:
1229 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001230 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001231 codes += c;
1232 offset += c;
1233 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001234
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001235 case 05:
1236 case 06:
1237 case 07:
1238 opex = c;
1239 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001240
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001241 case4(010):
1242 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001243 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001244 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 offset += 1;
1246 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001247
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001248 case4(014):
1249 /*
1250 * The test for BITS8 and SBYTE here is intended to avoid
1251 * warning on optimizer actions due to SBYTE, while still
1252 * warn on explicit BYTE directives. Also warn, obviously,
1253 * if the optimizer isn't enabled.
1254 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001255 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001256 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1257 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001258 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001259 "signed byte value exceeds bounds");
1260 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001261 if (opx->segment != NO_SEG) {
1262 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001263 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001264 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001265 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001266 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001267 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001268 NO_SEG);
1269 }
1270 offset += 1;
1271 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001272
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001273 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001274 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001275 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001276 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001277 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 if (opx->segment != NO_SEG) {
1279 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001280 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001282 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001283 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001284 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001285 NO_SEG);
1286 }
1287 offset += 1;
1288 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001289
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001290 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001291 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001292 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001293 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001294 if (opx->segment != NO_SEG) {
1295 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001296 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001298 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001299 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001300 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 NO_SEG);
1302 }
1303 offset += 1;
1304 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001305
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001306 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001307 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001309 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001311 offset += 2;
1312 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001313
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001314 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001315 if (opx->type & (BITS16 | BITS32))
1316 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001317 else
1318 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001319 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001320 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001321 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001323 offset += size;
1324 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001325
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001326 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001327 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001328 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001329 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001331 offset += 4;
1332 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001333
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001334 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001335 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001336 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001337 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001338 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001339 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 offset += size;
1341 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001342
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001343 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001344 if (opx->segment != segment) {
1345 data = opx->offset;
1346 out(offset, segment, &data,
1347 OUT_REL1ADR, insn_end - offset,
1348 opx->segment, opx->wrt);
1349 } else {
1350 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001351 if (data > 127 || data < -128)
1352 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001353 out(offset, segment, &data,
1354 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1355 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001356 offset += 1;
1357 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001358
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001359 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001360 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001361 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001362 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001363 offset += 8;
1364 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001365
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001366 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 if (opx->segment != segment) {
1368 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001369 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001370 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001373 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001375 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001376 }
1377 offset += 2;
1378 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001379
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001380 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 if (opx->type & (BITS16 | BITS32 | BITS64))
1382 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001383 else
1384 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001385 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001387 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001388 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1389 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001392 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001393 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001394 }
1395 offset += size;
1396 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001397
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001398 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001399 if (opx->segment != segment) {
1400 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001401 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001402 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001403 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001405 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001406 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001407 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001408 }
1409 offset += 4;
1410 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001411
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001412 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001413 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001414 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1415 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001416 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001417 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 outfmt->segbase(1 + opx->segment),
1419 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001420 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001422
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001423 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001424 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001425 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001426 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001427 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001428 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001429 NO_SEG);
1430 offset++;
1431 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001432 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001433 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001434 offset += 2;
1435 }
1436 break;
1437
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001438 case4(0144):
1439 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001440 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001441 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001442 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001443 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001444 offset++;
1445 break;
1446
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001447 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001448 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001449 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001450 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001452 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001453 NO_SEG);
1454 offset++;
1455 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001456 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001457 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001458 offset += 4;
1459 }
1460 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001461
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001462 case4(0154):
1463 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001465 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001466 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001467 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 offset++;
1469 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001470
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001471 case4(0160):
1472 case4(0164):
1473 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001474
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001475 case 0171:
1476 bytes[0] =
1477 (ins->drexdst << 4) |
1478 (ins->rex & REX_OC ? 0x08 : 0) |
1479 (ins->rex & (REX_R|REX_X|REX_B));
1480 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001481 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001482 offset++;
1483 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001484
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001485 case 0172:
1486 c = *codes++;
1487 opx = &ins->oprs[c >> 3];
1488 bytes[0] = nasm_regvals[opx->basereg] << 4;
1489 opx = &ins->oprs[c & 7];
1490 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1491 errfunc(ERR_NONFATAL,
1492 "non-absolute expression not permitted as argument %d",
1493 c & 7);
1494 } else {
1495 if (opx->offset & ~15) {
1496 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1497 "four-bit argument exceeds bounds");
1498 }
1499 bytes[0] |= opx->offset & 15;
1500 }
1501 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1502 offset++;
1503 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001504
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001505 case 0173:
1506 c = *codes++;
1507 opx = &ins->oprs[c >> 4];
1508 bytes[0] = nasm_regvals[opx->basereg] << 4;
1509 bytes[0] |= c & 15;
1510 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1511 offset++;
1512 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001513
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001514 case 0174:
1515 c = *codes++;
1516 opx = &ins->oprs[c];
1517 bytes[0] = nasm_regvals[opx->basereg] << 4;
1518 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1519 offset++;
1520 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001521
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001522 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001523 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001524 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1525 (int32_t)data != (int64_t)data) {
1526 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1527 "signed dword immediate exceeds bounds");
1528 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001529 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001530 bytes[0] = data;
1531 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1532 NO_SEG);
1533 offset++;
1534 } else {
1535 out(offset, segment, &data, OUT_ADDRESS, 4,
1536 opx->segment, opx->wrt);
1537 offset += 4;
1538 }
1539 break;
1540
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001541 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001542 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001543 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1544 (int32_t)data != (int64_t)data) {
1545 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1546 "signed dword immediate exceeds bounds");
1547 }
1548 out(offset, segment, &data, OUT_ADDRESS, 4,
1549 opx->segment, opx->wrt);
1550 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001551 break;
1552
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001553 case4(0260):
1554 case 0270:
1555 codes += 2;
1556 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1557 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1558 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1559 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
1560 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
1561 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1562 offset += 3;
1563 } else {
1564 bytes[0] = 0xc5;
1565 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1566 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
1567 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1568 offset += 2;
1569 }
1570 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001571
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001572 case4(0274):
1573 {
1574 uint64_t uv, um;
1575 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001576
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001577 if (ins->rex & REX_W)
1578 s = 64;
1579 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1580 s = 16;
1581 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1582 s = 32;
1583 else
1584 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001585
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001586 um = (uint64_t)2 << (s-1);
1587 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001588
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001589 if (uv > 127 && uv < (uint64_t)-128 &&
1590 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001591 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001592 "signed byte value exceeds bounds");
1593 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001594 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001595 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001596 out(offset, segment, &data, OUT_ADDRESS, 1,
1597 opx->segment, opx->wrt);
1598 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001599 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001600 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1601 NO_SEG);
1602 }
1603 offset += 1;
1604 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001605 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001606
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001607 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001608 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001609
H. Peter Anvine2c80182005-01-15 22:15:51 +00001610 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001611 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001612 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001613 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001614 offset += 1;
1615 } else
1616 offset += 0;
1617 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001618
H. Peter Anvine2c80182005-01-15 22:15:51 +00001619 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001620 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001621 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001622 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001623 offset += 1;
1624 } else
1625 offset += 0;
1626 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001627
H. Peter Anvine2c80182005-01-15 22:15:51 +00001628 case 0312:
1629 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001630
Keith Kaniosb7a89542007-04-12 02:40:54 +00001631 case 0313:
1632 ins->rex = 0;
1633 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001634
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001635 case4(0314):
1636 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001637
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 case 0320:
Victor van den Elzenb3cee5a2010-11-07 19:56:14 +01001639 {
1640 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1641 if (pfx != P_O16 && pfx != P_none)
1642 nasm_error(ERR_WARNING, "Invalid operand size prefix");
1643 if (pfx != P_O16 && bits != 16) {
1644 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001646 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 offset += 1;
Victor van den Elzenb3cee5a2010-11-07 19:56:14 +01001648 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001649 break;
Victor van den Elzenb3cee5a2010-11-07 19:56:14 +01001650 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001651
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 case 0321:
Victor van den Elzenb3cee5a2010-11-07 19:56:14 +01001653 {
1654 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
1655 if (pfx != P_O32 && pfx != P_none)
1656 nasm_error(ERR_WARNING, "Invalid operand size prefix");
1657 if (pfx != P_O32 && bits == 16) {
1658 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001659 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001660 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001661 offset += 1;
Victor van den Elzenb3cee5a2010-11-07 19:56:14 +01001662 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001663 break;
Victor van den Elzenb3cee5a2010-11-07 19:56:14 +01001664 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001665
H. Peter Anvine2c80182005-01-15 22:15:51 +00001666 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001667 case 0323:
1668 break;
1669
Keith Kaniosb7a89542007-04-12 02:40:54 +00001670 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001671 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001672 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001673
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001674 case 0325:
1675 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001676
H. Peter Anvine2c80182005-01-15 22:15:51 +00001677 case 0330:
1678 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001679 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 offset += 1;
1681 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001682
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001685
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001686 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001688 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001689 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001690 offset += 1;
1691 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001692
Keith Kanios48af1772007-08-17 07:37:52 +00001693 case 0334:
1694 if (ins->rex & REX_R) {
1695 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001696 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001697 offset += 1;
1698 }
1699 ins->rex &= ~(REX_L|REX_R);
1700 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001701
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001702 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001703 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001704
H. Peter Anvin962e3052008-08-28 17:47:16 -07001705 case 0336:
1706 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001707 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001708
H. Peter Anvine2c80182005-01-15 22:15:51 +00001709 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001710 if (ins->oprs[0].segment != NO_SEG)
1711 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1712 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001713 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001714 if (size > 0)
1715 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001716 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001717 offset += size;
1718 }
1719 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001720
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001721 case 0341:
1722 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001723
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001724 case 0344:
1725 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001726 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001727 switch (ins->oprs[0].basereg) {
1728 case R_CS:
1729 bytes[0] += 0x0E;
1730 break;
1731 case R_DS:
1732 bytes[0] += 0x1E;
1733 break;
1734 case R_ES:
1735 bytes[0] += 0x06;
1736 break;
1737 case R_SS:
1738 bytes[0] += 0x16;
1739 break;
1740 default:
1741 errfunc(ERR_PANIC,
1742 "bizarre 8086 segment register received");
1743 }
1744 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1745 offset++;
1746 break;
1747
1748 case 0346:
1749 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001750 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001751 switch (ins->oprs[0].basereg) {
1752 case R_FS:
1753 bytes[0] += 0xA0;
1754 break;
1755 case R_GS:
1756 bytes[0] += 0xA8;
1757 break;
1758 default:
1759 errfunc(ERR_PANIC,
1760 "bizarre 386 segment register received");
1761 }
1762 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1763 offset++;
1764 break;
1765
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001766 case 0360:
1767 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001768
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001769 case 0361:
1770 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001771 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1772 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001773 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001774
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001775 case 0362:
1776 case 0363:
1777 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001778 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1779 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001780 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001781
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001782 case 0364:
1783 case 0365:
1784 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001785
Keith Kanios48af1772007-08-17 07:37:52 +00001786 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001787 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001788 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001789 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001790 offset += 1;
1791 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001792
H. Peter Anvine2c80182005-01-15 22:15:51 +00001793 case 0370:
1794 case 0371:
1795 case 0372:
1796 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001797
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798 case 0373:
1799 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001800 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 offset += 1;
1802 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001803
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001804 case4(0100):
1805 case4(0110):
1806 case4(0120):
1807 case4(0130):
1808 case4(0200):
1809 case4(0204):
1810 case4(0210):
1811 case4(0214):
1812 case4(0220):
1813 case4(0224):
1814 case4(0230):
1815 case4(0234):
1816 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001817 ea ea_data;
1818 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001819 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001820 uint8_t *p;
1821 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001822 enum out_type type;
1823 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001824
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001825 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001826 /* pick rfield from operand b (opx) */
1827 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001828 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001829 } else {
1830 /* rfield is constant */
1831 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001832 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001833 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001835 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001836 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001837 errfunc(ERR_NONFATAL, "invalid effective address");
1838 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001839
Charles Crayne7e975552007-11-03 22:06:13 -07001840
H. Peter Anvine2c80182005-01-15 22:15:51 +00001841 p = bytes;
1842 *p++ = ea_data.modrm;
1843 if (ea_data.sib_present)
1844 *p++ = ea_data.sib;
1845
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001846 /* DREX suffixes come between the SIB and the displacement */
1847 if (ins->rex & REX_D) {
1848 *p++ = (ins->drexdst << 4) |
1849 (ins->rex & REX_OC ? 0x08 : 0) |
1850 (ins->rex & (REX_R|REX_X|REX_B));
1851 ins->rex = 0;
1852 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001853
H. Peter Anvine2c80182005-01-15 22:15:51 +00001854 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001855 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001856
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001857 /*
1858 * Make sure the address gets the right offset in case
1859 * the line breaks in the .lst file (BR 1197827)
1860 */
1861 offset += s;
1862 s = 0;
1863
H. Peter Anvine2c80182005-01-15 22:15:51 +00001864 switch (ea_data.bytes) {
1865 case 0:
1866 break;
1867 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001868 case 2:
1869 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001870 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001871 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001872 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001873 if (ea_data.rip) {
1874 if (opy->segment == segment) {
1875 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001876 if (overflow_signed(data, ea_data.bytes))
1877 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001878 out(offset, segment, &data, OUT_ADDRESS,
1879 ea_data.bytes, NO_SEG, NO_SEG);
1880 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001881 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001882 out(offset, segment, &data, OUT_REL4ADR,
1883 insn_end - offset, opy->segment, opy->wrt);
1884 }
1885 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001886 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1887 signed_bits(opy->offset, ins->addr_size) !=
1888 signed_bits(opy->offset, ea_data.bytes * 8))
1889 warn_overflow(ERR_PASS2, ea_data.bytes);
1890
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001891 type = OUT_ADDRESS;
1892 out(offset, segment, &data, OUT_ADDRESS,
1893 ea_data.bytes, opy->segment, opy->wrt);
1894 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001895 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001896 default:
1897 /* Impossible! */
1898 errfunc(ERR_PANIC,
1899 "Invalid amount of bytes (%d) for offset?!",
1900 ea_data.bytes);
1901 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001902 }
1903 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001904 }
1905 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001906
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001907 default:
1908 errfunc(ERR_PANIC, "internal instruction table corrupt"
1909 ": instruction code \\%o (0x%02X) given", c, c);
1910 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001911 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001912 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001913}
1914
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001915static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001916{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001917 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001918 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001919 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001920}
1921
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001922static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001923{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001924 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001925 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001926 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001927}
1928
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001929static int op_rexflags(const operand * o, int mask)
1930{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001931 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001932 int val;
1933
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001934 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001935 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001936
H. Peter Anvina4835d42008-05-20 14:21:29 -07001937 flags = nasm_reg_flags[o->basereg];
1938 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001939
1940 return rexflags(val, flags, mask);
1941}
1942
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001943static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001944{
1945 int rex = 0;
1946
1947 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001948 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001949 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001950 rex |= REX_W;
1951 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1952 rex |= REX_H;
1953 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1954 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001955
1956 return rex & mask;
1957}
1958
H. Peter Anvin23595f52009-07-25 17:44:25 -07001959static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001960 insn *instruction,
1961 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001962{
1963 const struct itemplate *temp;
1964 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001965 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001966 bool opsizemissing = false;
1967 int i;
1968
1969 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001970 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001971
1972 merr = MERR_INVALOP;
1973
1974 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001975 temp->opcode != I_none; temp++) {
1976 m = matches(temp, instruction, bits);
1977 if (m == MOK_JUMP) {
1978 if (jmp_match(segment, offset, bits, instruction, temp->code))
1979 m = MOK_GOOD;
1980 else
1981 m = MERR_INVALOP;
1982 } else if (m == MERR_OPSIZEMISSING &&
1983 (temp->flags & IF_SMASK) != IF_SX) {
1984 /*
1985 * Missing operand size and a candidate for fuzzy matching...
1986 */
1987 for (i = 0; i < temp->operands; i++) {
1988 if ((temp->opd[i] & SAME_AS) == 0)
1989 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1990 }
1991 opsizemissing = true;
1992 }
1993 if (m > merr)
1994 merr = m;
1995 if (merr == MOK_GOOD)
1996 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001997 }
1998
1999 /* No match, but see if we can get a fuzzy operand size match... */
2000 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002001 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07002002
2003 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002004 /*
2005 * We ignore extrinsic operand sizes on registers, so we should
2006 * never try to fuzzy-match on them. This also resolves the case
2007 * when we have e.g. "xmmrm128" in two different positions.
2008 */
2009 if (is_class(REGISTER, instruction->oprs[i].type))
2010 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002011
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002012 /* This tests if xsizeflags[i] has more than one bit set */
2013 if ((xsizeflags[i] & (xsizeflags[i]-1)))
2014 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002015
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002016 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07002017 }
2018
2019 /* Try matching again... */
2020 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002021 temp->opcode != I_none; temp++) {
2022 m = matches(temp, instruction, bits);
2023 if (m == MOK_JUMP) {
2024 if (jmp_match(segment, offset, bits, instruction, temp->code))
2025 m = MOK_GOOD;
2026 else
2027 m = MERR_INVALOP;
2028 }
2029 if (m > merr)
2030 merr = m;
2031 if (merr == MOK_GOOD)
2032 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07002033 }
2034
H. Peter Anvina81655b2009-07-25 18:15:28 -07002035done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07002036 *tempp = temp;
2037 return merr;
2038}
2039
H. Peter Anvin65289e82009-07-25 17:25:11 -07002040static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002041 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002042{
H. Peter Anvin60926242009-07-26 16:25:38 -07002043 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002044 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002045
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002046 /*
2047 * Check the opcode
2048 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002049 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002050 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002051
2052 /*
2053 * Count the operands
2054 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002055 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002056 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002057
2058 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002059 * Is it legal?
2060 */
2061 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2062 return MERR_INVALOP;
2063
2064 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002065 * Check that no spurious colons or TOs are present
2066 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002067 for (i = 0; i < itemp->operands; i++)
2068 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002069 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002070
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002071 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002072 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002073 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002074 switch (itemp->flags & IF_SMASK) {
2075 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002076 asize = BITS8;
2077 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002078 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002079 asize = BITS16;
2080 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002081 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002082 asize = BITS32;
2083 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002084 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002085 asize = BITS64;
2086 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002087 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002088 asize = BITS128;
2089 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002090 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002091 asize = BITS256;
2092 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002093 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002094 switch (bits) {
2095 case 16:
2096 asize = BITS16;
2097 break;
2098 case 32:
2099 asize = BITS32;
2100 break;
2101 case 64:
2102 asize = BITS64;
2103 break;
2104 default:
2105 asize = 0;
2106 break;
2107 }
2108 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002109 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002110 asize = 0;
2111 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002112 }
2113
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002114 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002115 /* S- flags only apply to a specific operand */
2116 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2117 memset(size, 0, sizeof size);
2118 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002119 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002120 /* S- flags apply to all operands */
2121 for (i = 0; i < MAX_OPERANDS; i++)
2122 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002123 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002124
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002125 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002126 * Check that the operand flags all match up,
2127 * it's a bit tricky so lets be verbose:
2128 *
2129 * 1) Find out the size of operand. If instruction
2130 * doesn't have one specified -- we're trying to
2131 * guess it either from template (IF_S* flag) or
2132 * from code bits.
2133 *
2134 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2135 * (ie the same operand as was specified somewhere in template, and
2136 * this referred operand index is being achieved via ~SAME_AS)
2137 * we are to be sure that both registers (in template and instruction)
2138 * do exactly match.
2139 *
2140 * 3) If template operand do not match the instruction OR
2141 * template has an operand size specified AND this size differ
2142 * from which instruction has (perhaps we got it from code bits)
2143 * we are:
2144 * a) Check that only size of instruction and operand is differ
2145 * other characteristics do match
2146 * b) Perhaps it's a register specified in instruction so
2147 * for such a case we just mark that operand as "size
2148 * missing" and this will turn on fuzzy operand size
2149 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002150 */
2151 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002152 opflags_t type = instruction->oprs[i].type;
2153 if (!(type & SIZE_MASK))
2154 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002155
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002156 if (itemp->opd[i] & SAME_AS) {
2157 int j = itemp->opd[i] & ~SAME_AS;
2158 if (type != instruction->oprs[j].type ||
2159 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2160 return MERR_INVALOP;
2161 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002162 ((itemp->opd[i] & SIZE_MASK) &&
2163 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002164 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002165 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002166 } else if (!is_class(REGISTER, type)) {
2167 /*
2168 * Note: we don't honor extrinsic operand sizes for registers,
2169 * so "missing operand size" for a register should be
2170 * considered a wildcard match rather than an error.
2171 */
2172 opsizemissing = true;
2173 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002174 }
2175 }
2176
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002177 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002178 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002179
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002180 /*
2181 * Check operand sizes
2182 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002183 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002184 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002185 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002186 asize = itemp->opd[i] & SIZE_MASK;
2187 if (asize) {
2188 for (i = 0; i < oprs; i++)
2189 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002190 break;
2191 }
2192 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002193 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002194 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002195 }
2196
Keith Kaniosb7a89542007-04-12 02:40:54 +00002197 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002198 if (!(itemp->opd[i] & SIZE_MASK) &&
2199 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002200 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002201 }
2202
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002203 /*
2204 * Check template is okay at the set cpu level
2205 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002206 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002207 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002208
Keith Kaniosb7a89542007-04-12 02:40:54 +00002209 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002210 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002211 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002212 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002213 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002214
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002215 /*
2216 * Check if special handling needed for Jumps
2217 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002218 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002219 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002220
H. Peter Anvin60926242009-07-26 16:25:38 -07002221 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002222}
2223
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002224static ea *process_ea(operand * input, ea * output, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002225 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002226{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002227 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002228
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002229 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002230
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002231 /* REX flags for the rfield operand */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002232 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002233
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002234 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002235 int i;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002236 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002237
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002238 if (!is_register(input->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002239 return NULL;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002240 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002241 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002242
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002243 if (REG_EA & ~f)
2244 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002245
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002246 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002247
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002248 output->sib_present = false; /* no SIB necessary */
2249 output->bytes = 0; /* no offset necessary either */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002250 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002251 } else { /* it's a memory reference */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002252 if (input->basereg == -1 &&
2253 (input->indexreg == -1 || input->scale == 0)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002254 /* it's a pure offset */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002255
2256 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2257 input->segment == NO_SEG) {
2258 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2259 input->type &= ~IP_REL;
2260 input->type |= MEMORY;
2261 }
2262
2263 if (input->eaflags & EAF_BYTEOFFS ||
2264 (input->eaflags & EAF_WORDOFFS &&
2265 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2266 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2267 }
2268
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002269 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002270 int scale, index, base;
2271 output->sib_present = true;
2272 scale = 0;
2273 index = 4;
2274 base = 5;
2275 output->sib = (scale << 6) | (index << 3) | base;
2276 output->bytes = 4;
2277 output->modrm = 4 | ((rfield & 7) << 3);
2278 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002279 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002280 output->sib_present = false;
2281 output->bytes = (addrbits != 16 ? 4 : 2);
2282 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
2283 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002284 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002285 } else { /* it's an indirection */
2286 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002287 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002288 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002289 int t, it, bt; /* register numbers */
2290 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002291
H. Peter Anvine2c80182005-01-15 22:15:51 +00002292 if (s == 0)
2293 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002294
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002295 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002296 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002297 ix = nasm_reg_flags[i];
2298 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002299 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002300 ix = 0;
2301 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002302
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002303 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002304 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002305 bx = nasm_reg_flags[b];
2306 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002307 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002308 bx = 0;
2309 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002310
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002311 /* check for a 32/64-bit memory reference... */
2312 if ((ix|bx) & (BITS32|BITS64)) {
2313 /*
2314 * it must be a 32/64-bit memory reference. Firstly we have
2315 * to check that all registers involved are type E/Rxx.
2316 */
2317 int32_t sok = BITS32 | BITS64, o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002318
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002319 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002320 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2321 sok &= ix;
2322 else
2323 return NULL;
2324 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002325
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002326 if (bt != -1) {
2327 if (REG_GPR & ~bx)
2328 return NULL; /* Invalid register */
2329 if (~sok & bx & SIZE_MASK)
2330 return NULL; /* Invalid size */
2331 sok &= bx;
2332 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002333
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002334 /*
2335 * While we're here, ensure the user didn't specify
2336 * WORD or QWORD
2337 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002338 if (input->disp_size == 16 || input->disp_size == 64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002339 return NULL;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002340
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002341 if (addrbits == 16 ||
2342 (addrbits == 32 && !(sok & BITS32)) ||
2343 (addrbits == 64 && !(sok & BITS64)))
2344 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002345
Keith Kaniosb7a89542007-04-12 02:40:54 +00002346 /* now reorganize base/index */
2347 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002348 ((hb == b && ht == EAH_NOTBASE) ||
2349 (hb == i && ht == EAH_MAKEBASE))) {
2350 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002351 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002352 x = bx, bx = ix, ix = x;
2353 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002354 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002355 bt = -1, bx = 0, s++;
2356 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002357 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002358 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002359 }
2360 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2361 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002362 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002363 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2364 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002365 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002366 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002367 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002368 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002369 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002370 x = ix, ix = bx, bx = x;
2371 }
2372 if (it == REG_NUM_ESP ||
2373 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002374 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002375
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002376 output->rex |= rexflags(it, ix, REX_X);
2377 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002378
Keith Kanios48af1772007-08-17 07:37:52 +00002379 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002380 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002381 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002382
Keith Kaniosb7a89542007-04-12 02:40:54 +00002383 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002384 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002385 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002386 } else {
2387 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002388 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002389 seg == NO_SEG && !forw_ref &&
2390 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002391 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002392 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002393 (o >= -128 && o <= 127 &&
2394 seg == NO_SEG && !forw_ref &&
2395 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002396 mod = 1;
2397 else
2398 mod = 2;
2399 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002400
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002401 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002402 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2403 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002404 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002405 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002406 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002407
Keith Kaniosb7a89542007-04-12 02:40:54 +00002408 if (it == -1)
2409 index = 4, s = 1;
2410 else
2411 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002412
H. Peter Anvine2c80182005-01-15 22:15:51 +00002413 switch (s) {
2414 case 1:
2415 scale = 0;
2416 break;
2417 case 2:
2418 scale = 1;
2419 break;
2420 case 4:
2421 scale = 2;
2422 break;
2423 case 8:
2424 scale = 3;
2425 break;
2426 default: /* then what the smeg is it? */
2427 return NULL; /* panic */
2428 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002429
Keith Kaniosb7a89542007-04-12 02:40:54 +00002430 if (bt == -1) {
2431 base = 5;
2432 mod = 0;
2433 } else {
2434 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002435 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002436 seg == NO_SEG && !forw_ref &&
2437 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002438 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002439 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002440 (o >= -128 && o <= 127 &&
2441 seg == NO_SEG && !forw_ref &&
2442 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002443 mod = 1;
2444 else
2445 mod = 2;
2446 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002447
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002448 output->sib_present = true;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002449 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002450 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002451 output->sib = (scale << 6) | (index << 3) | base;
2452 }
2453 } else { /* it's 16-bit */
2454 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002455 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002456
Keith Kaniosb7a89542007-04-12 02:40:54 +00002457 /* check for 64-bit long mode */
2458 if (addrbits == 64)
2459 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002460
H. Peter Anvine2c80182005-01-15 22:15:51 +00002461 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002462 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2463 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002464 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002465
Keith Kaniosb7a89542007-04-12 02:40:54 +00002466 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002467 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002468 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002469
H. Peter Anvine2c80182005-01-15 22:15:51 +00002470 if (s != 1 && i != -1)
2471 return NULL; /* no can do, in 16-bit EA */
2472 if (b == -1 && i != -1) {
2473 int tmp = b;
2474 b = i;
2475 i = tmp;
2476 } /* swap */
2477 if ((b == R_SI || b == R_DI) && i != -1) {
2478 int tmp = b;
2479 b = i;
2480 i = tmp;
2481 }
2482 /* have BX/BP as base, SI/DI index */
2483 if (b == i)
2484 return NULL; /* shouldn't ever happen, in theory */
2485 if (i != -1 && b != -1 &&
2486 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2487 return NULL; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002488 if (b == -1) /* pure offset: handled above */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002489 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002490
H. Peter Anvine2c80182005-01-15 22:15:51 +00002491 rm = -1;
2492 if (i != -1)
2493 switch (i * 256 + b) {
2494 case R_SI * 256 + R_BX:
2495 rm = 0;
2496 break;
2497 case R_DI * 256 + R_BX:
2498 rm = 1;
2499 break;
2500 case R_SI * 256 + R_BP:
2501 rm = 2;
2502 break;
2503 case R_DI * 256 + R_BP:
2504 rm = 3;
2505 break;
2506 } else
2507 switch (b) {
2508 case R_SI:
2509 rm = 4;
2510 break;
2511 case R_DI:
2512 rm = 5;
2513 break;
2514 case R_BP:
2515 rm = 6;
2516 break;
2517 case R_BX:
2518 rm = 7;
2519 break;
2520 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002521 if (rm == -1) /* can't happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002522 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002523
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002524 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2525 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002526 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002527 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002528 (o >= -128 && o <= 127 && seg == NO_SEG &&
2529 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002530 mod = 1;
2531 else
2532 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002533
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002534 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002535 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002536 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002537 }
2538 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002539 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002540
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002541 output->size = 1 + output->sib_present + output->bytes;
2542 return output;
2543}
2544
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002545static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002546{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002547 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002548 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002549
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002550 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002551
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002552 switch (ins->prefixes[PPS_ASIZE]) {
2553 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002554 valid &= 16;
2555 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002556 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002557 valid &= 32;
2558 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002559 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002560 valid &= 64;
2561 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002562 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002563 valid &= (addrbits == 32) ? 16 : 32;
2564 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002565 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002566 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002567 }
2568
2569 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002570 if (is_class(MEMORY, ins->oprs[j].type)) {
2571 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002572
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002573 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002574 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002575 i = 0;
2576 else
2577 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002578
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002579 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002580 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002581 b = 0;
2582 else
2583 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002584
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002585 if (ins->oprs[j].scale == 0)
2586 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002587
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002588 if (!i && !b) {
2589 int ds = ins->oprs[j].disp_size;
2590 if ((addrbits != 64 && ds > 8) ||
2591 (addrbits == 64 && ds == 16))
2592 valid &= ds;
2593 } else {
2594 if (!(REG16 & ~b))
2595 valid &= 16;
2596 if (!(REG32 & ~b))
2597 valid &= 32;
2598 if (!(REG64 & ~b))
2599 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002600
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002601 if (!(REG16 & ~i))
2602 valid &= 16;
2603 if (!(REG32 & ~i))
2604 valid &= 32;
2605 if (!(REG64 & ~i))
2606 valid &= 64;
2607 }
2608 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002609 }
2610
2611 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002612 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002613 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002614 /* Add an address size prefix */
2615 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2616 ins->prefixes[PPS_ASIZE] = pref;
2617 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002618 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002619 /* Impossible... */
2620 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2621 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002622 }
2623
2624 defdisp = ins->addr_size == 16 ? 16 : 32;
2625
2626 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002627 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2628 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2629 /*
2630 * mem_offs sizes must match the address size; if not,
2631 * strip the MEM_OFFS bit and match only EA instructions
2632 */
2633 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2634 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002635 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002636}