blob: 0397f5df72d6993d8370c7c127a5f11906241d4a [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
49 * the 4-bit immediate from operand b in bits 0..3.
H. Peter Anvind58656f2008-05-06 20:11:14 -070050 * \173\xab - the register number from operand a in bits 7..4, with
51 * the value b in bits 0..3.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000052 * \2ab - a ModRM, calculated on EA in operand a, with the spare
53 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070054 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
55 * is not equal to the truncated and sign-extended 32-bit
56 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070057 * \260..\263 - this instruction uses VEX rather than REX, with the
58 * V field taken from operand 0..3.
59 * \270 - this instruction uses VEX rather than REX, with the
60 * V field set to 1111b.
61 *
62 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070063 * \mm\wlp where mm is the M field; and wlp is:
64 * 00 0ww lpp
H. Peter Anvind85d2502008-05-04 17:53:31 -070065 * ww = 0 for W = 0
66 * ww = 1 for W = 1
67 * ww = 2 for W used as REX.W
68 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000069 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
70 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000071 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000072 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080073 * \314 - (disassembler only) invalid with REX.B
74 * \315 - (disassembler only) invalid with REX.X
75 * \316 - (disassembler only) invalid with REX.R
76 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000077 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
78 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
79 * \322 - indicates that this instruction is only valid when the
80 * operand size is the default (instruction to disassembler,
81 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000082 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000083 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000084 * \330 - a literal byte follows in the code stream, to be added
85 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000086 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000087 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070088 * \332 - REP prefix (0xF2 byte) used as opcode extension.
89 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000090 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070091 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000092 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000093 * Operand 0 had better be a segmentless constant.
H. Peter Anvinfff5a472008-05-20 09:46:24 -070094 * \360 - no SSE prefix (== \364\331)
95 * \361 - 66 SSE prefix (== \366\331)
96 * \362 - F2 SSE prefix (== \364\332)
97 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +000098 * \364 - operand-size prefix (0x66) not permitted
99 * \365 - address-size prefix (0x67) not permitted
100 * \366 - operand-size prefix (0x66) used as opcode extension
101 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000102 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
103 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000104 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
105 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000106 */
107
H. Peter Anvinfe501952007-10-02 21:53:51 -0700108#include "compiler.h"
109
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110#include <stdio.h>
111#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000112#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113
114#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000115#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000116#include "assemble.h"
117#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000118#include "preproc.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700119#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120
H. Peter Anvindfb91802008-05-20 11:43:53 -0700121/* Initialized to zero by the C standard */
122static const uint8_t const_zero_buf[256];
123
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000124typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000125 int sib_present; /* is a SIB byte necessary? */
126 int bytes; /* # of bytes of offset needed */
127 int size; /* lazy - this is sib+bytes+1 */
128 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000129} ea;
130
Keith Kaniosb7a89542007-04-12 02:40:54 +0000131static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000132static efunc errfunc;
133static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000134static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000135
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700136static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
137static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000138static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000139static int32_t regflag(const operand *);
140static int32_t regval(const operand *);
141static int rexflags(int, int32_t, int);
142static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700143static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700144static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000145
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700146static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000147{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700148 return ins->prefixes[pos] == prefix;
149}
150
151static void assert_no_prefix(insn * ins, enum prefix_pos pos)
152{
153 if (ins->prefixes[pos])
154 errfunc(ERR_NONFATAL, "invalid %s prefix",
155 prefix_name(ins->prefixes[pos]));
156}
157
158static const char *size_name(int size)
159{
160 switch (size) {
161 case 1:
162 return "byte";
163 case 2:
164 return "word";
165 case 4:
166 return "dword";
167 case 8:
168 return "qword";
169 case 10:
170 return "tword";
171 case 16:
172 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700173 case 32:
174 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700175 default:
176 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000177 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700178}
179
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700180static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700181{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700182 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800183 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000184
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700185 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700186 errfunc(ERR_WARNING | ERR_WARN_NOV,
187 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700188 }
189}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000190/*
191 * This routine wrappers the real output format's output routine,
192 * in order to pass a copy of the data off to the listing file
193 * generator at the same time.
194 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800195static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800196 enum out_type type, uint64_t size,
197 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000198{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000199 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000200 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800201 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000202
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800203 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
204 /*
205 * This is a non-relocated address, and we're going to
206 * convert it into RAWDATA format.
207 */
208 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800209
210 if (size > 8) {
211 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
212 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800213 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700214
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800215 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800216 data = p;
217 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000218 }
219
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800220 list->output(offset, data, type, size);
221
Frank Kotlerabebb082003-09-06 04:45:37 +0000222 /*
223 * this call to src_get determines when we call the
224 * debug-format-specific "linenum" function
225 * it updates lineno and lnfname to the current values
226 * returning 0 if "same as last time", -2 if lnfname
227 * changed, and the amount by which lineno changed,
228 * if it did. thus, these variables must be static
229 */
230
H. Peter Anvine2c80182005-01-15 22:15:51 +0000231 if (src_get(&lineno, &lnfname)) {
232 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000233 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000234
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800235 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000236}
237
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800238static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700239 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000240{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800241 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000242 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000243
H. Peter Anvine2c80182005-01-15 22:15:51 +0000244 if (c != 0370 && c != 0371)
245 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000246 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000247 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
248 && c == 0370)
249 return 1;
250 else
251 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000252 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000253 isize = calcsize(segment, offset, bits, ins, code);
254 if (ins->oprs[0].segment != segment)
255 return 0;
256 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
257 if (isize >= -128L && isize <= 127L)
258 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000259
260 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000261}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000262
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800263int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000264 insn * instruction, struct ofmt *output, efunc error,
265 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000266{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000267 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000268 int j;
269 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800270 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000271 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800272 int64_t start = offset;
273 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000274
H. Peter Anvine2c80182005-01-15 22:15:51 +0000275 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000276 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000277 outfmt = output; /* likewise */
278 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000279
H. Peter Anvine2c80182005-01-15 22:15:51 +0000280 switch (instruction->opcode) {
281 case -1:
282 return 0;
283 case I_DB:
284 wsize = 1;
285 break;
286 case I_DW:
287 wsize = 2;
288 break;
289 case I_DD:
290 wsize = 4;
291 break;
292 case I_DQ:
293 wsize = 8;
294 break;
295 case I_DT:
296 wsize = 10;
297 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700298 case I_DO:
299 wsize = 16;
300 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700301 case I_DY:
302 wsize = 32;
303 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700304 default:
305 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000306 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000307
H. Peter Anvineba20a72002-04-30 20:53:55 +0000308 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000309 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000310 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000311 if (t < 0)
312 errfunc(ERR_PANIC,
313 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000314
H. Peter Anvine2c80182005-01-15 22:15:51 +0000315 while (t--) { /* repeat TIMES times */
316 for (e = instruction->eops; e; e = e->next) {
317 if (e->type == EOT_DB_NUMBER) {
318 if (wsize == 1) {
319 if (e->segment != NO_SEG)
320 errfunc(ERR_NONFATAL,
321 "one-byte relocation attempted");
322 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000323 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800325 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000326 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000327 } else if (wsize > 8) {
H. Peter Anvindfb91802008-05-20 11:43:53 -0700328 errfunc(ERR_NONFATAL, "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000329 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 } else
331 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800332 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 offset += wsize;
334 } else if (e->type == EOT_DB_STRING) {
335 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000336
H. Peter Anvine2c80182005-01-15 22:15:51 +0000337 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800338 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000339 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000340
H. Peter Anvine2c80182005-01-15 22:15:51 +0000341 if (align) {
342 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700343 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800344 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 }
346 offset += e->stringlen + align;
347 }
348 }
349 if (t > 0 && t == instruction->times - 1) {
350 /*
351 * Dummy call to list->output to give the offset to the
352 * listing module.
353 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800354 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000355 list->uplevel(LIST_TIMES);
356 }
357 }
358 if (instruction->times > 1)
359 list->downlevel(LIST_TIMES);
360 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000361 }
362
H. Peter Anvine2c80182005-01-15 22:15:51 +0000363 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000364 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000365 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000366 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000367 char *prefix = "", *combine;
368 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000369
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 len = FILENAME_MAX - 1;
371 if (len > instruction->eops->stringlen)
372 len = instruction->eops->stringlen;
373 strncpy(fname, instruction->eops->stringval, len);
374 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000375
Keith Kaniosb7a89542007-04-12 02:40:54 +0000376 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 combine = nasm_malloc(strlen(prefix) + len + 1);
378 strcpy(combine, prefix);
379 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000380
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 if ((fp = fopen(combine, "rb")) != NULL) {
382 nasm_free(combine);
383 break;
384 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000385
H. Peter Anvine2c80182005-01-15 22:15:51 +0000386 nasm_free(combine);
387 pPrevPath = pp_get_include_path_ptr(pPrevPath);
388 if (pPrevPath == NULL)
389 break;
390 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000391 }
392
393 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
395 fname);
396 else if (fseek(fp, 0L, SEEK_END) < 0)
397 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
398 fname);
399 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000400 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000401 int32_t t = instruction->times;
402 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000403
H. Peter Anvine2c80182005-01-15 22:15:51 +0000404 len = ftell(fp);
405 if (instruction->eops->next) {
406 base = instruction->eops->next->offset;
407 len -= base;
408 if (instruction->eops->next->next &&
409 len > instruction->eops->next->next->offset)
410 len = instruction->eops->next->next->offset;
411 }
412 /*
413 * Dummy call to list->output to give the offset to the
414 * listing module.
415 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800416 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000417 list->uplevel(LIST_INCBIN);
418 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000419 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000420
H. Peter Anvine2c80182005-01-15 22:15:51 +0000421 fseek(fp, base, SEEK_SET);
422 l = len;
423 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000424 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700425 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000426 fp);
427 if (!m) {
428 /*
429 * This shouldn't happen unless the file
430 * actually changes while we are reading
431 * it.
432 */
433 error(ERR_NONFATAL,
434 "`incbin': unexpected EOF while"
435 " reading file `%s'", fname);
436 t = 0; /* Try to exit cleanly */
437 break;
438 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800439 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000440 NO_SEG, NO_SEG);
441 l -= m;
442 }
443 }
444 list->downlevel(LIST_INCBIN);
445 if (instruction->times > 1) {
446 /*
447 * Dummy call to list->output to give the offset to the
448 * listing module.
449 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800450 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000451 list->uplevel(LIST_TIMES);
452 list->downlevel(LIST_TIMES);
453 }
454 fclose(fp);
455 return instruction->times * len;
456 }
457 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000458 }
459
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700460 /* Check to see if we need an address-size prefix */
461 add_asp(instruction, bits);
462
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700463 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700464
465 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000466 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700467
H. Peter Anvine2c80182005-01-15 22:15:51 +0000468 if (m == 99)
469 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000470
H. Peter Anvine2c80182005-01-15 22:15:51 +0000471 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700472 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800473 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000474 instruction, codes);
475 itimes = instruction->times;
476 if (insn_size < 0) /* shouldn't be, on pass two */
477 error(ERR_PANIC, "errors made it through from pass one");
478 else
479 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700480 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000481 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000482 switch (instruction->prefixes[j]) {
483 case P_LOCK:
484 c = 0xF0;
485 break;
486 case P_REPNE:
487 case P_REPNZ:
488 c = 0xF2;
489 break;
490 case P_REPE:
491 case P_REPZ:
492 case P_REP:
493 c = 0xF3;
494 break;
495 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000496 if (bits == 64) {
497 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800498 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000499 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000500 c = 0x2E;
501 break;
502 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000503 if (bits == 64) {
504 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800505 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000506 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000507 c = 0x3E;
508 break;
509 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000510 if (bits == 64) {
511 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800512 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000513 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000514 c = 0x26;
515 break;
516 case R_FS:
517 c = 0x64;
518 break;
519 case R_GS:
520 c = 0x65;
521 break;
522 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000523 if (bits == 64) {
524 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800525 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000526 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000527 c = 0x36;
528 break;
529 case R_SEGR6:
530 case R_SEGR7:
531 error(ERR_NONFATAL,
532 "segr6 and segr7 cannot be used as prefixes");
533 break;
534 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000535 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000536 error(ERR_NONFATAL,
537 "16-bit addressing is not supported "
538 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700539 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000540 c = 0x67;
541 break;
542 case P_A32:
543 if (bits != 32)
544 c = 0x67;
545 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700546 case P_A64:
547 if (bits != 64) {
548 error(ERR_NONFATAL,
549 "64-bit addressing is only supported "
550 "in 64-bit mode");
551 }
552 break;
553 case P_ASP:
554 c = 0x67;
555 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000556 case P_O16:
557 if (bits != 16)
558 c = 0x66;
559 break;
560 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000561 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000562 c = 0x66;
563 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700564 case P_O64:
565 /* REX.W */
566 break;
567 case P_OSP:
568 c = 0x66;
569 break;
570 case P_none:
571 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000572 default:
573 error(ERR_PANIC, "invalid instruction prefix");
574 }
575 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800576 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000577 NO_SEG, NO_SEG);
578 offset++;
579 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700580 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000581 insn_end = offset + insn_size;
582 gencode(segment, offset, bits, instruction, codes,
583 insn_end);
584 offset += insn_size;
585 if (itimes > 0 && itimes == instruction->times - 1) {
586 /*
587 * Dummy call to list->output to give the offset to the
588 * listing module.
589 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800590 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000591 list->uplevel(LIST_TIMES);
592 }
593 }
594 if (instruction->times > 1)
595 list->downlevel(LIST_TIMES);
596 return offset - start;
597 } else if (m > 0 && m > size_prob) {
598 size_prob = m;
599 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000600// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000601 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000602
H. Peter Anvine2c80182005-01-15 22:15:51 +0000603 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000604 switch (size_prob) {
605 case 1:
606 error(ERR_NONFATAL, "operation size not specified");
607 break;
608 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000609 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000610 break;
611 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000612 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000613 break;
614 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000615 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000616 break;
617 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000618 error(ERR_NONFATAL,
619 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000620 break;
621 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000622 }
623 return 0;
624}
625
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800626int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000627 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000628{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000629 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000630
H. Peter Anvine2c80182005-01-15 22:15:51 +0000631 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000632 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000633
634 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000635 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000636
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700637 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
638 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700639 instruction->opcode == I_DT || instruction->opcode == I_DO ||
640 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000641 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000642 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000643
H. Peter Anvine2c80182005-01-15 22:15:51 +0000644 isize = 0;
645 switch (instruction->opcode) {
646 case I_DB:
647 wsize = 1;
648 break;
649 case I_DW:
650 wsize = 2;
651 break;
652 case I_DD:
653 wsize = 4;
654 break;
655 case I_DQ:
656 wsize = 8;
657 break;
658 case I_DT:
659 wsize = 10;
660 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700661 case I_DO:
662 wsize = 16;
663 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700664 case I_DY:
665 wsize = 32;
666 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700667 default:
668 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000672 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000673
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 osize = 0;
675 if (e->type == EOT_DB_NUMBER)
676 osize = 1;
677 else if (e->type == EOT_DB_STRING)
678 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000679
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 align = (-osize) % wsize;
681 if (align < 0)
682 align += wsize;
683 isize += osize + align;
684 }
685 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000686 }
687
H. Peter Anvine2c80182005-01-15 22:15:51 +0000688 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000689 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000690 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000691 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000692 char *prefix = "", *combine;
693 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000694
H. Peter Anvine2c80182005-01-15 22:15:51 +0000695 len = FILENAME_MAX - 1;
696 if (len > instruction->eops->stringlen)
697 len = instruction->eops->stringlen;
698 strncpy(fname, instruction->eops->stringval, len);
699 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000700
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700701 /* added by alexfru: 'incbin' uses include paths */
702 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000703 combine = nasm_malloc(strlen(prefix) + len + 1);
704 strcpy(combine, prefix);
705 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000706
H. Peter Anvine2c80182005-01-15 22:15:51 +0000707 if ((fp = fopen(combine, "rb")) != NULL) {
708 nasm_free(combine);
709 break;
710 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000711
H. Peter Anvine2c80182005-01-15 22:15:51 +0000712 nasm_free(combine);
713 pPrevPath = pp_get_include_path_ptr(pPrevPath);
714 if (pPrevPath == NULL)
715 break;
716 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000717 }
718
719 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000720 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
721 fname);
722 else if (fseek(fp, 0L, SEEK_END) < 0)
723 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
724 fname);
725 else {
726 len = ftell(fp);
727 fclose(fp);
728 if (instruction->eops->next) {
729 len -= instruction->eops->next->offset;
730 if (instruction->eops->next->next &&
731 len > instruction->eops->next->next->offset) {
732 len = instruction->eops->next->next->offset;
733 }
734 }
735 return instruction->times * len;
736 }
737 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000738 }
739
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700740 /* Check to see if we need an address-size prefix */
741 add_asp(instruction, bits);
742
Keith Kaniosb7a89542007-04-12 02:40:54 +0000743 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
744 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000745 if (m == 99)
746 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000747
H. Peter Anvine2c80182005-01-15 22:15:51 +0000748 if (m == 100) {
749 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800750 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700751 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000752 int j;
753
754 isize = calcsize(segment, offset, bits, instruction, codes);
755 if (isize < 0)
756 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700757 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700758 switch (instruction->prefixes[j]) {
759 case P_A16:
760 if (bits != 16)
761 isize++;
762 break;
763 case P_A32:
764 if (bits != 32)
765 isize++;
766 break;
767 case P_O16:
768 if (bits != 16)
769 isize++;
770 break;
771 case P_O32:
772 if (bits == 16)
773 isize++;
774 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700775 case P_A64:
776 case P_O64:
777 case P_none:
778 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700779 default:
780 isize++;
781 break;
782 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000783 }
784 return isize * instruction->times;
785 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000786 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000787 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000788}
789
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700790static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000791{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700792 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000793 optimizing >= 0 &&
794 !(ins->oprs[op].type & STRICT) &&
795 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000796}
797
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700798/* check that opn[op] is a signed byte of size 16 or 32 */
799static bool is_sbyte16(insn * ins, int op)
800{
801 int16_t v;
802
803 if (!possible_sbyte(ins, op))
804 return false;
805
806 v = ins->oprs[op].offset;
807 return v >= -128 && v <= 127;
808}
809
810static bool is_sbyte32(insn * ins, int op)
811{
812 int32_t v;
813
814 if (!possible_sbyte(ins, op))
815 return false;
816
817 v = ins->oprs[op].offset;
818 return v >= -128 && v <= 127;
819}
820
821/* check that opn[op] is a signed byte of size 32; warn if this is not
822 the original value when extended to 64 bits */
823static bool is_sbyte64(insn * ins, int op)
824{
825 int64_t v64;
826 int32_t v32;
827
828 /* dead in the water on forward reference or External */
829 if (!possible_sbyte(ins, op))
830 return false;
831
832 v64 = ins->oprs[op].offset;
833 v32 = (int32_t)v64;
834
835 warn_overflow(32, v64);
836
837 return v32 >= -128 && v32 <= 127;
838}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800839static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700840 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000841{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800842 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000843 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000844 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700845 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000846
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700847 ins->rex = 0; /* Ensure REX is reset */
848
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700849 if (ins->prefixes[PPS_OSIZE] == P_O64)
850 ins->rex |= REX_W;
851
H. Peter Anvine2c80182005-01-15 22:15:51 +0000852 (void)segment; /* Don't warn that this parameter is unused */
853 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000854
H. Peter Anvin839eca22007-10-29 23:12:47 -0700855 while (*codes) {
856 c = *codes++;
857 opx = &ins->oprs[c & 3];
858 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000859 case 01:
860 case 02:
861 case 03:
862 codes += c, length += c;
863 break;
864 case 04:
865 case 05:
866 case 06:
867 case 07:
868 length++;
869 break;
870 case 010:
871 case 011:
872 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700873 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000874 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700875 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000876 codes++, length++;
877 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 case 014:
879 case 015:
880 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700881 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000882 length++;
883 break;
884 case 020:
885 case 021:
886 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700887 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 length++;
889 break;
890 case 024:
891 case 025:
892 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700893 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 length++;
895 break;
896 case 030:
897 case 031:
898 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700899 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 length += 2;
901 break;
902 case 034:
903 case 035:
904 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700905 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700906 if (opx->type & (BITS16 | BITS32 | BITS64))
907 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000908 else
909 length += (bits == 16) ? 2 : 4;
910 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 case 040:
912 case 041:
913 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700914 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000915 length += 4;
916 break;
917 case 044:
918 case 045:
919 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700920 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700921 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000922 break;
923 case 050:
924 case 051:
925 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700926 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000927 length++;
928 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000929 case 054:
930 case 055:
931 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700932 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000933 length += 8; /* MOV reg64/imm */
934 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000935 case 060:
936 case 061:
937 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700938 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000939 length += 2;
940 break;
941 case 064:
942 case 065:
943 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700944 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700945 if (opx->type & (BITS16 | BITS32 | BITS64))
946 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000947 else
948 length += (bits == 16) ? 2 : 4;
949 break;
950 case 070:
951 case 071:
952 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700953 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000954 length += 4;
955 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700956 case 074:
957 case 075:
958 case 076:
959 case 077:
960 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000961 break;
962 case 0140:
963 case 0141:
964 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700965 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700966 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000967 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000968 case 0144:
969 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700970 case 0146:
971 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800972 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000973 length++;
974 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700975 case 0150:
976 case 0151:
977 case 0152:
978 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700979 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700980 break;
981 case 0154:
982 case 0155:
983 case 0156:
984 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800985 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700986 length++;
987 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700988 case 0160:
989 case 0161:
990 case 0162:
991 case 0163:
992 length++;
993 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700994 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700995 break;
996 case 0164:
997 case 0165:
998 case 0166:
999 case 0167:
1000 length++;
1001 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001002 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001003 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001004 case 0171:
1005 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001006 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -07001007 case 0173:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001008 codes++;
1009 length++;
1010 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001011 case 0250:
1012 case 0251:
1013 case 0252:
1014 case 0253:
1015 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1016 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001017 case 0260:
1018 case 0261:
1019 case 0262:
1020 case 0263:
1021 length += 2;
1022 ins->rex |= REX_V;
1023 ins->drexdst = regval(opx);
1024 ins->vex_m = *codes++;
1025 ins->vex_wlp = *codes++;
1026 break;
1027 case 0270:
1028 length += 2;
1029 ins->rex |= REX_V;
1030 ins->drexdst = 0;
1031 ins->vex_m = *codes++;
1032 ins->vex_wlp = *codes++;
1033 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001034 case 0300:
1035 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001036 case 0302:
1037 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001038 break;
1039 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001040 if (bits == 64)
1041 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001042 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001043 break;
1044 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001045 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001046 break;
1047 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001048 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001049 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001050 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1051 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001052 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001053 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001054 case 0314:
1055 case 0315:
1056 case 0316:
1057 case 0317:
1058 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001059 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001060 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001061 break;
1062 case 0321:
1063 length += (bits == 16);
1064 break;
1065 case 0322:
1066 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001067 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001068 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001069 break;
1070 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001071 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001072 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001073 case 0330:
1074 codes++, length++;
1075 break;
1076 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001077 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001078 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001079 case 0333:
1080 length++;
1081 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001082 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001083 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001084 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001085 case 0335:
1086 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001087 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001088 if (ins->oprs[0].segment != NO_SEG)
1089 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1090 " quantity of BSS space");
1091 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001092 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001093 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001094 case 0360:
1095 break;
1096 case 0361:
1097 case 0362:
1098 case 0363:
1099 length++;
1100 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001101 case 0364:
1102 case 0365:
1103 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001104 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001105 case 0367:
1106 length++;
1107 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001108 case 0370:
1109 case 0371:
1110 case 0372:
1111 break;
1112 case 0373:
1113 length++;
1114 break;
1115 default: /* can't do it by 'case' statements */
1116 if (c >= 0100 && c <= 0277) { /* it's an EA */
1117 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001118 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001119 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001120 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001121
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001122 if (c <= 0177) {
1123 /* pick rfield from operand b */
1124 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001125 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001126 } else {
1127 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001128 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001129 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001130
H. Peter Anvine2c80182005-01-15 22:15:51 +00001131 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001132 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001133 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001134 errfunc(ERR_NONFATAL, "invalid effective address");
1135 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001136 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001137 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001138 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001139 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001140 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001141 errfunc(ERR_PANIC, "internal instruction table corrupt"
1142 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001143 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001144 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001145 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001146
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001147 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001148
H. Peter Anvind85d2502008-05-04 17:53:31 -07001149 if (ins->rex & REX_V) {
1150 int bad32 = REX_R|REX_W|REX_X|REX_B;
1151
1152 if (ins->rex & REX_H) {
1153 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1154 return -1;
1155 }
1156 switch (ins->vex_wlp & 030) {
1157 case 000:
1158 ins->rex &= ~REX_W;
1159 break;
1160 case 010:
1161 ins->rex |= REX_W;
1162 bad32 &= ~REX_W;
1163 break;
1164 default:
1165 /* Follow REX_W */
1166 break;
1167 }
1168
1169 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1170 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1171 return -1;
1172 }
1173 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1174 length += 3;
1175 else
1176 length += 2;
1177 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001178 if (ins->rex & REX_H) {
1179 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1180 return -1;
1181 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001182 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001183 ins->drexdst > 7)) {
1184 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1185 return -1;
1186 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001187 length++;
1188 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001189 if (ins->rex & REX_H) {
1190 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1191 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001192 } else if (bits == 64) {
1193 length++;
1194 } else if ((ins->rex & REX_L) &&
1195 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1196 cpu >= IF_X86_64) {
1197 /* LOCK-as-REX.R */
1198 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001199 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001200 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001201 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1202 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001203 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001204 }
1205
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001206 return length;
1207}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001208
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001209#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001210 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001211 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001212 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001213 ins->rex = 0; \
1214 offset += 1; \
1215 }
1216
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001217static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001218 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001219{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001220 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001221 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1222 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1223 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001224 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001225 uint8_t c;
1226 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001227 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001228 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001229 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001230
H. Peter Anvin839eca22007-10-29 23:12:47 -07001231 while (*codes) {
1232 c = *codes++;
1233 opx = &ins->oprs[c & 3];
1234 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001235 case 01:
1236 case 02:
1237 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001238 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001239 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001240 codes += c;
1241 offset += c;
1242 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001243
H. Peter Anvine2c80182005-01-15 22:15:51 +00001244 case 04:
1245 case 06:
1246 switch (ins->oprs[0].basereg) {
1247 case R_CS:
1248 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1249 break;
1250 case R_DS:
1251 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1252 break;
1253 case R_ES:
1254 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1255 break;
1256 case R_SS:
1257 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1258 break;
1259 default:
1260 errfunc(ERR_PANIC,
1261 "bizarre 8086 segment register received");
1262 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001263 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001264 offset++;
1265 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001266
H. Peter Anvine2c80182005-01-15 22:15:51 +00001267 case 05:
1268 case 07:
1269 switch (ins->oprs[0].basereg) {
1270 case R_FS:
1271 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1272 break;
1273 case R_GS:
1274 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1275 break;
1276 default:
1277 errfunc(ERR_PANIC,
1278 "bizarre 386 segment register received");
1279 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001280 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 offset++;
1282 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001283
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 case 010:
1285 case 011:
1286 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001287 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001288 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001289 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001290 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001291 offset += 1;
1292 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001293
H. Peter Anvine2c80182005-01-15 22:15:51 +00001294 case 014:
1295 case 015:
1296 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001297 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001298 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001299 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001300 errfunc(ERR_WARNING | ERR_WARN_NOV,
1301 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001302 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001303
H. Peter Anvin839eca22007-10-29 23:12:47 -07001304 if (opx->segment != NO_SEG) {
1305 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001306 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001307 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001308 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001310 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001311 NO_SEG);
1312 }
1313 offset += 1;
1314 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001315
H. Peter Anvine2c80182005-01-15 22:15:51 +00001316 case 020:
1317 case 021:
1318 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001319 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001320 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001321 errfunc(ERR_WARNING | ERR_WARN_NOV,
1322 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001323 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001324 if (opx->segment != NO_SEG) {
1325 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001326 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001327 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001330 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001331 NO_SEG);
1332 }
1333 offset += 1;
1334 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001335
H. Peter Anvine2c80182005-01-15 22:15:51 +00001336 case 024:
1337 case 025:
1338 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001339 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001341 errfunc(ERR_WARNING | ERR_WARN_NOV,
1342 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001343 if (opx->segment != NO_SEG) {
1344 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001345 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001346 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001347 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001348 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001349 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001350 NO_SEG);
1351 }
1352 offset += 1;
1353 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001354
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 case 030:
1356 case 031:
1357 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001358 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 data = opx->offset;
1360 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001361 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001362 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001364 offset += 2;
1365 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001366
H. Peter Anvine2c80182005-01-15 22:15:51 +00001367 case 034:
1368 case 035:
1369 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001370 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 if (opx->type & (BITS16 | BITS32))
1372 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 else
1374 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001375 data = opx->offset;
1376 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001377 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001378 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001379 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 offset += size;
1381 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001382
H. Peter Anvine2c80182005-01-15 22:15:51 +00001383 case 040:
1384 case 041:
1385 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001386 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001387 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001388 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1389 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001390 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001392 offset += 4;
1393 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001394
H. Peter Anvine2c80182005-01-15 22:15:51 +00001395 case 044:
1396 case 045:
1397 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001398 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001399 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001400 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001401 if (opx->segment == NO_SEG &&
1402 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001403 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001404 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001405 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001406 offset += size;
1407 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001408
H. Peter Anvine2c80182005-01-15 22:15:51 +00001409 case 050:
1410 case 051:
1411 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001412 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001413 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001414 errfunc(ERR_NONFATAL,
1415 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001416 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001417 if (data > 127 || data < -128)
1418 errfunc(ERR_NONFATAL, "short jump is out of range");
1419 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001420 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 offset += 1;
1422 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001423
Keith Kaniosb7a89542007-04-12 02:40:54 +00001424 case 054:
1425 case 055:
1426 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001427 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001428 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001429 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001430 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001431 offset += 8;
1432 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001433
H. Peter Anvine2c80182005-01-15 22:15:51 +00001434 case 060:
1435 case 061:
1436 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001437 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001438 if (opx->segment != segment) {
1439 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001440 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001441 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001442 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001443 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001444 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001445 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001446 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001447 }
1448 offset += 2;
1449 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001450
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 case 064:
1452 case 065:
1453 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001454 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001455 if (opx->type & (BITS16 | BITS32 | BITS64))
1456 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001457 else
1458 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001459 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001460 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001461 out(offset, segment, &data,
1462 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1463 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001465 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001466 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001467 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 }
1469 offset += size;
1470 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001471
H. Peter Anvine2c80182005-01-15 22:15:51 +00001472 case 070:
1473 case 071:
1474 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001475 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001476 if (opx->segment != segment) {
1477 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001479 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001480 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001481 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001482 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001483 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001484 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001485 }
1486 offset += 4;
1487 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001488
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001489 case 074:
1490 case 075:
1491 case 076:
1492 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001493 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001494 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1495 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001496 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001497 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001498 outfmt->segbase(1 + opx->segment),
1499 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001500 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001501 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001502
H. Peter Anvine2c80182005-01-15 22:15:51 +00001503 case 0140:
1504 case 0141:
1505 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001506 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001507 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001508 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001509 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001510 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001511 NO_SEG);
1512 offset++;
1513 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001514 if (opx->segment == NO_SEG &&
1515 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001516 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001517 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001518 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001519 offset += 2;
1520 }
1521 break;
1522
1523 case 0144:
1524 case 0145:
1525 case 0146:
1526 case 0147:
1527 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001528 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001529 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001530 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001531 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001532 offset++;
1533 break;
1534
1535 case 0150:
1536 case 0151:
1537 case 0152:
1538 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001539 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001540 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001541 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001542 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001543 NO_SEG);
1544 offset++;
1545 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001546 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001547 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001548 offset += 4;
1549 }
1550 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001551
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001552 case 0154:
1553 case 0155:
1554 case 0156:
1555 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001556 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001557 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001558 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001559 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001560 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001561 offset++;
1562 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001563
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001564 case 0160:
1565 case 0161:
1566 case 0162:
1567 case 0163:
1568 case 0164:
1569 case 0165:
1570 case 0166:
1571 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001572 break;
1573
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001574 case 0171:
1575 bytes[0] =
1576 (ins->drexdst << 4) |
1577 (ins->rex & REX_OC ? 0x08 : 0) |
1578 (ins->rex & (REX_R|REX_X|REX_B));
1579 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001580 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001581 offset++;
1582 break;
1583
H. Peter Anvind85d2502008-05-04 17:53:31 -07001584 case 0172:
1585 c = *codes++;
1586 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001587 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001588 opx = &ins->oprs[c & 7];
1589 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1590 errfunc(ERR_NONFATAL,
1591 "non-absolute expression not permitted as argument %d",
1592 c & 7);
1593 } else {
1594 if (opx->offset & ~15) {
1595 errfunc(ERR_WARNING | ERR_WARN_NOV,
1596 "four-bit argument exceeds bounds");
1597 }
1598 bytes[0] |= opx->offset & 15;
1599 }
1600 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1601 offset++;
1602 break;
1603
H. Peter Anvind58656f2008-05-06 20:11:14 -07001604 case 0173:
1605 c = *codes++;
1606 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001607 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001608 bytes[0] |= c & 15;
1609 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1610 offset++;
1611 break;
1612
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001613 case 0250:
1614 case 0251:
1615 case 0252:
1616 case 0253:
1617 data = opx->offset;
1618 /* is_sbyte32() is right here, we have already warned */
1619 if (is_sbyte32(ins, c & 3)) {
1620 bytes[0] = data;
1621 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1622 NO_SEG);
1623 offset++;
1624 } else {
1625 out(offset, segment, &data, OUT_ADDRESS, 4,
1626 opx->segment, opx->wrt);
1627 offset += 4;
1628 }
1629 break;
1630
H. Peter Anvind85d2502008-05-04 17:53:31 -07001631 case 0260:
1632 case 0261:
1633 case 0262:
1634 case 0263:
1635 case 0270:
1636 codes += 2;
1637 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1638 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001639 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001640 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001641 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001642 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1643 offset += 3;
1644 } else {
1645 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001646 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1647 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001648 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1649 offset += 2;
1650 }
1651 break;
1652
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 case 0300:
1654 case 0301:
1655 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001656 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001657 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001658
H. Peter Anvine2c80182005-01-15 22:15:51 +00001659 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001660 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001661 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001662 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001663 offset += 1;
1664 } else
1665 offset += 0;
1666 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001667
H. Peter Anvine2c80182005-01-15 22:15:51 +00001668 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001669 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001671 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001672 offset += 1;
1673 } else
1674 offset += 0;
1675 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001676
H. Peter Anvine2c80182005-01-15 22:15:51 +00001677 case 0312:
1678 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001679
Keith Kaniosb7a89542007-04-12 02:40:54 +00001680 case 0313:
1681 ins->rex = 0;
1682 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001683
H. Peter Anvin23440102007-11-12 21:02:33 -08001684 case 0314:
1685 case 0315:
1686 case 0316:
1687 case 0317:
1688 break;
1689
H. Peter Anvine2c80182005-01-15 22:15:51 +00001690 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001691 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001692 *bytes = 0x66;
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 } else
1696 offset += 0;
1697 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001698
H. Peter Anvine2c80182005-01-15 22:15:51 +00001699 case 0321:
1700 if (bits == 16) {
1701 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001702 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001703 offset += 1;
1704 } else
1705 offset += 0;
1706 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001707
H. Peter Anvine2c80182005-01-15 22:15:51 +00001708 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001709 case 0323:
1710 break;
1711
Keith Kaniosb7a89542007-04-12 02:40:54 +00001712 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001713 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001714 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001715
H. Peter Anvine2c80182005-01-15 22:15:51 +00001716 case 0330:
1717 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001718 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001719 offset += 1;
1720 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001721
H. Peter Anvine2c80182005-01-15 22:15:51 +00001722 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001723 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001724
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001725 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001726 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001727 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001728 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001729 offset += 1;
1730 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001731
Keith Kanios48af1772007-08-17 07:37:52 +00001732 case 0334:
1733 if (ins->rex & REX_R) {
1734 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001735 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001736 offset += 1;
1737 }
1738 ins->rex &= ~(REX_L|REX_R);
1739 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001740
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001741 case 0335:
1742 break;
1743
H. Peter Anvine2c80182005-01-15 22:15:51 +00001744 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001745 if (ins->oprs[0].segment != NO_SEG)
1746 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1747 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001748 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001749 if (size > 0)
1750 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001751 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001752 offset += size;
1753 }
1754 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001755
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001756 case 0360:
1757 break;
1758
1759 case 0361:
1760 bytes[0] = 0x66;
1761 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1762 offset += 1;
1763 break;
1764
1765 case 0362:
1766 case 0363:
1767 bytes[0] = c - 0362 + 0xf2;
1768 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1769 offset += 1;
1770 break;
1771
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001772 case 0364:
1773 case 0365:
1774 break;
1775
Keith Kanios48af1772007-08-17 07:37:52 +00001776 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001777 case 0367:
1778 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001779 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001780 offset += 1;
1781 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001782
H. Peter Anvine2c80182005-01-15 22:15:51 +00001783 case 0370:
1784 case 0371:
1785 case 0372:
1786 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001787
H. Peter Anvine2c80182005-01-15 22:15:51 +00001788 case 0373:
1789 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001790 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001791 offset += 1;
1792 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001793
H. Peter Anvine2c80182005-01-15 22:15:51 +00001794 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001795 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001796 ea ea_data;
1797 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001798 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001799 uint8_t *p;
1800 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001801
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001802 if (c <= 0177) {
1803 /* pick rfield from operand b */
1804 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001805 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001806 } else {
1807 /* rfield is constant */
1808 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001810 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811
1812 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001813 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001814 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001815 errfunc(ERR_NONFATAL, "invalid effective address");
1816 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001817
Charles Crayne7e975552007-11-03 22:06:13 -07001818
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 p = bytes;
1820 *p++ = ea_data.modrm;
1821 if (ea_data.sib_present)
1822 *p++ = ea_data.sib;
1823
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001824 /* DREX suffixes come between the SIB and the displacement */
1825 if (ins->rex & REX_D) {
1826 *p++ =
1827 (ins->drexdst << 4) |
1828 (ins->rex & REX_OC ? 0x08 : 0) |
1829 (ins->rex & (REX_R|REX_X|REX_B));
1830 ins->rex = 0;
1831 }
1832
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001834 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001835
1836 switch (ea_data.bytes) {
1837 case 0:
1838 break;
1839 case 1:
1840 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1841 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001842 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 ins->oprs[(c >> 3) & 7].segment,
1844 ins->oprs[(c >> 3) & 7].wrt);
1845 } else {
1846 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001847 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001848 NO_SEG, NO_SEG);
1849 }
1850 s++;
1851 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001852 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001853 case 2:
1854 case 4:
1855 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001856 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001857 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001858 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1859 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001860 ins->oprs[(c >> 3) & 7].segment,
1861 ins->oprs[(c >> 3) & 7].wrt);
1862 s += ea_data.bytes;
1863 break;
1864 }
1865 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001866 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001867 errfunc(ERR_PANIC, "internal instruction table corrupt"
1868 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001869 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001870 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001871 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001872}
1873
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001874static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001875{
1876 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1877 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1878 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001879 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001880}
1881
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001882static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001883{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001884 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1885 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001886 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001887 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001888}
1889
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001890static int op_rexflags(const operand * o, int mask)
1891{
1892 int32_t flags;
1893 int val;
1894
1895 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1896 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1897 }
1898
H. Peter Anvina4835d42008-05-20 14:21:29 -07001899 flags = nasm_reg_flags[o->basereg];
1900 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001901
1902 return rexflags(val, flags, mask);
1903}
1904
1905static int rexflags(int val, int32_t flags, int mask)
1906{
1907 int rex = 0;
1908
1909 if (val >= 8)
1910 rex |= REX_B|REX_X|REX_R;
1911 if (flags & BITS64)
1912 rex |= REX_W;
1913 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1914 rex |= REX_H;
1915 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1916 rex |= REX_P;
1917
1918 return rex & mask;
1919}
1920
H. Peter Anvin3360d792007-09-11 04:16:57 +00001921static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001922{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001923 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001924
1925 ret = 100;
1926
1927 /*
1928 * Check the opcode
1929 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001930 if (itemp->opcode != instruction->opcode)
1931 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001932
1933 /*
1934 * Count the operands
1935 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001936 if (itemp->operands != instruction->operands)
1937 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001938
1939 /*
1940 * Check that no spurious colons or TOs are present
1941 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001942 for (i = 0; i < itemp->operands; i++)
1943 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1944 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001945
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001946 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001947 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001948 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001949 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001950 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001951
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001952 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1953
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001954 switch (itemp->flags & IF_SMASK) {
1955 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001956 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001957 break;
1958 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001959 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001960 break;
1961 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001962 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001963 break;
1964 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001965 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001966 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001967 case IF_SO:
1968 size[i] = BITS128;
1969 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001970 case IF_SY:
1971 size[i] = BITS256;
1972 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001973 case IF_SZ:
1974 switch (bits) {
1975 case 16:
1976 size[i] = BITS16;
1977 break;
1978 case 32:
1979 size[i] = BITS32;
1980 break;
1981 case 64:
1982 size[i] = BITS64;
1983 break;
1984 }
1985 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001986 default:
1987 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001988 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001989 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001990 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001991 switch (itemp->flags & IF_SMASK) {
1992 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001993 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001994 break;
1995 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001996 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001997 break;
1998 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001999 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002000 break;
2001 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002002 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002003 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002004 case IF_SO:
2005 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002006 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002007 case IF_SY:
2008 asize = BITS256;
2009 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002010 case IF_SZ:
2011 switch (bits) {
2012 case 16:
2013 asize = BITS16;
2014 break;
2015 case 32:
2016 asize = BITS32;
2017 break;
2018 case 64:
2019 asize = BITS64;
2020 break;
2021 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002022 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002023 default:
2024 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002025 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002026 for (i = 0; i < MAX_OPERANDS; i++)
2027 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002028 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002029
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002030 /*
2031 * Check that the operand flags all match up
2032 */
2033 for (i = 0; i < itemp->operands; i++) {
2034 int32_t type = instruction->oprs[i].type;
2035 if (!(type & SIZE_MASK))
2036 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002037
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002038 if (itemp->opd[i] & SAME_AS) {
2039 int j = itemp->opd[i] & ~SAME_AS;
2040 if (type != instruction->oprs[j].type ||
2041 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2042 return 0;
2043 } else if (itemp->opd[i] & ~type ||
2044 ((itemp->opd[i] & SIZE_MASK) &&
2045 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2046 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2047 (type & SIZE_MASK))
2048 return 0;
2049 else
2050 return 1;
2051 }
2052 }
2053
2054 /*
2055 * Check operand sizes
2056 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002057 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002058 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2059 asize = 0;
2060 for (i = 0; i < oprs; i++) {
2061 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2062 int j;
2063 for (j = 0; j < oprs; j++)
2064 size[j] = asize;
2065 break;
2066 }
2067 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002068 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002069 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002070 }
2071
Keith Kaniosb7a89542007-04-12 02:40:54 +00002072 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002073 if (!(itemp->opd[i] & SIZE_MASK) &&
2074 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002075 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002076 }
2077
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002078 /*
2079 * Check template is okay at the set cpu level
2080 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002081 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002082 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002083
Keith Kaniosb7a89542007-04-12 02:40:54 +00002084 /*
2085 * Check if instruction is available in long mode
2086 */
2087 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2088 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002089
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002090 /*
2091 * Check if special handling needed for Jumps
2092 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002093 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002094 return 99;
2095
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002096 return ret;
2097}
2098
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002099static ea *process_ea(operand * input, ea * output, int bits,
2100 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002101{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002102 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002103
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002104 /* REX flags for the rfield operand */
2105 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2106
Keith Kaniosb7a89542007-04-12 02:40:54 +00002107 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002108 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002109 int32_t f;
2110
2111 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002112 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002113 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002114 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002115 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002116
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002117 if (REG_EA & ~f)
2118 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002119
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002120 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2121
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002122 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002123 output->bytes = 0; /* no offset necessary either */
2124 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002125 } else { /* it's a memory reference */
2126 if (input->basereg == -1
2127 && (input->indexreg == -1 || input->scale == 0)) {
2128 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002129 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002130 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002131 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002132 scale = 0;
2133 index = 4;
2134 base = 5;
2135 output->sib = (scale << 6) | (index << 3) | base;
2136 output->bytes = 4;
2137 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002138 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002139 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002140 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002141 output->bytes = (addrbits != 16 ? 4 : 2);
2142 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002143 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002144 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002145 } else { /* it's an indirection */
2146 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002147 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002148 int hb = input->hintbase, ht = input->hinttype;
2149 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002150 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002151 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002152
H. Peter Anvine2c80182005-01-15 22:15:51 +00002153 if (s == 0)
2154 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002155
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002156 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002157 it = nasm_regvals[i];
2158 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002159 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002160 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002161 ix = 0;
2162 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002163
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002164 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002165 bt = nasm_regvals[b];
2166 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002167 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002168 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002169 bx = 0;
2170 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002171
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002172 /* check for a 32/64-bit memory reference... */
2173 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002174 /* it must be a 32/64-bit memory reference. Firstly we have
2175 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002176 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002177
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002178 if (it != -1) {
2179 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2180 sok &= ix;
2181 else
2182 return NULL;
2183 }
2184
2185 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002186 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002187 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002188 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002189 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002190 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002191 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002192
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002193 /* While we're here, ensure the user didn't specify
2194 WORD or QWORD. */
2195 if (input->disp_size == 16 || input->disp_size == 64)
2196 return NULL;
2197
2198 if (addrbits == 16 ||
2199 (addrbits == 32 && !(sok & BITS32)) ||
2200 (addrbits == 64 && !(sok & BITS64)))
2201 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002202
Keith Kaniosb7a89542007-04-12 02:40:54 +00002203 /* now reorganize base/index */
2204 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002205 ((hb == b && ht == EAH_NOTBASE)
2206 || (hb == i && ht == EAH_MAKEBASE))) {
2207 /* swap if hints say so */
2208 t = bt, bt = it, it = t;
2209 t = bx, bx = ix, ix = t;
2210 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002211 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002212 bt = -1, bx = 0, s++;
2213 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2214 /* make single reg base, unless hint */
2215 bt = it, bx = ix, it = -1, ix = 0;
2216 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002217 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002218 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002219 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002220 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002221 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002222 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002223 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002224 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002225 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002226 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002227 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002228 t = ix, ix = bx, bx = t;
2229 }
Keith Kanios48af1772007-08-17 07:37:52 +00002230 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002231 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002232 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002233
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002234 output->rex |= rexflags(it, ix, REX_X);
2235 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002236
Keith Kanios48af1772007-08-17 07:37:52 +00002237 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002238 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002239 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002240
Keith Kaniosb7a89542007-04-12 02:40:54 +00002241 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002242 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002243 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002244 } else {
2245 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002246 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002247 seg == NO_SEG && !forw_ref &&
2248 !(input->eaflags &
2249 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2250 mod = 0;
2251 else if (input->eaflags & EAF_BYTEOFFS ||
2252 (o >= -128 && o <= 127 && seg == NO_SEG
2253 && !forw_ref
2254 && !(input->eaflags & EAF_WORDOFFS)))
2255 mod = 1;
2256 else
2257 mod = 2;
2258 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002259
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002260 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002261 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2262 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002263 } else {
2264 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002265 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002266
Keith Kaniosb7a89542007-04-12 02:40:54 +00002267 if (it == -1)
2268 index = 4, s = 1;
2269 else
2270 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002271
H. Peter Anvine2c80182005-01-15 22:15:51 +00002272 switch (s) {
2273 case 1:
2274 scale = 0;
2275 break;
2276 case 2:
2277 scale = 1;
2278 break;
2279 case 4:
2280 scale = 2;
2281 break;
2282 case 8:
2283 scale = 3;
2284 break;
2285 default: /* then what the smeg is it? */
2286 return NULL; /* panic */
2287 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002288
Keith Kaniosb7a89542007-04-12 02:40:54 +00002289 if (bt == -1) {
2290 base = 5;
2291 mod = 0;
2292 } else {
2293 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002294 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002295 seg == NO_SEG && !forw_ref &&
2296 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002297 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2298 mod = 0;
2299 else if (input->eaflags & EAF_BYTEOFFS ||
2300 (o >= -128 && o <= 127 && seg == NO_SEG
2301 && !forw_ref
2302 && !(input->eaflags & EAF_WORDOFFS)))
2303 mod = 1;
2304 else
2305 mod = 2;
2306 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002307
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002308 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002309 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2310 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002311 output->sib = (scale << 6) | (index << 3) | base;
2312 }
2313 } else { /* it's 16-bit */
2314 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002315
Keith Kaniosb7a89542007-04-12 02:40:54 +00002316 /* check for 64-bit long mode */
2317 if (addrbits == 64)
2318 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002319
H. Peter Anvine2c80182005-01-15 22:15:51 +00002320 /* check all registers are BX, BP, SI or DI */
2321 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2322 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2323 && i != R_SI && i != R_DI))
2324 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002325
Keith Kaniosb7a89542007-04-12 02:40:54 +00002326 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002327 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002328 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002329
H. Peter Anvine2c80182005-01-15 22:15:51 +00002330 if (s != 1 && i != -1)
2331 return NULL; /* no can do, in 16-bit EA */
2332 if (b == -1 && i != -1) {
2333 int tmp = b;
2334 b = i;
2335 i = tmp;
2336 } /* swap */
2337 if ((b == R_SI || b == R_DI) && i != -1) {
2338 int tmp = b;
2339 b = i;
2340 i = tmp;
2341 }
2342 /* have BX/BP as base, SI/DI index */
2343 if (b == i)
2344 return NULL; /* shouldn't ever happen, in theory */
2345 if (i != -1 && b != -1 &&
2346 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2347 return NULL; /* invalid combinations */
2348 if (b == -1) /* pure offset: handled above */
2349 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002350
H. Peter Anvine2c80182005-01-15 22:15:51 +00002351 rm = -1;
2352 if (i != -1)
2353 switch (i * 256 + b) {
2354 case R_SI * 256 + R_BX:
2355 rm = 0;
2356 break;
2357 case R_DI * 256 + R_BX:
2358 rm = 1;
2359 break;
2360 case R_SI * 256 + R_BP:
2361 rm = 2;
2362 break;
2363 case R_DI * 256 + R_BP:
2364 rm = 3;
2365 break;
2366 } else
2367 switch (b) {
2368 case R_SI:
2369 rm = 4;
2370 break;
2371 case R_DI:
2372 rm = 5;
2373 break;
2374 case R_BP:
2375 rm = 6;
2376 break;
2377 case R_BX:
2378 rm = 7;
2379 break;
2380 }
2381 if (rm == -1) /* can't happen, in theory */
2382 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002383
H. Peter Anvine2c80182005-01-15 22:15:51 +00002384 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2385 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2386 mod = 0;
2387 else if (input->eaflags & EAF_BYTEOFFS ||
2388 (o >= -128 && o <= 127 && seg == NO_SEG
2389 && !forw_ref
2390 && !(input->eaflags & EAF_WORDOFFS)))
2391 mod = 1;
2392 else
2393 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002394
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002395 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002396 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002397 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002398 }
2399 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002400 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002401
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002402 output->size = 1 + output->sib_present + output->bytes;
2403 return output;
2404}
2405
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002406static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002407{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002408 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002409 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002410
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002411 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002412
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002413 switch (ins->prefixes[PPS_ASIZE]) {
2414 case P_A16:
2415 valid &= 16;
2416 break;
2417 case P_A32:
2418 valid &= 32;
2419 break;
2420 case P_A64:
2421 valid &= 64;
2422 break;
2423 case P_ASP:
2424 valid &= (addrbits == 32) ? 16 : 32;
2425 break;
2426 default:
2427 break;
2428 }
2429
2430 for (j = 0; j < ins->operands; j++) {
2431 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002432 int32_t i, b;
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].indexreg < EXPR_REG_START
2436 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002437 i = 0;
2438 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002439 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002440
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002441 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002442 if (ins->oprs[j].basereg < EXPR_REG_START
2443 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002444 b = 0;
2445 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002446 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002447
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002448 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002449 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002450
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002451 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002452 int ds = ins->oprs[j].disp_size;
2453 if ((addrbits != 64 && ds > 8) ||
2454 (addrbits == 64 && ds == 16))
2455 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002456 } else {
2457 if (!(REG16 & ~b))
2458 valid &= 16;
2459 if (!(REG32 & ~b))
2460 valid &= 32;
2461 if (!(REG64 & ~b))
2462 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002463
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002464 if (!(REG16 & ~i))
2465 valid &= 16;
2466 if (!(REG32 & ~i))
2467 valid &= 32;
2468 if (!(REG64 & ~i))
2469 valid &= 64;
2470 }
2471 }
2472 }
2473
2474 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002475 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002476 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002477 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002478 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002479 ins->prefixes[PPS_ASIZE] = pref;
2480 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002481 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002482 /* Impossible... */
2483 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002484 ins->addr_size = addrbits; /* Error recovery */
2485 }
2486
2487 defdisp = ins->addr_size == 16 ? 16 : 32;
2488
2489 for (j = 0; j < ins->operands; j++) {
2490 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2491 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2492 != ins->addr_size) {
2493 /* mem_offs sizes must match the address size; if not,
2494 strip the MEM_OFFS bit and match only EA instructions */
2495 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2496 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002497 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002498}