blob: fd78b21c69d073da949eb7fd01b7041886641786 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07003 * Copyright 1996-2011 The NASM Authors - All Rights Reserved
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07004 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
Cyrill Gorcunov1de95002009-11-06 00:08:38 +030017 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -070018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * assemble.c code generation for the Netwide Assembler
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036 *
37 * the actual codes (C syntax, i.e. octal):
38 * \0 - terminates the code. (Unless it's a literal of course.)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040039 * \1..\4 - that many literal bytes follow in the code stream
H. Peter Anvindcffe4b2008-10-10 22:10:31 -070040 * \5 - add 4 to the primary operand number (b, low octdigit)
41 * \6 - add 4 to the secondary operand number (a, middle octdigit)
42 * \7 - add 4 to both the primary and the secondary operand number
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070043 * \10..\13 - a literal byte follows in the code stream, to be added
44 * to the register value of operand 0..3
45 * \14..\17 - a signed byte immediate operand, from operand 0..3
46 * \20..\23 - a byte immediate operand, from operand 0..3
47 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
48 * \30..\33 - a word immediate operand, from operand 0..3
49 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000050 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070051 * \40..\43 - a long immediate operand, from operand 0..3
52 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040053 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070054 * \50..\53 - a byte relative operand, from operand 0..3
55 * \54..\57 - a qword immediate operand, from operand 0..3
56 * \60..\63 - a word relative operand, from operand 0..3
57 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000058 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070059 * \70..\73 - a long relative operand, from operand 0..3
H. Peter Anvinc1377e92008-10-06 23:40:31 -070060 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000061 * \1ab - a ModRM, calculated on EA in operand a, with the spare
62 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070063 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080064 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040065 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvinc1377e92008-10-06 23:40:31 -070066 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080067 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040068 * is a signed byte rather than a dword. Opcode byte follows.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040069 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070070 * the 4-bit immediate from operand b in bits 3..0.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040071 * \173\xab - the register number from operand a in bits 7..4, with
72 * the value b in bits 3..0.
H. Peter Anvincffe61e2011-07-07 17:21:24 -070073 * \174..\177 - the register number from operand 0..3 in bits 7..4, and
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040074 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000075 * \2ab - a ModRM, calculated on EA in operand a, with the spare
76 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070077 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
78 * is not equal to the truncated and sign-extended 32-bit
79 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvin588df782008-10-07 10:05:10 -070080 * \254..\257 - a signed 32-bit operand to be extended to 64 bits.
H. Peter Anvina04019c2009-05-03 21:42:34 -070081 * \260..\263 - this instruction uses VEX/XOP rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040082 * V field taken from operand 0..3.
83 * \270 - this instruction uses VEX/XOP rather than REX, with the
84 * V field set to 1111b.
H. Peter Anvind85d2502008-05-04 17:53:31 -070085 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070086 * VEX/XOP prefixes are followed by the sequence:
87 * \tmm\wlp where mm is the M field; and wlp is:
H. Peter Anvin421059c2010-08-16 14:56:33 -070088 * 00 wwl lpp
89 * [l0] ll = 0 for L = 0 (.128, .lz)
90 * [l1] ll = 1 for L = 1 (.256)
91 * [lig] ll = 2 for L don't care (always assembled as 0)
92 *
H. Peter Anvin978c2172010-08-16 13:48:43 -070093 * [w0] ww = 0 for W = 0
94 * [w1 ] ww = 1 for W = 1
95 * [wig] ww = 2 for W don't care (always assembled as 0)
96 * [ww] ww = 3 for W used as REX.W
H. Peter Anvinbd420c72008-05-22 11:24:35 -070097 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070098 * t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
H. Peter Anvind85d2502008-05-04 17:53:31 -070099 *
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700100 * \274..\277 - a signed byte immediate operand, from operand 0..3,
101 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
103 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -0700104 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +0000105 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -0800106 * \314 - (disassembler only) invalid with REX.B
107 * \315 - (disassembler only) invalid with REX.X
108 * \316 - (disassembler only) invalid with REX.R
109 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
111 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
112 * \322 - indicates that this instruction is only valid when the
113 * operand size is the default (instruction to disassembler,
114 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000115 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000116 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400117 * \325 - instruction which always uses spl/bpl/sil/dil
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118 * \330 - a literal byte follows in the code stream, to be added
119 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000120 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000121 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700122 * \332 - REP prefix (0xF2 byte) used as opcode extension.
123 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700124 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700125 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700126 * \336 - force a REP(E) prefix (0xF2) even if not specified.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400127 * \337 - force a REPNE prefix (0xF3) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700128 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000129 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400131 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700132 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
133 * (POP is never used for CS) depending on operand 0
134 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
135 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400136 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700137 * \361 - 66 SSE prefix (== \366\331)
138 * \362 - F2 SSE prefix (== \364\332)
139 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000140 * \364 - operand-size prefix (0x66) not permitted
141 * \365 - address-size prefix (0x67) not permitted
142 * \366 - operand-size prefix (0x66) used as opcode extension
143 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000144 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400145 * 370 is used for Jcc, 371 is used for JMP.
146 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
147 * used for conditional jump over longer jump
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700148 * \374 - this instruction takes an XMM VSIB memory EA
149 * \375 - this instruction takes an YMM VSIB memory EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000150 */
151
H. Peter Anvinfe501952007-10-02 21:53:51 -0700152#include "compiler.h"
153
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000154#include <stdio.h>
155#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000156#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000157
158#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000159#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000160#include "assemble.h"
161#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700162#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000163
H. Peter Anvin65289e82009-07-25 17:25:11 -0700164enum match_result {
165 /*
166 * Matching errors. These should be sorted so that more specific
167 * errors come later in the sequence.
168 */
169 MERR_INVALOP,
170 MERR_OPSIZEMISSING,
171 MERR_OPSIZEMISMATCH,
172 MERR_BADCPU,
173 MERR_BADMODE,
174 /*
175 * Matching success; the conditional ones first
176 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400177 MOK_JUMP, /* Matching OK but needs jmp_match() */
178 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700179};
180
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000181typedef struct {
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700182 enum ea_type type; /* what kind of EA is this? */
183 int sib_present; /* is a SIB byte necessary? */
184 int bytes; /* # of bytes of offset needed */
185 int size; /* lazy - this is sib+bytes+1 */
186 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000187} ea;
188
Keith Kaniosb7a89542007-04-12 02:40:54 +0000189static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000190static efunc errfunc;
191static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000192static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000193
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700194static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700195static void gencode(int32_t segment, int64_t offset, int bits,
196 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400197 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700198static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400199 insn *instruction,
200 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700201static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700202static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000203static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700204static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000205static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700206static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000207
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700208static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
209
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700210static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000211{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700212 return ins->prefixes[pos] == prefix;
213}
214
215static void assert_no_prefix(insn * ins, enum prefix_pos pos)
216{
217 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400218 errfunc(ERR_NONFATAL, "invalid %s prefix",
219 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700220}
221
222static const char *size_name(int size)
223{
224 switch (size) {
225 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400226 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700227 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400228 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700229 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400230 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700231 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400232 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700233 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400234 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700235 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400236 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700237 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400238 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700239 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400240 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000241 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700242}
243
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400244static void warn_overflow(int pass, int size)
245{
246 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
247 "%s data exceeds bounds", size_name(size));
248}
249
250static void warn_overflow_const(int64_t data, int size)
251{
252 if (overflow_general(data, size))
253 warn_overflow(ERR_PASS1, size);
254}
255
256static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700257{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100258 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400259 if (overflow_general(o->offset, size))
260 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700261 }
262}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400263
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000264/*
265 * This routine wrappers the real output format's output routine,
266 * in order to pass a copy of the data off to the listing file
267 * generator at the same time.
268 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800269static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800270 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400271 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000272{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000273 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000274 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800275 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000276
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800277 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400278 /*
279 * This is a non-relocated address, and we're going to
280 * convert it into RAWDATA format.
281 */
282 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800283
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400284 if (size > 8) {
285 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
286 return;
287 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700288
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400289 WRITEADDR(q, *(int64_t *)data, size);
290 data = p;
291 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000292 }
293
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800294 list->output(offset, data, type, size);
295
Frank Kotlerabebb082003-09-06 04:45:37 +0000296 /*
297 * this call to src_get determines when we call the
298 * debug-format-specific "linenum" function
299 * it updates lineno and lnfname to the current values
300 * returning 0 if "same as last time", -2 if lnfname
301 * changed, and the amount by which lineno changed,
302 * if it did. thus, these variables must be static
303 */
304
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400305 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000306 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000307
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800308 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000309}
310
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700311static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700312 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800314 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000315 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000316
Charles Craynef1aefd82008-09-30 16:11:32 -0700317 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700318 return false;
319 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400320 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700321 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400322 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700323
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324 isize = calcsize(segment, offset, bits, ins, code);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100325
Victor van den Elzen154e5922009-02-25 17:32:00 +0100326 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100327 /* Be optimistic in pass 1 */
328 return true;
329
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700331 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000332
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700333 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
334 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000336
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800337int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400338 insn * instruction, struct ofmt *output, efunc error,
339 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000340{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000341 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700343 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800344 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000345 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800346 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300347 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000348
H. Peter Anvine2c80182005-01-15 22:15:51 +0000349 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000350 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000351 outfmt = output; /* likewise */
352 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000353
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300354 wsize = idata_bytes(instruction->opcode);
355 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000357
H. Peter Anvineba20a72002-04-30 20:53:55 +0000358 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000360 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 if (t < 0)
362 errfunc(ERR_PANIC,
363 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000364
H. Peter Anvine2c80182005-01-15 22:15:51 +0000365 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400366 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400368 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700369 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400370 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000371 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700372 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800374 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400375 offset += wsize;
376 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700377 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400378 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000380
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800382 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000383 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000384
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 if (align) {
386 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100387 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800388 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 }
390 offset += e->stringlen + align;
391 }
392 }
393 if (t > 0 && t == instruction->times - 1) {
394 /*
395 * Dummy call to list->output to give the offset to the
396 * listing module.
397 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800398 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 list->uplevel(LIST_TIMES);
400 }
401 }
402 if (instruction->times > 1)
403 list->downlevel(LIST_TIMES);
404 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000405 }
406
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700408 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000410
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400411 fp = fopen(fname, "rb");
412 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
414 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400415 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000416 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
417 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400418 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700419 static char buf[4096];
420 size_t t = instruction->times;
421 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400422 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000423
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 len = ftell(fp);
425 if (instruction->eops->next) {
426 base = instruction->eops->next->offset;
427 len -= base;
428 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700429 len > (size_t)instruction->eops->next->next->offset)
430 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 }
432 /*
433 * Dummy call to list->output to give the offset to the
434 * listing module.
435 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800436 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000437 list->uplevel(LIST_INCBIN);
438 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700439 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000440
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 fseek(fp, base, SEEK_SET);
442 l = len;
443 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700444 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400445 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 if (!m) {
447 /*
448 * This shouldn't happen unless the file
449 * actually changes while we are reading
450 * it.
451 */
452 error(ERR_NONFATAL,
453 "`incbin': unexpected EOF while"
454 " reading file `%s'", fname);
455 t = 0; /* Try to exit cleanly */
456 break;
457 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800458 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000459 NO_SEG, NO_SEG);
460 l -= m;
461 }
462 }
463 list->downlevel(LIST_INCBIN);
464 if (instruction->times > 1) {
465 /*
466 * Dummy call to list->output to give the offset to the
467 * listing module.
468 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800469 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000470 list->uplevel(LIST_TIMES);
471 list->downlevel(LIST_TIMES);
472 }
473 fclose(fp);
474 return instruction->times * len;
475 }
476 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000477 }
478
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700479 /* Check to see if we need an address-size prefix */
480 add_asp(instruction, bits);
481
H. Peter Anvin23595f52009-07-25 17:44:25 -0700482 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700483
H. Peter Anvin23595f52009-07-25 17:44:25 -0700484 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400485 /* Matches! */
486 int64_t insn_size = calcsize(segment, offset, bits,
487 instruction, temp->code);
488 itimes = instruction->times;
489 if (insn_size < 0) /* shouldn't be, on pass two */
490 error(ERR_PANIC, "errors made it through from pass one");
491 else
492 while (itimes--) {
493 for (j = 0; j < MAXPREFIX; j++) {
494 uint8_t c = 0;
495 switch (instruction->prefixes[j]) {
496 case P_WAIT:
497 c = 0x9B;
498 break;
499 case P_LOCK:
500 c = 0xF0;
501 break;
502 case P_REPNE:
503 case P_REPNZ:
504 c = 0xF2;
505 break;
506 case P_REPE:
507 case P_REPZ:
508 case P_REP:
509 c = 0xF3;
510 break;
511 case R_CS:
512 if (bits == 64) {
513 error(ERR_WARNING | ERR_PASS2,
514 "cs segment base generated, but will be ignored in 64-bit mode");
515 }
516 c = 0x2E;
517 break;
518 case R_DS:
519 if (bits == 64) {
520 error(ERR_WARNING | ERR_PASS2,
521 "ds segment base generated, but will be ignored in 64-bit mode");
522 }
523 c = 0x3E;
524 break;
525 case R_ES:
526 if (bits == 64) {
527 error(ERR_WARNING | ERR_PASS2,
528 "es segment base generated, but will be ignored in 64-bit mode");
529 }
530 c = 0x26;
531 break;
532 case R_FS:
533 c = 0x64;
534 break;
535 case R_GS:
536 c = 0x65;
537 break;
538 case R_SS:
539 if (bits == 64) {
540 error(ERR_WARNING | ERR_PASS2,
541 "ss segment base generated, but will be ignored in 64-bit mode");
542 }
543 c = 0x36;
544 break;
545 case R_SEGR6:
546 case R_SEGR7:
547 error(ERR_NONFATAL,
548 "segr6 and segr7 cannot be used as prefixes");
549 break;
550 case P_A16:
551 if (bits == 64) {
552 error(ERR_NONFATAL,
553 "16-bit addressing is not supported "
554 "in 64-bit mode");
555 } else if (bits != 16)
556 c = 0x67;
557 break;
558 case P_A32:
559 if (bits != 32)
560 c = 0x67;
561 break;
562 case P_A64:
563 if (bits != 64) {
564 error(ERR_NONFATAL,
565 "64-bit addressing is only supported "
566 "in 64-bit mode");
567 }
568 break;
569 case P_ASP:
570 c = 0x67;
571 break;
572 case P_O16:
573 if (bits != 16)
574 c = 0x66;
575 break;
576 case P_O32:
577 if (bits == 16)
578 c = 0x66;
579 break;
580 case P_O64:
581 /* REX.W */
582 break;
583 case P_OSP:
584 c = 0x66;
585 break;
586 case P_none:
587 break;
588 default:
589 error(ERR_PANIC, "invalid instruction prefix");
590 }
591 if (c != 0) {
592 out(offset, segment, &c, OUT_RAWDATA, 1,
593 NO_SEG, NO_SEG);
594 offset++;
595 }
596 }
597 insn_end = offset + insn_size;
598 gencode(segment, offset, bits, instruction,
599 temp, insn_end);
600 offset += insn_size;
601 if (itimes > 0 && itimes == instruction->times - 1) {
602 /*
603 * Dummy call to list->output to give the offset to the
604 * listing module.
605 */
606 list->output(offset, NULL, OUT_RAWDATA, 0);
607 list->uplevel(LIST_TIMES);
608 }
609 }
610 if (instruction->times > 1)
611 list->downlevel(LIST_TIMES);
612 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700613 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400614 /* No match */
615 switch (m) {
616 case MERR_OPSIZEMISSING:
617 error(ERR_NONFATAL, "operation size not specified");
618 break;
619 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400621 break;
622 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400624 break;
625 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800626 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400627 bits);
628 break;
629 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000630 error(ERR_NONFATAL,
631 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400632 break;
633 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000634 }
635 return 0;
636}
637
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800638int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400639 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000640{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000641 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700642 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000643
H. Peter Anvine2c80182005-01-15 22:15:51 +0000644 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000645 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400647 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000648 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000649
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700650 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
651 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400652 instruction->opcode == I_DT || instruction->opcode == I_DO ||
653 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000654 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300655 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300658 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400660 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000661 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400664 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000665 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400666 warn_overflow_const(e->offset, wsize);
667 } else if (e->type == EOT_DB_STRING ||
668 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 align = (-osize) % wsize;
672 if (align < 0)
673 align += wsize;
674 isize += osize + align;
675 }
676 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000677 }
678
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400680 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300682 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700683 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000684
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400685 fp = fopen(fname, "rb");
686 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
688 fname);
689 else if (fseek(fp, 0L, SEEK_END) < 0)
690 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
691 fname);
692 else {
693 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000694 if (instruction->eops->next) {
695 len -= instruction->eops->next->offset;
696 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700697 len > (size_t)instruction->eops->next->next->offset) {
698 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000699 }
700 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300701 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300703 if (fp)
704 fclose(fp);
705 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000706 }
707
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700708 /* Check to see if we need an address-size prefix */
709 add_asp(instruction, bits);
710
H. Peter Anvin23595f52009-07-25 17:44:25 -0700711 m = find_match(&temp, instruction, segment, offset, bits);
712 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400713 /* we've matched an instruction. */
714 int64_t isize;
715 const uint8_t *codes = temp->code;
716 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100717
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400718 isize = calcsize(segment, offset, bits, instruction, codes);
719 if (isize < 0)
720 return -1;
721 for (j = 0; j < MAXPREFIX; j++) {
722 switch (instruction->prefixes[j]) {
723 case P_A16:
724 if (bits != 16)
725 isize++;
726 break;
727 case P_A32:
728 if (bits != 32)
729 isize++;
730 break;
731 case P_O16:
732 if (bits != 16)
733 isize++;
734 break;
735 case P_O32:
736 if (bits == 16)
737 isize++;
738 break;
739 case P_A64:
740 case P_O64:
741 case P_none:
742 break;
743 default:
744 isize++;
745 break;
746 }
747 }
748 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700749 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400750 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000751 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000752}
753
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700754static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000755{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700756 return o->wrt == NO_SEG && o->segment == NO_SEG &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400757 !(o->opflags & OPFLAG_UNKNOWN) &&
758 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000759}
760
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700761/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700762static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700763{
764 int16_t v;
765
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700766 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400767 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700768
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700769 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700770 return v >= -128 && v <= 127;
771}
772
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700773static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774{
775 int32_t v;
776
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700777 if (!possible_sbyte(o))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400778 return false;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700779
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700780 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700781 return v >= -128 && v <= 127;
782}
783
H. Peter Anvin507ae032008-10-09 15:37:10 -0700784/* Common construct */
785#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
786
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800787static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400788 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000789{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800790 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000791 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000792 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700793 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700794 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700795 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700796 enum ea_type eat;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000797
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700798 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700799 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700800
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700801 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400802 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700803
H. Peter Anvine2c80182005-01-15 22:15:51 +0000804 (void)segment; /* Don't warn that this parameter is unused */
805 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000806
H. Peter Anvin839eca22007-10-29 23:12:47 -0700807 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400808 c = *codes++;
809 op1 = (c & 3) + ((opex & 1) << 2);
810 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
811 opx = &ins->oprs[op1];
812 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700813
H. Peter Anvin839eca22007-10-29 23:12:47 -0700814 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 case 01:
816 case 02:
817 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400818 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000819 codes += c, length += c;
820 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700821
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400822 case 05:
823 case 06:
824 case 07:
825 opex = c;
826 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700827
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400828 case4(010):
829 ins->rex |=
830 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000831 codes++, length++;
832 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700833
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400834 case4(014):
835 case4(020):
836 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 length++;
838 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700839
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400840 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000841 length += 2;
842 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700843
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400844 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700845 if (opx->type & (BITS16 | BITS32 | BITS64))
846 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 else
848 length += (bits == 16) ? 2 : 4;
849 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700850
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400851 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000852 length += 4;
853 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700854
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400855 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700856 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700858
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400859 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000860 length++;
861 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700862
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400863 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000864 length += 8; /* MOV reg64/imm */
865 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700866
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400867 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 length += 2;
869 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700870
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400871 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700872 if (opx->type & (BITS16 | BITS32 | BITS64))
873 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 else
875 length += (bits == 16) ? 2 : 4;
876 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700877
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400878 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 length += 4;
880 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700881
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400882 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700883 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000884 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700885
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400886 case4(0140):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700887 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700889
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400890 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800891 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000892 length++;
893 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700894
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400895 case4(0150):
H. Peter Anvinab5bd052010-07-25 12:43:30 -0700896 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700897 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700898
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400899 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800900 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700901 length++;
902 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700903
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400904 case 0172:
905 case 0173:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400906 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700907 length++;
908 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700909
H. Peter Anvincffe61e2011-07-07 17:21:24 -0700910 case4(0174):
911 length++;
912 break;
913
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400914 case4(0250):
915 length += is_sbyte32(opx) ? 1 : 4;
916 break;
917
918 case4(0254):
919 length += 4;
920 break;
921
922 case4(0260):
923 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700924 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400925 ins->vex_cm = *codes++;
926 ins->vex_wlp = *codes++;
927 break;
928
929 case 0270:
930 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700931 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400932 ins->vex_cm = *codes++;
933 ins->vex_wlp = *codes++;
934 break;
935
936 case4(0274):
937 length++;
938 break;
939
940 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000941 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700942
H. Peter Anvine2c80182005-01-15 22:15:51 +0000943 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400944 if (bits == 64)
945 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700946 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000947 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700948
H. Peter Anvine2c80182005-01-15 22:15:51 +0000949 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700950 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000951 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700952
H. Peter Anvine2c80182005-01-15 22:15:51 +0000953 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700954 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700955
Keith Kaniosb7a89542007-04-12 02:40:54 +0000956 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400957 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
958 has_prefix(ins, PPS_ASIZE, P_A32))
959 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400962 case4(0314):
963 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700964
H. Peter Anvine2c80182005-01-15 22:15:51 +0000965 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000966 {
967 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
968 if (pfx == P_O16)
969 break;
970 if (pfx != P_none)
971 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
972 else
973 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000975 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700976
H. Peter Anvine2c80182005-01-15 22:15:51 +0000977 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000978 {
979 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
980 if (pfx == P_O32)
981 break;
982 if (pfx != P_none)
983 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
984 else
985 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000986 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000987 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700988
H. Peter Anvine2c80182005-01-15 22:15:51 +0000989 case 0322:
990 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700991
Keith Kaniosb7a89542007-04-12 02:40:54 +0000992 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000993 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000994 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700995
Keith Kaniosb7a89542007-04-12 02:40:54 +0000996 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400997 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000998 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700999
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001000 case 0325:
1001 ins->rex |= REX_NH;
1002 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001003
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 case 0330:
1005 codes++, length++;
1006 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001007
H. Peter Anvine2c80182005-01-15 22:15:51 +00001008 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001009 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001010
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001011 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001012 case 0333:
1013 length++;
1014 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001015
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001016 case 0334:
1017 ins->rex |= REX_L;
1018 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001019
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001020 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001021 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001022
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001023 case 0336:
1024 if (!ins->prefixes[PPS_LREP])
1025 ins->prefixes[PPS_LREP] = P_REP;
1026 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001027
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001028 case 0337:
1029 if (!ins->prefixes[PPS_LREP])
1030 ins->prefixes[PPS_LREP] = P_REPNE;
1031 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001032
H. Peter Anvine2c80182005-01-15 22:15:51 +00001033 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001034 if (ins->oprs[0].segment != NO_SEG)
1035 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1036 " quantity of BSS space");
1037 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001038 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001039 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001040
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001041 case 0341:
1042 if (!ins->prefixes[PPS_WAIT])
1043 ins->prefixes[PPS_WAIT] = P_WAIT;
1044 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001045
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001046 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001047 length++;
1048 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001049
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001050 case 0360:
1051 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001052
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001053 case 0361:
1054 case 0362:
1055 case 0363:
1056 length++;
1057 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001058
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001059 case 0364:
1060 case 0365:
1061 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001062
Keith Kanios48af1772007-08-17 07:37:52 +00001063 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001064 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001065 length++;
1066 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001067
H. Peter Anvine2c80182005-01-15 22:15:51 +00001068 case 0370:
1069 case 0371:
1070 case 0372:
1071 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001072
H. Peter Anvine2c80182005-01-15 22:15:51 +00001073 case 0373:
1074 length++;
1075 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001076
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001077 case 0374:
1078 eat = EA_XMMVSIB;
1079 break;
1080
1081 case 0375:
1082 eat = EA_YMMVSIB;
1083 break;
1084
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001085 case4(0100):
1086 case4(0110):
1087 case4(0120):
1088 case4(0130):
1089 case4(0200):
1090 case4(0204):
1091 case4(0210):
1092 case4(0214):
1093 case4(0220):
1094 case4(0224):
1095 case4(0230):
1096 case4(0234):
1097 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001098 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001099 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001100 opflags_t rflags;
1101 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001102
Keith Kaniosb7a89542007-04-12 02:40:54 +00001103 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001104
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001105 if (c <= 0177) {
1106 /* pick rfield from operand b (opx) */
1107 rflags = regflag(opx);
1108 rfield = nasm_regvals[opx->basereg];
1109 } else {
1110 rflags = 0;
1111 rfield = c & 7;
1112 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001113 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1114 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001115 errfunc(ERR_NONFATAL, "invalid effective address");
1116 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001117 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001118 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001119 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001120 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001121 }
1122 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001123
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001124 default:
1125 errfunc(ERR_PANIC, "internal instruction table corrupt"
1126 ": instruction code \\%o (0x%02X) given", c, c);
1127 break;
1128 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001129 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001130
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001131 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001132
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001133 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001134 if (ins->rex & REX_H) {
1135 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1136 return -1;
1137 }
1138 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001139 }
1140
H. Peter Anvind85d2502008-05-04 17:53:31 -07001141 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001142 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001143
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001144 if (ins->rex & REX_H) {
1145 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1146 return -1;
1147 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001148 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001149 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001150 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001151 ins->rex &= ~REX_W;
1152 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001153 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001154 ins->rex |= REX_W;
1155 bad32 &= ~REX_W;
1156 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001157 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001158 /* Follow REX_W */
1159 break;
1160 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001161
H. Peter Anvinfc561202011-07-07 16:58:22 -07001162 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001163 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1164 return -1;
1165 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001166 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001167 length += 3;
1168 else
1169 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001170 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001171 if (ins->rex & REX_H) {
1172 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1173 return -1;
1174 } else if (bits == 64) {
1175 length++;
1176 } else if ((ins->rex & REX_L) &&
1177 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1178 cpu >= IF_X86_64) {
1179 /* LOCK-as-REX.R */
1180 assert_no_prefix(ins, PPS_LREP);
1181 length++;
1182 } else {
1183 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1184 return -1;
1185 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001186 }
1187
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001188 return length;
1189}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001190
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001191#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001192 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001193 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1194 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1195 ins->rex = 0; \
1196 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001197 }
1198
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001199static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001200 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001201 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001202{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001203 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001204 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1205 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1206 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001207 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001208 uint8_t c;
1209 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001210 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001211 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001212 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001213 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001214 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001215 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001216 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001217
H. Peter Anvin839eca22007-10-29 23:12:47 -07001218 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001219 c = *codes++;
1220 op1 = (c & 3) + ((opex & 1) << 2);
1221 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1222 opx = &ins->oprs[op1];
1223 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001224
H. Peter Anvin839eca22007-10-29 23:12:47 -07001225 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001226 case 01:
1227 case 02:
1228 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001229 case 04:
1230 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001231 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001232 codes += c;
1233 offset += c;
1234 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001235
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001236 case 05:
1237 case 06:
1238 case 07:
1239 opex = c;
1240 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001241
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001242 case4(010):
1243 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001244 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001245 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001246 offset += 1;
1247 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001248
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001249 case4(014):
1250 /*
1251 * The test for BITS8 and SBYTE here is intended to avoid
1252 * warning on optimizer actions due to SBYTE, while still
1253 * warn on explicit BYTE directives. Also warn, obviously,
1254 * if the optimizer isn't enabled.
1255 */
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001256 if (((opx->type & BITS8) ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001257 !(opx->type & temp->opd[op1] & BYTENESS)) &&
1258 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001259 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001260 "signed byte value exceeds bounds");
1261 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001262 if (opx->segment != NO_SEG) {
1263 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001264 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001267 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001268 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 NO_SEG);
1270 }
1271 offset += 1;
1272 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001273
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001274 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001275 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001276 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001277 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001278 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 if (opx->segment != NO_SEG) {
1280 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001281 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001285 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 NO_SEG);
1287 }
1288 offset += 1;
1289 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001290
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001291 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001293 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001294 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001295 if (opx->segment != NO_SEG) {
1296 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001297 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001298 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001301 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001302 NO_SEG);
1303 }
1304 offset += 1;
1305 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001306
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001307 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001308 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001310 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001311 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001312 offset += 2;
1313 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001314
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001315 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001316 if (opx->type & (BITS16 | BITS32))
1317 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 else
1319 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001320 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001322 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001323 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 offset += size;
1325 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001326
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001327 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001328 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001330 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 offset += 4;
1333 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001334
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001335 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001336 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001337 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001338 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 offset += size;
1342 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001343
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001344 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001345 if (opx->segment != segment) {
1346 data = opx->offset;
1347 out(offset, segment, &data,
1348 OUT_REL1ADR, insn_end - offset,
1349 opx->segment, opx->wrt);
1350 } else {
1351 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001352 if (data > 127 || data < -128)
1353 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001354 out(offset, segment, &data,
1355 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1356 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001357 offset += 1;
1358 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001359
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001360 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001362 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001364 offset += 8;
1365 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001366
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001367 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001368 if (opx->segment != segment) {
1369 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001371 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001372 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001374 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001375 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001376 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 }
1378 offset += 2;
1379 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001380
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001381 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001382 if (opx->type & (BITS16 | BITS32 | BITS64))
1383 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001384 else
1385 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001387 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001388 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001389 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1390 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001392 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001394 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001395 }
1396 offset += size;
1397 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001398
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001399 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001400 if (opx->segment != segment) {
1401 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001403 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001404 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001405 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001408 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001409 }
1410 offset += 4;
1411 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001412
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001413 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001414 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001415 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1416 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001417 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001418 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001419 outfmt->segbase(1 + opx->segment),
1420 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001421 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001423
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001424 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001425 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001426 warn_overflow_opd(opx, 2);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001427 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001428 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001429 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001430 NO_SEG);
1431 offset++;
1432 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001433 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001435 offset += 2;
1436 }
1437 break;
1438
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001439 case4(0144):
1440 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001441 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001442 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001443 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001444 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001445 offset++;
1446 break;
1447
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001448 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001449 data = opx->offset;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001450 warn_overflow_opd(opx, 4);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001451 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001452 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001453 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001454 NO_SEG);
1455 offset++;
1456 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001457 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001458 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001459 offset += 4;
1460 }
1461 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001462
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001463 case4(0154):
1464 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001465 bytes[0] = *codes++;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001466 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001468 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 offset++;
1470 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001471
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001472 case 0172:
1473 c = *codes++;
1474 opx = &ins->oprs[c >> 3];
1475 bytes[0] = nasm_regvals[opx->basereg] << 4;
1476 opx = &ins->oprs[c & 7];
1477 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1478 errfunc(ERR_NONFATAL,
1479 "non-absolute expression not permitted as argument %d",
1480 c & 7);
1481 } else {
1482 if (opx->offset & ~15) {
1483 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1484 "four-bit argument exceeds bounds");
1485 }
1486 bytes[0] |= opx->offset & 15;
1487 }
1488 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1489 offset++;
1490 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001491
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001492 case 0173:
1493 c = *codes++;
1494 opx = &ins->oprs[c >> 4];
1495 bytes[0] = nasm_regvals[opx->basereg] << 4;
1496 bytes[0] |= c & 15;
1497 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1498 offset++;
1499 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001500
H. Peter Anvincffe61e2011-07-07 17:21:24 -07001501 case4(0174):
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001502 bytes[0] = nasm_regvals[opx->basereg] << 4;
1503 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1504 offset++;
1505 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001506
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001507 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001508 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001509 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1510 (int32_t)data != (int64_t)data) {
1511 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1512 "signed dword immediate exceeds bounds");
1513 }
H. Peter Anvinab5bd052010-07-25 12:43:30 -07001514 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001515 bytes[0] = data;
1516 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1517 NO_SEG);
1518 offset++;
1519 } else {
1520 out(offset, segment, &data, OUT_ADDRESS, 4,
1521 opx->segment, opx->wrt);
1522 offset += 4;
1523 }
1524 break;
1525
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001526 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001527 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001528 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1529 (int32_t)data != (int64_t)data) {
1530 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1531 "signed dword immediate exceeds bounds");
1532 }
1533 out(offset, segment, &data, OUT_ADDRESS, 4,
1534 opx->segment, opx->wrt);
1535 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001536 break;
1537
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001538 case4(0260):
1539 case 0270:
1540 codes += 2;
1541 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1542 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1543 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1544 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001545 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001546 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1547 offset += 3;
1548 } else {
1549 bytes[0] = 0xc5;
1550 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001551 ((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001552 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1553 offset += 2;
1554 }
1555 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001556
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001557 case4(0274):
1558 {
1559 uint64_t uv, um;
1560 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001561
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001562 if (ins->rex & REX_W)
1563 s = 64;
1564 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1565 s = 16;
1566 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1567 s = 32;
1568 else
1569 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001570
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001571 um = (uint64_t)2 << (s-1);
1572 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001573
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001574 if (uv > 127 && uv < (uint64_t)-128 &&
1575 (uv < um-128 || uv > um-1)) {
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001576 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001577 "signed byte value exceeds bounds");
1578 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001579 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001580 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001581 out(offset, segment, &data, OUT_ADDRESS, 1,
1582 opx->segment, opx->wrt);
1583 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001584 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001585 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1586 NO_SEG);
1587 }
1588 offset += 1;
1589 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001590 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001591
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001592 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001593 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001594
H. Peter Anvine2c80182005-01-15 22:15:51 +00001595 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001596 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001597 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001598 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001599 offset += 1;
1600 } else
1601 offset += 0;
1602 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001603
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001605 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001606 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001607 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001608 offset += 1;
1609 } else
1610 offset += 0;
1611 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001612
H. Peter Anvine2c80182005-01-15 22:15:51 +00001613 case 0312:
1614 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001615
Keith Kaniosb7a89542007-04-12 02:40:54 +00001616 case 0313:
1617 ins->rex = 0;
1618 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001619
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001620 case4(0314):
1621 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001622
H. Peter Anvine2c80182005-01-15 22:15:51 +00001623 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001624 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001626
H. Peter Anvine2c80182005-01-15 22:15:51 +00001627 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001628 case 0323:
1629 break;
1630
Keith Kaniosb7a89542007-04-12 02:40:54 +00001631 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001632 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001633 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001634
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001635 case 0325:
1636 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001637
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 case 0330:
1639 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001640 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001641 offset += 1;
1642 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001643
H. Peter Anvine2c80182005-01-15 22:15:51 +00001644 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001646
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001647 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001648 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001649 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001650 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001651 offset += 1;
1652 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001653
Keith Kanios48af1772007-08-17 07:37:52 +00001654 case 0334:
1655 if (ins->rex & REX_R) {
1656 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001657 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001658 offset += 1;
1659 }
1660 ins->rex &= ~(REX_L|REX_R);
1661 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001662
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001663 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001664 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001665
H. Peter Anvin962e3052008-08-28 17:47:16 -07001666 case 0336:
1667 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001668 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001669
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 if (ins->oprs[0].segment != NO_SEG)
1672 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1673 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001674 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 if (size > 0)
1676 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001677 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 offset += size;
1679 }
1680 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001681
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001682 case 0341:
1683 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001684
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001685 case 0344:
1686 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001687 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001688 switch (ins->oprs[0].basereg) {
1689 case R_CS:
1690 bytes[0] += 0x0E;
1691 break;
1692 case R_DS:
1693 bytes[0] += 0x1E;
1694 break;
1695 case R_ES:
1696 bytes[0] += 0x06;
1697 break;
1698 case R_SS:
1699 bytes[0] += 0x16;
1700 break;
1701 default:
1702 errfunc(ERR_PANIC,
1703 "bizarre 8086 segment register received");
1704 }
1705 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1706 offset++;
1707 break;
1708
1709 case 0346:
1710 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001711 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001712 switch (ins->oprs[0].basereg) {
1713 case R_FS:
1714 bytes[0] += 0xA0;
1715 break;
1716 case R_GS:
1717 bytes[0] += 0xA8;
1718 break;
1719 default:
1720 errfunc(ERR_PANIC,
1721 "bizarre 386 segment register received");
1722 }
1723 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1724 offset++;
1725 break;
1726
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001727 case 0360:
1728 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001729
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001730 case 0361:
1731 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001732 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1733 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001734 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001735
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001736 case 0362:
1737 case 0363:
1738 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001739 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1740 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001741 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001742
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001743 case 0364:
1744 case 0365:
1745 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001746
Keith Kanios48af1772007-08-17 07:37:52 +00001747 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001748 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001749 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001750 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001751 offset += 1;
1752 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001753
H. Peter Anvine2c80182005-01-15 22:15:51 +00001754 case 0370:
1755 case 0371:
1756 case 0372:
1757 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001758
H. Peter Anvine2c80182005-01-15 22:15:51 +00001759 case 0373:
1760 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001761 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001762 offset += 1;
1763 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001764
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001765 case 0374:
1766 eat = EA_XMMVSIB;
1767 break;
1768
1769 case 0375:
1770 eat = EA_YMMVSIB;
1771 break;
1772
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001773 case4(0100):
1774 case4(0110):
1775 case4(0120):
1776 case4(0130):
1777 case4(0200):
1778 case4(0204):
1779 case4(0210):
1780 case4(0214):
1781 case4(0220):
1782 case4(0224):
1783 case4(0230):
1784 case4(0234):
1785 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001786 ea ea_data;
1787 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001788 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001789 uint8_t *p;
1790 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001791 enum out_type type;
1792 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001793
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001794 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001795 /* pick rfield from operand b (opx) */
1796 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001797 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001798 } else {
1799 /* rfield is constant */
1800 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001802 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001803
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001804 if (process_ea(opy, &ea_data, bits, ins->addr_size,
1805 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 errfunc(ERR_NONFATAL, "invalid effective address");
1807 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001808
Charles Crayne7e975552007-11-03 22:06:13 -07001809
H. Peter Anvine2c80182005-01-15 22:15:51 +00001810 p = bytes;
1811 *p++ = ea_data.modrm;
1812 if (ea_data.sib_present)
1813 *p++ = ea_data.sib;
1814
1815 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001816 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001817
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001818 /*
1819 * Make sure the address gets the right offset in case
1820 * the line breaks in the .lst file (BR 1197827)
1821 */
1822 offset += s;
1823 s = 0;
1824
H. Peter Anvine2c80182005-01-15 22:15:51 +00001825 switch (ea_data.bytes) {
1826 case 0:
1827 break;
1828 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001829 case 2:
1830 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001831 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001832 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001834 if (ea_data.rip) {
1835 if (opy->segment == segment) {
1836 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001837 if (overflow_signed(data, ea_data.bytes))
1838 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001839 out(offset, segment, &data, OUT_ADDRESS,
1840 ea_data.bytes, NO_SEG, NO_SEG);
1841 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001842 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001843 out(offset, segment, &data, OUT_REL4ADR,
1844 insn_end - offset, opy->segment, opy->wrt);
1845 }
1846 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001847 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1848 signed_bits(opy->offset, ins->addr_size) !=
1849 signed_bits(opy->offset, ea_data.bytes * 8))
1850 warn_overflow(ERR_PASS2, ea_data.bytes);
1851
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001852 type = OUT_ADDRESS;
1853 out(offset, segment, &data, OUT_ADDRESS,
1854 ea_data.bytes, opy->segment, opy->wrt);
1855 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001856 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001857 default:
1858 /* Impossible! */
1859 errfunc(ERR_PANIC,
1860 "Invalid amount of bytes (%d) for offset?!",
1861 ea_data.bytes);
1862 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001863 }
1864 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001865 }
1866 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001867
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001868 default:
1869 errfunc(ERR_PANIC, "internal instruction table corrupt"
1870 ": instruction code \\%o (0x%02X) given", c, c);
1871 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001872 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001873 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001874}
1875
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001876static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001877{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001878 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001880 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001881}
1882
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001883static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001884{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001885 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001886 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001887 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001888}
1889
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001890static int op_rexflags(const operand * o, int mask)
1891{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001892 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001893 int val;
1894
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001895 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001896 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001897
H. Peter Anvina4835d42008-05-20 14:21:29 -07001898 flags = nasm_reg_flags[o->basereg];
1899 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001900
1901 return rexflags(val, flags, mask);
1902}
1903
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001904static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001905{
1906 int rex = 0;
1907
1908 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001909 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001910 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001911 rex |= REX_W;
1912 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1913 rex |= REX_H;
1914 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1915 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001916
1917 return rex & mask;
1918}
1919
H. Peter Anvin23595f52009-07-25 17:44:25 -07001920static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001921 insn *instruction,
1922 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001923{
1924 const struct itemplate *temp;
1925 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001926 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001927 bool opsizemissing = false;
1928 int i;
1929
1930 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001931 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001932
1933 merr = MERR_INVALOP;
1934
1935 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001936 temp->opcode != I_none; temp++) {
1937 m = matches(temp, instruction, bits);
1938 if (m == MOK_JUMP) {
1939 if (jmp_match(segment, offset, bits, instruction, temp->code))
1940 m = MOK_GOOD;
1941 else
1942 m = MERR_INVALOP;
1943 } else if (m == MERR_OPSIZEMISSING &&
1944 (temp->flags & IF_SMASK) != IF_SX) {
1945 /*
1946 * Missing operand size and a candidate for fuzzy matching...
1947 */
1948 for (i = 0; i < temp->operands; i++) {
1949 if ((temp->opd[i] & SAME_AS) == 0)
1950 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1951 }
1952 opsizemissing = true;
1953 }
1954 if (m > merr)
1955 merr = m;
1956 if (merr == MOK_GOOD)
1957 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001958 }
1959
1960 /* No match, but see if we can get a fuzzy operand size match... */
1961 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001962 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001963
1964 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001965 /*
1966 * We ignore extrinsic operand sizes on registers, so we should
1967 * never try to fuzzy-match on them. This also resolves the case
1968 * when we have e.g. "xmmrm128" in two different positions.
1969 */
1970 if (is_class(REGISTER, instruction->oprs[i].type))
1971 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001972
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001973 /* This tests if xsizeflags[i] has more than one bit set */
1974 if ((xsizeflags[i] & (xsizeflags[i]-1)))
1975 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001976
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001977 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001978 }
1979
1980 /* Try matching again... */
1981 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001982 temp->opcode != I_none; temp++) {
1983 m = matches(temp, instruction, bits);
1984 if (m == MOK_JUMP) {
1985 if (jmp_match(segment, offset, bits, instruction, temp->code))
1986 m = MOK_GOOD;
1987 else
1988 m = MERR_INVALOP;
1989 }
1990 if (m > merr)
1991 merr = m;
1992 if (merr == MOK_GOOD)
1993 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001994 }
1995
H. Peter Anvina81655b2009-07-25 18:15:28 -07001996done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07001997 *tempp = temp;
1998 return merr;
1999}
2000
H. Peter Anvin65289e82009-07-25 17:25:11 -07002001static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002002 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002003{
H. Peter Anvin60926242009-07-26 16:25:38 -07002004 int i, size[MAX_OPERANDS], asize, oprs;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002005 bool opsizemissing = false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002006
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002007 /*
2008 * Check the opcode
2009 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002010 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002011 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002012
2013 /*
2014 * Count the operands
2015 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002016 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07002017 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002018
2019 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07002020 * Is it legal?
2021 */
2022 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
2023 return MERR_INVALOP;
2024
2025 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002026 * Check that no spurious colons or TOs are present
2027 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002028 for (i = 0; i < itemp->operands; i++)
2029 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002030 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07002031
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002032 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002033 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002034 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002035 switch (itemp->flags & IF_SMASK) {
2036 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002037 asize = BITS8;
2038 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002039 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002040 asize = BITS16;
2041 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002042 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002043 asize = BITS32;
2044 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002045 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002046 asize = BITS64;
2047 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002048 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002049 asize = BITS128;
2050 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002051 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002052 asize = BITS256;
2053 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002054 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002055 switch (bits) {
2056 case 16:
2057 asize = BITS16;
2058 break;
2059 case 32:
2060 asize = BITS32;
2061 break;
2062 case 64:
2063 asize = BITS64;
2064 break;
2065 default:
2066 asize = 0;
2067 break;
2068 }
2069 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002070 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002071 asize = 0;
2072 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07002073 }
2074
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002075 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002076 /* S- flags only apply to a specific operand */
2077 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2078 memset(size, 0, sizeof size);
2079 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002080 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002081 /* S- flags apply to all operands */
2082 for (i = 0; i < MAX_OPERANDS; i++)
2083 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002084 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002085
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002086 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002087 * Check that the operand flags all match up,
2088 * it's a bit tricky so lets be verbose:
2089 *
2090 * 1) Find out the size of operand. If instruction
2091 * doesn't have one specified -- we're trying to
2092 * guess it either from template (IF_S* flag) or
2093 * from code bits.
2094 *
2095 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2096 * (ie the same operand as was specified somewhere in template, and
2097 * this referred operand index is being achieved via ~SAME_AS)
2098 * we are to be sure that both registers (in template and instruction)
2099 * do exactly match.
2100 *
2101 * 3) If template operand do not match the instruction OR
2102 * template has an operand size specified AND this size differ
2103 * from which instruction has (perhaps we got it from code bits)
2104 * we are:
2105 * a) Check that only size of instruction and operand is differ
2106 * other characteristics do match
2107 * b) Perhaps it's a register specified in instruction so
2108 * for such a case we just mark that operand as "size
2109 * missing" and this will turn on fuzzy operand size
2110 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002111 */
2112 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002113 opflags_t type = instruction->oprs[i].type;
2114 if (!(type & SIZE_MASK))
2115 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002116
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002117 if (itemp->opd[i] & SAME_AS) {
2118 int j = itemp->opd[i] & ~SAME_AS;
2119 if (type != instruction->oprs[j].type ||
2120 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2121 return MERR_INVALOP;
2122 } else if (itemp->opd[i] & ~type ||
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002123 ((itemp->opd[i] & SIZE_MASK) &&
2124 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
H. Peter Anvinff5d6562009-10-05 14:08:05 -07002125 if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK)) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002126 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002127 } else if (!is_class(REGISTER, type)) {
2128 /*
2129 * Note: we don't honor extrinsic operand sizes for registers,
2130 * so "missing operand size" for a register should be
2131 * considered a wildcard match rather than an error.
2132 */
2133 opsizemissing = true;
2134 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002135 }
2136 }
2137
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002138 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002139 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002140
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002141 /*
2142 * Check operand sizes
2143 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002144 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002145 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002146 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002147 asize = itemp->opd[i] & SIZE_MASK;
2148 if (asize) {
2149 for (i = 0; i < oprs; i++)
2150 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002151 break;
2152 }
2153 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002154 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002155 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002156 }
2157
Keith Kaniosb7a89542007-04-12 02:40:54 +00002158 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002159 if (!(itemp->opd[i] & SIZE_MASK) &&
2160 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002161 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002162 }
2163
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002164 /*
2165 * Check template is okay at the set cpu level
2166 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002167 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002168 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002169
Keith Kaniosb7a89542007-04-12 02:40:54 +00002170 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002171 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002172 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002173 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002174 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002175
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002176 /*
2177 * Check if special handling needed for Jumps
2178 */
H. Peter Anvin60926242009-07-26 16:25:38 -07002179 if ((itemp->code[0] & 0374) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002180 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002181
H. Peter Anvin60926242009-07-26 16:25:38 -07002182 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002183}
2184
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002185static enum ea_type process_ea(operand * input, ea * output, int bits,
2186 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002187{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002188 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002189
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002190 output->type = EA_SCALAR;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002191 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002192
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002193 /* REX flags for the rfield operand */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002194 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002195
Cyrill Gorcunov8a6345c2009-10-13 19:05:31 +04002196 if (is_class(REGISTER, input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002197 int i;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002198 opflags_t f;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002199
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002200 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002201 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002202 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002203 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002205 if (REG_EA & ~f)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002206 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002207
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002208 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002209
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002210 output->sib_present = false; /* no SIB necessary */
2211 output->bytes = 0; /* no offset necessary either */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002212 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002213 } else { /* it's a memory reference */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002214 if (input->basereg == -1 &&
2215 (input->indexreg == -1 || input->scale == 0)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002216 /* it's a pure offset */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002217
2218 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2219 input->segment == NO_SEG) {
2220 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2221 input->type &= ~IP_REL;
2222 input->type |= MEMORY;
2223 }
2224
2225 if (input->eaflags & EAF_BYTEOFFS ||
2226 (input->eaflags & EAF_WORDOFFS &&
2227 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2228 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2229 }
2230
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002231 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002232 int scale, index, base;
2233 output->sib_present = true;
2234 scale = 0;
2235 index = 4;
2236 base = 5;
2237 output->sib = (scale << 6) | (index << 3) | base;
2238 output->bytes = 4;
2239 output->modrm = 4 | ((rfield & 7) << 3);
2240 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002241 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002242 output->sib_present = false;
2243 output->bytes = (addrbits != 16 ? 4 : 2);
2244 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
2245 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002246 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002247 } else { /* it's an indirection */
2248 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002249 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002250 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002251 int t, it, bt; /* register numbers */
2252 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002253
H. Peter Anvine2c80182005-01-15 22:15:51 +00002254 if (s == 0)
2255 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002256
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002257 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002258 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002259 ix = nasm_reg_flags[i];
2260 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002261 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002262 ix = 0;
2263 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002264
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002265 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002266 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002267 bx = nasm_reg_flags[b];
2268 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002269 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002270 bx = 0;
2271 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002272
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002273 /* if either one are a vector register... */
2274 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
2275 int32_t sok = BITS32 | BITS64;
2276 int32_t o = input->offset;
2277 int mod, scale, index, base;
2278
2279 printf("bt = %x, bx = %x, it = %x, ix = %x, s = %d\n",
2280 bt, bx, it, ix, s);
2281
2282 /*
2283 * For a vector SIB, one has to be a vector and the other,
2284 * if present, a GPR. The vector must be the index operand.
2285 */
2286 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2287 if (s == 0)
2288 s = 1;
2289 else if (s != 1)
2290 goto err;
2291
2292 t = bt, bt = it, it = t;
2293 x = bx, bx = ix, ix = x;
2294 }
2295
2296 if (bt != -1) {
2297 if (REG_GPR & ~bx)
2298 goto err;
2299 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2300 sok &= bx;
2301 else
2302 goto err;
2303 }
2304
2305 /*
2306 * While we're here, ensure the user didn't specify
2307 * WORD or QWORD
2308 */
2309 if (input->disp_size == 16 || input->disp_size == 64)
2310 goto err;
2311
2312 if (addrbits == 16 ||
2313 (addrbits == 32 && !(sok & BITS32)) ||
2314 (addrbits == 64 && !(sok & BITS64)))
2315 goto err;
2316
2317 output->type = (ix & YMMREG & ~REG_EA)
2318 ? EA_YMMVSIB : EA_XMMVSIB;
2319
2320 output->rex |= rexflags(it, ix, REX_X);
2321 output->rex |= rexflags(bt, bx, REX_B);
2322
2323 index = it & 7; /* it is known to be != -1 */
2324
2325 switch (s) {
2326 case 1:
2327 scale = 0;
2328 break;
2329 case 2:
2330 scale = 1;
2331 break;
2332 case 4:
2333 scale = 2;
2334 break;
2335 case 8:
2336 scale = 3;
2337 break;
2338 default: /* then what the smeg is it? */
2339 goto err; /* panic */
2340 }
2341
2342 if (bt == -1) {
2343 base = 5;
2344 mod = 0;
2345 } else {
2346 base = (bt & 7);
2347 if (base != REG_NUM_EBP && o == 0 &&
2348 seg == NO_SEG && !forw_ref &&
2349 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2350 mod = 0;
2351 else if (input->eaflags & EAF_BYTEOFFS ||
2352 (o >= -128 && o <= 127 &&
2353 seg == NO_SEG && !forw_ref &&
2354 !(input->eaflags & EAF_WORDOFFS)))
2355 mod = 1;
2356 else
2357 mod = 2;
2358 }
2359
2360 output->sib_present = true;
2361 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2362 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
2363 output->sib = (scale << 6) | (index << 3) | base;
2364 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002365 /*
2366 * it must be a 32/64-bit memory reference. Firstly we have
2367 * to check that all registers involved are type E/Rxx.
2368 */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002369 int32_t sok = BITS32 | BITS64;
2370 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002371
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002372 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002373 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2374 sok &= ix;
2375 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002376 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002377 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002378
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002379 if (bt != -1) {
2380 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002381 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002382 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002383 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002384 sok &= bx;
2385 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002386
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002387 /*
2388 * While we're here, ensure the user didn't specify
2389 * WORD or QWORD
2390 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002391 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002392 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002393
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002394 if (addrbits == 16 ||
2395 (addrbits == 32 && !(sok & BITS32)) ||
2396 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002397 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002398
Keith Kaniosb7a89542007-04-12 02:40:54 +00002399 /* now reorganize base/index */
2400 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002401 ((hb == b && ht == EAH_NOTBASE) ||
2402 (hb == i && ht == EAH_MAKEBASE))) {
2403 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002404 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002405 x = bx, bx = ix, ix = x;
2406 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002407 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002408 bt = -1, bx = 0, s++;
2409 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002410 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002411 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002412 }
2413 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2414 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002415 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002416 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2417 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002418 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002419 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002420 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002421 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002422 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002423 x = ix, ix = bx, bx = x;
2424 }
2425 if (it == REG_NUM_ESP ||
2426 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002427 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002428
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002429 output->rex |= rexflags(it, ix, REX_X);
2430 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002431
Keith Kanios48af1772007-08-17 07:37:52 +00002432 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002433 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002434 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002435
Keith Kaniosb7a89542007-04-12 02:40:54 +00002436 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002437 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002438 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002439 } else {
2440 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002441 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002442 seg == NO_SEG && !forw_ref &&
2443 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002444 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002445 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002446 (o >= -128 && o <= 127 &&
2447 seg == NO_SEG && !forw_ref &&
2448 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002449 mod = 1;
2450 else
2451 mod = 2;
2452 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002453
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002454 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002455 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2456 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002457 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002458 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002459 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002460
Keith Kaniosb7a89542007-04-12 02:40:54 +00002461 if (it == -1)
2462 index = 4, s = 1;
2463 else
2464 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002465
H. Peter Anvine2c80182005-01-15 22:15:51 +00002466 switch (s) {
2467 case 1:
2468 scale = 0;
2469 break;
2470 case 2:
2471 scale = 1;
2472 break;
2473 case 4:
2474 scale = 2;
2475 break;
2476 case 8:
2477 scale = 3;
2478 break;
2479 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002480 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002481 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002482
Keith Kaniosb7a89542007-04-12 02:40:54 +00002483 if (bt == -1) {
2484 base = 5;
2485 mod = 0;
2486 } else {
2487 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002488 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002489 seg == NO_SEG && !forw_ref &&
2490 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002491 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002492 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002493 (o >= -128 && o <= 127 &&
2494 seg == NO_SEG && !forw_ref &&
2495 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002496 mod = 1;
2497 else
2498 mod = 2;
2499 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002500
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002501 output->sib_present = true;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002502 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002503 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002504 output->sib = (scale << 6) | (index << 3) | base;
2505 }
2506 } else { /* it's 16-bit */
2507 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002508 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002509
Keith Kaniosb7a89542007-04-12 02:40:54 +00002510 /* check for 64-bit long mode */
2511 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002512 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002513
H. Peter Anvine2c80182005-01-15 22:15:51 +00002514 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002515 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2516 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002517 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002518
Keith Kaniosb7a89542007-04-12 02:40:54 +00002519 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002520 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002521 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002522
H. Peter Anvine2c80182005-01-15 22:15:51 +00002523 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002524 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002525 if (b == -1 && i != -1) {
2526 int tmp = b;
2527 b = i;
2528 i = tmp;
2529 } /* swap */
2530 if ((b == R_SI || b == R_DI) && i != -1) {
2531 int tmp = b;
2532 b = i;
2533 i = tmp;
2534 }
2535 /* have BX/BP as base, SI/DI index */
2536 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002537 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002538 if (i != -1 && b != -1 &&
2539 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002540 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002541 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002542 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002543
H. Peter Anvine2c80182005-01-15 22:15:51 +00002544 rm = -1;
2545 if (i != -1)
2546 switch (i * 256 + b) {
2547 case R_SI * 256 + R_BX:
2548 rm = 0;
2549 break;
2550 case R_DI * 256 + R_BX:
2551 rm = 1;
2552 break;
2553 case R_SI * 256 + R_BP:
2554 rm = 2;
2555 break;
2556 case R_DI * 256 + R_BP:
2557 rm = 3;
2558 break;
2559 } else
2560 switch (b) {
2561 case R_SI:
2562 rm = 4;
2563 break;
2564 case R_DI:
2565 rm = 5;
2566 break;
2567 case R_BP:
2568 rm = 6;
2569 break;
2570 case R_BX:
2571 rm = 7;
2572 break;
2573 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002574 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002575 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002576
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002577 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2578 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002579 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002580 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002581 (o >= -128 && o <= 127 && seg == NO_SEG &&
2582 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002583 mod = 1;
2584 else
2585 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002586
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002587 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002588 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002589 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002590 }
2591 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002592 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002593
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002594 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002595 return output->type;
2596
2597err:
2598 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002599}
2600
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002601static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002602{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002603 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002604 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002605
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002606 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002607
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002608 switch (ins->prefixes[PPS_ASIZE]) {
2609 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002610 valid &= 16;
2611 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002612 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002613 valid &= 32;
2614 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002615 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002616 valid &= 64;
2617 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002618 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002619 valid &= (addrbits == 32) ? 16 : 32;
2620 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002621 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002622 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002623 }
2624
2625 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002626 if (is_class(MEMORY, ins->oprs[j].type)) {
2627 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002628
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002629 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002630 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002631 i = 0;
2632 else
2633 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002634
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002635 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002636 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002637 b = 0;
2638 else
2639 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002640
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002641 if (ins->oprs[j].scale == 0)
2642 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002643
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002644 if (!i && !b) {
2645 int ds = ins->oprs[j].disp_size;
2646 if ((addrbits != 64 && ds > 8) ||
2647 (addrbits == 64 && ds == 16))
2648 valid &= ds;
2649 } else {
2650 if (!(REG16 & ~b))
2651 valid &= 16;
2652 if (!(REG32 & ~b))
2653 valid &= 32;
2654 if (!(REG64 & ~b))
2655 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002656
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002657 if (!(REG16 & ~i))
2658 valid &= 16;
2659 if (!(REG32 & ~i))
2660 valid &= 32;
2661 if (!(REG64 & ~i))
2662 valid &= 64;
2663 }
2664 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002665 }
2666
2667 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002668 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002669 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002670 /* Add an address size prefix */
2671 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2672 ins->prefixes[PPS_ASIZE] = pref;
2673 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002674 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002675 /* Impossible... */
2676 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2677 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002678 }
2679
2680 defdisp = ins->addr_size == 16 ? 16 : 32;
2681
2682 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002683 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2684 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2685 /*
2686 * mem_offs sizes must match the address size; if not,
2687 * strip the MEM_OFFS bit and match only EA instructions
2688 */
2689 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2690 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002691 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002692}