blob: d4e7f25c02af3692577def8ff08fd2ae32fd4b23 [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);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100265
Victor van den Elzen154e5922009-02-25 17:32:00 +0100266 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100267 /* Be optimistic in pass 1 */
268 return true;
269
H. Peter Anvine2c80182005-01-15 22:15:51 +0000270 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700271 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000272
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700273 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
274 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000275}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000276
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800277int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000278 insn * instruction, struct ofmt *output, efunc error,
279 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000280{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000281 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000282 int j;
283 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800284 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000285 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800286 int64_t start = offset;
287 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000288
H. Peter Anvine2c80182005-01-15 22:15:51 +0000289 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000290 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000291 outfmt = output; /* likewise */
292 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000293
H. Peter Anvine2c80182005-01-15 22:15:51 +0000294 switch (instruction->opcode) {
295 case -1:
296 return 0;
297 case I_DB:
298 wsize = 1;
299 break;
300 case I_DW:
301 wsize = 2;
302 break;
303 case I_DD:
304 wsize = 4;
305 break;
306 case I_DQ:
307 wsize = 8;
308 break;
309 case I_DT:
310 wsize = 10;
311 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700312 case I_DO:
313 wsize = 16;
314 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700315 case I_DY:
316 wsize = 32;
317 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700318 default:
319 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000320 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000321
H. Peter Anvineba20a72002-04-30 20:53:55 +0000322 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000323 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000324 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000325 if (t < 0)
326 errfunc(ERR_PANIC,
327 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000328
H. Peter Anvine2c80182005-01-15 22:15:51 +0000329 while (t--) { /* repeat TIMES times */
330 for (e = instruction->eops; e; e = e->next) {
331 if (e->type == EOT_DB_NUMBER) {
332 if (wsize == 1) {
333 if (e->segment != NO_SEG)
334 errfunc(ERR_NONFATAL,
335 "one-byte relocation attempted");
336 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000337 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800339 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000341 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700342 errfunc(ERR_NONFATAL,
343 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000344 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 } else
346 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800347 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700349 } else if (e->type == EOT_DB_STRING ||
350 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000351 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000352
H. Peter Anvine2c80182005-01-15 22:15:51 +0000353 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800354 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000355 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000356
H. Peter Anvine2c80182005-01-15 22:15:51 +0000357 if (align) {
358 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100359 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800360 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 }
362 offset += e->stringlen + align;
363 }
364 }
365 if (t > 0 && t == instruction->times - 1) {
366 /*
367 * Dummy call to list->output to give the offset to the
368 * listing module.
369 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800370 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 list->uplevel(LIST_TIMES);
372 }
373 }
374 if (instruction->times > 1)
375 list->downlevel(LIST_TIMES);
376 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000377 }
378
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700380 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000382
H. Peter Anvin418ca702008-05-30 10:42:30 -0700383 fp = fopen(fname, "rb");
384 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
386 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700387 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000388 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
389 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700390 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700391 static char buf[4096];
392 size_t t = instruction->times;
393 size_t base = 0;
394 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000395
H. Peter Anvine2c80182005-01-15 22:15:51 +0000396 len = ftell(fp);
397 if (instruction->eops->next) {
398 base = instruction->eops->next->offset;
399 len -= base;
400 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700401 len > (size_t)instruction->eops->next->next->offset)
402 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000403 }
404 /*
405 * Dummy call to list->output to give the offset to the
406 * listing module.
407 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800408 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 list->uplevel(LIST_INCBIN);
410 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700411 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000412
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 fseek(fp, base, SEEK_SET);
414 l = len;
415 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000416 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700417 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000418 fp);
419 if (!m) {
420 /*
421 * This shouldn't happen unless the file
422 * actually changes while we are reading
423 * it.
424 */
425 error(ERR_NONFATAL,
426 "`incbin': unexpected EOF while"
427 " reading file `%s'", fname);
428 t = 0; /* Try to exit cleanly */
429 break;
430 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800431 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000432 NO_SEG, NO_SEG);
433 l -= m;
434 }
435 }
436 list->downlevel(LIST_INCBIN);
437 if (instruction->times > 1) {
438 /*
439 * Dummy call to list->output to give the offset to the
440 * listing module.
441 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800442 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000443 list->uplevel(LIST_TIMES);
444 list->downlevel(LIST_TIMES);
445 }
446 fclose(fp);
447 return instruction->times * len;
448 }
449 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000450 }
451
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700452 /* Check to see if we need an address-size prefix */
453 add_asp(instruction, bits);
454
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800455 size_prob = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -0700456
457 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000458 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700459 if (m == 100 ||
460 (m == 99 && jmp_match(segment, offset, bits,
461 instruction, temp->code))) {
462 /* Matches! */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800463 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -0700464 instruction, temp->code);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000465 itimes = instruction->times;
466 if (insn_size < 0) /* shouldn't be, on pass two */
467 error(ERR_PANIC, "errors made it through from pass one");
468 else
469 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700470 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000471 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000472 switch (instruction->prefixes[j]) {
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -0800473 case P_WAIT:
474 c = 0x9B;
475 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000476 case P_LOCK:
477 c = 0xF0;
478 break;
479 case P_REPNE:
480 case P_REPNZ:
481 c = 0xF2;
482 break;
483 case P_REPE:
484 case P_REPZ:
485 case P_REP:
486 c = 0xF3;
487 break;
488 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000489 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700490 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800491 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000492 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000493 c = 0x2E;
494 break;
495 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000496 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700497 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800498 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000499 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000500 c = 0x3E;
501 break;
502 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000503 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700504 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800505 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000506 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000507 c = 0x26;
508 break;
509 case R_FS:
510 c = 0x64;
511 break;
512 case R_GS:
513 c = 0x65;
514 break;
515 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000516 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700517 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800518 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000519 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000520 c = 0x36;
521 break;
522 case R_SEGR6:
523 case R_SEGR7:
524 error(ERR_NONFATAL,
525 "segr6 and segr7 cannot be used as prefixes");
526 break;
527 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000528 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000529 error(ERR_NONFATAL,
530 "16-bit addressing is not supported "
531 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700532 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000533 c = 0x67;
534 break;
535 case P_A32:
536 if (bits != 32)
537 c = 0x67;
538 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700539 case P_A64:
540 if (bits != 64) {
541 error(ERR_NONFATAL,
542 "64-bit addressing is only supported "
543 "in 64-bit mode");
544 }
545 break;
546 case P_ASP:
547 c = 0x67;
548 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000549 case P_O16:
550 if (bits != 16)
551 c = 0x66;
552 break;
553 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000554 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000555 c = 0x66;
556 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700557 case P_O64:
558 /* REX.W */
559 break;
560 case P_OSP:
561 c = 0x66;
562 break;
563 case P_none:
564 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000565 default:
566 error(ERR_PANIC, "invalid instruction prefix");
567 }
568 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800569 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000570 NO_SEG, NO_SEG);
571 offset++;
572 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700573 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000574 insn_end = offset + insn_size;
H. Peter Anvin833caea2008-10-04 19:02:30 -0700575 gencode(segment, offset, bits, instruction,
576 temp, insn_end);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000577 offset += insn_size;
578 if (itimes > 0 && itimes == instruction->times - 1) {
579 /*
580 * Dummy call to list->output to give the offset to the
581 * listing module.
582 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800583 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000584 list->uplevel(LIST_TIMES);
585 }
586 }
587 if (instruction->times > 1)
588 list->downlevel(LIST_TIMES);
589 return offset - start;
590 } else if (m > 0 && m > size_prob) {
591 size_prob = m;
592 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000593 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000594
H. Peter Anvine2c80182005-01-15 22:15:51 +0000595 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000596 switch (size_prob) {
597 case 1:
598 error(ERR_NONFATAL, "operation size not specified");
599 break;
600 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000601 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000602 break;
603 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000604 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000605 break;
606 case 4:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800607 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
608 bits);
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000609 break;
610 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000611 error(ERR_NONFATAL,
612 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000613 break;
614 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000615 }
616 return 0;
617}
618
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800619int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000621{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000622 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000623
H. Peter Anvine2c80182005-01-15 22:15:51 +0000624 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000625 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000626
627 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000628 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000629
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700630 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
631 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700632 instruction->opcode == I_DT || instruction->opcode == I_DO ||
633 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000634 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000635 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000636
H. Peter Anvine2c80182005-01-15 22:15:51 +0000637 isize = 0;
638 switch (instruction->opcode) {
639 case I_DB:
640 wsize = 1;
641 break;
642 case I_DW:
643 wsize = 2;
644 break;
645 case I_DD:
646 wsize = 4;
647 break;
648 case I_DQ:
649 wsize = 8;
650 break;
651 case I_DT:
652 wsize = 10;
653 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700654 case I_DO:
655 wsize = 16;
656 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700657 case I_DY:
658 wsize = 32;
659 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700660 default:
661 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000662 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000663
H. Peter Anvine2c80182005-01-15 22:15:51 +0000664 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000665 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000666
H. Peter Anvine2c80182005-01-15 22:15:51 +0000667 osize = 0;
668 if (e->type == EOT_DB_NUMBER)
669 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700670 else if (e->type == EOT_DB_STRING ||
671 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000673
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 align = (-osize) % wsize;
675 if (align < 0)
676 align += wsize;
677 isize += osize + align;
678 }
679 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000680 }
681
H. Peter Anvine2c80182005-01-15 22:15:51 +0000682 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700683 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000684 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700685 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000686
H. Peter Anvin418ca702008-05-30 10:42:30 -0700687 fp = fopen(fname, "rb");
688 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
690 fname);
691 else if (fseek(fp, 0L, SEEK_END) < 0)
692 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
693 fname);
694 else {
695 len = ftell(fp);
696 fclose(fp);
697 if (instruction->eops->next) {
698 len -= instruction->eops->next->offset;
699 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700700 len > (size_t)instruction->eops->next->next->offset) {
701 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 }
703 }
704 return instruction->times * len;
705 }
706 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000707 }
708
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700709 /* Check to see if we need an address-size prefix */
710 add_asp(instruction, bits);
711
Keith Kaniosb7a89542007-04-12 02:40:54 +0000712 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
713 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700714 if (m == 100 ||
715 (m == 99 && jmp_match(segment, offset, bits,
716 instruction, temp->code))) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000717 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800718 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700719 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000720 int j;
721
722 isize = calcsize(segment, offset, bits, instruction, codes);
723 if (isize < 0)
724 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700725 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700726 switch (instruction->prefixes[j]) {
727 case P_A16:
728 if (bits != 16)
729 isize++;
730 break;
731 case P_A32:
732 if (bits != 32)
733 isize++;
734 break;
735 case P_O16:
736 if (bits != 16)
737 isize++;
738 break;
739 case P_O32:
740 if (bits == 16)
741 isize++;
742 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700743 case P_A64:
744 case P_O64:
745 case P_none:
746 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700747 default:
748 isize++;
749 break;
750 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000751 }
752 return isize * instruction->times;
753 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000754 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000755 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000756}
757
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700758static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000759{
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700760 return o->wrt == NO_SEG && o->segment == NO_SEG &&
761 !(o->opflags & OPFLAG_FORWARD) &&
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700762 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000763}
764
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700765/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700766static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700767{
768 int16_t v;
769
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700770 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700771 return false;
772
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700773 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774 return v >= -128 && v <= 127;
775}
776
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700777static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700778{
779 int32_t v;
780
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700781 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700782 return false;
783
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700784 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700785 return v >= -128 && v <= 127;
786}
787
H. Peter Anvin507ae032008-10-09 15:37:10 -0700788/* Common construct */
789#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
790
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800791static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700792 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000793{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800794 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000795 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000796 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700797 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700798 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700799 uint8_t opex = 0;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000800
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700801 ins->rex = 0; /* Ensure REX is reset */
802
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700803 if (ins->prefixes[PPS_OSIZE] == P_O64)
804 ins->rex |= REX_W;
805
H. Peter Anvine2c80182005-01-15 22:15:51 +0000806 (void)segment; /* Don't warn that this parameter is unused */
807 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000808
H. Peter Anvin839eca22007-10-29 23:12:47 -0700809 while (*codes) {
810 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700811 op1 = (c & 3) + ((opex & 1) << 2);
812 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
813 opx = &ins->oprs[op1];
814 opex = 0; /* For the next iteration */
815
H. Peter Anvin839eca22007-10-29 23:12:47 -0700816 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000817 case 01:
818 case 02:
819 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700820 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000821 codes += c, length += c;
822 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700823
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700824 case 05:
825 case 06:
826 case 07:
827 opex = c;
828 break;
829
H. Peter Anvin507ae032008-10-09 15:37:10 -0700830 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000831 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700832 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000833 codes++, length++;
834 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700835
836 case4(014):
837 case4(020):
838 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000839 length++;
840 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700841
842 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000843 length += 2;
844 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700845
846 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700847 if (opx->type & (BITS16 | BITS32 | BITS64))
848 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 else
850 length += (bits == 16) ? 2 : 4;
851 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700852
853 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 length += 4;
855 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700856
857 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700858 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000859 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700860
861 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000862 length++;
863 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700864
865 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000866 length += 8; /* MOV reg64/imm */
867 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700868
869 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000870 length += 2;
871 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700872
873 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700874 if (opx->type & (BITS16 | BITS32 | BITS64))
875 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000876 else
877 length += (bits == 16) ? 2 : 4;
878 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700879
880 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 length += 4;
882 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700883
884 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700885 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000886 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700887
888 case4(0140):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700889 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000890 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700891
892 case4(0144):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800893 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 length++;
895 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700896
897 case4(0150):
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700898 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700899 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700900
901 case4(0154):
H. Peter Anvina30cc072007-11-18 21:55:26 -0800902 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700903 length++;
904 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700905
906 case4(0160):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700907 length++;
908 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700909 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700910 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700911
912 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700913 length++;
914 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700915 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700916 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700917
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700918 case 0171:
919 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700920
H. Peter Anvind85d2502008-05-04 17:53:31 -0700921 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700922 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700923 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700924 codes++;
925 length++;
926 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700927
928 case4(0250):
H. Peter Anvinad6b8592008-10-07 09:56:38 -0700929 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700930 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700931
932 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -0700933 length += 4;
934 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700935
936 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -0700937 ins->rex |= REX_V;
938 ins->drexdst = regval(opx);
939 ins->vex_m = *codes++;
940 ins->vex_wlp = *codes++;
941 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700942
H. Peter Anvind85d2502008-05-04 17:53:31 -0700943 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700944 ins->rex |= REX_V;
945 ins->drexdst = 0;
946 ins->vex_m = *codes++;
947 ins->vex_wlp = *codes++;
948 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700949
950 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700951 length++;
952 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700953
954 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000955 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700956
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700958 if (bits == 64)
959 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700960 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000961 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700962
H. Peter Anvine2c80182005-01-15 22:15:51 +0000963 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700964 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000965 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700966
H. Peter Anvine2c80182005-01-15 22:15:51 +0000967 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700968 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700969
Keith Kaniosb7a89542007-04-12 02:40:54 +0000970 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700971 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
972 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700973 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700975
976 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -0800977 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700978
H. Peter Anvine2c80182005-01-15 22:15:51 +0000979 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000980 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000981 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700982
H. Peter Anvine2c80182005-01-15 22:15:51 +0000983 case 0321:
984 length += (bits == 16);
985 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700986
H. Peter Anvine2c80182005-01-15 22:15:51 +0000987 case 0322:
988 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700989
Keith Kaniosb7a89542007-04-12 02:40:54 +0000990 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000991 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000992 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700993
Keith Kaniosb7a89542007-04-12 02:40:54 +0000994 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000995 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000996 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700997
H. Peter Anvine2c80182005-01-15 22:15:51 +0000998 case 0330:
999 codes++, length++;
1000 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001001
H. Peter Anvine2c80182005-01-15 22:15:51 +00001002 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001003 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001004
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001005 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001006 case 0333:
1007 length++;
1008 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001009
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001010 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001011 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001012 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001013
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001014 case 0335:
1015 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001016
H. Peter Anvin962e3052008-08-28 17:47:16 -07001017 case 0336:
1018 if (!ins->prefixes[PPS_LREP])
1019 ins->prefixes[PPS_LREP] = P_REP;
1020 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001021
H. Peter Anvin962e3052008-08-28 17:47:16 -07001022 case 0337:
1023 if (!ins->prefixes[PPS_LREP])
1024 ins->prefixes[PPS_LREP] = P_REPNE;
1025 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001026
H. Peter Anvine2c80182005-01-15 22:15:51 +00001027 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001028 if (ins->oprs[0].segment != NO_SEG)
1029 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1030 " quantity of BSS space");
1031 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001032 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001033 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001034
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001035 case 0341:
1036 if (!ins->prefixes[PPS_WAIT])
1037 ins->prefixes[PPS_WAIT] = P_WAIT;
1038 break;
1039
H. Peter Anvin507ae032008-10-09 15:37:10 -07001040 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001041 length++;
1042 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001043
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001044 case 0360:
1045 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001046
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001047 case 0361:
1048 case 0362:
1049 case 0363:
1050 length++;
1051 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001052
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001053 case 0364:
1054 case 0365:
1055 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001056
Keith Kanios48af1772007-08-17 07:37:52 +00001057 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001058 case 0367:
1059 length++;
1060 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001061
H. Peter Anvine2c80182005-01-15 22:15:51 +00001062 case 0370:
1063 case 0371:
1064 case 0372:
1065 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001066
H. Peter Anvine2c80182005-01-15 22:15:51 +00001067 case 0373:
1068 length++;
1069 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001070
1071 case4(0100):
1072 case4(0110):
1073 case4(0120):
1074 case4(0130):
1075 case4(0200):
1076 case4(0204):
1077 case4(0210):
1078 case4(0214):
1079 case4(0220):
1080 case4(0224):
1081 case4(0230):
1082 case4(0234):
1083 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001084 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001085 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001086 int32_t rflags;
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001087 struct operand *opy = &ins->oprs[op2];
1088
Keith Kaniosb7a89542007-04-12 02:40:54 +00001089 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001090
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001091 if (c <= 0177) {
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001092 /* pick rfield from operand b (opx) */
1093 rflags = regflag(opx);
1094 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001095 } else {
1096 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001097 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001098 }
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001099 if (!process_ea(opy, &ea_data, bits,
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001100 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001101 errfunc(ERR_NONFATAL, "invalid effective address");
1102 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001103 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001104 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001105 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001106 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001107 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001108 break;
1109
1110 default:
1111 errfunc(ERR_PANIC, "internal instruction table corrupt"
1112 ": instruction code 0x%02X given", c);
1113 break;
1114 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001115 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001116
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001117 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001118
H. Peter Anvind85d2502008-05-04 17:53:31 -07001119 if (ins->rex & REX_V) {
1120 int bad32 = REX_R|REX_W|REX_X|REX_B;
1121
1122 if (ins->rex & REX_H) {
1123 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1124 return -1;
1125 }
1126 switch (ins->vex_wlp & 030) {
1127 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001128 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001129 ins->rex &= ~REX_W;
1130 break;
1131 case 010:
1132 ins->rex |= REX_W;
1133 bad32 &= ~REX_W;
1134 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001135 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001136 /* Follow REX_W */
1137 break;
1138 }
1139
1140 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1141 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1142 return -1;
1143 }
1144 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1145 length += 3;
1146 else
1147 length += 2;
1148 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001149 if (ins->rex & REX_H) {
1150 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1151 return -1;
1152 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001153 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001154 ins->drexdst > 7)) {
1155 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1156 return -1;
1157 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001158 length++;
1159 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001160 if (ins->rex & REX_H) {
1161 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1162 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001163 } else if (bits == 64) {
1164 length++;
1165 } else if ((ins->rex & REX_L) &&
1166 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1167 cpu >= IF_X86_64) {
1168 /* LOCK-as-REX.R */
1169 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001170 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001171 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001172 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1173 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001174 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001175 }
1176
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001177 return length;
1178}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001179
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001180#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001181 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001182 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001183 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001184 ins->rex = 0; \
1185 offset += 1; \
1186 }
1187
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001188static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001189 insn * ins, const struct itemplate *temp,
1190 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001191{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001192 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001193 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1194 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1195 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001196 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001197 uint8_t c;
1198 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001199 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001200 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001201 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001202 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001203 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001204 uint8_t opex = 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001205
H. Peter Anvin839eca22007-10-29 23:12:47 -07001206 while (*codes) {
1207 c = *codes++;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001208 op1 = (c & 3) + ((opex & 1) << 2);
1209 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1210 opx = &ins->oprs[op1];
1211 opex = 0; /* For the next iteration */
1212
H. Peter Anvin839eca22007-10-29 23:12:47 -07001213 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001214 case 01:
1215 case 02:
1216 case 03:
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001217 case 04:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001218 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001219 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001220 codes += c;
1221 offset += c;
1222 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001223
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001224 case 05:
1225 case 06:
1226 case 07:
1227 opex = c;
1228 break;
1229
H. Peter Anvin507ae032008-10-09 15:37:10 -07001230 case4(010):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001231 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001232 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001233 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001234 offset += 1;
1235 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001236
H. Peter Anvin507ae032008-10-09 15:37:10 -07001237 case4(014):
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001238 /* The test for BITS8 and SBYTE here is intended to avoid
1239 warning on optimizer actions due to SBYTE, while still
1240 warn on explicit BYTE directives. Also warn, obviously,
1241 if the optimizer isn't enabled. */
1242 if (((opx->type & BITS8) ||
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001243 !(opx->type & temp->opd[op1] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001244 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001245 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001246 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001247 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001248 if (opx->segment != NO_SEG) {
1249 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001250 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001251 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001252 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001253 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001254 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001255 NO_SEG);
1256 }
1257 offset += 1;
1258 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001259
H. Peter Anvin507ae032008-10-09 15:37:10 -07001260 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001261 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001262 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001263 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001264 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 if (opx->segment != NO_SEG) {
1266 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001267 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001270 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001271 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001272 NO_SEG);
1273 }
1274 offset += 1;
1275 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001276
H. Peter Anvin507ae032008-10-09 15:37:10 -07001277 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001279 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001280 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 if (opx->segment != NO_SEG) {
1282 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001283 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001285 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001286 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001287 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001288 NO_SEG);
1289 }
1290 offset += 1;
1291 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001292
H. Peter Anvin507ae032008-10-09 15:37:10 -07001293 case4(030):
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001294 warn_overflow(2, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001295 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001296 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001298 offset += 2;
1299 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001300
H. Peter Anvin507ae032008-10-09 15:37:10 -07001301 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001302 if (opx->type & (BITS16 | BITS32))
1303 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001304 else
1305 size = (bits == 16) ? 2 : 4;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001306 warn_overflow(size, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001307 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001308 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001310 offset += size;
1311 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001312
H. Peter Anvin507ae032008-10-09 15:37:10 -07001313 case4(040):
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001314 warn_overflow(4, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001315 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001316 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 offset += 4;
1319 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001320
H. Peter Anvin507ae032008-10-09 15:37:10 -07001321 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001323 size = ins->addr_size >> 3;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001324 warn_overflow(size, opx);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001325 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001326 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001327 offset += size;
1328 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001329
H. Peter Anvin507ae032008-10-09 15:37:10 -07001330 case4(050):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 errfunc(ERR_NONFATAL,
1333 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001334 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001335 if (data > 127 || data < -128)
1336 errfunc(ERR_NONFATAL, "short jump is out of range");
1337 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001338 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001339 offset += 1;
1340 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001341
H. Peter Anvin507ae032008-10-09 15:37:10 -07001342 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001343 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001344 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001345 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001346 offset += 8;
1347 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001348
H. Peter Anvin507ae032008-10-09 15:37:10 -07001349 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 if (opx->segment != segment) {
1351 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001352 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001353 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001354 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001356 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001357 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001358 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001359 }
1360 offset += 2;
1361 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001362
H. Peter Anvin507ae032008-10-09 15:37:10 -07001363 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001364 if (opx->type & (BITS16 | BITS32 | BITS64))
1365 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001366 else
1367 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001368 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001370 out(offset, segment, &data,
1371 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1372 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001374 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001375 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001376 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 }
1378 offset += size;
1379 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001380
H. Peter Anvin507ae032008-10-09 15:37:10 -07001381 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001382 if (opx->segment != segment) {
1383 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001384 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001385 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001388 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001389 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001390 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 }
1392 offset += 4;
1393 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001394
H. Peter Anvin507ae032008-10-09 15:37:10 -07001395 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001396 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001397 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1398 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001399 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001400 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001401 outfmt->segbase(1 + opx->segment),
1402 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001403 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001405
H. Peter Anvin507ae032008-10-09 15:37:10 -07001406 case4(0140):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001407 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001408 warn_overflow(2, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001409 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001410 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001411 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001412 NO_SEG);
1413 offset++;
1414 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001415 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001416 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001417 offset += 2;
1418 }
1419 break;
1420
H. Peter Anvin507ae032008-10-09 15:37:10 -07001421 case4(0144):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001422 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001423 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001424 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001425 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001426 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001427 offset++;
1428 break;
1429
H. Peter Anvin507ae032008-10-09 15:37:10 -07001430 case4(0150):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001431 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001432 warn_overflow(4, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001433 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001434 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001435 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 NO_SEG);
1437 offset++;
1438 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001439 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001440 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001441 offset += 4;
1442 }
1443 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001444
H. Peter Anvin507ae032008-10-09 15:37:10 -07001445 case4(0154):
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001446 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001447 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001448 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001449 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001450 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 offset++;
1452 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001453
H. Peter Anvin507ae032008-10-09 15:37:10 -07001454 case4(0160):
1455 case4(0164):
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001456 break;
1457
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001458 case 0171:
1459 bytes[0] =
1460 (ins->drexdst << 4) |
1461 (ins->rex & REX_OC ? 0x08 : 0) |
1462 (ins->rex & (REX_R|REX_X|REX_B));
1463 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001464 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001465 offset++;
1466 break;
1467
H. Peter Anvind85d2502008-05-04 17:53:31 -07001468 case 0172:
1469 c = *codes++;
1470 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001471 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001472 opx = &ins->oprs[c & 7];
1473 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1474 errfunc(ERR_NONFATAL,
1475 "non-absolute expression not permitted as argument %d",
1476 c & 7);
1477 } else {
1478 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001479 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001480 "four-bit argument exceeds bounds");
1481 }
1482 bytes[0] |= opx->offset & 15;
1483 }
1484 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1485 offset++;
1486 break;
1487
H. Peter Anvind58656f2008-05-06 20:11:14 -07001488 case 0173:
1489 c = *codes++;
1490 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001491 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001492 bytes[0] |= c & 15;
1493 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1494 offset++;
1495 break;
1496
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001497 case 0174:
1498 c = *codes++;
1499 opx = &ins->oprs[c];
1500 bytes[0] = nasm_regvals[opx->basereg] << 4;
1501 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1502 offset++;
1503 break;
1504
H. Peter Anvin507ae032008-10-09 15:37:10 -07001505 case4(0250):
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001506 data = opx->offset;
H. Peter Anvinad6b8592008-10-07 09:56:38 -07001507 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1508 (int32_t)data != (int64_t)data) {
1509 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1510 "signed dword immediate exceeds bounds");
1511 }
1512 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001513 bytes[0] = data;
1514 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1515 NO_SEG);
1516 offset++;
1517 } else {
1518 out(offset, segment, &data, OUT_ADDRESS, 4,
1519 opx->segment, opx->wrt);
1520 offset += 4;
1521 }
1522 break;
1523
H. Peter Anvin507ae032008-10-09 15:37:10 -07001524 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001525 data = opx->offset;
1526 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1527 (int32_t)data != (int64_t)data) {
1528 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1529 "signed dword immediate exceeds bounds");
1530 }
1531 out(offset, segment, &data, OUT_ADDRESS, 4,
1532 opx->segment, opx->wrt);
1533 offset += 4;
1534 break;
1535
H. Peter Anvin507ae032008-10-09 15:37:10 -07001536 case4(0260):
H. Peter Anvind85d2502008-05-04 17:53:31 -07001537 case 0270:
1538 codes += 2;
1539 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1540 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001541 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001542 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001543 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001544 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1545 offset += 3;
1546 } else {
1547 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001548 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1549 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001550 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1551 offset += 2;
1552 }
1553 break;
1554
H. Peter Anvin507ae032008-10-09 15:37:10 -07001555 case4(0274):
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001556 {
1557 uint64_t uv, um;
1558 int s;
1559
1560 if (ins->rex & REX_W)
1561 s = 64;
1562 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1563 s = 16;
1564 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1565 s = 32;
1566 else
1567 s = bits;
1568
1569 um = (uint64_t)2 << (s-1);
1570 uv = opx->offset;
1571
1572 if (uv > 127 && uv < (uint64_t)-128 &&
1573 (uv < um-128 || uv > um-1)) {
1574 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1575 "signed byte value exceeds bounds");
1576 }
1577 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001578 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001579 out(offset, segment, &data, OUT_ADDRESS, 1,
1580 opx->segment, opx->wrt);
1581 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001582 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001583 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1584 NO_SEG);
1585 }
1586 offset += 1;
1587 break;
1588 }
1589
H. Peter Anvin507ae032008-10-09 15:37:10 -07001590 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001591 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001592
H. Peter Anvine2c80182005-01-15 22:15:51 +00001593 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001594 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001595 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001596 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001597 offset += 1;
1598 } else
1599 offset += 0;
1600 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001601
H. Peter Anvine2c80182005-01-15 22:15:51 +00001602 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001603 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001605 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001606 offset += 1;
1607 } else
1608 offset += 0;
1609 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001610
H. Peter Anvine2c80182005-01-15 22:15:51 +00001611 case 0312:
1612 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001613
Keith Kaniosb7a89542007-04-12 02:40:54 +00001614 case 0313:
1615 ins->rex = 0;
1616 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001617
H. Peter Anvin507ae032008-10-09 15:37:10 -07001618 case4(0314):
H. Peter Anvin23440102007-11-12 21:02:33 -08001619 break;
1620
H. Peter Anvine2c80182005-01-15 22:15:51 +00001621 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001622 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001623 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001624 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625 offset += 1;
1626 } else
1627 offset += 0;
1628 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001629
H. Peter Anvine2c80182005-01-15 22:15:51 +00001630 case 0321:
1631 if (bits == 16) {
1632 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001633 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001634 offset += 1;
1635 } else
1636 offset += 0;
1637 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001638
H. Peter Anvine2c80182005-01-15 22:15:51 +00001639 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001640 case 0323:
1641 break;
1642
Keith Kaniosb7a89542007-04-12 02:40:54 +00001643 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001644 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001646
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 case 0330:
1648 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001649 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 offset += 1;
1651 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001652
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001654 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001655
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001656 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001657 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001658 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001659 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 offset += 1;
1661 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001662
Keith Kanios48af1772007-08-17 07:37:52 +00001663 case 0334:
1664 if (ins->rex & REX_R) {
1665 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001666 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001667 offset += 1;
1668 }
1669 ins->rex &= ~(REX_L|REX_R);
1670 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001671
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001672 case 0335:
1673 break;
1674
H. Peter Anvin962e3052008-08-28 17:47:16 -07001675 case 0336:
1676 case 0337:
1677 break;
1678
H. Peter Anvine2c80182005-01-15 22:15:51 +00001679 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 if (ins->oprs[0].segment != NO_SEG)
1681 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1682 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001683 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 if (size > 0)
1685 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001686 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 offset += size;
1688 }
1689 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001690
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001691 case 0341:
1692 break;
1693
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001694 case 0344:
1695 case 0345:
1696 bytes[0] = c & 1;
1697 switch (ins->oprs[0].basereg) {
1698 case R_CS:
1699 bytes[0] += 0x0E;
1700 break;
1701 case R_DS:
1702 bytes[0] += 0x1E;
1703 break;
1704 case R_ES:
1705 bytes[0] += 0x06;
1706 break;
1707 case R_SS:
1708 bytes[0] += 0x16;
1709 break;
1710 default:
1711 errfunc(ERR_PANIC,
1712 "bizarre 8086 segment register received");
1713 }
1714 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1715 offset++;
1716 break;
1717
1718 case 0346:
1719 case 0347:
1720 bytes[0] = c & 1;
1721 switch (ins->oprs[0].basereg) {
1722 case R_FS:
1723 bytes[0] += 0xA0;
1724 break;
1725 case R_GS:
1726 bytes[0] += 0xA8;
1727 break;
1728 default:
1729 errfunc(ERR_PANIC,
1730 "bizarre 386 segment register received");
1731 }
1732 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1733 offset++;
1734 break;
1735
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001736 case 0360:
1737 break;
1738
1739 case 0361:
1740 bytes[0] = 0x66;
1741 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1742 offset += 1;
1743 break;
1744
1745 case 0362:
1746 case 0363:
1747 bytes[0] = c - 0362 + 0xf2;
1748 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1749 offset += 1;
1750 break;
1751
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001752 case 0364:
1753 case 0365:
1754 break;
1755
Keith Kanios48af1772007-08-17 07:37:52 +00001756 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001757 case 0367:
1758 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001759 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001760 offset += 1;
1761 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001762
H. Peter Anvine2c80182005-01-15 22:15:51 +00001763 case 0370:
1764 case 0371:
1765 case 0372:
1766 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001767
H. Peter Anvine2c80182005-01-15 22:15:51 +00001768 case 0373:
1769 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001770 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001771 offset += 1;
1772 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001773
H. Peter Anvin507ae032008-10-09 15:37:10 -07001774 case4(0100):
1775 case4(0110):
1776 case4(0120):
1777 case4(0130):
1778 case4(0200):
1779 case4(0204):
1780 case4(0210):
1781 case4(0214):
1782 case4(0220):
1783 case4(0224):
1784 case4(0230):
1785 case4(0234):
1786 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001787 ea ea_data;
1788 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001789 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001790 uint8_t *p;
1791 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001792 enum out_type type;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001793 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001794
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001795 if (c <= 0177) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001796 /* pick rfield from operand b (opx) */
1797 rflags = regflag(opx);
1798 rfield = nasm_regvals[opx->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001799 } else {
1800 /* rfield is constant */
1801 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001802 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001803 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001804
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001805 if (!process_ea(opy, &ea_data, bits, ins->addr_size,
1806 rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001807 errfunc(ERR_NONFATAL, "invalid effective address");
1808 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001809
Charles Crayne7e975552007-11-03 22:06:13 -07001810
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811 p = bytes;
1812 *p++ = ea_data.modrm;
1813 if (ea_data.sib_present)
1814 *p++ = ea_data.sib;
1815
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001816 /* DREX suffixes come between the SIB and the displacement */
1817 if (ins->rex & REX_D) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001818 *p++ = (ins->drexdst << 4) |
1819 (ins->rex & REX_OC ? 0x08 : 0) |
1820 (ins->rex & (REX_R|REX_X|REX_B));
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001821 ins->rex = 0;
1822 }
1823
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001825 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001826
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001827 /*
1828 * Make sure the address gets the right offset in case
1829 * the line breaks in the .lst file (BR 1197827)
1830 */
1831 offset += s;
1832 s = 0;
1833
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 switch (ea_data.bytes) {
1835 case 0:
1836 break;
1837 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001838 case 2:
1839 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001840 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001841 data = opy->offset;
1842 warn_overflow(ea_data.bytes, opy);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001844 if (ea_data.rip) {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001845 if (opy->segment == segment) {
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001846 data -= insn_end;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001847 out(offset, segment, &data, OUT_ADDRESS,
1848 ea_data.bytes, NO_SEG, NO_SEG);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001849 } else {
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001850 out(offset, segment, &data, OUT_REL4ADR,
1851 insn_end - offset, opy->segment, opy->wrt);
H. Peter Anvine286c7e2008-10-22 11:15:00 -07001852 }
H. Peter Anvin9f817132008-10-06 19:11:07 -07001853 } else {
1854 type = OUT_ADDRESS;
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001855 out(offset, segment, &data, OUT_ADDRESS,
1856 ea_data.bytes, opy->segment, opy->wrt);
H. Peter Anvin9f817132008-10-06 19:11:07 -07001857 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001858 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001859 default:
1860 /* Impossible! */
1861 errfunc(ERR_PANIC,
1862 "Invalid amount of bytes (%d) for offset?!",
1863 ea_data.bytes);
1864 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001865 }
1866 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001867 }
H. Peter Anvin507ae032008-10-09 15:37:10 -07001868 break;
1869
1870 default:
1871 errfunc(ERR_PANIC, "internal instruction table corrupt"
1872 ": instruction code 0x%02X given", c);
1873 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001874 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001875 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001876}
1877
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001878static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879{
1880 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1881 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1882 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001883 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001884}
1885
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001886static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001887{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001888 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1889 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001890 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001891 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001892}
1893
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001894static int op_rexflags(const operand * o, int mask)
1895{
1896 int32_t flags;
1897 int val;
1898
1899 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1900 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1901 }
1902
H. Peter Anvina4835d42008-05-20 14:21:29 -07001903 flags = nasm_reg_flags[o->basereg];
1904 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001905
1906 return rexflags(val, flags, mask);
1907}
1908
1909static int rexflags(int val, int32_t flags, int mask)
1910{
1911 int rex = 0;
1912
1913 if (val >= 8)
1914 rex |= REX_B|REX_X|REX_R;
1915 if (flags & BITS64)
1916 rex |= REX_W;
1917 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1918 rex |= REX_H;
1919 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1920 rex |= REX_P;
1921
1922 return rex & mask;
1923}
1924
H. Peter Anvin3360d792007-09-11 04:16:57 +00001925static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001926{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001927 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001928
1929 ret = 100;
1930
1931 /*
1932 * Check the opcode
1933 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001934 if (itemp->opcode != instruction->opcode)
1935 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001936
1937 /*
1938 * Count the operands
1939 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001940 if (itemp->operands != instruction->operands)
1941 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001942
1943 /*
1944 * Check that no spurious colons or TOs are present
1945 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001946 for (i = 0; i < itemp->operands; i++)
1947 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1948 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001949
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001950 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001951 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001952 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001953 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001954 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001955
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001956 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1957
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001958 switch (itemp->flags & IF_SMASK) {
1959 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001960 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001961 break;
1962 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001963 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001964 break;
1965 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001966 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001967 break;
1968 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001969 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001970 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001971 case IF_SO:
1972 size[i] = BITS128;
1973 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001974 case IF_SY:
1975 size[i] = BITS256;
1976 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001977 case IF_SZ:
1978 switch (bits) {
1979 case 16:
1980 size[i] = BITS16;
1981 break;
1982 case 32:
1983 size[i] = BITS32;
1984 break;
1985 case 64:
1986 size[i] = BITS64;
1987 break;
1988 }
1989 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001990 default:
1991 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001992 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001993 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001994 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001995 switch (itemp->flags & IF_SMASK) {
1996 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001997 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001998 break;
1999 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002000 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002001 break;
2002 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002003 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002004 break;
2005 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002006 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002007 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002008 case IF_SO:
2009 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002010 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002011 case IF_SY:
2012 asize = BITS256;
2013 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002014 case IF_SZ:
2015 switch (bits) {
2016 case 16:
2017 asize = BITS16;
2018 break;
2019 case 32:
2020 asize = BITS32;
2021 break;
2022 case 64:
2023 asize = BITS64;
2024 break;
2025 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002026 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002027 default:
2028 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002029 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002030 for (i = 0; i < MAX_OPERANDS; i++)
2031 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002032 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002033
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002034 /*
2035 * Check that the operand flags all match up
2036 */
2037 for (i = 0; i < itemp->operands; i++) {
2038 int32_t type = instruction->oprs[i].type;
2039 if (!(type & SIZE_MASK))
2040 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002041
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002042 if (itemp->opd[i] & SAME_AS) {
2043 int j = itemp->opd[i] & ~SAME_AS;
2044 if (type != instruction->oprs[j].type ||
2045 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2046 return 0;
2047 } else if (itemp->opd[i] & ~type ||
2048 ((itemp->opd[i] & SIZE_MASK) &&
2049 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2050 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2051 (type & SIZE_MASK))
2052 return 0;
2053 else
2054 return 1;
2055 }
2056 }
2057
2058 /*
2059 * Check operand sizes
2060 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002061 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002062 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2063 asize = 0;
2064 for (i = 0; i < oprs; i++) {
2065 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2066 int j;
2067 for (j = 0; j < oprs; j++)
2068 size[j] = asize;
2069 break;
2070 }
2071 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002072 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002073 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002074 }
2075
Keith Kaniosb7a89542007-04-12 02:40:54 +00002076 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002077 if (!(itemp->opd[i] & SIZE_MASK) &&
2078 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002079 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002080 }
2081
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002082 /*
2083 * Check template is okay at the set cpu level
2084 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002085 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002086 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002087
Keith Kaniosb7a89542007-04-12 02:40:54 +00002088 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002089 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002090 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002091 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002092 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002093
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002094 /*
2095 * Check if special handling needed for Jumps
2096 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002097 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002098 return 99;
2099
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002100 return ret;
2101}
2102
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002103static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002104 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002105{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002106 bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);
2107
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002108 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002109
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002110 /* REX flags for the rfield operand */
2111 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2112
Keith Kaniosb7a89542007-04-12 02:40:54 +00002113 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002114 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002115 int32_t f;
2116
2117 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002118 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002119 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002120 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002121 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002122
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002123 if (REG_EA & ~f)
2124 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002125
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002126 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2127
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002128 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002129 output->bytes = 0; /* no offset necessary either */
2130 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002131 } else { /* it's a memory reference */
2132 if (input->basereg == -1
2133 && (input->indexreg == -1 || input->scale == 0)) {
2134 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002135 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002136 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002137 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002138 scale = 0;
2139 index = 4;
2140 base = 5;
2141 output->sib = (scale << 6) | (index << 3) | base;
2142 output->bytes = 4;
2143 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002144 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002145 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002146 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002147 output->bytes = (addrbits != 16 ? 4 : 2);
2148 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002149 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002150 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002151 } else { /* it's an indirection */
2152 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002153 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002154 int hb = input->hintbase, ht = input->hinttype;
2155 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002156 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002157 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002158
H. Peter Anvine2c80182005-01-15 22:15:51 +00002159 if (s == 0)
2160 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002161
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002162 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002163 it = nasm_regvals[i];
2164 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002165 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002166 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002167 ix = 0;
2168 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002169
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002170 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002171 bt = nasm_regvals[b];
2172 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002173 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002174 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002175 bx = 0;
2176 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002177
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002178 /* check for a 32/64-bit memory reference... */
2179 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002180 /* it must be a 32/64-bit memory reference. Firstly we have
2181 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002182 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002183
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002184 if (it != -1) {
2185 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2186 sok &= ix;
2187 else
2188 return NULL;
2189 }
2190
2191 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002192 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002193 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002194 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002195 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002196 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002197 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002198
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002199 /* While we're here, ensure the user didn't specify
2200 WORD or QWORD. */
2201 if (input->disp_size == 16 || input->disp_size == 64)
2202 return NULL;
2203
2204 if (addrbits == 16 ||
2205 (addrbits == 32 && !(sok & BITS32)) ||
2206 (addrbits == 64 && !(sok & BITS64)))
2207 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002208
Keith Kaniosb7a89542007-04-12 02:40:54 +00002209 /* now reorganize base/index */
2210 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002211 ((hb == b && ht == EAH_NOTBASE)
2212 || (hb == i && ht == EAH_MAKEBASE))) {
2213 /* swap if hints say so */
2214 t = bt, bt = it, it = t;
2215 t = bx, bx = ix, ix = t;
2216 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002217 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002218 bt = -1, bx = 0, s++;
2219 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2220 /* make single reg base, unless hint */
2221 bt = it, bx = ix, it = -1, ix = 0;
2222 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002223 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002224 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002225 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002226 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002227 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002228 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002229 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002230 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002231 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002232 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002233 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002234 t = ix, ix = bx, bx = t;
2235 }
Keith Kanios48af1772007-08-17 07:37:52 +00002236 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002237 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002238 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002239
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002240 output->rex |= rexflags(it, ix, REX_X);
2241 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002242
Keith Kanios48af1772007-08-17 07:37:52 +00002243 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002244 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002245 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002246
Keith Kaniosb7a89542007-04-12 02:40:54 +00002247 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002248 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002249 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002250 } else {
2251 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002252 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002253 seg == NO_SEG && !forw_ref &&
2254 !(input->eaflags &
2255 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2256 mod = 0;
2257 else if (input->eaflags & EAF_BYTEOFFS ||
2258 (o >= -128 && o <= 127 && seg == NO_SEG
2259 && !forw_ref
2260 && !(input->eaflags & EAF_WORDOFFS)))
2261 mod = 1;
2262 else
2263 mod = 2;
2264 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002265
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002266 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002267 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2268 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002269 } else {
2270 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002271 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002272
Keith Kaniosb7a89542007-04-12 02:40:54 +00002273 if (it == -1)
2274 index = 4, s = 1;
2275 else
2276 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002277
H. Peter Anvine2c80182005-01-15 22:15:51 +00002278 switch (s) {
2279 case 1:
2280 scale = 0;
2281 break;
2282 case 2:
2283 scale = 1;
2284 break;
2285 case 4:
2286 scale = 2;
2287 break;
2288 case 8:
2289 scale = 3;
2290 break;
2291 default: /* then what the smeg is it? */
2292 return NULL; /* panic */
2293 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002294
Keith Kaniosb7a89542007-04-12 02:40:54 +00002295 if (bt == -1) {
2296 base = 5;
2297 mod = 0;
2298 } else {
2299 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002300 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002301 seg == NO_SEG && !forw_ref &&
2302 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002303 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2304 mod = 0;
2305 else if (input->eaflags & EAF_BYTEOFFS ||
2306 (o >= -128 && o <= 127 && seg == NO_SEG
2307 && !forw_ref
2308 && !(input->eaflags & EAF_WORDOFFS)))
2309 mod = 1;
2310 else
2311 mod = 2;
2312 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002313
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002314 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002315 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2316 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002317 output->sib = (scale << 6) | (index << 3) | base;
2318 }
2319 } else { /* it's 16-bit */
2320 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002321
Keith Kaniosb7a89542007-04-12 02:40:54 +00002322 /* check for 64-bit long mode */
2323 if (addrbits == 64)
2324 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002325
H. Peter Anvine2c80182005-01-15 22:15:51 +00002326 /* check all registers are BX, BP, SI or DI */
2327 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2328 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2329 && i != R_SI && i != R_DI))
2330 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002331
Keith Kaniosb7a89542007-04-12 02:40:54 +00002332 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002333 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002334 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002335
H. Peter Anvine2c80182005-01-15 22:15:51 +00002336 if (s != 1 && i != -1)
2337 return NULL; /* no can do, in 16-bit EA */
2338 if (b == -1 && i != -1) {
2339 int tmp = b;
2340 b = i;
2341 i = tmp;
2342 } /* swap */
2343 if ((b == R_SI || b == R_DI) && i != -1) {
2344 int tmp = b;
2345 b = i;
2346 i = tmp;
2347 }
2348 /* have BX/BP as base, SI/DI index */
2349 if (b == i)
2350 return NULL; /* shouldn't ever happen, in theory */
2351 if (i != -1 && b != -1 &&
2352 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2353 return NULL; /* invalid combinations */
2354 if (b == -1) /* pure offset: handled above */
2355 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002356
H. Peter Anvine2c80182005-01-15 22:15:51 +00002357 rm = -1;
2358 if (i != -1)
2359 switch (i * 256 + b) {
2360 case R_SI * 256 + R_BX:
2361 rm = 0;
2362 break;
2363 case R_DI * 256 + R_BX:
2364 rm = 1;
2365 break;
2366 case R_SI * 256 + R_BP:
2367 rm = 2;
2368 break;
2369 case R_DI * 256 + R_BP:
2370 rm = 3;
2371 break;
2372 } else
2373 switch (b) {
2374 case R_SI:
2375 rm = 4;
2376 break;
2377 case R_DI:
2378 rm = 5;
2379 break;
2380 case R_BP:
2381 rm = 6;
2382 break;
2383 case R_BX:
2384 rm = 7;
2385 break;
2386 }
2387 if (rm == -1) /* can't happen, in theory */
2388 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002389
H. Peter Anvine2c80182005-01-15 22:15:51 +00002390 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2391 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2392 mod = 0;
2393 else if (input->eaflags & EAF_BYTEOFFS ||
2394 (o >= -128 && o <= 127 && seg == NO_SEG
2395 && !forw_ref
2396 && !(input->eaflags & EAF_WORDOFFS)))
2397 mod = 1;
2398 else
2399 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002400
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002401 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002402 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002403 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002404 }
2405 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002406 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002407
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002408 output->size = 1 + output->sib_present + output->bytes;
2409 return output;
2410}
2411
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002412static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002413{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002414 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002415 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002416
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002417 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002418
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002419 switch (ins->prefixes[PPS_ASIZE]) {
2420 case P_A16:
2421 valid &= 16;
2422 break;
2423 case P_A32:
2424 valid &= 32;
2425 break;
2426 case P_A64:
2427 valid &= 64;
2428 break;
2429 case P_ASP:
2430 valid &= (addrbits == 32) ? 16 : 32;
2431 break;
2432 default:
2433 break;
2434 }
2435
2436 for (j = 0; j < ins->operands; j++) {
2437 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002438 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002439
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002440 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002441 if (ins->oprs[j].indexreg < EXPR_REG_START
2442 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002443 i = 0;
2444 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002445 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002446
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002447 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002448 if (ins->oprs[j].basereg < EXPR_REG_START
2449 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002450 b = 0;
2451 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002452 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002453
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002454 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002455 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002456
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002457 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002458 int ds = ins->oprs[j].disp_size;
2459 if ((addrbits != 64 && ds > 8) ||
2460 (addrbits == 64 && ds == 16))
2461 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002462 } else {
2463 if (!(REG16 & ~b))
2464 valid &= 16;
2465 if (!(REG32 & ~b))
2466 valid &= 32;
2467 if (!(REG64 & ~b))
2468 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002469
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002470 if (!(REG16 & ~i))
2471 valid &= 16;
2472 if (!(REG32 & ~i))
2473 valid &= 32;
2474 if (!(REG64 & ~i))
2475 valid &= 64;
2476 }
2477 }
2478 }
2479
2480 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002481 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002482 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002483 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002484 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002485 ins->prefixes[PPS_ASIZE] = pref;
2486 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002487 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002488 /* Impossible... */
2489 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002490 ins->addr_size = addrbits; /* Error recovery */
2491 }
2492
2493 defdisp = ins->addr_size == 16 ? 16 : 32;
2494
2495 for (j = 0; j < ins->operands; j++) {
2496 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2497 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2498 != ins->addr_size) {
2499 /* mem_offs sizes must match the address size; if not,
2500 strip the MEM_OFFS bit and match only EA instructions */
2501 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2502 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002503 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002504}