blob: 91a45d548aa7f2284c01efd8543e86b1f5a0faf4 [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* assemble.c code generation for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
Beroset095e6a22007-12-29 09:44:23 -05005 * redistributable under the license given in the file "LICENSE"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 * distributed in the NASM archive.
7 *
8 * the actual codes (C syntax, i.e. octal):
9 * \0 - terminates the code. (Unless it's a literal of course.)
10 * \1, \2, \3 - that many literal bytes follow in the code stream
11 * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS
12 * (POP is never used for CS) depending on operand 0
13 * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending
14 * on operand 0
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070015 * \10..\13 - a literal byte follows in the code stream, to be added
16 * to the register value of operand 0..3
17 * \14..\17 - a signed byte immediate operand, from operand 0..3
18 * \20..\23 - a byte immediate operand, from operand 0..3
19 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
20 * \30..\33 - a word immediate operand, from operand 0..3
21 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000022 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070023 * \40..\43 - a long immediate operand, from operand 0..3
24 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070025 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070026 * \50..\53 - a byte relative operand, from operand 0..3
27 * \54..\57 - a qword immediate operand, from operand 0..3
28 * \60..\63 - a word relative operand, from operand 0..3
29 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000030 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070031 * \70..\73 - a long relative operand, from operand 0..3
32 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070035 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080036 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
37 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080039 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070040 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070047 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070048 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070049 * the 4-bit immediate from operand b in bits 3..0.
H. Peter Anvind58656f2008-05-06 20:11:14 -070050 * \173\xab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070051 * the value b in bits 3..0.
52 * \174\a - the register number from operand a in bits 7..4, and
53 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000054 * \2ab - a ModRM, calculated on EA in operand a, with the spare
55 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070056 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
57 * is not equal to the truncated and sign-extended 32-bit
58 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070059 * \260..\263 - this instruction uses VEX rather than REX, with the
60 * V field taken from operand 0..3.
61 * \270 - this instruction uses VEX rather than REX, with the
62 * V field set to 1111b.
63 *
64 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070065 * \mm\wlp where mm is the M field; and wlp is:
66 * 00 0ww lpp
H. Peter Anvinbd420c72008-05-22 11:24:35 -070067 * [w0] ww = 0 for W = 0
68 * [w1] ww = 1 for W = 1
69 * [wx] ww = 2 for W don't care (always assembled as 0)
70 * [ww] ww = 3 for W used as REX.W
71 *
H. Peter Anvind85d2502008-05-04 17:53:31 -070072 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000073 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
74 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000075 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000076 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080077 * \314 - (disassembler only) invalid with REX.B
78 * \315 - (disassembler only) invalid with REX.X
79 * \316 - (disassembler only) invalid with REX.R
80 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000081 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
82 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
83 * \322 - indicates that this instruction is only valid when the
84 * operand size is the default (instruction to disassembler,
85 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000086 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000087 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000088 * \330 - a literal byte follows in the code stream, to be added
89 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000090 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000091 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070092 * \332 - REP prefix (0xF2 byte) used as opcode extension.
93 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000094 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070095 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -070096 * \336 - force a REP(E) prefix (0xF2) even if not specified.
97 * \337 - force a REPNE prefix (0xF3) even if not specified.
98 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +000099 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000100 * Operand 0 had better be a segmentless constant.
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700101 * \360 - no SSE prefix (== \364\331)
102 * \361 - 66 SSE prefix (== \366\331)
103 * \362 - F2 SSE prefix (== \364\332)
104 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000105 * \364 - operand-size prefix (0x66) not permitted
106 * \365 - address-size prefix (0x67) not permitted
107 * \366 - operand-size prefix (0x66) used as opcode extension
108 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000109 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
110 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000111 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
112 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113 */
114
H. Peter Anvinfe501952007-10-02 21:53:51 -0700115#include "compiler.h"
116
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000117#include <stdio.h>
118#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000119#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120
121#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000122#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123#include "assemble.h"
124#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700125#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000126
H. Peter Anvindfb91802008-05-20 11:43:53 -0700127/* Initialized to zero by the C standard */
128static const uint8_t const_zero_buf[256];
129
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000131 int sib_present; /* is a SIB byte necessary? */
132 int bytes; /* # of bytes of offset needed */
133 int size; /* lazy - this is sib+bytes+1 */
134 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000135} ea;
136
Keith Kaniosb7a89542007-04-12 02:40:54 +0000137static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000138static efunc errfunc;
139static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000140static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000141
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700142static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
143static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000144static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000145static int32_t regflag(const operand *);
146static int32_t regval(const operand *);
147static int rexflags(int, int32_t, int);
148static int op_rexflags(const operand *, int);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700149static ea *process_ea(operand *, ea *, int, int, int, int32_t);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700150static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000151
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700152static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000153{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700154 return ins->prefixes[pos] == prefix;
155}
156
157static void assert_no_prefix(insn * ins, enum prefix_pos pos)
158{
159 if (ins->prefixes[pos])
160 errfunc(ERR_NONFATAL, "invalid %s prefix",
161 prefix_name(ins->prefixes[pos]));
162}
163
164static const char *size_name(int size)
165{
166 switch (size) {
167 case 1:
168 return "byte";
169 case 2:
170 return "word";
171 case 4:
172 return "dword";
173 case 8:
174 return "qword";
175 case 10:
176 return "tword";
177 case 16:
178 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700179 case 32:
180 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700181 default:
182 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000183 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700184}
185
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700186static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700187{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700188 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800189 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000190
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700191 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700192 errfunc(ERR_WARNING | ERR_WARN_NOV,
193 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700194 }
195}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000196/*
197 * This routine wrappers the real output format's output routine,
198 * in order to pass a copy of the data off to the listing file
199 * generator at the same time.
200 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800201static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800202 enum out_type type, uint64_t size,
203 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000204{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000205 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000206 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800207 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000208
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800209 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
210 /*
211 * This is a non-relocated address, and we're going to
212 * convert it into RAWDATA format.
213 */
214 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800215
216 if (size > 8) {
217 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
218 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800219 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700220
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800221 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800222 data = p;
223 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000224 }
225
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800226 list->output(offset, data, type, size);
227
Frank Kotlerabebb082003-09-06 04:45:37 +0000228 /*
229 * this call to src_get determines when we call the
230 * debug-format-specific "linenum" function
231 * it updates lineno and lnfname to the current values
232 * returning 0 if "same as last time", -2 if lnfname
233 * changed, and the amount by which lineno changed,
234 * if it did. thus, these variables must be static
235 */
236
H. Peter Anvine2c80182005-01-15 22:15:51 +0000237 if (src_get(&lineno, &lnfname)) {
238 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000239 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000240
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800241 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000242}
243
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700244static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700245 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000246{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800247 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000248 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000249
Charles Craynef1aefd82008-09-30 16:11:32 -0700250 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700251 return false;
252 if (!optimizing)
253 return false;
254 if (optimizing < 0 && c == 0371)
255 return false;
256
H. Peter Anvine2c80182005-01-15 22:15:51 +0000257 isize = calcsize(segment, offset, bits, ins, code);
258 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700259 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000260
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700261 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
262 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000263}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000264
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800265int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000266 insn * instruction, struct ofmt *output, efunc error,
267 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000268{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000269 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000270 int j;
271 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800272 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000273 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800274 int64_t start = offset;
275 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000276
H. Peter Anvine2c80182005-01-15 22:15:51 +0000277 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000278 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000279 outfmt = output; /* likewise */
280 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000281
H. Peter Anvine2c80182005-01-15 22:15:51 +0000282 switch (instruction->opcode) {
283 case -1:
284 return 0;
285 case I_DB:
286 wsize = 1;
287 break;
288 case I_DW:
289 wsize = 2;
290 break;
291 case I_DD:
292 wsize = 4;
293 break;
294 case I_DQ:
295 wsize = 8;
296 break;
297 case I_DT:
298 wsize = 10;
299 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700300 case I_DO:
301 wsize = 16;
302 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700303 case I_DY:
304 wsize = 32;
305 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700306 default:
307 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000308 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000309
H. Peter Anvineba20a72002-04-30 20:53:55 +0000310 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000311 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000312 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313 if (t < 0)
314 errfunc(ERR_PANIC,
315 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000316
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 while (t--) { /* repeat TIMES times */
318 for (e = instruction->eops; e; e = e->next) {
319 if (e->type == EOT_DB_NUMBER) {
320 if (wsize == 1) {
321 if (e->segment != NO_SEG)
322 errfunc(ERR_NONFATAL,
323 "one-byte relocation attempted");
324 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000325 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000326 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800327 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000329 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700330 errfunc(ERR_NONFATAL,
331 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000332 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 } else
334 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800335 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000336 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700337 } else if (e->type == EOT_DB_STRING ||
338 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000339 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000340
H. Peter Anvine2c80182005-01-15 22:15:51 +0000341 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800342 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000343 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000344
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 if (align) {
346 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700347 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800348 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000349 }
350 offset += e->stringlen + align;
351 }
352 }
353 if (t > 0 && t == instruction->times - 1) {
354 /*
355 * Dummy call to list->output to give the offset to the
356 * listing module.
357 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800358 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 list->uplevel(LIST_TIMES);
360 }
361 }
362 if (instruction->times > 1)
363 list->downlevel(LIST_TIMES);
364 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000365 }
366
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700368 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000369 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000370
H. Peter Anvin418ca702008-05-30 10:42:30 -0700371 fp = fopen(fname, "rb");
372 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
374 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700375 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
377 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700378 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700379 static char buf[4096];
380 size_t t = instruction->times;
381 size_t base = 0;
382 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000383
H. Peter Anvine2c80182005-01-15 22:15:51 +0000384 len = ftell(fp);
385 if (instruction->eops->next) {
386 base = instruction->eops->next->offset;
387 len -= base;
388 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700389 len > (size_t)instruction->eops->next->next->offset)
390 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 }
392 /*
393 * Dummy call to list->output to give the offset to the
394 * listing module.
395 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800396 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000397 list->uplevel(LIST_INCBIN);
398 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700399 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000400
H. Peter Anvine2c80182005-01-15 22:15:51 +0000401 fseek(fp, base, SEEK_SET);
402 l = len;
403 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000404 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700405 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000406 fp);
407 if (!m) {
408 /*
409 * This shouldn't happen unless the file
410 * actually changes while we are reading
411 * it.
412 */
413 error(ERR_NONFATAL,
414 "`incbin': unexpected EOF while"
415 " reading file `%s'", fname);
416 t = 0; /* Try to exit cleanly */
417 break;
418 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800419 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000420 NO_SEG, NO_SEG);
421 l -= m;
422 }
423 }
424 list->downlevel(LIST_INCBIN);
425 if (instruction->times > 1) {
426 /*
427 * Dummy call to list->output to give the offset to the
428 * listing module.
429 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800430 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 list->uplevel(LIST_TIMES);
432 list->downlevel(LIST_TIMES);
433 }
434 fclose(fp);
435 return instruction->times * len;
436 }
437 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000438 }
439
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700440 /* Check to see if we need an address-size prefix */
441 add_asp(instruction, bits);
442
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700443 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700444
445 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000446 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700447 if (m == 100 ||
448 (m == 99 && jmp_match(segment, offset, bits,
449 instruction, temp->code))) {
450 /* Matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700451 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800452 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000453 instruction, codes);
454 itimes = instruction->times;
455 if (insn_size < 0) /* shouldn't be, on pass two */
456 error(ERR_PANIC, "errors made it through from pass one");
457 else
458 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700459 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000460 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000461 switch (instruction->prefixes[j]) {
462 case P_LOCK:
463 c = 0xF0;
464 break;
465 case P_REPNE:
466 case P_REPNZ:
467 c = 0xF2;
468 break;
469 case P_REPE:
470 case P_REPZ:
471 case P_REP:
472 c = 0xF3;
473 break;
474 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000475 if (bits == 64) {
476 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800477 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000478 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000479 c = 0x2E;
480 break;
481 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000482 if (bits == 64) {
483 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800484 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000485 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000486 c = 0x3E;
487 break;
488 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000489 if (bits == 64) {
490 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800491 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000492 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000493 c = 0x26;
494 break;
495 case R_FS:
496 c = 0x64;
497 break;
498 case R_GS:
499 c = 0x65;
500 break;
501 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000502 if (bits == 64) {
503 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800504 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000505 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000506 c = 0x36;
507 break;
508 case R_SEGR6:
509 case R_SEGR7:
510 error(ERR_NONFATAL,
511 "segr6 and segr7 cannot be used as prefixes");
512 break;
513 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000514 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000515 error(ERR_NONFATAL,
516 "16-bit addressing is not supported "
517 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700518 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000519 c = 0x67;
520 break;
521 case P_A32:
522 if (bits != 32)
523 c = 0x67;
524 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700525 case P_A64:
526 if (bits != 64) {
527 error(ERR_NONFATAL,
528 "64-bit addressing is only supported "
529 "in 64-bit mode");
530 }
531 break;
532 case P_ASP:
533 c = 0x67;
534 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000535 case P_O16:
536 if (bits != 16)
537 c = 0x66;
538 break;
539 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000540 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000541 c = 0x66;
542 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700543 case P_O64:
544 /* REX.W */
545 break;
546 case P_OSP:
547 c = 0x66;
548 break;
549 case P_none:
550 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000551 default:
552 error(ERR_PANIC, "invalid instruction prefix");
553 }
554 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800555 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000556 NO_SEG, NO_SEG);
557 offset++;
558 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700559 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000560 insn_end = offset + insn_size;
561 gencode(segment, offset, bits, instruction, codes,
562 insn_end);
563 offset += insn_size;
564 if (itimes > 0 && itimes == instruction->times - 1) {
565 /*
566 * Dummy call to list->output to give the offset to the
567 * listing module.
568 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800569 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000570 list->uplevel(LIST_TIMES);
571 }
572 }
573 if (instruction->times > 1)
574 list->downlevel(LIST_TIMES);
575 return offset - start;
576 } else if (m > 0 && m > size_prob) {
577 size_prob = m;
578 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000579 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000580
H. Peter Anvine2c80182005-01-15 22:15:51 +0000581 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000582 switch (size_prob) {
583 case 1:
584 error(ERR_NONFATAL, "operation size not specified");
585 break;
586 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000587 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000588 break;
589 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000590 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000591 break;
592 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000593 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000594 break;
595 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000596 error(ERR_NONFATAL,
597 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000598 break;
599 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000600 }
601 return 0;
602}
603
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800604int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000605 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000606{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000607 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000608
H. Peter Anvine2c80182005-01-15 22:15:51 +0000609 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000610 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000611
612 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000613 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000614
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700615 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
616 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700617 instruction->opcode == I_DT || instruction->opcode == I_DO ||
618 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000619 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000620 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000621
H. Peter Anvine2c80182005-01-15 22:15:51 +0000622 isize = 0;
623 switch (instruction->opcode) {
624 case I_DB:
625 wsize = 1;
626 break;
627 case I_DW:
628 wsize = 2;
629 break;
630 case I_DD:
631 wsize = 4;
632 break;
633 case I_DQ:
634 wsize = 8;
635 break;
636 case I_DT:
637 wsize = 10;
638 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700639 case I_DO:
640 wsize = 16;
641 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700642 case I_DY:
643 wsize = 32;
644 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700645 default:
646 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000647 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000648
H. Peter Anvine2c80182005-01-15 22:15:51 +0000649 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000650 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000651
H. Peter Anvine2c80182005-01-15 22:15:51 +0000652 osize = 0;
653 if (e->type == EOT_DB_NUMBER)
654 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700655 else if (e->type == EOT_DB_STRING ||
656 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000658
H. Peter Anvine2c80182005-01-15 22:15:51 +0000659 align = (-osize) % wsize;
660 if (align < 0)
661 align += wsize;
662 isize += osize + align;
663 }
664 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000665 }
666
H. Peter Anvine2c80182005-01-15 22:15:51 +0000667 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700668 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700670 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000671
H. Peter Anvin418ca702008-05-30 10:42:30 -0700672 fp = fopen(fname, "rb");
673 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
675 fname);
676 else if (fseek(fp, 0L, SEEK_END) < 0)
677 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
678 fname);
679 else {
680 len = ftell(fp);
681 fclose(fp);
682 if (instruction->eops->next) {
683 len -= instruction->eops->next->offset;
684 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700685 len > (size_t)instruction->eops->next->next->offset) {
686 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 }
688 }
689 return instruction->times * len;
690 }
691 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000692 }
693
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700694 /* Check to see if we need an address-size prefix */
695 add_asp(instruction, bits);
696
Keith Kaniosb7a89542007-04-12 02:40:54 +0000697 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
698 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700699 if (m == 100 ||
700 (m == 99 && jmp_match(segment, offset, bits,
701 instruction, temp->code))) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800703 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700704 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000705 int j;
706
707 isize = calcsize(segment, offset, bits, instruction, codes);
708 if (isize < 0)
709 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700710 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700711 switch (instruction->prefixes[j]) {
712 case P_A16:
713 if (bits != 16)
714 isize++;
715 break;
716 case P_A32:
717 if (bits != 32)
718 isize++;
719 break;
720 case P_O16:
721 if (bits != 16)
722 isize++;
723 break;
724 case P_O32:
725 if (bits == 16)
726 isize++;
727 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700728 case P_A64:
729 case P_O64:
730 case P_none:
731 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700732 default:
733 isize++;
734 break;
735 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000736 }
737 return isize * instruction->times;
738 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000739 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000740 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000741}
742
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700743static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000744{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700745 return !(o->opflags & OPFLAG_FORWARD) &&
746 optimizing >= 0 && !(o->type & STRICT) &&
747 o->wrt == NO_SEG && o->segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000748}
749
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700750/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700751static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700752{
753 int16_t v;
754
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700755 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700756 return false;
757
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700758 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700759 return v >= -128 && v <= 127;
760}
761
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700762static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700763{
764 int32_t v;
765
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700766 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700767 return false;
768
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
773/* check that opn[op] is a signed byte of size 32; warn if this is not
774 the original value when extended to 64 bits */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700775static bool is_sbyte64(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700776{
777 int64_t v64;
778 int32_t v32;
779
780 /* dead in the water on forward reference or External */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700781 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700782 return false;
783
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700784 v64 = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700785 v32 = (int32_t)v64;
786
787 warn_overflow(32, v64);
788
789 return v32 >= -128 && v32 <= 127;
790}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800791static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700792 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000793{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800794 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000795 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000796 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700797 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000798
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700799 ins->rex = 0; /* Ensure REX is reset */
800
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700801 if (ins->prefixes[PPS_OSIZE] == P_O64)
802 ins->rex |= REX_W;
803
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) {
808 c = *codes++;
809 opx = &ins->oprs[c & 3];
810 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000811 case 01:
812 case 02:
813 case 03:
814 codes += c, length += c;
815 break;
816 case 04:
817 case 05:
818 case 06:
819 case 07:
820 length++;
821 break;
822 case 010:
823 case 011:
824 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700825 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000826 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700827 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000828 codes++, length++;
829 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000830 case 014:
831 case 015:
832 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700833 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000834 length++;
835 break;
836 case 020:
837 case 021:
838 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700839 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000840 length++;
841 break;
842 case 024:
843 case 025:
844 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700845 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000846 length++;
847 break;
848 case 030:
849 case 031:
850 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700851 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000852 length += 2;
853 break;
854 case 034:
855 case 035:
856 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700857 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700858 if (opx->type & (BITS16 | BITS32 | BITS64))
859 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000860 else
861 length += (bits == 16) ? 2 : 4;
862 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000863 case 040:
864 case 041:
865 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700866 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 length += 4;
868 break;
869 case 044:
870 case 045:
871 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700872 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700873 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 break;
875 case 050:
876 case 051:
877 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700878 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 length++;
880 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000881 case 054:
882 case 055:
883 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700884 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000885 length += 8; /* MOV reg64/imm */
886 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000887 case 060:
888 case 061:
889 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700890 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000891 length += 2;
892 break;
893 case 064:
894 case 065:
895 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700896 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700897 if (opx->type & (BITS16 | BITS32 | BITS64))
898 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000899 else
900 length += (bits == 16) ? 2 : 4;
901 break;
902 case 070:
903 case 071:
904 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700905 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000906 length += 4;
907 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700908 case 074:
909 case 075:
910 case 076:
911 case 077:
912 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000913 break;
914 case 0140:
915 case 0141:
916 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700917 case 0143:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700918 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000919 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000920 case 0144:
921 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700922 case 0146:
923 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800924 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000925 length++;
926 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700927 case 0150:
928 case 0151:
929 case 0152:
930 case 0153:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700931 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700932 break;
933 case 0154:
934 case 0155:
935 case 0156:
936 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800937 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700938 length++;
939 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700940 case 0160:
941 case 0161:
942 case 0162:
943 case 0163:
944 length++;
945 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700946 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700947 break;
948 case 0164:
949 case 0165:
950 case 0166:
951 case 0167:
952 length++;
953 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700954 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700955 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700956 case 0171:
957 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700958 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700959 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700960 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700961 codes++;
962 length++;
963 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700964 case 0250:
965 case 0251:
966 case 0252:
967 case 0253:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700968 length += is_sbyte64(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700969 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700970 case 0260:
971 case 0261:
972 case 0262:
973 case 0263:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700974 ins->rex |= REX_V;
975 ins->drexdst = regval(opx);
976 ins->vex_m = *codes++;
977 ins->vex_wlp = *codes++;
978 break;
979 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700980 ins->rex |= REX_V;
981 ins->drexdst = 0;
982 ins->vex_m = *codes++;
983 ins->vex_wlp = *codes++;
984 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000985 case 0300:
986 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700987 case 0302:
988 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000989 break;
990 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700991 if (bits == 64)
992 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700993 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000994 break;
995 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700996 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000997 break;
998 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700999 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001000 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001001 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1002 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001003 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001005 case 0314:
1006 case 0315:
1007 case 0316:
1008 case 0317:
1009 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001010 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001011 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001012 break;
1013 case 0321:
1014 length += (bits == 16);
1015 break;
1016 case 0322:
1017 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001018 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001019 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001020 break;
1021 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001022 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001023 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001024 case 0330:
1025 codes++, length++;
1026 break;
1027 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001028 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001029 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001030 case 0333:
1031 length++;
1032 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001033 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001034 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001035 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001036 case 0335:
1037 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001038 case 0336:
1039 if (!ins->prefixes[PPS_LREP])
1040 ins->prefixes[PPS_LREP] = P_REP;
1041 break;
1042 case 0337:
1043 if (!ins->prefixes[PPS_LREP])
1044 ins->prefixes[PPS_LREP] = P_REPNE;
1045 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001046 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 if (ins->oprs[0].segment != NO_SEG)
1048 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1049 " quantity of BSS space");
1050 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001051 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001052 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001053 case 0360:
1054 break;
1055 case 0361:
1056 case 0362:
1057 case 0363:
1058 length++;
1059 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001060 case 0364:
1061 case 0365:
1062 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001063 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001064 case 0367:
1065 length++;
1066 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001067 case 0370:
1068 case 0371:
1069 case 0372:
1070 break;
1071 case 0373:
1072 length++;
1073 break;
1074 default: /* can't do it by 'case' statements */
1075 if (c >= 0100 && c <= 0277) { /* it's an EA */
1076 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001077 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001078 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001079 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001080
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001081 if (c <= 0177) {
1082 /* pick rfield from operand b */
1083 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001084 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001085 } else {
1086 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001087 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001088 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001089
H. Peter Anvine2c80182005-01-15 22:15:51 +00001090 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001091 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001092 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001093 errfunc(ERR_NONFATAL, "invalid effective address");
1094 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001095 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001096 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001097 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001098 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001099 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001100 errfunc(ERR_PANIC, "internal instruction table corrupt"
1101 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001102 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001103 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001104 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001105
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001106 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001107
H. Peter Anvind85d2502008-05-04 17:53:31 -07001108 if (ins->rex & REX_V) {
1109 int bad32 = REX_R|REX_W|REX_X|REX_B;
1110
1111 if (ins->rex & REX_H) {
1112 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1113 return -1;
1114 }
1115 switch (ins->vex_wlp & 030) {
1116 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001117 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001118 ins->rex &= ~REX_W;
1119 break;
1120 case 010:
1121 ins->rex |= REX_W;
1122 bad32 &= ~REX_W;
1123 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001124 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001125 /* Follow REX_W */
1126 break;
1127 }
1128
1129 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1130 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1131 return -1;
1132 }
1133 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1134 length += 3;
1135 else
1136 length += 2;
1137 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001138 if (ins->rex & REX_H) {
1139 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1140 return -1;
1141 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001142 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001143 ins->drexdst > 7)) {
1144 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1145 return -1;
1146 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001147 length++;
1148 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001149 if (ins->rex & REX_H) {
1150 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1151 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001152 } else if (bits == 64) {
1153 length++;
1154 } else if ((ins->rex & REX_L) &&
1155 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1156 cpu >= IF_X86_64) {
1157 /* LOCK-as-REX.R */
1158 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001159 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001160 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001161 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1162 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001163 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001164 }
1165
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001166 return length;
1167}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001168
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001169#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001170 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001171 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001172 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001173 ins->rex = 0; \
1174 offset += 1; \
1175 }
1176
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001177static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001178 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001179{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001180 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001181 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1182 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1183 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001184 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001185 uint8_t c;
1186 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001187 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001188 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001189 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001190
H. Peter Anvin839eca22007-10-29 23:12:47 -07001191 while (*codes) {
1192 c = *codes++;
1193 opx = &ins->oprs[c & 3];
1194 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001195 case 01:
1196 case 02:
1197 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001198 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001199 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001200 codes += c;
1201 offset += c;
1202 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001203
H. Peter Anvine2c80182005-01-15 22:15:51 +00001204 case 04:
1205 case 06:
1206 switch (ins->oprs[0].basereg) {
1207 case R_CS:
1208 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1209 break;
1210 case R_DS:
1211 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1212 break;
1213 case R_ES:
1214 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1215 break;
1216 case R_SS:
1217 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1218 break;
1219 default:
1220 errfunc(ERR_PANIC,
1221 "bizarre 8086 segment register received");
1222 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001223 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001224 offset++;
1225 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001226
H. Peter Anvine2c80182005-01-15 22:15:51 +00001227 case 05:
1228 case 07:
1229 switch (ins->oprs[0].basereg) {
1230 case R_FS:
1231 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1232 break;
1233 case R_GS:
1234 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1235 break;
1236 default:
1237 errfunc(ERR_PANIC,
1238 "bizarre 386 segment register received");
1239 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001240 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001241 offset++;
1242 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001243
H. Peter Anvine2c80182005-01-15 22:15:51 +00001244 case 010:
1245 case 011:
1246 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001247 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001248 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001249 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001250 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001251 offset += 1;
1252 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001253
H. Peter Anvine2c80182005-01-15 22:15:51 +00001254 case 014:
1255 case 015:
1256 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001257 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001258 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001259 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001260 errfunc(ERR_WARNING | ERR_WARN_NOV,
1261 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001262 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001263
H. Peter Anvin839eca22007-10-29 23:12:47 -07001264 if (opx->segment != NO_SEG) {
1265 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001266 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001267 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001268 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001269 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001270 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001271 NO_SEG);
1272 }
1273 offset += 1;
1274 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001275
H. Peter Anvine2c80182005-01-15 22:15:51 +00001276 case 020:
1277 case 021:
1278 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001279 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001280 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001281 errfunc(ERR_WARNING | ERR_WARN_NOV,
1282 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 if (opx->segment != NO_SEG) {
1285 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001286 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001287 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001288 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001289 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001290 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001291 NO_SEG);
1292 }
1293 offset += 1;
1294 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001295
H. Peter Anvine2c80182005-01-15 22:15:51 +00001296 case 024:
1297 case 025:
1298 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001299 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001301 errfunc(ERR_WARNING | ERR_WARN_NOV,
1302 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001303 if (opx->segment != NO_SEG) {
1304 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001305 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001307 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001309 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001310 NO_SEG);
1311 }
1312 offset += 1;
1313 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001314
H. Peter Anvine2c80182005-01-15 22:15:51 +00001315 case 030:
1316 case 031:
1317 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001318 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001319 data = opx->offset;
1320 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001321 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001322 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001323 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 offset += 2;
1325 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001326
H. Peter Anvine2c80182005-01-15 22:15:51 +00001327 case 034:
1328 case 035:
1329 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001330 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 if (opx->type & (BITS16 | BITS32))
1332 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001333 else
1334 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001335 data = opx->offset;
1336 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001337 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001338 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001339 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 offset += size;
1341 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001342
H. Peter Anvine2c80182005-01-15 22:15:51 +00001343 case 040:
1344 case 041:
1345 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001346 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001348 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1349 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001350 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001351 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001352 offset += 4;
1353 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001354
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 case 044:
1356 case 045:
1357 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001358 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001360 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 if (opx->segment == NO_SEG &&
1362 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001363 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001364 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001365 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001366 offset += size;
1367 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001368
H. Peter Anvine2c80182005-01-15 22:15:51 +00001369 case 050:
1370 case 051:
1371 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001372 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001373 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 errfunc(ERR_NONFATAL,
1375 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001376 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 if (data > 127 || data < -128)
1378 errfunc(ERR_NONFATAL, "short jump is out of range");
1379 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001380 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001381 offset += 1;
1382 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001383
Keith Kaniosb7a89542007-04-12 02:40:54 +00001384 case 054:
1385 case 055:
1386 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001387 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001388 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001389 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001390 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001391 offset += 8;
1392 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001393
H. Peter Anvine2c80182005-01-15 22:15:51 +00001394 case 060:
1395 case 061:
1396 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001397 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 if (opx->segment != segment) {
1399 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001400 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001401 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001402 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001403 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001404 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001405 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001406 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 }
1408 offset += 2;
1409 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001410
H. Peter Anvine2c80182005-01-15 22:15:51 +00001411 case 064:
1412 case 065:
1413 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001414 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001415 if (opx->type & (BITS16 | BITS32 | BITS64))
1416 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001417 else
1418 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001419 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001421 out(offset, segment, &data,
1422 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1423 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001424 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001425 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001426 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001427 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 }
1429 offset += size;
1430 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001431
H. Peter Anvine2c80182005-01-15 22:15:51 +00001432 case 070:
1433 case 071:
1434 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001435 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001436 if (opx->segment != segment) {
1437 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001438 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001439 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001440 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001441 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001442 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001443 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001444 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001445 }
1446 offset += 4;
1447 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001448
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001449 case 074:
1450 case 075:
1451 case 076:
1452 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001453 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001454 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1455 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001456 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001457 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001458 outfmt->segbase(1 + opx->segment),
1459 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001460 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001461 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001462
H. Peter Anvine2c80182005-01-15 22:15:51 +00001463 case 0140:
1464 case 0141:
1465 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001466 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001467 data = opx->offset;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001468 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001469 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001470 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001471 NO_SEG);
1472 offset++;
1473 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001474 if (opx->segment == NO_SEG &&
1475 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001476 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001477 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001478 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001479 offset += 2;
1480 }
1481 break;
1482
1483 case 0144:
1484 case 0145:
1485 case 0146:
1486 case 0147:
1487 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001488 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001489 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001491 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001492 offset++;
1493 break;
1494
1495 case 0150:
1496 case 0151:
1497 case 0152:
1498 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001499 data = opx->offset;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001500 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001501 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001502 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001503 NO_SEG);
1504 offset++;
1505 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001506 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001507 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001508 offset += 4;
1509 }
1510 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001511
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001512 case 0154:
1513 case 0155:
1514 case 0156:
1515 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001516 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001517 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001518 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001519 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001520 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001521 offset++;
1522 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001523
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001524 case 0160:
1525 case 0161:
1526 case 0162:
1527 case 0163:
1528 case 0164:
1529 case 0165:
1530 case 0166:
1531 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001532 break;
1533
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001534 case 0171:
1535 bytes[0] =
1536 (ins->drexdst << 4) |
1537 (ins->rex & REX_OC ? 0x08 : 0) |
1538 (ins->rex & (REX_R|REX_X|REX_B));
1539 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001540 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001541 offset++;
1542 break;
1543
H. Peter Anvind85d2502008-05-04 17:53:31 -07001544 case 0172:
1545 c = *codes++;
1546 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001547 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001548 opx = &ins->oprs[c & 7];
1549 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1550 errfunc(ERR_NONFATAL,
1551 "non-absolute expression not permitted as argument %d",
1552 c & 7);
1553 } else {
1554 if (opx->offset & ~15) {
1555 errfunc(ERR_WARNING | ERR_WARN_NOV,
1556 "four-bit argument exceeds bounds");
1557 }
1558 bytes[0] |= opx->offset & 15;
1559 }
1560 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1561 offset++;
1562 break;
1563
H. Peter Anvind58656f2008-05-06 20:11:14 -07001564 case 0173:
1565 c = *codes++;
1566 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001567 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001568 bytes[0] |= c & 15;
1569 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1570 offset++;
1571 break;
1572
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001573 case 0174:
1574 c = *codes++;
1575 opx = &ins->oprs[c];
1576 bytes[0] = nasm_regvals[opx->basereg] << 4;
1577 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1578 offset++;
1579 break;
1580
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001581 case 0250:
1582 case 0251:
1583 case 0252:
1584 case 0253:
1585 data = opx->offset;
1586 /* is_sbyte32() is right here, we have already warned */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001587 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001588 bytes[0] = data;
1589 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1590 NO_SEG);
1591 offset++;
1592 } else {
1593 out(offset, segment, &data, OUT_ADDRESS, 4,
1594 opx->segment, opx->wrt);
1595 offset += 4;
1596 }
1597 break;
1598
H. Peter Anvind85d2502008-05-04 17:53:31 -07001599 case 0260:
1600 case 0261:
1601 case 0262:
1602 case 0263:
1603 case 0270:
1604 codes += 2;
1605 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1606 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001607 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001608 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001609 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001610 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1611 offset += 3;
1612 } else {
1613 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001614 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1615 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001616 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1617 offset += 2;
1618 }
1619 break;
1620
H. Peter Anvine2c80182005-01-15 22:15:51 +00001621 case 0300:
1622 case 0301:
1623 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001624 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001626
H. Peter Anvine2c80182005-01-15 22:15:51 +00001627 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001628 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001629 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001630 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001631 offset += 1;
1632 } else
1633 offset += 0;
1634 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001635
H. Peter Anvine2c80182005-01-15 22:15:51 +00001636 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001637 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001639 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001640 offset += 1;
1641 } else
1642 offset += 0;
1643 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001644
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 case 0312:
1646 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001647
Keith Kaniosb7a89542007-04-12 02:40:54 +00001648 case 0313:
1649 ins->rex = 0;
1650 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001651
H. Peter Anvin23440102007-11-12 21:02:33 -08001652 case 0314:
1653 case 0315:
1654 case 0316:
1655 case 0317:
1656 break;
1657
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001659 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001661 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001662 offset += 1;
1663 } else
1664 offset += 0;
1665 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001666
H. Peter Anvine2c80182005-01-15 22:15:51 +00001667 case 0321:
1668 if (bits == 16) {
1669 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001670 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 offset += 1;
1672 } else
1673 offset += 0;
1674 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001675
H. Peter Anvine2c80182005-01-15 22:15:51 +00001676 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001677 case 0323:
1678 break;
1679
Keith Kaniosb7a89542007-04-12 02:40:54 +00001680 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001681 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001683
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 case 0330:
1685 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001686 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 offset += 1;
1688 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001689
H. Peter Anvine2c80182005-01-15 22:15:51 +00001690 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001692
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001693 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001694 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001695 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001696 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001697 offset += 1;
1698 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001699
Keith Kanios48af1772007-08-17 07:37:52 +00001700 case 0334:
1701 if (ins->rex & REX_R) {
1702 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001703 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001704 offset += 1;
1705 }
1706 ins->rex &= ~(REX_L|REX_R);
1707 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001708
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001709 case 0335:
1710 break;
1711
H. Peter Anvin962e3052008-08-28 17:47:16 -07001712 case 0336:
1713 case 0337:
1714 break;
1715
H. Peter Anvine2c80182005-01-15 22:15:51 +00001716 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001717 if (ins->oprs[0].segment != NO_SEG)
1718 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1719 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001720 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001721 if (size > 0)
1722 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001723 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001724 offset += size;
1725 }
1726 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001727
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001728 case 0360:
1729 break;
1730
1731 case 0361:
1732 bytes[0] = 0x66;
1733 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1734 offset += 1;
1735 break;
1736
1737 case 0362:
1738 case 0363:
1739 bytes[0] = c - 0362 + 0xf2;
1740 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1741 offset += 1;
1742 break;
1743
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001744 case 0364:
1745 case 0365:
1746 break;
1747
Keith Kanios48af1772007-08-17 07:37:52 +00001748 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001749 case 0367:
1750 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001751 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001752 offset += 1;
1753 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001754
H. Peter Anvine2c80182005-01-15 22:15:51 +00001755 case 0370:
1756 case 0371:
1757 case 0372:
1758 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001759
H. Peter Anvine2c80182005-01-15 22:15:51 +00001760 case 0373:
1761 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001762 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001763 offset += 1;
1764 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001765
H. Peter Anvine2c80182005-01-15 22:15:51 +00001766 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001767 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001768 ea ea_data;
1769 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001770 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001771 uint8_t *p;
1772 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001773
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001774 if (c <= 0177) {
1775 /* pick rfield from operand b */
1776 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001777 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001778 } else {
1779 /* rfield is constant */
1780 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001781 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001782 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001783
1784 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001785 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001786 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001787 errfunc(ERR_NONFATAL, "invalid effective address");
1788 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001789
Charles Crayne7e975552007-11-03 22:06:13 -07001790
H. Peter Anvine2c80182005-01-15 22:15:51 +00001791 p = bytes;
1792 *p++ = ea_data.modrm;
1793 if (ea_data.sib_present)
1794 *p++ = ea_data.sib;
1795
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001796 /* DREX suffixes come between the SIB and the displacement */
1797 if (ins->rex & REX_D) {
1798 *p++ =
1799 (ins->drexdst << 4) |
1800 (ins->rex & REX_OC ? 0x08 : 0) |
1801 (ins->rex & (REX_R|REX_X|REX_B));
1802 ins->rex = 0;
1803 }
1804
H. Peter Anvine2c80182005-01-15 22:15:51 +00001805 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001806 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001807
1808 switch (ea_data.bytes) {
1809 case 0:
1810 break;
1811 case 1:
1812 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1813 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001814 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001815 ins->oprs[(c >> 3) & 7].segment,
1816 ins->oprs[(c >> 3) & 7].wrt);
1817 } else {
1818 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001819 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001820 NO_SEG, NO_SEG);
1821 }
1822 s++;
1823 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001824 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001825 case 2:
1826 case 4:
1827 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001828 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001829 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001830 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1831 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001832 ins->oprs[(c >> 3) & 7].segment,
1833 ins->oprs[(c >> 3) & 7].wrt);
1834 s += ea_data.bytes;
1835 break;
1836 }
1837 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001838 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001839 errfunc(ERR_PANIC, "internal instruction table corrupt"
1840 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001841 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001842 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001843 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001844}
1845
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001846static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001847{
1848 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1849 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1850 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001851 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001852}
1853
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001854static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001855{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001856 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1857 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001858 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001859 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001860}
1861
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001862static int op_rexflags(const operand * o, int mask)
1863{
1864 int32_t flags;
1865 int val;
1866
1867 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1868 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1869 }
1870
H. Peter Anvina4835d42008-05-20 14:21:29 -07001871 flags = nasm_reg_flags[o->basereg];
1872 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001873
1874 return rexflags(val, flags, mask);
1875}
1876
1877static int rexflags(int val, int32_t flags, int mask)
1878{
1879 int rex = 0;
1880
1881 if (val >= 8)
1882 rex |= REX_B|REX_X|REX_R;
1883 if (flags & BITS64)
1884 rex |= REX_W;
1885 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1886 rex |= REX_H;
1887 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1888 rex |= REX_P;
1889
1890 return rex & mask;
1891}
1892
H. Peter Anvin3360d792007-09-11 04:16:57 +00001893static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001894{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001895 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001896
1897 ret = 100;
1898
1899 /*
1900 * Check the opcode
1901 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001902 if (itemp->opcode != instruction->opcode)
1903 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001904
1905 /*
1906 * Count the operands
1907 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001908 if (itemp->operands != instruction->operands)
1909 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001910
1911 /*
1912 * Check that no spurious colons or TOs are present
1913 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001914 for (i = 0; i < itemp->operands; i++)
1915 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1916 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001917
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001918 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001919 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001920 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001921 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001922 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001923
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001924 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1925
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001926 switch (itemp->flags & IF_SMASK) {
1927 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001928 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001929 break;
1930 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001931 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001932 break;
1933 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001934 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001935 break;
1936 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001937 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001938 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001939 case IF_SO:
1940 size[i] = BITS128;
1941 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001942 case IF_SY:
1943 size[i] = BITS256;
1944 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001945 case IF_SZ:
1946 switch (bits) {
1947 case 16:
1948 size[i] = BITS16;
1949 break;
1950 case 32:
1951 size[i] = BITS32;
1952 break;
1953 case 64:
1954 size[i] = BITS64;
1955 break;
1956 }
1957 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001958 default:
1959 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001960 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001961 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001962 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001963 switch (itemp->flags & IF_SMASK) {
1964 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001965 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001966 break;
1967 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001968 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001969 break;
1970 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001971 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001972 break;
1973 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001974 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001975 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001976 case IF_SO:
1977 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001978 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001979 case IF_SY:
1980 asize = BITS256;
1981 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001982 case IF_SZ:
1983 switch (bits) {
1984 case 16:
1985 asize = BITS16;
1986 break;
1987 case 32:
1988 asize = BITS32;
1989 break;
1990 case 64:
1991 asize = BITS64;
1992 break;
1993 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001994 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001995 default:
1996 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001997 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001998 for (i = 0; i < MAX_OPERANDS; i++)
1999 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002000 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002001
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002002 /*
2003 * Check that the operand flags all match up
2004 */
2005 for (i = 0; i < itemp->operands; i++) {
2006 int32_t type = instruction->oprs[i].type;
2007 if (!(type & SIZE_MASK))
2008 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002009
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002010 if (itemp->opd[i] & SAME_AS) {
2011 int j = itemp->opd[i] & ~SAME_AS;
2012 if (type != instruction->oprs[j].type ||
2013 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2014 return 0;
2015 } else if (itemp->opd[i] & ~type ||
2016 ((itemp->opd[i] & SIZE_MASK) &&
2017 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2018 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2019 (type & SIZE_MASK))
2020 return 0;
2021 else
2022 return 1;
2023 }
2024 }
2025
2026 /*
2027 * Check operand sizes
2028 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002029 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002030 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2031 asize = 0;
2032 for (i = 0; i < oprs; i++) {
2033 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2034 int j;
2035 for (j = 0; j < oprs; j++)
2036 size[j] = asize;
2037 break;
2038 }
2039 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002040 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002041 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002042 }
2043
Keith Kaniosb7a89542007-04-12 02:40:54 +00002044 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002045 if (!(itemp->opd[i] & SIZE_MASK) &&
2046 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002047 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002048 }
2049
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002050 /*
2051 * Check template is okay at the set cpu level
2052 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002053 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002054 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002055
Keith Kaniosb7a89542007-04-12 02:40:54 +00002056 /*
2057 * Check if instruction is available in long mode
2058 */
2059 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2060 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002061
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002062 /*
2063 * Check if special handling needed for Jumps
2064 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002065 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002066 return 99;
2067
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002068 return ret;
2069}
2070
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002071static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002072 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002073{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002074 bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);
2075
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002076 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002077
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002078 /* REX flags for the rfield operand */
2079 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2080
Keith Kaniosb7a89542007-04-12 02:40:54 +00002081 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002082 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002083 int32_t f;
2084
2085 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002086 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002087 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002088 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002089 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002090
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002091 if (REG_EA & ~f)
2092 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002093
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002094 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2095
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002096 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002097 output->bytes = 0; /* no offset necessary either */
2098 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002099 } else { /* it's a memory reference */
2100 if (input->basereg == -1
2101 && (input->indexreg == -1 || input->scale == 0)) {
2102 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002103 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002104 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002105 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002106 scale = 0;
2107 index = 4;
2108 base = 5;
2109 output->sib = (scale << 6) | (index << 3) | base;
2110 output->bytes = 4;
2111 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002112 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002113 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002114 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002115 output->bytes = (addrbits != 16 ? 4 : 2);
2116 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002117 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002118 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002119 } else { /* it's an indirection */
2120 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002121 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002122 int hb = input->hintbase, ht = input->hinttype;
2123 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002124 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002125 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002126
H. Peter Anvine2c80182005-01-15 22:15:51 +00002127 if (s == 0)
2128 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002129
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002130 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002131 it = nasm_regvals[i];
2132 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002133 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002134 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002135 ix = 0;
2136 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002137
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002138 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002139 bt = nasm_regvals[b];
2140 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002141 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002142 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002143 bx = 0;
2144 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002145
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002146 /* check for a 32/64-bit memory reference... */
2147 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002148 /* it must be a 32/64-bit memory reference. Firstly we have
2149 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002150 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002151
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002152 if (it != -1) {
2153 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2154 sok &= ix;
2155 else
2156 return NULL;
2157 }
2158
2159 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002160 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002161 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002162 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002163 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002164 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002165 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002166
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002167 /* While we're here, ensure the user didn't specify
2168 WORD or QWORD. */
2169 if (input->disp_size == 16 || input->disp_size == 64)
2170 return NULL;
2171
2172 if (addrbits == 16 ||
2173 (addrbits == 32 && !(sok & BITS32)) ||
2174 (addrbits == 64 && !(sok & BITS64)))
2175 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002176
Keith Kaniosb7a89542007-04-12 02:40:54 +00002177 /* now reorganize base/index */
2178 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002179 ((hb == b && ht == EAH_NOTBASE)
2180 || (hb == i && ht == EAH_MAKEBASE))) {
2181 /* swap if hints say so */
2182 t = bt, bt = it, it = t;
2183 t = bx, bx = ix, ix = t;
2184 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002185 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002186 bt = -1, bx = 0, s++;
2187 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2188 /* make single reg base, unless hint */
2189 bt = it, bx = ix, it = -1, ix = 0;
2190 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002191 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002192 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002193 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002194 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002195 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002196 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002197 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002198 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002199 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002200 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002201 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002202 t = ix, ix = bx, bx = t;
2203 }
Keith Kanios48af1772007-08-17 07:37:52 +00002204 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002205 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002206 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002207
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002208 output->rex |= rexflags(it, ix, REX_X);
2209 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002210
Keith Kanios48af1772007-08-17 07:37:52 +00002211 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002212 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002213 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002214
Keith Kaniosb7a89542007-04-12 02:40:54 +00002215 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002216 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002217 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002218 } else {
2219 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002220 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002221 seg == NO_SEG && !forw_ref &&
2222 !(input->eaflags &
2223 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2224 mod = 0;
2225 else if (input->eaflags & EAF_BYTEOFFS ||
2226 (o >= -128 && o <= 127 && seg == NO_SEG
2227 && !forw_ref
2228 && !(input->eaflags & EAF_WORDOFFS)))
2229 mod = 1;
2230 else
2231 mod = 2;
2232 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002233
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002234 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002235 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2236 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002237 } else {
2238 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002239 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002240
Keith Kaniosb7a89542007-04-12 02:40:54 +00002241 if (it == -1)
2242 index = 4, s = 1;
2243 else
2244 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002245
H. Peter Anvine2c80182005-01-15 22:15:51 +00002246 switch (s) {
2247 case 1:
2248 scale = 0;
2249 break;
2250 case 2:
2251 scale = 1;
2252 break;
2253 case 4:
2254 scale = 2;
2255 break;
2256 case 8:
2257 scale = 3;
2258 break;
2259 default: /* then what the smeg is it? */
2260 return NULL; /* panic */
2261 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002262
Keith Kaniosb7a89542007-04-12 02:40:54 +00002263 if (bt == -1) {
2264 base = 5;
2265 mod = 0;
2266 } else {
2267 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002268 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002269 seg == NO_SEG && !forw_ref &&
2270 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002271 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2272 mod = 0;
2273 else if (input->eaflags & EAF_BYTEOFFS ||
2274 (o >= -128 && o <= 127 && seg == NO_SEG
2275 && !forw_ref
2276 && !(input->eaflags & EAF_WORDOFFS)))
2277 mod = 1;
2278 else
2279 mod = 2;
2280 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002281
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002282 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002283 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2284 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002285 output->sib = (scale << 6) | (index << 3) | base;
2286 }
2287 } else { /* it's 16-bit */
2288 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002289
Keith Kaniosb7a89542007-04-12 02:40:54 +00002290 /* check for 64-bit long mode */
2291 if (addrbits == 64)
2292 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002293
H. Peter Anvine2c80182005-01-15 22:15:51 +00002294 /* check all registers are BX, BP, SI or DI */
2295 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2296 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2297 && i != R_SI && i != R_DI))
2298 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002299
Keith Kaniosb7a89542007-04-12 02:40:54 +00002300 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002301 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002302 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002303
H. Peter Anvine2c80182005-01-15 22:15:51 +00002304 if (s != 1 && i != -1)
2305 return NULL; /* no can do, in 16-bit EA */
2306 if (b == -1 && i != -1) {
2307 int tmp = b;
2308 b = i;
2309 i = tmp;
2310 } /* swap */
2311 if ((b == R_SI || b == R_DI) && i != -1) {
2312 int tmp = b;
2313 b = i;
2314 i = tmp;
2315 }
2316 /* have BX/BP as base, SI/DI index */
2317 if (b == i)
2318 return NULL; /* shouldn't ever happen, in theory */
2319 if (i != -1 && b != -1 &&
2320 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2321 return NULL; /* invalid combinations */
2322 if (b == -1) /* pure offset: handled above */
2323 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002324
H. Peter Anvine2c80182005-01-15 22:15:51 +00002325 rm = -1;
2326 if (i != -1)
2327 switch (i * 256 + b) {
2328 case R_SI * 256 + R_BX:
2329 rm = 0;
2330 break;
2331 case R_DI * 256 + R_BX:
2332 rm = 1;
2333 break;
2334 case R_SI * 256 + R_BP:
2335 rm = 2;
2336 break;
2337 case R_DI * 256 + R_BP:
2338 rm = 3;
2339 break;
2340 } else
2341 switch (b) {
2342 case R_SI:
2343 rm = 4;
2344 break;
2345 case R_DI:
2346 rm = 5;
2347 break;
2348 case R_BP:
2349 rm = 6;
2350 break;
2351 case R_BX:
2352 rm = 7;
2353 break;
2354 }
2355 if (rm == -1) /* can't happen, in theory */
2356 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002357
H. Peter Anvine2c80182005-01-15 22:15:51 +00002358 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2359 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2360 mod = 0;
2361 else if (input->eaflags & EAF_BYTEOFFS ||
2362 (o >= -128 && o <= 127 && seg == NO_SEG
2363 && !forw_ref
2364 && !(input->eaflags & EAF_WORDOFFS)))
2365 mod = 1;
2366 else
2367 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002368
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002369 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002370 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002371 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002372 }
2373 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002374 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002375
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002376 output->size = 1 + output->sib_present + output->bytes;
2377 return output;
2378}
2379
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002380static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002381{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002382 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002383 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002384
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002385 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002386
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002387 switch (ins->prefixes[PPS_ASIZE]) {
2388 case P_A16:
2389 valid &= 16;
2390 break;
2391 case P_A32:
2392 valid &= 32;
2393 break;
2394 case P_A64:
2395 valid &= 64;
2396 break;
2397 case P_ASP:
2398 valid &= (addrbits == 32) ? 16 : 32;
2399 break;
2400 default:
2401 break;
2402 }
2403
2404 for (j = 0; j < ins->operands; j++) {
2405 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002406 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002407
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002408 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002409 if (ins->oprs[j].indexreg < EXPR_REG_START
2410 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002411 i = 0;
2412 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002413 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002414
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002415 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002416 if (ins->oprs[j].basereg < EXPR_REG_START
2417 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002418 b = 0;
2419 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002420 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002421
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002422 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002423 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002424
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002425 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002426 int ds = ins->oprs[j].disp_size;
2427 if ((addrbits != 64 && ds > 8) ||
2428 (addrbits == 64 && ds == 16))
2429 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002430 } else {
2431 if (!(REG16 & ~b))
2432 valid &= 16;
2433 if (!(REG32 & ~b))
2434 valid &= 32;
2435 if (!(REG64 & ~b))
2436 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002437
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002438 if (!(REG16 & ~i))
2439 valid &= 16;
2440 if (!(REG32 & ~i))
2441 valid &= 32;
2442 if (!(REG64 & ~i))
2443 valid &= 64;
2444 }
2445 }
2446 }
2447
2448 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002449 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002450 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002451 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002452 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002453 ins->prefixes[PPS_ASIZE] = pref;
2454 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002455 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002456 /* Impossible... */
2457 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002458 ins->addr_size = addrbits; /* Error recovery */
2459 }
2460
2461 defdisp = ins->addr_size == 16 ? 16 : 32;
2462
2463 for (j = 0; j < ins->operands; j++) {
2464 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2465 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2466 != ins->addr_size) {
2467 /* mem_offs sizes must match the address size; if not,
2468 strip the MEM_OFFS bit and match only EA instructions */
2469 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2470 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002471 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002472}