blob: d7e9eae7a4243d047f60ca922be237d1d75352b5 [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 *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700143static void gencode(int32_t segment, int64_t offset, int bits,
144 insn * ins, const struct itemplate *temp,
145 int64_t insn_end);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000146static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000147static int32_t regflag(const operand *);
148static int32_t regval(const operand *);
149static int rexflags(int, int32_t, int);
150static int op_rexflags(const operand *, int);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700151static ea *process_ea(operand *, ea *, int, int, int, int32_t);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700152static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000153
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700154static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000155{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700156 return ins->prefixes[pos] == prefix;
157}
158
159static void assert_no_prefix(insn * ins, enum prefix_pos pos)
160{
161 if (ins->prefixes[pos])
162 errfunc(ERR_NONFATAL, "invalid %s prefix",
163 prefix_name(ins->prefixes[pos]));
164}
165
166static const char *size_name(int size)
167{
168 switch (size) {
169 case 1:
170 return "byte";
171 case 2:
172 return "word";
173 case 4:
174 return "dword";
175 case 8:
176 return "qword";
177 case 10:
178 return "tword";
179 case 16:
180 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700181 case 32:
182 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700183 default:
184 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000185 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700186}
187
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700188static void warn_overflow(int size, const struct operand *o)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700189{
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700190 if (size < 8 && o->wrt == NO_SEG && o->segment == NO_SEG) {
Charles Craynedd462c82007-11-04 15:28:30 -0800191 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700192 int64_t data = o->offset;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000193
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700194 if (data < ~lim || data > lim)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700195 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700196 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700197 }
198}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000199/*
200 * This routine wrappers the real output format's output routine,
201 * in order to pass a copy of the data off to the listing file
202 * generator at the same time.
203 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800204static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800205 enum out_type type, uint64_t size,
206 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000207{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000208 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000209 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800210 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000211
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800212 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
213 /*
214 * This is a non-relocated address, and we're going to
215 * convert it into RAWDATA format.
216 */
217 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800218
219 if (size > 8) {
220 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
221 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800222 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700223
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800224 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800225 data = p;
226 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000227 }
228
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800229 list->output(offset, data, type, size);
230
Frank Kotlerabebb082003-09-06 04:45:37 +0000231 /*
232 * this call to src_get determines when we call the
233 * debug-format-specific "linenum" function
234 * it updates lineno and lnfname to the current values
235 * returning 0 if "same as last time", -2 if lnfname
236 * changed, and the amount by which lineno changed,
237 * if it did. thus, these variables must be static
238 */
239
H. Peter Anvine2c80182005-01-15 22:15:51 +0000240 if (src_get(&lineno, &lnfname)) {
241 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000242 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000243
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800244 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000245}
246
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700247static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700248 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000249{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800250 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000251 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000252
Charles Craynef1aefd82008-09-30 16:11:32 -0700253 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700254 return false;
255 if (!optimizing)
256 return false;
257 if (optimizing < 0 && c == 0371)
258 return false;
259
H. Peter Anvine2c80182005-01-15 22:15:51 +0000260 isize = calcsize(segment, offset, bits, ins, code);
261 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700262 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000263
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700264 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
265 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000266}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000267
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800268int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000269 insn * instruction, struct ofmt *output, efunc error,
270 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000271{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000272 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000273 int j;
274 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800275 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000276 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800277 int64_t start = offset;
278 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000279
H. Peter Anvine2c80182005-01-15 22:15:51 +0000280 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000281 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000282 outfmt = output; /* likewise */
283 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000284
H. Peter Anvine2c80182005-01-15 22:15:51 +0000285 switch (instruction->opcode) {
286 case -1:
287 return 0;
288 case I_DB:
289 wsize = 1;
290 break;
291 case I_DW:
292 wsize = 2;
293 break;
294 case I_DD:
295 wsize = 4;
296 break;
297 case I_DQ:
298 wsize = 8;
299 break;
300 case I_DT:
301 wsize = 10;
302 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700303 case I_DO:
304 wsize = 16;
305 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700306 case I_DY:
307 wsize = 32;
308 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700309 default:
310 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000311 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000312
H. Peter Anvineba20a72002-04-30 20:53:55 +0000313 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000314 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000315 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 if (t < 0)
317 errfunc(ERR_PANIC,
318 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000319
H. Peter Anvine2c80182005-01-15 22:15:51 +0000320 while (t--) { /* repeat TIMES times */
321 for (e = instruction->eops; e; e = e->next) {
322 if (e->type == EOT_DB_NUMBER) {
323 if (wsize == 1) {
324 if (e->segment != NO_SEG)
325 errfunc(ERR_NONFATAL,
326 "one-byte relocation attempted");
327 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000328 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000329 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800330 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000331 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000332 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700333 errfunc(ERR_NONFATAL,
334 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000335 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000336 } else
337 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800338 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000339 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700340 } else if (e->type == EOT_DB_STRING ||
341 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000343
H. Peter Anvine2c80182005-01-15 22:15:51 +0000344 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800345 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000346 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000347
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 if (align) {
349 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700350 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800351 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000352 }
353 offset += e->stringlen + align;
354 }
355 }
356 if (t > 0 && t == instruction->times - 1) {
357 /*
358 * Dummy call to list->output to give the offset to the
359 * listing module.
360 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800361 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000362 list->uplevel(LIST_TIMES);
363 }
364 }
365 if (instruction->times > 1)
366 list->downlevel(LIST_TIMES);
367 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000368 }
369
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700371 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000372 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000373
H. Peter Anvin418ca702008-05-30 10:42:30 -0700374 fp = fopen(fname, "rb");
375 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
377 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700378 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
380 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700381 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700382 static char buf[4096];
383 size_t t = instruction->times;
384 size_t base = 0;
385 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000386
H. Peter Anvine2c80182005-01-15 22:15:51 +0000387 len = ftell(fp);
388 if (instruction->eops->next) {
389 base = instruction->eops->next->offset;
390 len -= base;
391 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700392 len > (size_t)instruction->eops->next->next->offset)
393 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 }
395 /*
396 * Dummy call to list->output to give the offset to the
397 * listing module.
398 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800399 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000400 list->uplevel(LIST_INCBIN);
401 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700402 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000403
H. Peter Anvine2c80182005-01-15 22:15:51 +0000404 fseek(fp, base, SEEK_SET);
405 l = len;
406 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000407 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700408 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 fp);
410 if (!m) {
411 /*
412 * This shouldn't happen unless the file
413 * actually changes while we are reading
414 * it.
415 */
416 error(ERR_NONFATAL,
417 "`incbin': unexpected EOF while"
418 " reading file `%s'", fname);
419 t = 0; /* Try to exit cleanly */
420 break;
421 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800422 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000423 NO_SEG, NO_SEG);
424 l -= m;
425 }
426 }
427 list->downlevel(LIST_INCBIN);
428 if (instruction->times > 1) {
429 /*
430 * Dummy call to list->output to give the offset to the
431 * listing module.
432 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800433 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000434 list->uplevel(LIST_TIMES);
435 list->downlevel(LIST_TIMES);
436 }
437 fclose(fp);
438 return instruction->times * len;
439 }
440 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000441 }
442
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700443 /* Check to see if we need an address-size prefix */
444 add_asp(instruction, bits);
445
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700446 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700447
448 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000449 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700450 if (m == 100 ||
451 (m == 99 && jmp_match(segment, offset, bits,
452 instruction, temp->code))) {
453 /* Matches! */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800454 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -0700455 instruction, temp->code);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000456 itimes = instruction->times;
457 if (insn_size < 0) /* shouldn't be, on pass two */
458 error(ERR_PANIC, "errors made it through from pass one");
459 else
460 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700461 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000462 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000463 switch (instruction->prefixes[j]) {
464 case P_LOCK:
465 c = 0xF0;
466 break;
467 case P_REPNE:
468 case P_REPNZ:
469 c = 0xF2;
470 break;
471 case P_REPE:
472 case P_REPZ:
473 case P_REP:
474 c = 0xF3;
475 break;
476 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000477 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700478 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800479 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000480 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000481 c = 0x2E;
482 break;
483 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000484 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700485 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800486 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000487 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000488 c = 0x3E;
489 break;
490 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000491 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700492 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800493 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000494 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000495 c = 0x26;
496 break;
497 case R_FS:
498 c = 0x64;
499 break;
500 case R_GS:
501 c = 0x65;
502 break;
503 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000504 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700505 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800506 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000507 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000508 c = 0x36;
509 break;
510 case R_SEGR6:
511 case R_SEGR7:
512 error(ERR_NONFATAL,
513 "segr6 and segr7 cannot be used as prefixes");
514 break;
515 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000516 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000517 error(ERR_NONFATAL,
518 "16-bit addressing is not supported "
519 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700520 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000521 c = 0x67;
522 break;
523 case P_A32:
524 if (bits != 32)
525 c = 0x67;
526 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700527 case P_A64:
528 if (bits != 64) {
529 error(ERR_NONFATAL,
530 "64-bit addressing is only supported "
531 "in 64-bit mode");
532 }
533 break;
534 case P_ASP:
535 c = 0x67;
536 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000537 case P_O16:
538 if (bits != 16)
539 c = 0x66;
540 break;
541 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000542 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000543 c = 0x66;
544 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700545 case P_O64:
546 /* REX.W */
547 break;
548 case P_OSP:
549 c = 0x66;
550 break;
551 case P_none:
552 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000553 default:
554 error(ERR_PANIC, "invalid instruction prefix");
555 }
556 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800557 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000558 NO_SEG, NO_SEG);
559 offset++;
560 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700561 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000562 insn_end = offset + insn_size;
H. Peter Anvin833caea2008-10-04 19:02:30 -0700563 gencode(segment, offset, bits, instruction,
564 temp, insn_end);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000565 offset += insn_size;
566 if (itimes > 0 && itimes == instruction->times - 1) {
567 /*
568 * Dummy call to list->output to give the offset to the
569 * listing module.
570 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800571 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000572 list->uplevel(LIST_TIMES);
573 }
574 }
575 if (instruction->times > 1)
576 list->downlevel(LIST_TIMES);
577 return offset - start;
578 } else if (m > 0 && m > size_prob) {
579 size_prob = m;
580 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000581 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000582
H. Peter Anvine2c80182005-01-15 22:15:51 +0000583 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000584 switch (size_prob) {
585 case 1:
586 error(ERR_NONFATAL, "operation size not specified");
587 break;
588 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000589 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000590 break;
591 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000592 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000593 break;
594 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000595 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000596 break;
597 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000598 error(ERR_NONFATAL,
599 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000600 break;
601 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000602 }
603 return 0;
604}
605
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800606int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000607 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000608{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000609 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000610
H. Peter Anvine2c80182005-01-15 22:15:51 +0000611 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000612 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000613
614 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000615 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000616
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700617 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
618 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700619 instruction->opcode == I_DT || instruction->opcode == I_DO ||
620 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000621 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000622 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000623
H. Peter Anvine2c80182005-01-15 22:15:51 +0000624 isize = 0;
625 switch (instruction->opcode) {
626 case I_DB:
627 wsize = 1;
628 break;
629 case I_DW:
630 wsize = 2;
631 break;
632 case I_DD:
633 wsize = 4;
634 break;
635 case I_DQ:
636 wsize = 8;
637 break;
638 case I_DT:
639 wsize = 10;
640 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700641 case I_DO:
642 wsize = 16;
643 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700644 case I_DY:
645 wsize = 32;
646 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700647 default:
648 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000649 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000650
H. Peter Anvine2c80182005-01-15 22:15:51 +0000651 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000652 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000653
H. Peter Anvine2c80182005-01-15 22:15:51 +0000654 osize = 0;
655 if (e->type == EOT_DB_NUMBER)
656 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700657 else if (e->type == EOT_DB_STRING ||
658 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000659 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000660
H. Peter Anvine2c80182005-01-15 22:15:51 +0000661 align = (-osize) % wsize;
662 if (align < 0)
663 align += wsize;
664 isize += osize + align;
665 }
666 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000667 }
668
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700670 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700672 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000673
H. Peter Anvin418ca702008-05-30 10:42:30 -0700674 fp = fopen(fname, "rb");
675 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
677 fname);
678 else if (fseek(fp, 0L, SEEK_END) < 0)
679 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
680 fname);
681 else {
682 len = ftell(fp);
683 fclose(fp);
684 if (instruction->eops->next) {
685 len -= instruction->eops->next->offset;
686 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700687 len > (size_t)instruction->eops->next->next->offset) {
688 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 }
690 }
691 return instruction->times * len;
692 }
693 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000694 }
695
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700696 /* Check to see if we need an address-size prefix */
697 add_asp(instruction, bits);
698
Keith Kaniosb7a89542007-04-12 02:40:54 +0000699 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
700 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700701 if (m == 100 ||
702 (m == 99 && jmp_match(segment, offset, bits,
703 instruction, temp->code))) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000704 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800705 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700706 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000707 int j;
708
709 isize = calcsize(segment, offset, bits, instruction, codes);
710 if (isize < 0)
711 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700712 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700713 switch (instruction->prefixes[j]) {
714 case P_A16:
715 if (bits != 16)
716 isize++;
717 break;
718 case P_A32:
719 if (bits != 32)
720 isize++;
721 break;
722 case P_O16:
723 if (bits != 16)
724 isize++;
725 break;
726 case P_O32:
727 if (bits == 16)
728 isize++;
729 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700730 case P_A64:
731 case P_O64:
732 case P_none:
733 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700734 default:
735 isize++;
736 break;
737 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000738 }
739 return isize * instruction->times;
740 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000741 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000742 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000743}
744
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700745static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000746{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700747 return !(o->opflags & OPFLAG_FORWARD) &&
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700748 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000749}
750
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700751/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700752static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700753{
754 int16_t v;
755
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700756 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700757 return false;
758
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700759 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700760 return v >= -128 && v <= 127;
761}
762
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700763static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700764{
765 int32_t v;
766
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700767 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700768 return false;
769
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700770 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700771 return v >= -128 && v <= 127;
772}
773
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700774/* check that opn[op] is a signed byte of size 32; warn if this is not
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700775 the original value when extended to 64 bits */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700776static bool is_sbyte64(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700777{
778 int64_t v64;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700779 int32_t v;
780
781 if (!(o->wrt == NO_SEG && o->segment == NO_SEG))
782 return false; /* Not a pure immediate */
783
784 v64 = o->offset;
785 v = (int32_t)v64;
786
787 if (v64 != v)
788 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
789 "signed dword immediate exceeds bounds");
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700790
791 /* dead in the water on forward reference or External */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700792 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700793 return false;
794
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700795 v = o->offset;
796 return v >= -128 && v <= 127;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700797}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800798static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700799 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000800{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800801 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000802 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000803 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700804 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000805
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700806 ins->rex = 0; /* Ensure REX is reset */
807
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700808 if (ins->prefixes[PPS_OSIZE] == P_O64)
809 ins->rex |= REX_W;
810
H. Peter Anvine2c80182005-01-15 22:15:51 +0000811 (void)segment; /* Don't warn that this parameter is unused */
812 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000813
H. Peter Anvin839eca22007-10-29 23:12:47 -0700814 while (*codes) {
815 c = *codes++;
816 opx = &ins->oprs[c & 3];
817 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000818 case 01:
819 case 02:
820 case 03:
821 codes += c, length += c;
822 break;
823 case 04:
824 case 05:
825 case 06:
826 case 07:
827 length++;
828 break;
829 case 010:
830 case 011:
831 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700832 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000833 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700834 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000835 codes++, length++;
836 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 case 014:
838 case 015:
839 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700840 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000841 length++;
842 break;
843 case 020:
844 case 021:
845 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700846 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 length++;
848 break;
849 case 024:
850 case 025:
851 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700852 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000853 length++;
854 break;
855 case 030:
856 case 031:
857 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700858 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000859 length += 2;
860 break;
861 case 034:
862 case 035:
863 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700864 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700865 if (opx->type & (BITS16 | BITS32 | BITS64))
866 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 else
868 length += (bits == 16) ? 2 : 4;
869 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000870 case 040:
871 case 041:
872 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700873 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 length += 4;
875 break;
876 case 044:
877 case 045:
878 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700879 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700880 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 break;
882 case 050:
883 case 051:
884 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700885 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000886 length++;
887 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000888 case 054:
889 case 055:
890 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700891 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000892 length += 8; /* MOV reg64/imm */
893 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 case 060:
895 case 061:
896 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700897 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000898 length += 2;
899 break;
900 case 064:
901 case 065:
902 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700903 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700904 if (opx->type & (BITS16 | BITS32 | BITS64))
905 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000906 else
907 length += (bits == 16) ? 2 : 4;
908 break;
909 case 070:
910 case 071:
911 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700912 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000913 length += 4;
914 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700915 case 074:
916 case 075:
917 case 076:
918 case 077:
919 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000920 break;
921 case 0140:
922 case 0141:
923 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700924 case 0143:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700925 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000926 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000927 case 0144:
928 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700929 case 0146:
930 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800931 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000932 length++;
933 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700934 case 0150:
935 case 0151:
936 case 0152:
937 case 0153:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700938 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700939 break;
940 case 0154:
941 case 0155:
942 case 0156:
943 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800944 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700945 length++;
946 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700947 case 0160:
948 case 0161:
949 case 0162:
950 case 0163:
951 length++;
952 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700953 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700954 break;
955 case 0164:
956 case 0165:
957 case 0166:
958 case 0167:
959 length++;
960 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700961 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700962 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700963 case 0171:
964 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700965 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700966 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700967 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700968 codes++;
969 length++;
970 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700971 case 0250:
972 case 0251:
973 case 0252:
974 case 0253:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700975 length += is_sbyte64(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700976 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700977 case 0260:
978 case 0261:
979 case 0262:
980 case 0263:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700981 ins->rex |= REX_V;
982 ins->drexdst = regval(opx);
983 ins->vex_m = *codes++;
984 ins->vex_wlp = *codes++;
985 break;
986 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700987 ins->rex |= REX_V;
988 ins->drexdst = 0;
989 ins->vex_m = *codes++;
990 ins->vex_wlp = *codes++;
991 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000992 case 0300:
993 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700994 case 0302:
995 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000996 break;
997 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700998 if (bits == 64)
999 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001000 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 break;
1002 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001003 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 break;
1005 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001006 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001007 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001008 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1009 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001010 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001011 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001012 case 0314:
1013 case 0315:
1014 case 0316:
1015 case 0317:
1016 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001017 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001018 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001019 break;
1020 case 0321:
1021 length += (bits == 16);
1022 break;
1023 case 0322:
1024 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001025 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001026 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001027 break;
1028 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001029 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001030 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001031 case 0330:
1032 codes++, length++;
1033 break;
1034 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001035 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001036 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001037 case 0333:
1038 length++;
1039 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001040 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001041 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001042 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001043 case 0335:
1044 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001045 case 0336:
1046 if (!ins->prefixes[PPS_LREP])
1047 ins->prefixes[PPS_LREP] = P_REP;
1048 break;
1049 case 0337:
1050 if (!ins->prefixes[PPS_LREP])
1051 ins->prefixes[PPS_LREP] = P_REPNE;
1052 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001053 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001054 if (ins->oprs[0].segment != NO_SEG)
1055 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1056 " quantity of BSS space");
1057 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001058 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001059 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001060 case 0360:
1061 break;
1062 case 0361:
1063 case 0362:
1064 case 0363:
1065 length++;
1066 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001067 case 0364:
1068 case 0365:
1069 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001070 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001071 case 0367:
1072 length++;
1073 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001074 case 0370:
1075 case 0371:
1076 case 0372:
1077 break;
1078 case 0373:
1079 length++;
1080 break;
1081 default: /* can't do it by 'case' statements */
1082 if (c >= 0100 && c <= 0277) { /* it's an EA */
1083 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001084 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001085 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001086 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001087
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001088 if (c <= 0177) {
1089 /* pick rfield from operand b */
1090 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001091 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001092 } else {
1093 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001094 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001095 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001096
H. Peter Anvine2c80182005-01-15 22:15:51 +00001097 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001098 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001099 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001100 errfunc(ERR_NONFATAL, "invalid effective address");
1101 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001102 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001103 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001104 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001105 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001106 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001107 errfunc(ERR_PANIC, "internal instruction table corrupt"
1108 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001109 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001110 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001111 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001112
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001113 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001114
H. Peter Anvind85d2502008-05-04 17:53:31 -07001115 if (ins->rex & REX_V) {
1116 int bad32 = REX_R|REX_W|REX_X|REX_B;
1117
1118 if (ins->rex & REX_H) {
1119 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1120 return -1;
1121 }
1122 switch (ins->vex_wlp & 030) {
1123 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001124 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001125 ins->rex &= ~REX_W;
1126 break;
1127 case 010:
1128 ins->rex |= REX_W;
1129 bad32 &= ~REX_W;
1130 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001131 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001132 /* Follow REX_W */
1133 break;
1134 }
1135
1136 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1137 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1138 return -1;
1139 }
1140 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1141 length += 3;
1142 else
1143 length += 2;
1144 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001145 if (ins->rex & REX_H) {
1146 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1147 return -1;
1148 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001149 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001150 ins->drexdst > 7)) {
1151 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1152 return -1;
1153 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001154 length++;
1155 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001156 if (ins->rex & REX_H) {
1157 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1158 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001159 } else if (bits == 64) {
1160 length++;
1161 } else if ((ins->rex & REX_L) &&
1162 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1163 cpu >= IF_X86_64) {
1164 /* LOCK-as-REX.R */
1165 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001166 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001167 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001168 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1169 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001170 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001171 }
1172
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001173 return length;
1174}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001175
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001176#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001177 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001178 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001179 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001180 ins->rex = 0; \
1181 offset += 1; \
1182 }
1183
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001184static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001185 insn * ins, const struct itemplate *temp,
1186 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001187{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001188 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001189 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1190 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1191 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001192 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001193 uint8_t c;
1194 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001195 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001196 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001197 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001198 const uint8_t *codes = temp->code;
H. Peter Anvin70653092007-10-19 14:42:29 -07001199
H. Peter Anvin839eca22007-10-29 23:12:47 -07001200 while (*codes) {
1201 c = *codes++;
1202 opx = &ins->oprs[c & 3];
1203 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001204 case 01:
1205 case 02:
1206 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001207 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001208 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001209 codes += c;
1210 offset += c;
1211 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001212
H. Peter Anvine2c80182005-01-15 22:15:51 +00001213 case 04:
1214 case 06:
1215 switch (ins->oprs[0].basereg) {
1216 case R_CS:
1217 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1218 break;
1219 case R_DS:
1220 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1221 break;
1222 case R_ES:
1223 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1224 break;
1225 case R_SS:
1226 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1227 break;
1228 default:
1229 errfunc(ERR_PANIC,
1230 "bizarre 8086 segment register received");
1231 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001232 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001233 offset++;
1234 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001235
H. Peter Anvine2c80182005-01-15 22:15:51 +00001236 case 05:
1237 case 07:
1238 switch (ins->oprs[0].basereg) {
1239 case R_FS:
1240 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1241 break;
1242 case R_GS:
1243 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1244 break;
1245 default:
1246 errfunc(ERR_PANIC,
1247 "bizarre 386 segment register received");
1248 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001249 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001250 offset++;
1251 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001252
H. Peter Anvine2c80182005-01-15 22:15:51 +00001253 case 010:
1254 case 011:
1255 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001256 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001257 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001258 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001259 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001260 offset += 1;
1261 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001262
H. Peter Anvine2c80182005-01-15 22:15:51 +00001263 case 014:
1264 case 015:
1265 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001266 case 017:
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001267 /* The test for BITS8 and SBYTE here is intended to avoid
1268 warning on optimizer actions due to SBYTE, while still
1269 warn on explicit BYTE directives. Also warn, obviously,
1270 if the optimizer isn't enabled. */
1271 if (((opx->type & BITS8) ||
H. Peter Anvin833caea2008-10-04 19:02:30 -07001272 !(opx->type & temp->opd[c & 3] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001273 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001274 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001275 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001276 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001277 if (opx->segment != NO_SEG) {
1278 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001279 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001280 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001283 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 NO_SEG);
1285 }
1286 offset += 1;
1287 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001288
H. Peter Anvine2c80182005-01-15 22:15:51 +00001289 case 020:
1290 case 021:
1291 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001292 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001293 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001294 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001295 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001296 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 if (opx->segment != NO_SEG) {
1298 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001299 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001302 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001303 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001304 NO_SEG);
1305 }
1306 offset += 1;
1307 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001308
H. Peter Anvine2c80182005-01-15 22:15:51 +00001309 case 024:
1310 case 025:
1311 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001312 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001313 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001314 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001315 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001316 if (opx->segment != NO_SEG) {
1317 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001318 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001319 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001320 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001322 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001323 NO_SEG);
1324 }
1325 offset += 1;
1326 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001327
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 case 030:
1329 case 031:
1330 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001331 case 033:
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001332 warn_overflow(2, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001334 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001335 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001336 offset += 2;
1337 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001338
H. Peter Anvine2c80182005-01-15 22:15:51 +00001339 case 034:
1340 case 035:
1341 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001342 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001343 if (opx->type & (BITS16 | BITS32))
1344 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001345 else
1346 size = (bits == 16) ? 2 : 4;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001347 warn_overflow(size, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001348 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001349 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 offset += size;
1352 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001353
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 case 040:
1355 case 041:
1356 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001357 case 043:
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001358 warn_overflow(4, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001360 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 offset += 4;
1363 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001364
H. Peter Anvine2c80182005-01-15 22:15:51 +00001365 case 044:
1366 case 045:
1367 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001368 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001370 size = ins->addr_size >> 3;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001371 warn_overflow(size, opx);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001372 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001373 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 offset += size;
1375 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001376
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 case 050:
1378 case 051:
1379 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001380 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001382 errfunc(ERR_NONFATAL,
1383 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001385 if (data > 127 || data < -128)
1386 errfunc(ERR_NONFATAL, "short jump is out of range");
1387 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001388 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001389 offset += 1;
1390 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001391
Keith Kaniosb7a89542007-04-12 02:40:54 +00001392 case 054:
1393 case 055:
1394 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001395 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001396 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001397 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001399 offset += 8;
1400 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001401
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 case 060:
1403 case 061:
1404 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001405 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 if (opx->segment != segment) {
1407 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001408 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001409 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001410 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001411 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001412 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001413 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001414 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001415 }
1416 offset += 2;
1417 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001418
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 case 064:
1420 case 065:
1421 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001422 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 if (opx->type & (BITS16 | BITS32 | BITS64))
1424 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 else
1426 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001427 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001428 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001429 out(offset, segment, &data,
1430 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1431 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001432 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001433 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001434 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001435 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 }
1437 offset += size;
1438 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001439
H. Peter Anvine2c80182005-01-15 22:15:51 +00001440 case 070:
1441 case 071:
1442 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001443 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001444 if (opx->segment != segment) {
1445 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001447 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001448 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001449 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001450 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001452 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001453 }
1454 offset += 4;
1455 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001456
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001457 case 074:
1458 case 075:
1459 case 076:
1460 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001461 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001462 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1463 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001464 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001465 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 outfmt->segbase(1 + opx->segment),
1467 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001468 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001470
H. Peter Anvine2c80182005-01-15 22:15:51 +00001471 case 0140:
1472 case 0141:
1473 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001474 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001475 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001476 warn_overflow(2, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001477 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001478 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001479 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001480 NO_SEG);
1481 offset++;
1482 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001483 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001484 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001485 offset += 2;
1486 }
1487 break;
1488
1489 case 0144:
1490 case 0145:
1491 case 0146:
1492 case 0147:
1493 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001494 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001495 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001496 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001497 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001498 offset++;
1499 break;
1500
1501 case 0150:
1502 case 0151:
1503 case 0152:
1504 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001505 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001506 warn_overflow(4, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001507 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001508 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001509 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001510 NO_SEG);
1511 offset++;
1512 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001513 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001514 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001515 offset += 4;
1516 }
1517 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001518
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001519 case 0154:
1520 case 0155:
1521 case 0156:
1522 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001523 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001524 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001525 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001526 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001527 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001528 offset++;
1529 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001530
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001531 case 0160:
1532 case 0161:
1533 case 0162:
1534 case 0163:
1535 case 0164:
1536 case 0165:
1537 case 0166:
1538 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001539 break;
1540
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001541 case 0171:
1542 bytes[0] =
1543 (ins->drexdst << 4) |
1544 (ins->rex & REX_OC ? 0x08 : 0) |
1545 (ins->rex & (REX_R|REX_X|REX_B));
1546 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001547 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001548 offset++;
1549 break;
1550
H. Peter Anvind85d2502008-05-04 17:53:31 -07001551 case 0172:
1552 c = *codes++;
1553 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001554 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001555 opx = &ins->oprs[c & 7];
1556 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1557 errfunc(ERR_NONFATAL,
1558 "non-absolute expression not permitted as argument %d",
1559 c & 7);
1560 } else {
1561 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001562 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001563 "four-bit argument exceeds bounds");
1564 }
1565 bytes[0] |= opx->offset & 15;
1566 }
1567 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1568 offset++;
1569 break;
1570
H. Peter Anvind58656f2008-05-06 20:11:14 -07001571 case 0173:
1572 c = *codes++;
1573 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001574 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001575 bytes[0] |= c & 15;
1576 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1577 offset++;
1578 break;
1579
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001580 case 0174:
1581 c = *codes++;
1582 opx = &ins->oprs[c];
1583 bytes[0] = nasm_regvals[opx->basereg] << 4;
1584 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1585 offset++;
1586 break;
1587
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001588 case 0250:
1589 case 0251:
1590 case 0252:
1591 case 0253:
1592 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001593 warn_overflow(4, opx);
1594 if (is_sbyte64(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001595 bytes[0] = data;
1596 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1597 NO_SEG);
1598 offset++;
1599 } else {
1600 out(offset, segment, &data, OUT_ADDRESS, 4,
1601 opx->segment, opx->wrt);
1602 offset += 4;
1603 }
1604 break;
1605
H. Peter Anvind85d2502008-05-04 17:53:31 -07001606 case 0260:
1607 case 0261:
1608 case 0262:
1609 case 0263:
1610 case 0270:
1611 codes += 2;
1612 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1613 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001614 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001615 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001616 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001617 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1618 offset += 3;
1619 } else {
1620 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001621 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1622 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001623 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1624 offset += 2;
1625 }
1626 break;
1627
H. Peter Anvine2c80182005-01-15 22:15:51 +00001628 case 0300:
1629 case 0301:
1630 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001631 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001632 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001633
H. Peter Anvine2c80182005-01-15 22:15:51 +00001634 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001635 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001636 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001637 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 offset += 1;
1639 } else
1640 offset += 0;
1641 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001642
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001644 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001646 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 offset += 1;
1648 } else
1649 offset += 0;
1650 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001651
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 case 0312:
1653 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001654
Keith Kaniosb7a89542007-04-12 02:40:54 +00001655 case 0313:
1656 ins->rex = 0;
1657 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001658
H. Peter Anvin23440102007-11-12 21:02:33 -08001659 case 0314:
1660 case 0315:
1661 case 0316:
1662 case 0317:
1663 break;
1664
H. Peter Anvine2c80182005-01-15 22:15:51 +00001665 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001666 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001667 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001668 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 offset += 1;
1670 } else
1671 offset += 0;
1672 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001673
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 case 0321:
1675 if (bits == 16) {
1676 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001677 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 offset += 1;
1679 } else
1680 offset += 0;
1681 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001682
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001684 case 0323:
1685 break;
1686
Keith Kaniosb7a89542007-04-12 02:40:54 +00001687 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001688 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001689 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001690
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 case 0330:
1692 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001693 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001694 offset += 1;
1695 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001696
H. Peter Anvine2c80182005-01-15 22:15:51 +00001697 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001698 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001699
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001700 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001701 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001702 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001703 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001704 offset += 1;
1705 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001706
Keith Kanios48af1772007-08-17 07:37:52 +00001707 case 0334:
1708 if (ins->rex & REX_R) {
1709 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001710 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001711 offset += 1;
1712 }
1713 ins->rex &= ~(REX_L|REX_R);
1714 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001715
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001716 case 0335:
1717 break;
1718
H. Peter Anvin962e3052008-08-28 17:47:16 -07001719 case 0336:
1720 case 0337:
1721 break;
1722
H. Peter Anvine2c80182005-01-15 22:15:51 +00001723 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001724 if (ins->oprs[0].segment != NO_SEG)
1725 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1726 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001727 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001728 if (size > 0)
1729 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001730 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001731 offset += size;
1732 }
1733 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001734
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001735 case 0360:
1736 break;
1737
1738 case 0361:
1739 bytes[0] = 0x66;
1740 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1741 offset += 1;
1742 break;
1743
1744 case 0362:
1745 case 0363:
1746 bytes[0] = c - 0362 + 0xf2;
1747 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1748 offset += 1;
1749 break;
1750
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001751 case 0364:
1752 case 0365:
1753 break;
1754
Keith Kanios48af1772007-08-17 07:37:52 +00001755 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001756 case 0367:
1757 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001758 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001759 offset += 1;
1760 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001761
H. Peter Anvine2c80182005-01-15 22:15:51 +00001762 case 0370:
1763 case 0371:
1764 case 0372:
1765 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001766
H. Peter Anvine2c80182005-01-15 22:15:51 +00001767 case 0373:
1768 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001769 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001770 offset += 1;
1771 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001772
H. Peter Anvine2c80182005-01-15 22:15:51 +00001773 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001774 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001775 ea ea_data;
1776 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001777 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001778 uint8_t *p;
1779 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001780 enum out_type type;
H. Peter Anvin70653092007-10-19 14:42:29 -07001781
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001782 if (c <= 0177) {
1783 /* pick rfield from operand b */
1784 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001785 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001786 } else {
1787 /* rfield is constant */
1788 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001789 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001790 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001791
1792 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001793 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001794 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 errfunc(ERR_NONFATAL, "invalid effective address");
1796 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001797
Charles Crayne7e975552007-11-03 22:06:13 -07001798
H. Peter Anvine2c80182005-01-15 22:15:51 +00001799 p = bytes;
1800 *p++ = ea_data.modrm;
1801 if (ea_data.sib_present)
1802 *p++ = ea_data.sib;
1803
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001804 /* DREX suffixes come between the SIB and the displacement */
1805 if (ins->rex & REX_D) {
1806 *p++ =
1807 (ins->drexdst << 4) |
1808 (ins->rex & REX_OC ? 0x08 : 0) |
1809 (ins->rex & (REX_R|REX_X|REX_B));
1810 ins->rex = 0;
1811 }
1812
H. Peter Anvine2c80182005-01-15 22:15:51 +00001813 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001814 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001815
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001816 /*
1817 * Make sure the address gets the right offset in case
1818 * the line breaks in the .lst file (BR 1197827)
1819 */
1820 offset += s;
1821 s = 0;
1822
H. Peter Anvine2c80182005-01-15 22:15:51 +00001823 switch (ea_data.bytes) {
1824 case 0:
1825 break;
1826 case 1:
1827 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1828 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001829 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001830 ins->oprs[(c >> 3) & 7].segment,
1831 ins->oprs[(c >> 3) & 7].wrt);
1832 } else {
1833 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001834 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001835 NO_SEG, NO_SEG);
1836 }
1837 s++;
1838 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001839 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001840 case 2:
1841 case 4:
1842 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001843 warn_overflow(ea_data.bytes, opx);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001844 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001845 if (ea_data.rip) {
1846 data -= insn_end - (offset+ea_data.bytes);
1847 type = OUT_REL4ADR;
1848 } else {
1849 type = OUT_ADDRESS;
1850 }
1851 out(offset, segment, &data, type, ea_data.bytes,
1852 ins->oprs[(c >> 3) & 7].segment,
1853 ins->oprs[(c >> 3) & 7].wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001854 break;
1855 }
1856 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001857 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001858 errfunc(ERR_PANIC, "internal instruction table corrupt"
1859 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001860 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001861 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001862 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001863}
1864
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001865static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001866{
1867 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1868 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1869 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001870 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001871}
1872
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001873static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001874{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001875 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1876 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001877 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001878 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001879}
1880
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001881static int op_rexflags(const operand * o, int mask)
1882{
1883 int32_t flags;
1884 int val;
1885
1886 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1887 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1888 }
1889
H. Peter Anvina4835d42008-05-20 14:21:29 -07001890 flags = nasm_reg_flags[o->basereg];
1891 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001892
1893 return rexflags(val, flags, mask);
1894}
1895
1896static int rexflags(int val, int32_t flags, int mask)
1897{
1898 int rex = 0;
1899
1900 if (val >= 8)
1901 rex |= REX_B|REX_X|REX_R;
1902 if (flags & BITS64)
1903 rex |= REX_W;
1904 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1905 rex |= REX_H;
1906 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1907 rex |= REX_P;
1908
1909 return rex & mask;
1910}
1911
H. Peter Anvin3360d792007-09-11 04:16:57 +00001912static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001913{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001914 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001915
1916 ret = 100;
1917
1918 /*
1919 * Check the opcode
1920 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001921 if (itemp->opcode != instruction->opcode)
1922 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001923
1924 /*
1925 * Count the operands
1926 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001927 if (itemp->operands != instruction->operands)
1928 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001929
1930 /*
1931 * Check that no spurious colons or TOs are present
1932 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001933 for (i = 0; i < itemp->operands; i++)
1934 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1935 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001936
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001937 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001938 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001939 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001940 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001941 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001942
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001943 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1944
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001945 switch (itemp->flags & IF_SMASK) {
1946 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001947 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001948 break;
1949 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001950 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001951 break;
1952 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001953 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001954 break;
1955 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001956 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001957 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001958 case IF_SO:
1959 size[i] = BITS128;
1960 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001961 case IF_SY:
1962 size[i] = BITS256;
1963 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001964 case IF_SZ:
1965 switch (bits) {
1966 case 16:
1967 size[i] = BITS16;
1968 break;
1969 case 32:
1970 size[i] = BITS32;
1971 break;
1972 case 64:
1973 size[i] = BITS64;
1974 break;
1975 }
1976 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001977 default:
1978 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001979 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001980 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001981 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001982 switch (itemp->flags & IF_SMASK) {
1983 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001984 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001985 break;
1986 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001987 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001988 break;
1989 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001990 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001991 break;
1992 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001993 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001994 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001995 case IF_SO:
1996 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001997 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001998 case IF_SY:
1999 asize = BITS256;
2000 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002001 case IF_SZ:
2002 switch (bits) {
2003 case 16:
2004 asize = BITS16;
2005 break;
2006 case 32:
2007 asize = BITS32;
2008 break;
2009 case 64:
2010 asize = BITS64;
2011 break;
2012 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002013 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002014 default:
2015 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002016 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002017 for (i = 0; i < MAX_OPERANDS; i++)
2018 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002019 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002020
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002021 /*
2022 * Check that the operand flags all match up
2023 */
2024 for (i = 0; i < itemp->operands; i++) {
2025 int32_t type = instruction->oprs[i].type;
2026 if (!(type & SIZE_MASK))
2027 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002028
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002029 if (itemp->opd[i] & SAME_AS) {
2030 int j = itemp->opd[i] & ~SAME_AS;
2031 if (type != instruction->oprs[j].type ||
2032 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2033 return 0;
2034 } else if (itemp->opd[i] & ~type ||
2035 ((itemp->opd[i] & SIZE_MASK) &&
2036 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2037 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2038 (type & SIZE_MASK))
2039 return 0;
2040 else
2041 return 1;
2042 }
2043 }
2044
2045 /*
2046 * Check operand sizes
2047 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002048 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002049 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2050 asize = 0;
2051 for (i = 0; i < oprs; i++) {
2052 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2053 int j;
2054 for (j = 0; j < oprs; j++)
2055 size[j] = asize;
2056 break;
2057 }
2058 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002059 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002060 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002061 }
2062
Keith Kaniosb7a89542007-04-12 02:40:54 +00002063 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002064 if (!(itemp->opd[i] & SIZE_MASK) &&
2065 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002066 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002067 }
2068
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002069 /*
2070 * Check template is okay at the set cpu level
2071 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002072 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002073 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002074
Keith Kaniosb7a89542007-04-12 02:40:54 +00002075 /*
2076 * Check if instruction is available in long mode
2077 */
2078 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2079 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002080
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002081 /*
2082 * Check if special handling needed for Jumps
2083 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002084 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002085 return 99;
2086
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002087 return ret;
2088}
2089
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002090static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002091 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002092{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002093 bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);
2094
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002095 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002096
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002097 /* REX flags for the rfield operand */
2098 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2099
Keith Kaniosb7a89542007-04-12 02:40:54 +00002100 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002101 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002102 int32_t f;
2103
2104 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002105 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002106 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002107 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002108 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002109
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002110 if (REG_EA & ~f)
2111 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002112
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002113 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2114
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002115 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002116 output->bytes = 0; /* no offset necessary either */
2117 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002118 } else { /* it's a memory reference */
2119 if (input->basereg == -1
2120 && (input->indexreg == -1 || input->scale == 0)) {
2121 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002122 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002123 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002124 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002125 scale = 0;
2126 index = 4;
2127 base = 5;
2128 output->sib = (scale << 6) | (index << 3) | base;
2129 output->bytes = 4;
2130 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002131 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002132 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002133 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002134 output->bytes = (addrbits != 16 ? 4 : 2);
2135 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002136 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002137 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002138 } else { /* it's an indirection */
2139 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002140 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002141 int hb = input->hintbase, ht = input->hinttype;
2142 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002143 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002144 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002145
H. Peter Anvine2c80182005-01-15 22:15:51 +00002146 if (s == 0)
2147 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002148
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002149 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002150 it = nasm_regvals[i];
2151 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002152 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002153 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002154 ix = 0;
2155 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002156
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002157 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002158 bt = nasm_regvals[b];
2159 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002160 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002161 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002162 bx = 0;
2163 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002164
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002165 /* check for a 32/64-bit memory reference... */
2166 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002167 /* it must be a 32/64-bit memory reference. Firstly we have
2168 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002169 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002170
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002171 if (it != -1) {
2172 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2173 sok &= ix;
2174 else
2175 return NULL;
2176 }
2177
2178 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002179 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002180 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002181 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002182 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002183 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002184 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002185
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002186 /* While we're here, ensure the user didn't specify
2187 WORD or QWORD. */
2188 if (input->disp_size == 16 || input->disp_size == 64)
2189 return NULL;
2190
2191 if (addrbits == 16 ||
2192 (addrbits == 32 && !(sok & BITS32)) ||
2193 (addrbits == 64 && !(sok & BITS64)))
2194 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002195
Keith Kaniosb7a89542007-04-12 02:40:54 +00002196 /* now reorganize base/index */
2197 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002198 ((hb == b && ht == EAH_NOTBASE)
2199 || (hb == i && ht == EAH_MAKEBASE))) {
2200 /* swap if hints say so */
2201 t = bt, bt = it, it = t;
2202 t = bx, bx = ix, ix = t;
2203 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002205 bt = -1, bx = 0, s++;
2206 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2207 /* make single reg base, unless hint */
2208 bt = it, bx = ix, it = -1, ix = 0;
2209 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002210 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002211 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002212 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002213 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002214 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002215 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002216 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002217 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002218 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002219 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002220 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002221 t = ix, ix = bx, bx = t;
2222 }
Keith Kanios48af1772007-08-17 07:37:52 +00002223 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002224 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002225 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002226
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002227 output->rex |= rexflags(it, ix, REX_X);
2228 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002229
Keith Kanios48af1772007-08-17 07:37:52 +00002230 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002231 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002232 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002233
Keith Kaniosb7a89542007-04-12 02:40:54 +00002234 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002235 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002236 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002237 } else {
2238 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002239 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002240 seg == NO_SEG && !forw_ref &&
2241 !(input->eaflags &
2242 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2243 mod = 0;
2244 else if (input->eaflags & EAF_BYTEOFFS ||
2245 (o >= -128 && o <= 127 && seg == NO_SEG
2246 && !forw_ref
2247 && !(input->eaflags & EAF_WORDOFFS)))
2248 mod = 1;
2249 else
2250 mod = 2;
2251 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002252
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002253 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002254 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2255 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002256 } else {
2257 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002258 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002259
Keith Kaniosb7a89542007-04-12 02:40:54 +00002260 if (it == -1)
2261 index = 4, s = 1;
2262 else
2263 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002264
H. Peter Anvine2c80182005-01-15 22:15:51 +00002265 switch (s) {
2266 case 1:
2267 scale = 0;
2268 break;
2269 case 2:
2270 scale = 1;
2271 break;
2272 case 4:
2273 scale = 2;
2274 break;
2275 case 8:
2276 scale = 3;
2277 break;
2278 default: /* then what the smeg is it? */
2279 return NULL; /* panic */
2280 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002281
Keith Kaniosb7a89542007-04-12 02:40:54 +00002282 if (bt == -1) {
2283 base = 5;
2284 mod = 0;
2285 } else {
2286 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002287 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002288 seg == NO_SEG && !forw_ref &&
2289 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002290 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2291 mod = 0;
2292 else if (input->eaflags & EAF_BYTEOFFS ||
2293 (o >= -128 && o <= 127 && seg == NO_SEG
2294 && !forw_ref
2295 && !(input->eaflags & EAF_WORDOFFS)))
2296 mod = 1;
2297 else
2298 mod = 2;
2299 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002300
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002301 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002302 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2303 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002304 output->sib = (scale << 6) | (index << 3) | base;
2305 }
2306 } else { /* it's 16-bit */
2307 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002308
Keith Kaniosb7a89542007-04-12 02:40:54 +00002309 /* check for 64-bit long mode */
2310 if (addrbits == 64)
2311 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002312
H. Peter Anvine2c80182005-01-15 22:15:51 +00002313 /* check all registers are BX, BP, SI or DI */
2314 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2315 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2316 && i != R_SI && i != R_DI))
2317 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002318
Keith Kaniosb7a89542007-04-12 02:40:54 +00002319 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002320 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002321 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002322
H. Peter Anvine2c80182005-01-15 22:15:51 +00002323 if (s != 1 && i != -1)
2324 return NULL; /* no can do, in 16-bit EA */
2325 if (b == -1 && i != -1) {
2326 int tmp = b;
2327 b = i;
2328 i = tmp;
2329 } /* swap */
2330 if ((b == R_SI || b == R_DI) && i != -1) {
2331 int tmp = b;
2332 b = i;
2333 i = tmp;
2334 }
2335 /* have BX/BP as base, SI/DI index */
2336 if (b == i)
2337 return NULL; /* shouldn't ever happen, in theory */
2338 if (i != -1 && b != -1 &&
2339 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2340 return NULL; /* invalid combinations */
2341 if (b == -1) /* pure offset: handled above */
2342 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002343
H. Peter Anvine2c80182005-01-15 22:15:51 +00002344 rm = -1;
2345 if (i != -1)
2346 switch (i * 256 + b) {
2347 case R_SI * 256 + R_BX:
2348 rm = 0;
2349 break;
2350 case R_DI * 256 + R_BX:
2351 rm = 1;
2352 break;
2353 case R_SI * 256 + R_BP:
2354 rm = 2;
2355 break;
2356 case R_DI * 256 + R_BP:
2357 rm = 3;
2358 break;
2359 } else
2360 switch (b) {
2361 case R_SI:
2362 rm = 4;
2363 break;
2364 case R_DI:
2365 rm = 5;
2366 break;
2367 case R_BP:
2368 rm = 6;
2369 break;
2370 case R_BX:
2371 rm = 7;
2372 break;
2373 }
2374 if (rm == -1) /* can't happen, in theory */
2375 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002376
H. Peter Anvine2c80182005-01-15 22:15:51 +00002377 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2378 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2379 mod = 0;
2380 else if (input->eaflags & EAF_BYTEOFFS ||
2381 (o >= -128 && o <= 127 && seg == NO_SEG
2382 && !forw_ref
2383 && !(input->eaflags & EAF_WORDOFFS)))
2384 mod = 1;
2385 else
2386 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002387
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002388 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002389 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002390 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002391 }
2392 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002393 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002394
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002395 output->size = 1 + output->sib_present + output->bytes;
2396 return output;
2397}
2398
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002399static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002400{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002401 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002402 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002403
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002404 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002405
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002406 switch (ins->prefixes[PPS_ASIZE]) {
2407 case P_A16:
2408 valid &= 16;
2409 break;
2410 case P_A32:
2411 valid &= 32;
2412 break;
2413 case P_A64:
2414 valid &= 64;
2415 break;
2416 case P_ASP:
2417 valid &= (addrbits == 32) ? 16 : 32;
2418 break;
2419 default:
2420 break;
2421 }
2422
2423 for (j = 0; j < ins->operands; j++) {
2424 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002425 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002426
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002427 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002428 if (ins->oprs[j].indexreg < EXPR_REG_START
2429 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002430 i = 0;
2431 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002432 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002433
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002434 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002435 if (ins->oprs[j].basereg < EXPR_REG_START
2436 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002437 b = 0;
2438 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002439 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002440
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002441 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002442 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002443
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002444 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002445 int ds = ins->oprs[j].disp_size;
2446 if ((addrbits != 64 && ds > 8) ||
2447 (addrbits == 64 && ds == 16))
2448 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002449 } else {
2450 if (!(REG16 & ~b))
2451 valid &= 16;
2452 if (!(REG32 & ~b))
2453 valid &= 32;
2454 if (!(REG64 & ~b))
2455 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002456
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002457 if (!(REG16 & ~i))
2458 valid &= 16;
2459 if (!(REG32 & ~i))
2460 valid &= 32;
2461 if (!(REG64 & ~i))
2462 valid &= 64;
2463 }
2464 }
2465 }
2466
2467 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002468 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002469 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002470 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002471 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002472 ins->prefixes[PPS_ASIZE] = pref;
2473 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002474 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002475 /* Impossible... */
2476 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002477 ins->addr_size = addrbits; /* Error recovery */
2478 }
2479
2480 defdisp = ins->addr_size == 16 ? 16 : 32;
2481
2482 for (j = 0; j < ins->operands; j++) {
2483 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2484 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2485 != ins->addr_size) {
2486 /* mem_offs sizes must match the address size; if not,
2487 strip the MEM_OFFS bit and match only EA instructions */
2488 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2489 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002490 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002491}