blob: ad7ea70603243f15a563bd6df189473cdb490e3d [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.)
H. Peter Anvindcffe4b2008-10-10 22:10:31 -070010 * \1..\4 - that many literal bytes follow in the code stream
11 * \5 - add 4 to the primary operand number (b, low octdigit)
12 * \6 - add 4 to the secondary operand number (a, middle octdigit)
13 * \7 - add 4 to both the primary and the secondary operand number
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070014 * \10..\13 - a literal byte follows in the code stream, to be added
15 * to the register value of operand 0..3
16 * \14..\17 - a signed byte immediate operand, from operand 0..3
17 * \20..\23 - a byte immediate operand, from operand 0..3
18 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
19 * \30..\33 - a word immediate operand, from operand 0..3
20 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000021 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070022 * \40..\43 - a long immediate operand, from operand 0..3
23 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070024 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070025 * \50..\53 - a byte relative operand, from operand 0..3
26 * \54..\57 - a qword immediate operand, from operand 0..3
27 * \60..\63 - a word relative operand, from operand 0..3
28 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000029 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070030 * \70..\73 - a long relative operand, from operand 0..3
H. Peter Anvinc1377e92008-10-06 23:40:31 -070031 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000032 * \1ab - a ModRM, calculated on EA in operand a, with the spare
33 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070034 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080035 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
36 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvinc1377e92008-10-06 23:40:31 -070037 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080038 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070039 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070040 * \160..\163 - this instruction uses DREX rather than REX, with the
41 * OC0 field set to 0, and the dest field taken from
42 * operand 0..3.
43 * \164..\167 - this instruction uses DREX rather than REX, with the
44 * OC0 field set to 1, and the dest field taken from
45 * operand 0..3.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070046 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070047 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070048 * the 4-bit immediate from operand b in bits 3..0.
H. Peter Anvind58656f2008-05-06 20:11:14 -070049 * \173\xab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070050 * the value b in bits 3..0.
51 * \174\a - the register number from operand a in bits 7..4, and
52 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000053 * \2ab - a ModRM, calculated on EA in operand a, with the spare
54 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070055 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
56 * is not equal to the truncated and sign-extended 32-bit
57 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvin588df782008-10-07 10:05:10 -070058 * \254..\257 - a signed 32-bit operand to be extended to 64 bits.
H. Peter Anvind85d2502008-05-04 17:53:31 -070059 * \260..\263 - this instruction uses VEX rather than REX, with the
60 * V field taken from operand 0..3.
61 * \270 - this instruction uses VEX rather than REX, with the
62 * V field set to 1111b.
63 *
64 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070065 * \mm\wlp where mm is the M field; and wlp is:
66 * 00 0ww lpp
H. Peter Anvinbd420c72008-05-22 11:24:35 -070067 * [w0] ww = 0 for W = 0
68 * [w1] ww = 1 for W = 1
69 * [wx] ww = 2 for W don't care (always assembled as 0)
70 * [ww] ww = 3 for W used as REX.W
71 *
H. Peter Anvind85d2502008-05-04 17:53:31 -070072 *
H. Peter Anvinc1377e92008-10-06 23:40:31 -070073 * \274..\277 - a signed byte immediate operand, from operand 0..3,
74 * which is to be extended to the operand size.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000075 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
76 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000077 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000078 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080079 * \314 - (disassembler only) invalid with REX.B
80 * \315 - (disassembler only) invalid with REX.X
81 * \316 - (disassembler only) invalid with REX.R
82 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000083 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
84 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
85 * \322 - indicates that this instruction is only valid when the
86 * operand size is the default (instruction to disassembler,
87 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000088 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000089 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000090 * \330 - a literal byte follows in the code stream, to be added
91 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000092 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000093 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070094 * \332 - REP prefix (0xF2 byte) used as opcode extension.
95 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000096 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070097 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin962e3052008-08-28 17:47:16 -070098 * \336 - force a REP(E) prefix (0xF2) even if not specified.
99 * \337 - force a REPNE prefix (0xF3) even if not specified.
100 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000101 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102 * Operand 0 had better be a segmentless constant.
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -0800103 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700104 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
105 * (POP is never used for CS) depending on operand 0
106 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
107 * on operand 0
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700108 * \360 - no SSE prefix (== \364\331)
109 * \361 - 66 SSE prefix (== \366\331)
110 * \362 - F2 SSE prefix (== \364\332)
111 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000112 * \364 - operand-size prefix (0x66) not permitted
113 * \365 - address-size prefix (0x67) not permitted
114 * \366 - operand-size prefix (0x66) used as opcode extension
115 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000116 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
117 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000118 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
119 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120 */
121
H. Peter Anvinfe501952007-10-02 21:53:51 -0700122#include "compiler.h"
123
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000124#include <stdio.h>
125#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000126#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000127
128#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000129#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130#include "assemble.h"
131#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700132#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000133
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000134typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000135 int sib_present; /* is a SIB byte necessary? */
136 int bytes; /* # of bytes of offset needed */
137 int size; /* lazy - this is sib+bytes+1 */
138 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000139} ea;
140
Keith Kaniosb7a89542007-04-12 02:40:54 +0000141static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000142static efunc errfunc;
143static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000144static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000145
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700146static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700147static void gencode(int32_t segment, int64_t offset, int bits,
148 insn * ins, const struct itemplate *temp,
149 int64_t insn_end);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000150static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000151static int32_t regflag(const operand *);
152static int32_t regval(const operand *);
153static int rexflags(int, int32_t, int);
154static int op_rexflags(const operand *, int);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700155static ea *process_ea(operand *, ea *, int, int, int, int32_t);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700156static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000157
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700158static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000159{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700160 return ins->prefixes[pos] == prefix;
161}
162
163static void assert_no_prefix(insn * ins, enum prefix_pos pos)
164{
165 if (ins->prefixes[pos])
166 errfunc(ERR_NONFATAL, "invalid %s prefix",
167 prefix_name(ins->prefixes[pos]));
168}
169
170static const char *size_name(int size)
171{
172 switch (size) {
173 case 1:
174 return "byte";
175 case 2:
176 return "word";
177 case 4:
178 return "dword";
179 case 8:
180 return "qword";
181 case 10:
182 return "tword";
183 case 16:
184 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700185 case 32:
186 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700187 default:
188 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000189 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700190}
191
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700192static void warn_overflow(int size, const struct operand *o)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700193{
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700194 if (size < 8 && o->wrt == NO_SEG && o->segment == NO_SEG) {
Charles Craynedd462c82007-11-04 15:28:30 -0800195 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700196 int64_t data = o->offset;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000197
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700198 if (data < ~lim || data > lim)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700199 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700200 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700201 }
202}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000203/*
204 * This routine wrappers the real output format's output routine,
205 * in order to pass a copy of the data off to the listing file
206 * generator at the same time.
207 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800208static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800209 enum out_type type, uint64_t size,
210 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000211{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000212 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000213 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800214 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000215
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800216 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
217 /*
218 * This is a non-relocated address, and we're going to
219 * convert it into RAWDATA format.
220 */
221 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800222
223 if (size > 8) {
224 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
225 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800226 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700227
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800228 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800229 data = p;
230 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000231 }
232
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800233 list->output(offset, data, type, size);
234
Frank Kotlerabebb082003-09-06 04:45:37 +0000235 /*
236 * this call to src_get determines when we call the
237 * debug-format-specific "linenum" function
238 * it updates lineno and lnfname to the current values
239 * returning 0 if "same as last time", -2 if lnfname
240 * changed, and the amount by which lineno changed,
241 * if it did. thus, these variables must be static
242 */
243
H. Peter Anvine2c80182005-01-15 22:15:51 +0000244 if (src_get(&lineno, &lnfname)) {
245 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000246 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000247
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800248 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000249}
250
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700251static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700252 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000253{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800254 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000255 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000256
Charles Craynef1aefd82008-09-30 16:11:32 -0700257 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700258 return false;
259 if (!optimizing)
260 return false;
261 if (optimizing < 0 && c == 0371)
262 return false;
263
H. Peter Anvine2c80182005-01-15 22:15:51 +0000264 isize = calcsize(segment, offset, bits, ins, code);
265 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700266 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000267
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700268 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
269 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000270}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000271
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800272int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000273 insn * instruction, struct ofmt *output, efunc error,
274 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000275{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000276 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000277 int j;
278 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800279 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000280 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800281 int64_t start = offset;
282 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000283
H. Peter Anvine2c80182005-01-15 22:15:51 +0000284 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000285 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000286 outfmt = output; /* likewise */
287 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000288
H. Peter Anvine2c80182005-01-15 22:15:51 +0000289 switch (instruction->opcode) {
290 case -1:
291 return 0;
292 case I_DB:
293 wsize = 1;
294 break;
295 case I_DW:
296 wsize = 2;
297 break;
298 case I_DD:
299 wsize = 4;
300 break;
301 case I_DQ:
302 wsize = 8;
303 break;
304 case I_DT:
305 wsize = 10;
306 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700307 case I_DO:
308 wsize = 16;
309 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700310 case I_DY:
311 wsize = 32;
312 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700313 default:
314 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000315 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000316
H. Peter Anvineba20a72002-04-30 20:53:55 +0000317 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000319 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000320 if (t < 0)
321 errfunc(ERR_PANIC,
322 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000323
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324 while (t--) { /* repeat TIMES times */
325 for (e = instruction->eops; e; e = e->next) {
326 if (e->type == EOT_DB_NUMBER) {
327 if (wsize == 1) {
328 if (e->segment != NO_SEG)
329 errfunc(ERR_NONFATAL,
330 "one-byte relocation attempted");
331 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000332 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800334 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000336 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700337 errfunc(ERR_NONFATAL,
338 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000339 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 } else
341 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800342 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000343 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700344 } else if (e->type == EOT_DB_STRING ||
345 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000346 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000347
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800349 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000351
H. Peter Anvine2c80182005-01-15 22:15:51 +0000352 if (align) {
353 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100354 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800355 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 }
357 offset += e->stringlen + align;
358 }
359 }
360 if (t > 0 && t == instruction->times - 1) {
361 /*
362 * Dummy call to list->output to give the offset to the
363 * listing module.
364 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800365 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 list->uplevel(LIST_TIMES);
367 }
368 }
369 if (instruction->times > 1)
370 list->downlevel(LIST_TIMES);
371 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000372 }
373
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700375 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000377
H. Peter Anvin418ca702008-05-30 10:42:30 -0700378 fp = fopen(fname, "rb");
379 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000380 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
381 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700382 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000383 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
384 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700385 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700386 static char buf[4096];
387 size_t t = instruction->times;
388 size_t base = 0;
389 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000390
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 len = ftell(fp);
392 if (instruction->eops->next) {
393 base = instruction->eops->next->offset;
394 len -= base;
395 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700396 len > (size_t)instruction->eops->next->next->offset)
397 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 }
399 /*
400 * Dummy call to list->output to give the offset to the
401 * listing module.
402 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800403 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000404 list->uplevel(LIST_INCBIN);
405 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700406 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000407
H. Peter Anvine2c80182005-01-15 22:15:51 +0000408 fseek(fp, base, SEEK_SET);
409 l = len;
410 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000411 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700412 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 fp);
414 if (!m) {
415 /*
416 * This shouldn't happen unless the file
417 * actually changes while we are reading
418 * it.
419 */
420 error(ERR_NONFATAL,
421 "`incbin': unexpected EOF while"
422 " reading file `%s'", fname);
423 t = 0; /* Try to exit cleanly */
424 break;
425 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800426 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000427 NO_SEG, NO_SEG);
428 l -= m;
429 }
430 }
431 list->downlevel(LIST_INCBIN);
432 if (instruction->times > 1) {
433 /*
434 * Dummy call to list->output to give the offset to the
435 * listing module.
436 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800437 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000438 list->uplevel(LIST_TIMES);
439 list->downlevel(LIST_TIMES);
440 }
441 fclose(fp);
442 return instruction->times * len;
443 }
444 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000445 }
446
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700447 /* Check to see if we need an address-size prefix */
448 add_asp(instruction, bits);
449
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800450 size_prob = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -0700451
452 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000453 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700454 if (m == 100 ||
455 (m == 99 && jmp_match(segment, offset, bits,
456 instruction, temp->code))) {
457 /* Matches! */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800458 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -0700459 instruction, temp->code);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000460 itimes = instruction->times;
461 if (insn_size < 0) /* shouldn't be, on pass two */
462 error(ERR_PANIC, "errors made it through from pass one");
463 else
464 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700465 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000466 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000467 switch (instruction->prefixes[j]) {
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -0800468 case P_WAIT:
469 c = 0x9B;
470 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000471 case P_LOCK:
472 c = 0xF0;
473 break;
474 case P_REPNE:
475 case P_REPNZ:
476 c = 0xF2;
477 break;
478 case P_REPE:
479 case P_REPZ:
480 case P_REP:
481 c = 0xF3;
482 break;
483 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000484 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700485 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800486 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000487 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000488 c = 0x2E;
489 break;
490 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000491 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700492 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800493 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000494 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000495 c = 0x3E;
496 break;
497 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000498 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700499 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800500 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000501 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000502 c = 0x26;
503 break;
504 case R_FS:
505 c = 0x64;
506 break;
507 case R_GS:
508 c = 0x65;
509 break;
510 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000511 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700512 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800513 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000514 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000515 c = 0x36;
516 break;
517 case R_SEGR6:
518 case R_SEGR7:
519 error(ERR_NONFATAL,
520 "segr6 and segr7 cannot be used as prefixes");
521 break;
522 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000523 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000524 error(ERR_NONFATAL,
525 "16-bit addressing is not supported "
526 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700527 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000528 c = 0x67;
529 break;
530 case P_A32:
531 if (bits != 32)
532 c = 0x67;
533 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700534 case P_A64:
535 if (bits != 64) {
536 error(ERR_NONFATAL,
537 "64-bit addressing is only supported "
538 "in 64-bit mode");
539 }
540 break;
541 case P_ASP:
542 c = 0x67;
543 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000544 case P_O16:
545 if (bits != 16)
546 c = 0x66;
547 break;
548 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000549 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000550 c = 0x66;
551 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700552 case P_O64:
553 /* REX.W */
554 break;
555 case P_OSP:
556 c = 0x66;
557 break;
558 case P_none:
559 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000560 default:
561 error(ERR_PANIC, "invalid instruction prefix");
562 }
563 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800564 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000565 NO_SEG, NO_SEG);
566 offset++;
567 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700568 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000569 insn_end = offset + insn_size;
H. Peter Anvin833caea2008-10-04 19:02:30 -0700570 gencode(segment, offset, bits, instruction,
571 temp, insn_end);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000572 offset += insn_size;
573 if (itimes > 0 && itimes == instruction->times - 1) {
574 /*
575 * Dummy call to list->output to give the offset to the
576 * listing module.
577 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800578 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000579 list->uplevel(LIST_TIMES);
580 }
581 }
582 if (instruction->times > 1)
583 list->downlevel(LIST_TIMES);
584 return offset - start;
585 } else if (m > 0 && m > size_prob) {
586 size_prob = m;
587 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000588 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000589
H. Peter Anvine2c80182005-01-15 22:15:51 +0000590 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000591 switch (size_prob) {
592 case 1:
593 error(ERR_NONFATAL, "operation size not specified");
594 break;
595 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000596 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000597 break;
598 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000599 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000600 break;
601 case 4:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800602 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
603 bits);
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000604 break;
605 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000606 error(ERR_NONFATAL,
607 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000608 break;
609 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000610 }
611 return 0;
612}
613
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800614int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000615 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000616{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000617 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000618
H. Peter Anvine2c80182005-01-15 22:15:51 +0000619 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000620 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000621
622 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000624
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700625 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
626 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700627 instruction->opcode == I_DT || instruction->opcode == I_DO ||
628 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000629 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000630 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000631
H. Peter Anvine2c80182005-01-15 22:15:51 +0000632 isize = 0;
633 switch (instruction->opcode) {
634 case I_DB:
635 wsize = 1;
636 break;
637 case I_DW:
638 wsize = 2;
639 break;
640 case I_DD:
641 wsize = 4;
642 break;
643 case I_DQ:
644 wsize = 8;
645 break;
646 case I_DT:
647 wsize = 10;
648 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700649 case I_DO:
650 wsize = 16;
651 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700652 case I_DY:
653 wsize = 32;
654 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700655 default:
656 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000658
H. Peter Anvine2c80182005-01-15 22:15:51 +0000659 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000660 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000661
H. Peter Anvine2c80182005-01-15 22:15:51 +0000662 osize = 0;
663 if (e->type == EOT_DB_NUMBER)
664 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700665 else if (e->type == EOT_DB_STRING ||
666 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000667 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000668
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 align = (-osize) % wsize;
670 if (align < 0)
671 align += wsize;
672 isize += osize + align;
673 }
674 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000675 }
676
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700678 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700680 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000681
H. Peter Anvin418ca702008-05-30 10:42:30 -0700682 fp = fopen(fname, "rb");
683 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000684 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
685 fname);
686 else if (fseek(fp, 0L, SEEK_END) < 0)
687 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
688 fname);
689 else {
690 len = ftell(fp);
691 fclose(fp);
692 if (instruction->eops->next) {
693 len -= instruction->eops->next->offset;
694 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700695 len > (size_t)instruction->eops->next->next->offset) {
696 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000697 }
698 }
699 return instruction->times * len;
700 }
701 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000702 }
703
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700704 /* Check to see if we need an address-size prefix */
705 add_asp(instruction, bits);
706
Keith Kaniosb7a89542007-04-12 02:40:54 +0000707 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
708 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700709 if (m == 100 ||
710 (m == 99 && jmp_match(segment, offset, bits,
711 instruction, temp->code))) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000712 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800713 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700714 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000715 int j;
716
717 isize = calcsize(segment, offset, bits, instruction, codes);
718 if (isize < 0)
719 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700720 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700721 switch (instruction->prefixes[j]) {
722 case P_A16:
723 if (bits != 16)
724 isize++;
725 break;
726 case P_A32:
727 if (bits != 32)
728 isize++;
729 break;
730 case P_O16:
731 if (bits != 16)
732 isize++;
733 break;
734 case P_O32:
735 if (bits == 16)
736 isize++;
737 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700738 case P_A64:
739 case P_O64:
740 case P_none:
741 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700742 default:
743 isize++;
744 break;
745 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000746 }
747 return isize * instruction->times;
748 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000749 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000750 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000751}
752
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700753static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000754{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700755 return o->wrt == NO_SEG && o->segment == NO_SEG &&
756 !(o->opflags & OPFLAG_FORWARD) &&
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700757 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000758}
759
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700760/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700761static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700762{
763 int16_t v;
764
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700765 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700766 return false;
767
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700768 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700769 return v >= -128 && v <= 127;
770}
771
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700772static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700773{
774 int32_t v;
775
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700776 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700777 return false;
778
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700779 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700780 return v >= -128 && v <= 127;
781}
782
H. Peter Anvin507ae032008-10-09 15:37:10 -0700783/* Common construct */
784#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
785
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800786static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700787 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000788{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800789 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000790 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000791 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700792 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700793 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700794 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000795
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700796 ins->rex = 0; /* Ensure REX is reset */
797
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700798 if (ins->prefixes[PPS_OSIZE] == P_O64)
799 ins->rex |= REX_W;
800
H. Peter Anvine2c80182005-01-15 22:15:51 +0000801 (void)segment; /* Don't warn that this parameter is unused */
802 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000803
H. Peter Anvin839eca22007-10-29 23:12:47 -0700804 while (*codes) {
805 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700806 op1 = (c & 3) + ((opex & 1) << 2);
807 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
808 opx = &ins->oprs[op1];
809 opex = 0; /* For the next iteration */
810
H. Peter Anvin839eca22007-10-29 23:12:47 -0700811 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000812 case 01:
813 case 02:
814 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700815 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000816 codes += c, length += c;
817 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700818
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700819 case 05:
820 case 06:
821 case 07:
822 opex = c;
823 break;
824
H. Peter Anvin507ae032008-10-09 15:37:10 -0700825 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000826 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700827 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000828 codes++, length++;
829 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700830
831 case4(014):
832 case4(020):
833 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000834 length++;
835 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700836
837 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000838 length += 2;
839 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700840
841 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700842 if (opx->type & (BITS16 | BITS32 | BITS64))
843 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000844 else
845 length += (bits == 16) ? 2 : 4;
846 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700847
848 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 length += 4;
850 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700851
852 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700853 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700855
856 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 length++;
858 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700859
860 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000861 length += 8; /* MOV reg64/imm */
862 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700863
864 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 length += 2;
866 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700867
868 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700869 if (opx->type & (BITS16 | BITS32 | BITS64))
870 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000871 else
872 length += (bits == 16) ? 2 : 4;
873 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700874
875 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000876 length += 4;
877 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700878
879 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700880 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700882
883 case4(0140):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700884 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700886
887 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800888 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 length++;
890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
892 case4(0150):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700893 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700894 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700895
896 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800897 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700898 length++;
899 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700900
901 case4(0160):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700902 length++;
903 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700904 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700905 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700906
907 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700908 length++;
909 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700910 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700911 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700912
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700913 case 0171:
914 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700915
H. Peter Anvind85d2502008-05-04 17:53:31 -0700916 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700917 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700918 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700919 codes++;
920 length++;
921 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700922
923 case4(0250):
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700924 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700925 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700926
927 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -0700928 length += 4;
929 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700930
931 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -0700932 ins->rex |= REX_V;
933 ins->drexdst = regval(opx);
934 ins->vex_m = *codes++;
935 ins->vex_wlp = *codes++;
936 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700937
H. Peter Anvind85d2502008-05-04 17:53:31 -0700938 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700939 ins->rex |= REX_V;
940 ins->drexdst = 0;
941 ins->vex_m = *codes++;
942 ins->vex_wlp = *codes++;
943 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700944
945 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700946 length++;
947 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700948
949 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000950 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700951
H. Peter Anvine2c80182005-01-15 22:15:51 +0000952 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700953 if (bits == 64)
954 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700955 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000956 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700957
H. Peter Anvine2c80182005-01-15 22:15:51 +0000958 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700959 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700961
H. Peter Anvine2c80182005-01-15 22:15:51 +0000962 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700963 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700964
Keith Kaniosb7a89542007-04-12 02:40:54 +0000965 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700966 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
967 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700968 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000969 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700970
971 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -0800972 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700973
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000975 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000976 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700977
H. Peter Anvine2c80182005-01-15 22:15:51 +0000978 case 0321:
979 length += (bits == 16);
980 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700981
H. Peter Anvine2c80182005-01-15 22:15:51 +0000982 case 0322:
983 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700984
Keith Kaniosb7a89542007-04-12 02:40:54 +0000985 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000986 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000987 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700988
Keith Kaniosb7a89542007-04-12 02:40:54 +0000989 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000990 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000991 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700992
H. Peter Anvine2c80182005-01-15 22:15:51 +0000993 case 0330:
994 codes++, length++;
995 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700996
H. Peter Anvine2c80182005-01-15 22:15:51 +0000997 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000998 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700999
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001000 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 case 0333:
1002 length++;
1003 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001004
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001005 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001006 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001007 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001008
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001009 case 0335:
1010 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001011
H. Peter Anvin962e3052008-08-28 17:47:16 -07001012 case 0336:
1013 if (!ins->prefixes[PPS_LREP])
1014 ins->prefixes[PPS_LREP] = P_REP;
1015 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001016
H. Peter Anvin962e3052008-08-28 17:47:16 -07001017 case 0337:
1018 if (!ins->prefixes[PPS_LREP])
1019 ins->prefixes[PPS_LREP] = P_REPNE;
1020 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001021
H. Peter Anvine2c80182005-01-15 22:15:51 +00001022 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001023 if (ins->oprs[0].segment != NO_SEG)
1024 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1025 " quantity of BSS space");
1026 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001027 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001028 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001029
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001030 case 0341:
1031 if (!ins->prefixes[PPS_WAIT])
1032 ins->prefixes[PPS_WAIT] = P_WAIT;
1033 break;
1034
H. Peter Anvin507ae032008-10-09 15:37:10 -07001035 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001036 length++;
1037 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001038
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001039 case 0360:
1040 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001041
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001042 case 0361:
1043 case 0362:
1044 case 0363:
1045 length++;
1046 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001047
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001048 case 0364:
1049 case 0365:
1050 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001051
Keith Kanios48af1772007-08-17 07:37:52 +00001052 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001053 case 0367:
1054 length++;
1055 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001056
H. Peter Anvine2c80182005-01-15 22:15:51 +00001057 case 0370:
1058 case 0371:
1059 case 0372:
1060 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001061
H. Peter Anvine2c80182005-01-15 22:15:51 +00001062 case 0373:
1063 length++;
1064 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001065
1066 case4(0100):
1067 case4(0110):
1068 case4(0120):
1069 case4(0130):
1070 case4(0200):
1071 case4(0204):
1072 case4(0210):
1073 case4(0214):
1074 case4(0220):
1075 case4(0224):
1076 case4(0230):
1077 case4(0234):
1078 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001079 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001080 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001081 int32_t rflags;
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001082 struct operand *opy = &ins->oprs[op2];
1083
Keith Kaniosb7a89542007-04-12 02:40:54 +00001084 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001085
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001086 if (c <= 0177) {
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001087 /* pick rfield from operand b (opx) */
1088 rflags = regflag(opx);
1089 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001090 } else {
1091 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001092 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001093 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001094 if (!process_ea(opy, &ea_data, bits,
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001095 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001096 errfunc(ERR_NONFATAL, "invalid effective address");
1097 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001098 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001099 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001100 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001101 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001102 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001103 break;
1104
1105 default:
1106 errfunc(ERR_PANIC, "internal instruction table corrupt"
1107 ": instruction code 0x%02X given", c);
1108 break;
1109 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001110 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001111
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001112 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001113
H. Peter Anvind85d2502008-05-04 17:53:31 -07001114 if (ins->rex & REX_V) {
1115 int bad32 = REX_R|REX_W|REX_X|REX_B;
1116
1117 if (ins->rex & REX_H) {
1118 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1119 return -1;
1120 }
1121 switch (ins->vex_wlp & 030) {
1122 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001123 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001124 ins->rex &= ~REX_W;
1125 break;
1126 case 010:
1127 ins->rex |= REX_W;
1128 bad32 &= ~REX_W;
1129 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001130 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001131 /* Follow REX_W */
1132 break;
1133 }
1134
1135 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1136 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1137 return -1;
1138 }
1139 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1140 length += 3;
1141 else
1142 length += 2;
1143 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001144 if (ins->rex & REX_H) {
1145 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1146 return -1;
1147 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001148 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001149 ins->drexdst > 7)) {
1150 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1151 return -1;
1152 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001153 length++;
1154 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001155 if (ins->rex & REX_H) {
1156 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1157 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001158 } else if (bits == 64) {
1159 length++;
1160 } else if ((ins->rex & REX_L) &&
1161 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1162 cpu >= IF_X86_64) {
1163 /* LOCK-as-REX.R */
1164 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001165 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001166 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001167 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1168 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001169 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001170 }
1171
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001172 return length;
1173}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001174
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001175#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001176 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001177 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001178 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001179 ins->rex = 0; \
1180 offset += 1; \
1181 }
1182
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001183static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001184 insn * ins, const struct itemplate *temp,
1185 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001186{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001187 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001188 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1189 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1190 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001191 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001192 uint8_t c;
1193 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001194 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001195 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001196 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001197 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001198 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001199 uint8_t opex = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001200
H. Peter Anvin839eca22007-10-29 23:12:47 -07001201 while (*codes) {
1202 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001203 op1 = (c & 3) + ((opex & 1) << 2);
1204 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1205 opx = &ins->oprs[op1];
1206 opex = 0; /* For the next iteration */
1207
H. Peter Anvin839eca22007-10-29 23:12:47 -07001208 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001209 case 01:
1210 case 02:
1211 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001212 case 04:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001213 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001214 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001215 codes += c;
1216 offset += c;
1217 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001218
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001219 case 05:
1220 case 06:
1221 case 07:
1222 opex = c;
1223 break;
1224
H. Peter Anvin507ae032008-10-09 15:37:10 -07001225 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001226 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001227 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001228 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001229 offset += 1;
1230 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001231
H. Peter Anvin507ae032008-10-09 15:37:10 -07001232 case4(014):
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001233 /* The test for BITS8 and SBYTE here is intended to avoid
1234 warning on optimizer actions due to SBYTE, while still
1235 warn on explicit BYTE directives. Also warn, obviously,
1236 if the optimizer isn't enabled. */
1237 if (((opx->type & BITS8) ||
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001238 !(opx->type & temp->opd[op1] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001239 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001240 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001241 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001242 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001243 if (opx->segment != NO_SEG) {
1244 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001245 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001246 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001247 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001248 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001249 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001250 NO_SEG);
1251 }
1252 offset += 1;
1253 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001254
H. Peter Anvin507ae032008-10-09 15:37:10 -07001255 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001256 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001257 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001258 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001259 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001260 if (opx->segment != NO_SEG) {
1261 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001262 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001263 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001264 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001266 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001267 NO_SEG);
1268 }
1269 offset += 1;
1270 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001271
H. Peter Anvin507ae032008-10-09 15:37:10 -07001272 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001273 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001274 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001275 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001276 if (opx->segment != NO_SEG) {
1277 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001278 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001280 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001282 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 NO_SEG);
1284 }
1285 offset += 1;
1286 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001287
H. Peter Anvin507ae032008-10-09 15:37:10 -07001288 case4(030):
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001289 warn_overflow(2, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001291 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001293 offset += 2;
1294 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001295
H. Peter Anvin507ae032008-10-09 15:37:10 -07001296 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 if (opx->type & (BITS16 | BITS32))
1298 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 else
1300 size = (bits == 16) ? 2 : 4;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001301 warn_overflow(size, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001302 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001303 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001304 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001305 offset += size;
1306 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001307
H. Peter Anvin507ae032008-10-09 15:37:10 -07001308 case4(040):
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001309 warn_overflow(4, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001311 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001312 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 offset += 4;
1314 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001315
H. Peter Anvin507ae032008-10-09 15:37:10 -07001316 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001318 size = ins->addr_size >> 3;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001319 warn_overflow(size, opx);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001320 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001322 offset += size;
1323 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001324
H. Peter Anvin507ae032008-10-09 15:37:10 -07001325 case4(050):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001326 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001327 errfunc(ERR_NONFATAL,
1328 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001330 if (data > 127 || data < -128)
1331 errfunc(ERR_NONFATAL, "short jump is out of range");
1332 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001333 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001334 offset += 1;
1335 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001336
H. Peter Anvin507ae032008-10-09 15:37:10 -07001337 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001341 offset += 8;
1342 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001343
H. Peter Anvin507ae032008-10-09 15:37:10 -07001344 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001345 if (opx->segment != segment) {
1346 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001347 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001348 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001349 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001350 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001351 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001352 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001353 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 }
1355 offset += 2;
1356 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001357
H. Peter Anvin507ae032008-10-09 15:37:10 -07001358 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 if (opx->type & (BITS16 | BITS32 | BITS64))
1360 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001361 else
1362 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001364 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001365 out(offset, segment, &data,
1366 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1367 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001368 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001371 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 }
1373 offset += size;
1374 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001375
H. Peter Anvin507ae032008-10-09 15:37:10 -07001376 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001377 if (opx->segment != segment) {
1378 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001379 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001380 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001382 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001383 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001384 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001385 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001386 }
1387 offset += 4;
1388 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001389
H. Peter Anvin507ae032008-10-09 15:37:10 -07001390 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001392 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1393 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001394 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001395 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001396 outfmt->segbase(1 + opx->segment),
1397 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001398 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001400
H. Peter Anvin507ae032008-10-09 15:37:10 -07001401 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001402 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001403 warn_overflow(2, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001404 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001405 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001406 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001407 NO_SEG);
1408 offset++;
1409 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001410 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001411 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001412 offset += 2;
1413 }
1414 break;
1415
H. Peter Anvin507ae032008-10-09 15:37:10 -07001416 case4(0144):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001417 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001418 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001419 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001420 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001421 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001422 offset++;
1423 break;
1424
H. Peter Anvin507ae032008-10-09 15:37:10 -07001425 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001426 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001427 warn_overflow(4, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001428 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001429 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001430 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001431 NO_SEG);
1432 offset++;
1433 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001434 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001435 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 offset += 4;
1437 }
1438 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001439
H. Peter Anvin507ae032008-10-09 15:37:10 -07001440 case4(0154):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001441 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001442 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001443 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001444 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001445 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 offset++;
1447 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001448
H. Peter Anvin507ae032008-10-09 15:37:10 -07001449 case4(0160):
1450 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001451 break;
1452
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001453 case 0171:
1454 bytes[0] =
1455 (ins->drexdst << 4) |
1456 (ins->rex & REX_OC ? 0x08 : 0) |
1457 (ins->rex & (REX_R|REX_X|REX_B));
1458 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001459 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001460 offset++;
1461 break;
1462
H. Peter Anvind85d2502008-05-04 17:53:31 -07001463 case 0172:
1464 c = *codes++;
1465 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001466 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001467 opx = &ins->oprs[c & 7];
1468 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1469 errfunc(ERR_NONFATAL,
1470 "non-absolute expression not permitted as argument %d",
1471 c & 7);
1472 } else {
1473 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001474 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001475 "four-bit argument exceeds bounds");
1476 }
1477 bytes[0] |= opx->offset & 15;
1478 }
1479 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1480 offset++;
1481 break;
1482
H. Peter Anvind58656f2008-05-06 20:11:14 -07001483 case 0173:
1484 c = *codes++;
1485 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001486 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001487 bytes[0] |= c & 15;
1488 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1489 offset++;
1490 break;
1491
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001492 case 0174:
1493 c = *codes++;
1494 opx = &ins->oprs[c];
1495 bytes[0] = nasm_regvals[opx->basereg] << 4;
1496 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1497 offset++;
1498 break;
1499
H. Peter Anvin507ae032008-10-09 15:37:10 -07001500 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001501 data = opx->offset;
H. Peter Anvinad6b8592008-10-07 09:56:38 -07001502 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1503 (int32_t)data != (int64_t)data) {
1504 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1505 "signed dword immediate exceeds bounds");
1506 }
1507 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001508 bytes[0] = data;
1509 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1510 NO_SEG);
1511 offset++;
1512 } else {
1513 out(offset, segment, &data, OUT_ADDRESS, 4,
1514 opx->segment, opx->wrt);
1515 offset += 4;
1516 }
1517 break;
1518
H. Peter Anvin507ae032008-10-09 15:37:10 -07001519 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001520 data = opx->offset;
1521 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1522 (int32_t)data != (int64_t)data) {
1523 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1524 "signed dword immediate exceeds bounds");
1525 }
1526 out(offset, segment, &data, OUT_ADDRESS, 4,
1527 opx->segment, opx->wrt);
1528 offset += 4;
1529 break;
1530
H. Peter Anvin507ae032008-10-09 15:37:10 -07001531 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -07001532 case 0270:
1533 codes += 2;
1534 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1535 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001536 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001537 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001538 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001539 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1540 offset += 3;
1541 } else {
1542 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001543 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1544 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001545 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1546 offset += 2;
1547 }
1548 break;
1549
H. Peter Anvin507ae032008-10-09 15:37:10 -07001550 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001551 {
1552 uint64_t uv, um;
1553 int s;
1554
1555 if (ins->rex & REX_W)
1556 s = 64;
1557 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1558 s = 16;
1559 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1560 s = 32;
1561 else
1562 s = bits;
1563
1564 um = (uint64_t)2 << (s-1);
1565 uv = opx->offset;
1566
1567 if (uv > 127 && uv < (uint64_t)-128 &&
1568 (uv < um-128 || uv > um-1)) {
1569 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1570 "signed byte value exceeds bounds");
1571 }
1572 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001573 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001574 out(offset, segment, &data, OUT_ADDRESS, 1,
1575 opx->segment, opx->wrt);
1576 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001577 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001578 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1579 NO_SEG);
1580 }
1581 offset += 1;
1582 break;
1583 }
1584
H. Peter Anvin507ae032008-10-09 15:37:10 -07001585 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001586 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001587
H. Peter Anvine2c80182005-01-15 22:15:51 +00001588 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001589 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001590 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001591 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001592 offset += 1;
1593 } else
1594 offset += 0;
1595 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001596
H. Peter Anvine2c80182005-01-15 22:15:51 +00001597 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001598 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001599 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001600 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001601 offset += 1;
1602 } else
1603 offset += 0;
1604 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001605
H. Peter Anvine2c80182005-01-15 22:15:51 +00001606 case 0312:
1607 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001608
Keith Kaniosb7a89542007-04-12 02:40:54 +00001609 case 0313:
1610 ins->rex = 0;
1611 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001612
H. Peter Anvin507ae032008-10-09 15:37:10 -07001613 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001614 break;
1615
H. Peter Anvine2c80182005-01-15 22:15:51 +00001616 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001617 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001618 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001619 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001620 offset += 1;
1621 } else
1622 offset += 0;
1623 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001624
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625 case 0321:
1626 if (bits == 16) {
1627 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001628 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001629 offset += 1;
1630 } else
1631 offset += 0;
1632 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001633
H. Peter Anvine2c80182005-01-15 22:15:51 +00001634 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001635 case 0323:
1636 break;
1637
Keith Kaniosb7a89542007-04-12 02:40:54 +00001638 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001639 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001640 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001641
H. Peter Anvine2c80182005-01-15 22:15:51 +00001642 case 0330:
1643 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001644 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 offset += 1;
1646 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001647
H. Peter Anvine2c80182005-01-15 22:15:51 +00001648 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001649 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001650
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001651 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001653 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001654 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001655 offset += 1;
1656 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001657
Keith Kanios48af1772007-08-17 07:37:52 +00001658 case 0334:
1659 if (ins->rex & REX_R) {
1660 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001661 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001662 offset += 1;
1663 }
1664 ins->rex &= ~(REX_L|REX_R);
1665 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001666
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001667 case 0335:
1668 break;
1669
H. Peter Anvin962e3052008-08-28 17:47:16 -07001670 case 0336:
1671 case 0337:
1672 break;
1673
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 if (ins->oprs[0].segment != NO_SEG)
1676 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1677 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001678 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001679 if (size > 0)
1680 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001681 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 offset += size;
1683 }
1684 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001685
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001686 case 0341:
1687 break;
1688
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001689 case 0344:
1690 case 0345:
1691 bytes[0] = c & 1;
1692 switch (ins->oprs[0].basereg) {
1693 case R_CS:
1694 bytes[0] += 0x0E;
1695 break;
1696 case R_DS:
1697 bytes[0] += 0x1E;
1698 break;
1699 case R_ES:
1700 bytes[0] += 0x06;
1701 break;
1702 case R_SS:
1703 bytes[0] += 0x16;
1704 break;
1705 default:
1706 errfunc(ERR_PANIC,
1707 "bizarre 8086 segment register received");
1708 }
1709 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1710 offset++;
1711 break;
1712
1713 case 0346:
1714 case 0347:
1715 bytes[0] = c & 1;
1716 switch (ins->oprs[0].basereg) {
1717 case R_FS:
1718 bytes[0] += 0xA0;
1719 break;
1720 case R_GS:
1721 bytes[0] += 0xA8;
1722 break;
1723 default:
1724 errfunc(ERR_PANIC,
1725 "bizarre 386 segment register received");
1726 }
1727 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1728 offset++;
1729 break;
1730
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001731 case 0360:
1732 break;
1733
1734 case 0361:
1735 bytes[0] = 0x66;
1736 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1737 offset += 1;
1738 break;
1739
1740 case 0362:
1741 case 0363:
1742 bytes[0] = c - 0362 + 0xf2;
1743 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1744 offset += 1;
1745 break;
1746
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001747 case 0364:
1748 case 0365:
1749 break;
1750
Keith Kanios48af1772007-08-17 07:37:52 +00001751 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001752 case 0367:
1753 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001754 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001755 offset += 1;
1756 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001757
H. Peter Anvine2c80182005-01-15 22:15:51 +00001758 case 0370:
1759 case 0371:
1760 case 0372:
1761 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001762
H. Peter Anvine2c80182005-01-15 22:15:51 +00001763 case 0373:
1764 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001765 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001766 offset += 1;
1767 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001768
H. Peter Anvin507ae032008-10-09 15:37:10 -07001769 case4(0100):
1770 case4(0110):
1771 case4(0120):
1772 case4(0130):
1773 case4(0200):
1774 case4(0204):
1775 case4(0210):
1776 case4(0214):
1777 case4(0220):
1778 case4(0224):
1779 case4(0230):
1780 case4(0234):
1781 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001782 ea ea_data;
1783 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001784 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001785 uint8_t *p;
1786 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001787 enum out_type type;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001788 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001789
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001790 if (c <= 0177) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001791 /* pick rfield from operand b (opx) */
1792 rflags = regflag(opx);
1793 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001794 } else {
1795 /* rfield is constant */
1796 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001797 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001798 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001799
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001800 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
1801 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001802 errfunc(ERR_NONFATAL, "invalid effective address");
1803 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001804
Charles Crayne7e975552007-11-03 22:06:13 -07001805
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 p = bytes;
1807 *p++ = ea_data.modrm;
1808 if (ea_data.sib_present)
1809 *p++ = ea_data.sib;
1810
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001811 /* DREX suffixes come between the SIB and the displacement */
1812 if (ins->rex & REX_D) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001813 *p++ = (ins->drexdst << 4) |
1814 (ins->rex & REX_OC ? 0x08 : 0) |
1815 (ins->rex & (REX_R|REX_X|REX_B));
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001816 ins->rex = 0;
1817 }
1818
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001820 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001821
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001822 /*
1823 * Make sure the address gets the right offset in case
1824 * the line breaks in the .lst file (BR 1197827)
1825 */
1826 offset += s;
1827 s = 0;
1828
H. Peter Anvine2c80182005-01-15 22:15:51 +00001829 switch (ea_data.bytes) {
1830 case 0:
1831 break;
1832 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 case 2:
1834 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001835 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001836 data = opy->offset;
1837 warn_overflow(ea_data.bytes, opy);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001838 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001839 if (ea_data.rip) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001840 if (opy->segment == segment) {
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001841 data -= insn_end;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001842 out(offset, segment, &data, OUT_ADDRESS,
1843 ea_data.bytes, NO_SEG, NO_SEG);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001844 } else {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001845 out(offset, segment, &data, OUT_REL4ADR,
1846 insn_end - offset, opy->segment, opy->wrt);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001847 }
H. Peter Anvin9f817132008-10-06 19:11:07 -07001848 } else {
1849 type = OUT_ADDRESS;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001850 out(offset, segment, &data, OUT_ADDRESS,
1851 ea_data.bytes, opy->segment, opy->wrt);
H. Peter Anvin9f817132008-10-06 19:11:07 -07001852 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001853 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001854 default:
1855 /* Impossible! */
1856 errfunc(ERR_PANIC,
1857 "Invalid amount of bytes (%d) for offset?!",
1858 ea_data.bytes);
1859 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001860 }
1861 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001862 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001863 break;
1864
1865 default:
1866 errfunc(ERR_PANIC, "internal instruction table corrupt"
1867 ": instruction code 0x%02X given", c);
1868 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001869 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001870 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001871}
1872
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001873static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001874{
1875 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1876 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1877 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001878 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879}
1880
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001881static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001882{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001883 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1884 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001885 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001886 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001887}
1888
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001889static int op_rexflags(const operand * o, int mask)
1890{
1891 int32_t flags;
1892 int val;
1893
1894 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1895 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1896 }
1897
H. Peter Anvina4835d42008-05-20 14:21:29 -07001898 flags = nasm_reg_flags[o->basereg];
1899 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001900
1901 return rexflags(val, flags, mask);
1902}
1903
1904static int rexflags(int val, int32_t flags, int mask)
1905{
1906 int rex = 0;
1907
1908 if (val >= 8)
1909 rex |= REX_B|REX_X|REX_R;
1910 if (flags & BITS64)
1911 rex |= REX_W;
1912 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1913 rex |= REX_H;
1914 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1915 rex |= REX_P;
1916
1917 return rex & mask;
1918}
1919
H. Peter Anvin3360d792007-09-11 04:16:57 +00001920static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001921{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001922 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001923
1924 ret = 100;
1925
1926 /*
1927 * Check the opcode
1928 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001929 if (itemp->opcode != instruction->opcode)
1930 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001931
1932 /*
1933 * Count the operands
1934 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001935 if (itemp->operands != instruction->operands)
1936 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001937
1938 /*
1939 * Check that no spurious colons or TOs are present
1940 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001941 for (i = 0; i < itemp->operands; i++)
1942 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1943 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001944
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001945 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001946 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001947 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001948 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001949 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001950
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001951 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1952
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001953 switch (itemp->flags & IF_SMASK) {
1954 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001955 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001956 break;
1957 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001958 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001959 break;
1960 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001961 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001962 break;
1963 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001964 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001965 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001966 case IF_SO:
1967 size[i] = BITS128;
1968 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001969 case IF_SY:
1970 size[i] = BITS256;
1971 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001972 case IF_SZ:
1973 switch (bits) {
1974 case 16:
1975 size[i] = BITS16;
1976 break;
1977 case 32:
1978 size[i] = BITS32;
1979 break;
1980 case 64:
1981 size[i] = BITS64;
1982 break;
1983 }
1984 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001985 default:
1986 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001987 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001988 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001989 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001990 switch (itemp->flags & IF_SMASK) {
1991 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001992 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001993 break;
1994 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001995 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001996 break;
1997 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001998 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001999 break;
2000 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002001 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002002 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002003 case IF_SO:
2004 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002005 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002006 case IF_SY:
2007 asize = BITS256;
2008 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002009 case IF_SZ:
2010 switch (bits) {
2011 case 16:
2012 asize = BITS16;
2013 break;
2014 case 32:
2015 asize = BITS32;
2016 break;
2017 case 64:
2018 asize = BITS64;
2019 break;
2020 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002021 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002022 default:
2023 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002024 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002025 for (i = 0; i < MAX_OPERANDS; i++)
2026 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002027 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002028
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002029 /*
2030 * Check that the operand flags all match up
2031 */
2032 for (i = 0; i < itemp->operands; i++) {
2033 int32_t type = instruction->oprs[i].type;
2034 if (!(type & SIZE_MASK))
2035 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002036
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002037 if (itemp->opd[i] & SAME_AS) {
2038 int j = itemp->opd[i] & ~SAME_AS;
2039 if (type != instruction->oprs[j].type ||
2040 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2041 return 0;
2042 } else if (itemp->opd[i] & ~type ||
2043 ((itemp->opd[i] & SIZE_MASK) &&
2044 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2045 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2046 (type & SIZE_MASK))
2047 return 0;
2048 else
2049 return 1;
2050 }
2051 }
2052
2053 /*
2054 * Check operand sizes
2055 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002056 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002057 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2058 asize = 0;
2059 for (i = 0; i < oprs; i++) {
2060 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2061 int j;
2062 for (j = 0; j < oprs; j++)
2063 size[j] = asize;
2064 break;
2065 }
2066 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002067 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002068 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002069 }
2070
Keith Kaniosb7a89542007-04-12 02:40:54 +00002071 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002072 if (!(itemp->opd[i] & SIZE_MASK) &&
2073 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002074 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002075 }
2076
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002077 /*
2078 * Check template is okay at the set cpu level
2079 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002080 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002081 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002082
Keith Kaniosb7a89542007-04-12 02:40:54 +00002083 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002084 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002085 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002086 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002087 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002088
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002089 /*
2090 * Check if special handling needed for Jumps
2091 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002092 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002093 return 99;
2094
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002095 return ret;
2096}
2097
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002098static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002099 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002100{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002101 bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);
2102
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002103 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002104
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002105 /* REX flags for the rfield operand */
2106 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2107
Keith Kaniosb7a89542007-04-12 02:40:54 +00002108 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002109 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002110 int32_t f;
2111
2112 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002113 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002114 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002115 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002116 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002117
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002118 if (REG_EA & ~f)
2119 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002120
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002121 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2122
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002123 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002124 output->bytes = 0; /* no offset necessary either */
2125 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002126 } else { /* it's a memory reference */
2127 if (input->basereg == -1
2128 && (input->indexreg == -1 || input->scale == 0)) {
2129 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002130 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002131 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002132 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002133 scale = 0;
2134 index = 4;
2135 base = 5;
2136 output->sib = (scale << 6) | (index << 3) | base;
2137 output->bytes = 4;
2138 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002139 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002140 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002141 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002142 output->bytes = (addrbits != 16 ? 4 : 2);
2143 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002144 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002145 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002146 } else { /* it's an indirection */
2147 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002148 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002149 int hb = input->hintbase, ht = input->hinttype;
2150 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002151 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002152 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002153
H. Peter Anvine2c80182005-01-15 22:15:51 +00002154 if (s == 0)
2155 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002156
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002157 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002158 it = nasm_regvals[i];
2159 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002160 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002161 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002162 ix = 0;
2163 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002164
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002165 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002166 bt = nasm_regvals[b];
2167 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002168 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002169 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002170 bx = 0;
2171 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002172
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002173 /* check for a 32/64-bit memory reference... */
2174 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002175 /* it must be a 32/64-bit memory reference. Firstly we have
2176 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002177 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002178
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002179 if (it != -1) {
2180 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2181 sok &= ix;
2182 else
2183 return NULL;
2184 }
2185
2186 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002187 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002188 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002189 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002190 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002191 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002192 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002193
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002194 /* While we're here, ensure the user didn't specify
2195 WORD or QWORD. */
2196 if (input->disp_size == 16 || input->disp_size == 64)
2197 return NULL;
2198
2199 if (addrbits == 16 ||
2200 (addrbits == 32 && !(sok & BITS32)) ||
2201 (addrbits == 64 && !(sok & BITS64)))
2202 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002203
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204 /* now reorganize base/index */
2205 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002206 ((hb == b && ht == EAH_NOTBASE)
2207 || (hb == i && ht == EAH_MAKEBASE))) {
2208 /* swap if hints say so */
2209 t = bt, bt = it, it = t;
2210 t = bx, bx = ix, ix = t;
2211 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002212 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002213 bt = -1, bx = 0, s++;
2214 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2215 /* make single reg base, unless hint */
2216 bt = it, bx = ix, it = -1, ix = 0;
2217 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002218 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002219 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002220 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002221 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002222 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002223 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002224 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002225 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002226 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002227 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002228 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002229 t = ix, ix = bx, bx = t;
2230 }
Keith Kanios48af1772007-08-17 07:37:52 +00002231 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002232 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002233 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002234
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002235 output->rex |= rexflags(it, ix, REX_X);
2236 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002237
Keith Kanios48af1772007-08-17 07:37:52 +00002238 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002239 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002240 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002241
Keith Kaniosb7a89542007-04-12 02:40:54 +00002242 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002243 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002244 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002245 } else {
2246 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002247 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002248 seg == NO_SEG && !forw_ref &&
2249 !(input->eaflags &
2250 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2251 mod = 0;
2252 else if (input->eaflags & EAF_BYTEOFFS ||
2253 (o >= -128 && o <= 127 && seg == NO_SEG
2254 && !forw_ref
2255 && !(input->eaflags & EAF_WORDOFFS)))
2256 mod = 1;
2257 else
2258 mod = 2;
2259 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002260
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002261 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002262 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2263 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002264 } else {
2265 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002266 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002267
Keith Kaniosb7a89542007-04-12 02:40:54 +00002268 if (it == -1)
2269 index = 4, s = 1;
2270 else
2271 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002272
H. Peter Anvine2c80182005-01-15 22:15:51 +00002273 switch (s) {
2274 case 1:
2275 scale = 0;
2276 break;
2277 case 2:
2278 scale = 1;
2279 break;
2280 case 4:
2281 scale = 2;
2282 break;
2283 case 8:
2284 scale = 3;
2285 break;
2286 default: /* then what the smeg is it? */
2287 return NULL; /* panic */
2288 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002289
Keith Kaniosb7a89542007-04-12 02:40:54 +00002290 if (bt == -1) {
2291 base = 5;
2292 mod = 0;
2293 } else {
2294 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002295 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002296 seg == NO_SEG && !forw_ref &&
2297 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002298 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2299 mod = 0;
2300 else if (input->eaflags & EAF_BYTEOFFS ||
2301 (o >= -128 && o <= 127 && seg == NO_SEG
2302 && !forw_ref
2303 && !(input->eaflags & EAF_WORDOFFS)))
2304 mod = 1;
2305 else
2306 mod = 2;
2307 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002308
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002309 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002310 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2311 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002312 output->sib = (scale << 6) | (index << 3) | base;
2313 }
2314 } else { /* it's 16-bit */
2315 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002316
Keith Kaniosb7a89542007-04-12 02:40:54 +00002317 /* check for 64-bit long mode */
2318 if (addrbits == 64)
2319 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002320
H. Peter Anvine2c80182005-01-15 22:15:51 +00002321 /* check all registers are BX, BP, SI or DI */
2322 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2323 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2324 && i != R_SI && i != R_DI))
2325 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002326
Keith Kaniosb7a89542007-04-12 02:40:54 +00002327 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002328 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002329 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002330
H. Peter Anvine2c80182005-01-15 22:15:51 +00002331 if (s != 1 && i != -1)
2332 return NULL; /* no can do, in 16-bit EA */
2333 if (b == -1 && i != -1) {
2334 int tmp = b;
2335 b = i;
2336 i = tmp;
2337 } /* swap */
2338 if ((b == R_SI || b == R_DI) && i != -1) {
2339 int tmp = b;
2340 b = i;
2341 i = tmp;
2342 }
2343 /* have BX/BP as base, SI/DI index */
2344 if (b == i)
2345 return NULL; /* shouldn't ever happen, in theory */
2346 if (i != -1 && b != -1 &&
2347 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2348 return NULL; /* invalid combinations */
2349 if (b == -1) /* pure offset: handled above */
2350 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002351
H. Peter Anvine2c80182005-01-15 22:15:51 +00002352 rm = -1;
2353 if (i != -1)
2354 switch (i * 256 + b) {
2355 case R_SI * 256 + R_BX:
2356 rm = 0;
2357 break;
2358 case R_DI * 256 + R_BX:
2359 rm = 1;
2360 break;
2361 case R_SI * 256 + R_BP:
2362 rm = 2;
2363 break;
2364 case R_DI * 256 + R_BP:
2365 rm = 3;
2366 break;
2367 } else
2368 switch (b) {
2369 case R_SI:
2370 rm = 4;
2371 break;
2372 case R_DI:
2373 rm = 5;
2374 break;
2375 case R_BP:
2376 rm = 6;
2377 break;
2378 case R_BX:
2379 rm = 7;
2380 break;
2381 }
2382 if (rm == -1) /* can't happen, in theory */
2383 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002384
H. Peter Anvine2c80182005-01-15 22:15:51 +00002385 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2386 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2387 mod = 0;
2388 else if (input->eaflags & EAF_BYTEOFFS ||
2389 (o >= -128 && o <= 127 && seg == NO_SEG
2390 && !forw_ref
2391 && !(input->eaflags & EAF_WORDOFFS)))
2392 mod = 1;
2393 else
2394 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002395
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002396 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002397 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002398 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002399 }
2400 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002401 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002402
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002403 output->size = 1 + output->sib_present + output->bytes;
2404 return output;
2405}
2406
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002407static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002408{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002409 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002410 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002411
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002412 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002413
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002414 switch (ins->prefixes[PPS_ASIZE]) {
2415 case P_A16:
2416 valid &= 16;
2417 break;
2418 case P_A32:
2419 valid &= 32;
2420 break;
2421 case P_A64:
2422 valid &= 64;
2423 break;
2424 case P_ASP:
2425 valid &= (addrbits == 32) ? 16 : 32;
2426 break;
2427 default:
2428 break;
2429 }
2430
2431 for (j = 0; j < ins->operands; j++) {
2432 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002433 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002434
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002435 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002436 if (ins->oprs[j].indexreg < EXPR_REG_START
2437 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002438 i = 0;
2439 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002440 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002441
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002442 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002443 if (ins->oprs[j].basereg < EXPR_REG_START
2444 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002445 b = 0;
2446 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002447 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002448
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002449 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002450 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002451
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002452 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002453 int ds = ins->oprs[j].disp_size;
2454 if ((addrbits != 64 && ds > 8) ||
2455 (addrbits == 64 && ds == 16))
2456 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002457 } else {
2458 if (!(REG16 & ~b))
2459 valid &= 16;
2460 if (!(REG32 & ~b))
2461 valid &= 32;
2462 if (!(REG64 & ~b))
2463 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002464
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002465 if (!(REG16 & ~i))
2466 valid &= 16;
2467 if (!(REG32 & ~i))
2468 valid &= 32;
2469 if (!(REG64 & ~i))
2470 valid &= 64;
2471 }
2472 }
2473 }
2474
2475 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002476 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002477 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002478 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002479 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002480 ins->prefixes[PPS_ASIZE] = pref;
2481 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002482 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002483 /* Impossible... */
2484 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002485 ins->addr_size = addrbits; /* Error recovery */
2486 }
2487
2488 defdisp = ins->addr_size == 16 ? 16 : 32;
2489
2490 for (j = 0; j < ins->operands; j++) {
2491 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2492 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2493 != ins->addr_size) {
2494 /* mem_offs sizes must match the address size; if not,
2495 strip the MEM_OFFS bit and match only EA instructions */
2496 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2497 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002498 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002499}